diff --git a/etc/system.conf b/etc/system.conf index 6f09d66f4..adb6b4d4d 100644 --- a/etc/system.conf +++ b/etc/system.conf @@ -255,7 +255,10 @@ service dp8390 SDEVIO # 22 ; pci device 10ec:8029; - uid 0; + io + 300:20 + ; + irq 9; }; service dpeth diff --git a/etc/usr/rc b/etc/usr/rc index f540bdf97..16d8b1a8e 100644 --- a/etc/usr/rc +++ b/etc/usr/rc @@ -184,7 +184,7 @@ start|autoboot) for label in $(get_eth_labels); do driver=$(echo $label | sed 's/\(.*\)_.*/\1/') instance=$(echo $label | sed 's/.*_//') - eval arg=\$${label}_arg + eval arg=\$${driver}_arg if [ ! -z "$arg" ]; then arg=" $arg"; fi arg="-args \"instance=$instance$arg\"" eval up $driver -label $label $arg -period 5HZ diff --git a/minix/commands/netconf/netconf.sh b/minix/commands/netconf/netconf.sh index c9f75ad9f..80f2b3776 100644 --- a/minix/commands/netconf/netconf.sh +++ b/minix/commands/netconf/netconf.sh @@ -109,7 +109,7 @@ cards() card 0 "No Ethernet card (no networking)" card 1 "3Com 501 or 3Com 509 based card" card 2 "Realtek 8029 based card (also emulated by Qemu)" "10EC:8029" - card 3 "NE2000, 3com 503 or WD based card (also emulated by Bochs)" + card 3 "NE2000, 3com 503 or WD based card (also emulated by Qemu, Bochs)" card 4 "lan8710a (on BeagleBone, BeagleBone Black)" n=$first_pcicard for pcicard in $pci_list @@ -197,10 +197,11 @@ drv_params() test "$v" = 1 && echo "Note: After installing, edit $LOCALRC to the right configuration." ;; 2) driver=dp8390; driverargs="dp8390_arg='DPETH0=pci'"; ;; - 3) driver=dp8390; driverargs="dp8390_arg='DPETH0=240:9'"; + 3) driver=dp8390; driverargs="dp8390_arg='DPETH0=300:9'"; test "$v" = 1 && echo "" test "$v" = 1 && echo "Note: After installing, edit $LOCALRC to the right configuration." - test "$v" = 1 && echo " chose option 4, the defaults for emulation by Bochs have been set." + test "$v" = 1 && echo "You may then also have to edit /etc/system.conf ." + test "$v" = 1 && echo "For now, the defaults for emulation by Bochs/Qemu have been set." ;; 4) driver=lan8710a; ;; $first_after_pci) driver="psip0"; ;; diff --git a/minix/drivers/net/Makefile b/minix/drivers/net/Makefile index 069ab5c19..7cd278f2e 100644 --- a/minix/drivers/net/Makefile +++ b/minix/drivers/net/Makefile @@ -18,6 +18,4 @@ SUBDIR+= virtio_net SUBDIR+= lan8710a .endif # ${MACHINE_ARCH} == "earm" -SUBDIR+= uds - .include diff --git a/minix/drivers/net/atl2/atl2.c b/minix/drivers/net/atl2/atl2.c index b07e3536c..e9f332fbd 100644 --- a/minix/drivers/net/atl2/atl2.c +++ b/minix/drivers/net/atl2/atl2.c @@ -1,24 +1,20 @@ /* Attansic/Atheros L2 FastEthernet driver, by D.C. van Moolenbroek */ - -/* No documentation is available for this card. The FreeBSD driver is based +/* + * No documentation is available for this card. The FreeBSD driver is based * heavily on the official Linux driver; this driver is based heavily on both. */ #include #include -#include -#include -#include #include -#include -#include +#include #include #include "atl2.h" #define VERBOSE 0 /* Verbose debugging output */ -#define ATL2_FKEY 1 /* Register Shift+F11 for dumping statistics */ +#define ATL2_FKEY 11 /* Use Shift+Fn to dump statistics (0=off) */ #if VERBOSE #define ATL2_DEBUG(x) printf x @@ -27,24 +23,23 @@ #endif typedef struct { - u32_t hdr; - u32_t vtag; - u8_t data[ATL2_RXD_SIZE - sizeof(u32_t) * 2]; + uint32_t hdr; + uint32_t vtag; + uint8_t data[ATL2_RXD_SIZE - sizeof(uint32_t) * 2]; } rxd_t; static struct { int devind; /* PCI device index */ int irq; /* IRQ number */ int hook_id; /* IRQ hook ID */ - int mode; /* datalink mode */ - volatile u8_t *base; /* base address of memory-mapped registers */ - u32_t size; /* size of memory-mapped area */ - u32_t hwaddr[2]; /* MAC address, in register representation */ + uint8_t *base; /* base address of memory-mapped registers */ + uint32_t size; /* size of memory-mapped area */ + uint32_t hwaddr[2]; /* MAC address, in register representation */ - u8_t *txd_base; /* local address of TxD ring buffer base */ - u32_t *txs_base; /* local address of TxS ring buffer base */ - u8_t *rxd_base_u; /* unaligned base address of RxD ring buffer */ - rxd_t *rxd_base; /* local address of RxD ring buffer base */ + uint8_t *txd_base; /* local address of TxD ring buffer base */ + uint32_t *txs_base; /* local address of TxS ring buffer base */ + uint8_t *rxd_base_u; /* unaligned base address of RxD ring buffer */ + rxd_t *rxd_base; /* local address of RxD ring buffer base */ int rxd_align; /* alignment offset of RxD ring buffer */ @@ -58,50 +53,58 @@ static struct { int txs_num; /* head-tail offset into TxS, in elements */ int rxd_tail; /* tail index into RxD, in elements */ - int flags; /* state flags (ATL2_FLAG_) */ - message read_msg; /* suspended read request (READ_PEND) */ - message write_msg; /* suspended write request (WRITE_PEND) */ - endpoint_t task_endpt; /* requester endpoint (PACK_RCVD|PACK_SENT) */ - size_t recv_count; /* packet size (PACK_RCVD) */ + int rx_avail; /* is there a packet available for receipt? */ eth_stat_t stat; /* statistics */ } state; -#define ATL2_FLAG_RX_AVAIL 0x01 /* packet available for receipt */ -#define ATL2_FLAG_READ_PEND 0x02 /* read request pending */ -#define ATL2_FLAG_WRITE_PEND 0x04 /* write request pending */ -#define ATL2_FLAG_PACK_RCVD 0x08 /* packet received */ -#define ATL2_FLAG_PACK_SENT 0x10 /* packet transmitted */ - -#define ATL2_READ_U8(off) (* (u8_t *) (state.base + (off))) -#define ATL2_READ_U16(off) (* (u16_t *) (state.base + (off))) -#define ATL2_READ_U32(off) (* (u32_t *) (state.base + (off))) -#define ATL2_WRITE_U8(off, val) * (u8_t *) (state.base + (off)) = (val); -#define ATL2_WRITE_U16(off, val) * (u16_t *) (state.base + (off)) = (val); -#define ATL2_WRITE_U32(off, val) * (u32_t *) (state.base + (off)) = (val); +#define ATL2_READ_U8(off) (*(volatile uint8_t *)(state.base + (off))) +#define ATL2_READ_U16(off) (*(volatile uint16_t *)(state.base + (off))) +#define ATL2_READ_U32(off) (*(volatile uint32_t *)(state.base + (off))) +#define ATL2_WRITE_U8(off, val) \ + *(volatile uint8_t *)(state.base + (off)) = (val) +#define ATL2_WRITE_U16(off, val) \ + *(volatile uint16_t *)(state.base + (off)) = (val) +#define ATL2_WRITE_U32(off, val) \ + *(volatile uint32_t *)(state.base + (off)) = (val) #define ATL2_ALIGN_32(n) (((n) + 3) & ~3) -static iovec_s_t iovec[NR_IOREQS]; +static int atl2_init(unsigned int instance, ether_addr_t *addr); +static void atl2_stop(void); +static void atl2_mode(unsigned int mode); +static int atl2_send(struct netdriver_data *data, size_t size); +static ssize_t atl2_recv(struct netdriver_data *data, size_t max); +static void atl2_stat(eth_stat_t *stat); +static void atl2_intr(unsigned int mask); +static void atl2_other(const message *m_ptr, int ipc_status); -static int instance; +static const struct netdriver atl2_table = { + .ndr_init = atl2_init, + .ndr_stop = atl2_stop, + .ndr_mode = atl2_mode, + .ndr_recv = atl2_recv, + .ndr_send = atl2_send, + .ndr_stat = atl2_stat, + .ndr_intr = atl2_intr, + .ndr_other = atl2_other +}; -/*===========================================================================* - * atl2_read_vpd * - *===========================================================================*/ -static int atl2_read_vpd(int index, u32_t *res) +/* + * Read a value from the VPD register area. + */ +static int +atl2_read_vpd(int index, uint32_t * res) { - /* Read a value from the VPD register area. - */ - u32_t off, val; + uint32_t off, val; int i; ATL2_WRITE_U32(ATL2_VPD_DATA_REG, 0); - off = ATL2_VPD_REGBASE + index * sizeof(u32_t); + off = ATL2_VPD_REGBASE + index * sizeof(uint32_t); ATL2_WRITE_U32(ATL2_VPD_CAP_REG, - (off << ATL2_VPD_CAP_ADDR_SHIFT) & ATL2_VPD_CAP_ADDR_MASK); + (off << ATL2_VPD_CAP_ADDR_SHIFT) & ATL2_VPD_CAP_ADDR_MASK); for (i = 0; i < ATL2_VPD_NTRIES; i++) { micro_delay(ATL2_VPD_DELAY); @@ -120,15 +123,14 @@ static int atl2_read_vpd(int index, u32_t *res) return TRUE; } -/*===========================================================================* - * atl2_get_vpd_hwaddr * - *===========================================================================*/ -static int atl2_get_vpd_hwaddr(void) +/* + * Read the MAC address from the EEPROM, using the Vital Product Data register + * interface. + */ +static int +atl2_get_vpd_hwaddr(void) { - /* Read the MAC address from the EEPROM, using the Vital Product Data - * register interface. - */ - u32_t key, val; + uint32_t key, val; int i, n, found[2]; /* No idea, copied from FreeBSD which copied it from Linux. */ @@ -144,7 +146,8 @@ static int atl2_get_vpd_hwaddr(void) return FALSE; #endif - /* Read out the set of key/value pairs. Look for the two parts that + /* + * Read out the set of key/value pairs. Look for the two parts that * make up the MAC address. */ found[0] = found[1] = FALSE; @@ -173,14 +176,13 @@ static int atl2_get_vpd_hwaddr(void) return found[0] && found[1]; } -/*===========================================================================* - * atl2_get_hwaddr * - *===========================================================================*/ -static void atl2_get_hwaddr(void) +/* + * Get the MAC address of the card. First try the EEPROM; if that fails, just + * use whatever the card was already set to. + */ +static void +atl2_get_hwaddr(ether_addr_t * addr) { - /* Get the MAC address of the card. First try the EEPROM; if that - * fails, just use whatever the card was already set to. - */ if (!atl2_get_vpd_hwaddr()) { printf("ATL2: unable to read from VPD\n"); @@ -189,23 +191,29 @@ static void atl2_get_hwaddr(void) state.hwaddr[1] = ATL2_READ_U32(ATL2_HWADDR1_REG) & 0xffff; } - ATL2_DEBUG(("ATL2: MAC address %04lx%08lx\n", - state.hwaddr[1], state.hwaddr[0])); + ATL2_DEBUG(("ATL2: MAC address %04x%08x\n", + state.hwaddr[1], state.hwaddr[0])); + + addr->ea_addr[0] = state.hwaddr[1] >> 8; + addr->ea_addr[1] = state.hwaddr[1] & 0xff; + addr->ea_addr[2] = state.hwaddr[0] >> 24; + addr->ea_addr[3] = (state.hwaddr[0] >> 16) & 0xff; + addr->ea_addr[4] = (state.hwaddr[0] >> 8) & 0xff; + addr->ea_addr[5] = state.hwaddr[0] & 0xff; } -/*===========================================================================* - * atl2_read_mdio * - *===========================================================================*/ -static int atl2_read_mdio(int addr, u16_t *res) +/* + * Read a MII PHY register using MDIO. + */ +static int +atl2_read_mdio(int addr, uint16_t * res) { - /* Read a MII PHY register using MDIO. - */ - u32_t rval; + uint32_t rval; int i; rval = ((addr << ATL2_MDIO_ADDR_SHIFT) & ATL2_MDIO_ADDR_MASK) | - ATL2_MDIO_START | ATL2_MDIO_READ | ATL2_MDIO_SUP_PREAMBLE | - ATL2_MDIO_CLK_25_4; + ATL2_MDIO_START | ATL2_MDIO_READ | ATL2_MDIO_SUP_PREAMBLE | + ATL2_MDIO_CLK_25_4; ATL2_WRITE_U32(ATL2_MDIO_REG, rval); @@ -220,54 +228,52 @@ static int atl2_read_mdio(int addr, u16_t *res) if (i == ATL2_MDIO_NTRIES) return FALSE; - *res = (u16_t) (rval & ATL2_MDIO_DATA_MASK); + *res = (uint16_t)(rval & ATL2_MDIO_DATA_MASK); return TRUE; } -/*===========================================================================* - * atl2_alloc_dma * - *===========================================================================*/ -static int atl2_alloc_dma(void) +/* + * Allocate DMA ring buffers. + */ +static int +atl2_alloc_dma(void) { - /* Allocate DMA ring buffers. - */ - state.txd_base = alloc_contig(ATL2_TXD_BUFSIZE, - AC_ALIGN4K, &state.txd_phys); - state.txs_base = alloc_contig(ATL2_TXS_COUNT * sizeof(u32_t), - AC_ALIGN4K, &state.txs_phys); + state.txd_base = alloc_contig(ATL2_TXD_BUFSIZE, AC_ALIGN4K, + &state.txd_phys); + state.txs_base = alloc_contig(ATL2_TXS_COUNT * sizeof(uint32_t), + AC_ALIGN4K, &state.txs_phys); - /* The data buffer in each RxD descriptor must be 128-byte aligned. + /* + * The data buffer in each RxD descriptor must be 128-byte aligned. * The two Tx buffers merely require a 4-byte start alignment. */ state.rxd_align = 128 - offsetof(rxd_t, data); - state.rxd_base_u = - alloc_contig(state.rxd_align + ATL2_RXD_COUNT * ATL2_RXD_SIZE, - AC_ALIGN4K, &state.rxd_phys); + state.rxd_base_u = alloc_contig(state.rxd_align + + ATL2_RXD_COUNT * ATL2_RXD_SIZE, AC_ALIGN4K, &state.rxd_phys); /* Unlike mmap, alloc_contig returns NULL on failure. */ if (!state.txd_base || !state.txs_base || !state.rxd_base_u) return ENOMEM; - state.rxd_base = (rxd_t *) (state.rxd_base_u + state.rxd_align); + state.rxd_base = (rxd_t *)(state.rxd_base_u + state.rxd_align); state.rxd_phys += state.rxd_align; /* Zero out just in case. */ memset(state.txd_base, 0, ATL2_TXD_BUFSIZE); - memset(state.txs_base, 0, ATL2_TXS_COUNT * sizeof(u32_t)); + memset(state.txs_base, 0, ATL2_TXS_COUNT * sizeof(uint32_t)); memset(state.rxd_base, 0, ATL2_RXD_COUNT * ATL2_RXD_SIZE); return OK; } -/*===========================================================================* - * atl2_stop * - *===========================================================================*/ -static int atl2_stop(void) +/* + * Stop the device. + */ +static void +atl2_stop(void) { - /* Stop the device. - */ - u32_t val; + uint32_t val; int i; /* Clear and disable interrupts. */ @@ -292,18 +298,16 @@ static int atl2_stop(void) micro_delay(ATL2_IDLE_DELAY); } - /* The caller will generally ignore this return value. */ - return (i < ATL2_IDLE_NTRIES); + assert(i < ATL2_IDLE_NTRIES); } -/*===========================================================================* - * atl2_reset * - *===========================================================================*/ -static int atl2_reset(void) +/* + * Reset the device to a known good state. + */ +static int +atl2_reset(void) { - /* Reset the device to a known good state. - */ - u32_t val; + uint32_t val; int i; /* Issue a soft reset, and wait for the device to respond. */ @@ -331,44 +335,42 @@ static int atl2_reset(void) return (i < ATL2_IDLE_NTRIES); } -/*===========================================================================* - * atl2_set_mode * - *===========================================================================*/ -static void atl2_set_mode(void) +/* + * Reconfigure the device's promiscuity, multicast, and broadcast mode + * settings. + */ +static void +atl2_mode(unsigned int mode) { - /* Reconfigure the device's promiscuity, multicast, and broadcast mode - * settings. - */ - u32_t val; + uint32_t val; val = ATL2_READ_U32(ATL2_MAC_REG); val &= ~(ATL2_MAC_PROMISC_EN | ATL2_MAC_MCAST_EN | ATL2_MAC_BCAST_EN); - if (state.mode & DL_PROMISC_REQ) + if (mode & NDEV_PROMISC) val |= ATL2_MAC_PROMISC_EN; - if (state.mode & DL_MULTI_REQ) + if (mode & NDEV_MULTI) val |= ATL2_MAC_MCAST_EN; - if (state.mode & DL_BROAD_REQ) + if (mode & NDEV_BROAD) val |= ATL2_MAC_BCAST_EN; ATL2_WRITE_U32(ATL2_MAC_REG, val); } -/*===========================================================================* - * atl2_setup * - *===========================================================================*/ -static int atl2_setup(void) +/* + * Set up the device for normal operation. + */ +static int +atl2_setup(void) { - /* Set up the device for normal operation. - */ - u32_t val; + uint32_t val; atl2_stop(); if (!atl2_reset()) return FALSE; - /* Initialize PCIE module. Magic. */ + /* Initialize PCIe module. Magic. */ ATL2_WRITE_U32(ATL2_LTSSM_TESTMODE_REG, ATL2_LTSSM_TESTMODE_DEFAULT); ATL2_WRITE_U32(ATL2_DLL_TX_CTRL_REG, ATL2_DLL_TX_CTRL_DEFAULT); @@ -390,7 +392,8 @@ static int atl2_setup(void) ATL2_WRITE_U32(ATL2_RXD_ADDR_LO_REG, state.rxd_phys); ATL2_WRITE_U16(ATL2_RXD_COUNT_REG, ATL2_RXD_COUNT); - ATL2_WRITE_U16(ATL2_TXD_BUFSIZE_REG, ATL2_TXD_BUFSIZE / sizeof(u32_t)); + ATL2_WRITE_U16(ATL2_TXD_BUFSIZE_REG, + ATL2_TXD_BUFSIZE / sizeof(uint32_t)); ATL2_WRITE_U16(ATL2_TXS_COUNT_REG, ATL2_TXS_COUNT); /* A whole lot of other initialization copied from Linux/FreeBSD. */ @@ -415,7 +418,7 @@ static int atl2_setup(void) /* Reset descriptors, and enable DMA. */ state.txd_tail = state.txs_tail = state.rxd_tail = 0; state.txd_num = state.txs_num = 0; - state.flags &= ~ATL2_FLAG_RX_AVAIL; + state.rx_avail = FALSE; ATL2_WRITE_U16(ATL2_TXD_IDX_REG, 0); ATL2_WRITE_U16(ATL2_RXD_IDX_REG, 0); @@ -439,13 +442,14 @@ static int atl2_setup(void) /* Configure MAC. */ ATL2_WRITE_U32(ATL2_MAC_REG, ATL2_MAC_DEFAULT); - /* Inet does not tell us about the multicast addresses that it is + /* + * Inet does not tell us about the multicast addresses that it is * interested in, so we have to simply accept all multicast packets. */ ATL2_WRITE_U32(ATL2_MHT0_REG, 0xffffffff); ATL2_WRITE_U32(ATL2_MHT1_REG, 0xffffffff); - atl2_set_mode(); + atl2_mode(NDEV_NOMODE); /* Enable Tx/Rx. */ val = ATL2_READ_U32(ATL2_MAC_REG); @@ -454,14 +458,13 @@ static int atl2_setup(void) return TRUE; } -/*===========================================================================* - * atl2_probe * - *===========================================================================*/ -static int atl2_probe(int skip) +/* + * Find a matching PCI device. + */ +static int +atl2_probe(int skip) { - /* Find a matching PCI device. - */ - u16_t vid, did; + uint16_t vid, did; #if VERBOSE char *dname; #endif @@ -482,8 +485,7 @@ static int atl2_probe(int skip) #if VERBOSE dname = pci_dev_name(vid, did); ATL2_DEBUG(("ATL2: found %s (%x/%x) at %s\n", - dname ? dname : "", vid, did, - pci_slot_name(devind))); + dname ? dname : "", vid, did, pci_slot_name(devind))); #endif pci_reserve(devind); @@ -491,23 +493,17 @@ static int atl2_probe(int skip) return devind; } -/*===========================================================================* - * atl2_init * - *===========================================================================*/ -static void atl2_init(int devind) +/* + * Initialize the device. + */ +static void +atl2_init_hw(int devind, ether_addr_t * addr) { - /* Initialize the device. - */ - u32_t bar; + uint32_t bar; int r, flag; /* Initialize global state. */ state.devind = devind; - state.mode = DL_NOMODE; - state.flags = 0; - state.recv_count = 0; - - memset(&state.stat, 0, sizeof(state.stat)); if ((r = pci_get_bar(devind, PCI_BAR, &bar, &state.size, &flag)) != OK) panic("unable to retrieve bar: %d", r); @@ -515,7 +511,7 @@ static void atl2_init(int devind) if (state.size < ATL2_MIN_MMAP_SIZE || flag) panic("invalid register bar"); - state.base = vm_map_phys(SELF, (void *) bar, state.size); + state.base = vm_map_phys(SELF, (void *)bar, state.size); if (state.base == MAP_FAILED) panic("unable to map in registers"); @@ -534,18 +530,17 @@ static void atl2_init(int devind) if ((r = sys_irqenable(&state.hook_id)) != OK) panic("unable to enable IRQ: %d", r); - atl2_get_hwaddr(); + atl2_get_hwaddr(addr); atl2_setup(); } -/*===========================================================================* - * atl2_tx_stat * - *===========================================================================*/ -static void atl2_tx_stat(u32_t stat) +/* + * Update statistics for packet transmission. + */ +static void +atl2_tx_stat(uint32_t stat) { - /* Update statistics for packet transmission. - */ if (stat & ATL2_TXS_SUCCESS) state.stat.ets_packetT++; @@ -566,13 +561,12 @@ static void atl2_tx_stat(u32_t stat) state.stat.ets_fifoUnder++; } -/*===========================================================================* - * atl2_rx_stat * - *===========================================================================*/ -static void atl2_rx_stat(u32_t stat) +/* + * Update statistics for packet receipt. + */ +static void +atl2_rx_stat(uint32_t stat) { - /* Update statistics for packet receipt. - */ if (stat & ATL2_RXD_SUCCESS) state.stat.ets_packetR++; @@ -589,14 +583,13 @@ static void atl2_rx_stat(u32_t stat) state.stat.ets_frameAll++; } -/*===========================================================================* - * atl2_tx_advance * - *===========================================================================*/ -static int atl2_tx_advance(void) +/* + * Advance the TxD/TxS tails by as many sent packets as found. + */ +static int +atl2_tx_advance(void) { - /* Advance the TxD/TxS tails by as many sent packets as found. - */ - u32_t stat, size, dsize; + uint32_t stat, size, dsize; int advanced; advanced = FALSE; @@ -608,32 +601,33 @@ static int atl2_tx_advance(void) if (!(stat & ATL2_TXS_UPDATE)) break; - /* The packet size from the status must match the packet size - * we put in. If they don't, there's not much we can do.. + /* + * The packet size from the status must match the packet size + * we put in. If they don't, there's not much we can do.. */ size = stat & ATL2_TXS_SIZE_MASK; - assert((u32_t) state.txd_tail <= - ATL2_TXD_BUFSIZE - sizeof(u32_t)); - dsize = * (u32_t *) (state.txd_base + state.txd_tail); + assert((uint32_t)state.txd_tail <= + ATL2_TXD_BUFSIZE - sizeof(uint32_t)); + dsize = + *(volatile uint32_t *)(state.txd_base + state.txd_tail); if (size != dsize) printf("ATL2: TxD/TxS size mismatch (%x vs %x)\n", - size, dsize); + size, dsize); /* Advance tails accordingly. */ - size = sizeof(u32_t) + ATL2_ALIGN_32(dsize); - assert((u32_t) state.txd_num >= size); + size = sizeof(uint32_t) + ATL2_ALIGN_32(dsize); + assert((uint32_t)state.txd_num >= size); state.txd_tail = (state.txd_tail + size) % ATL2_TXD_BUFSIZE; state.txd_num -= size; state.txs_tail = (state.txs_tail + 1) % ATL2_TXS_COUNT; state.txs_num--; - if (stat & ATL2_TXS_SUCCESS) { + if (stat & ATL2_TXS_SUCCESS) ATL2_DEBUG(("ATL2: successfully sent packet\n")); - } else { + else ATL2_DEBUG(("ATL2: failed to send packet\n")); - } /* Update statistics. */ atl2_tx_stat(stat); @@ -644,18 +638,18 @@ static int atl2_tx_advance(void) return advanced; } -/*===========================================================================* - * atl2_rx_advance * - *===========================================================================*/ -static void atl2_rx_advance(int next) +/* + * Advance the RxD tail by as many failed receipts as possible, and see if + * there is an actual packet left to receive. If 'next' is set, the packet at + * the current tail has been processed. + */ +static void +atl2_rx_advance(int next) { - /* Advance the RxD tail by as many failed receipts as possible, and - * see if there is an actual packet left to receive. If 'next' is set, - * the packet at the current tail has been processed. - */ int update_tail; rxd_t *rxd; - u32_t hdr, size; + uint32_t hdr; + size_t size; update_tail = FALSE; @@ -665,10 +659,10 @@ static void atl2_rx_advance(int next) ATL2_DEBUG(("ATL2: successfully received packet\n")); - state.flags &= ~ATL2_FLAG_RX_AVAIL; + state.rx_avail = FALSE; } - assert(!(state.flags & ATL2_FLAG_RX_AVAIL)); + assert(!state.rx_avail); for (;;) { /* Check the RxD tail for updates. */ @@ -679,21 +673,23 @@ static void atl2_rx_advance(int next) if (!(hdr & ATL2_RXD_UPDATE)) break; - rxd->hdr = hdr & ~(ATL2_RXD_UPDATE); + rxd->hdr = hdr & ~ATL2_RXD_UPDATE; /* Update statistics. */ atl2_rx_stat(hdr); - /* Stop at the first successful receipt. The packet will be + /* + * Stop at the first successful receipt. The packet will be * picked up by Inet later. */ size = hdr & ATL2_RXD_SIZE_MASK; - if ((hdr & ATL2_RXD_SUCCESS) && size >= ETH_MIN_PACK_SIZE) { - ATL2_DEBUG(("ATL2: packet available, size %ld\n", - size)); + if ((hdr & ATL2_RXD_SUCCESS) && + size >= ETH_MIN_PACK_SIZE + ETH_CRC_SIZE) { + ATL2_DEBUG(("ATL2: packet available, size %zu\n", + size)); - state.flags |= ATL2_FLAG_RX_AVAIL; + state.rx_avail = TRUE; break; } @@ -712,223 +708,81 @@ static void atl2_rx_advance(int next) } } -/*===========================================================================* - * atl2_reply * - *===========================================================================*/ -static void atl2_reply(void) +/* + * Receive a packet. + */ +static ssize_t +atl2_recv(struct netdriver_data * data, size_t max) { - /* Send a task reply to Inet. - */ - message m; - int r, flags; - - flags = DL_NOFLAGS; - if (state.flags & ATL2_FLAG_PACK_SENT) - flags |= DL_PACK_SEND; - if (state.flags & ATL2_FLAG_PACK_RCVD) - flags |= DL_PACK_RECV; - - m.m_type = DL_TASK_REPLY; - m.m_netdrv_net_dl_task.flags = flags; - m.m_netdrv_net_dl_task.count = state.recv_count; - - ATL2_DEBUG(("ATL2: sending reply, flags %x count %d\n", flags, - m.m_netdrv_net_dl_task.count)); - - if ((r = ipc_send(state.task_endpt, &m)) != OK) - panic("unable to reply: %d", r); - - state.flags &= ~(ATL2_FLAG_PACK_SENT | ATL2_FLAG_PACK_RCVD); - state.recv_count = 0; -} - -/*===========================================================================* - * atl2_readv * - *===========================================================================*/ -static void atl2_readv(const message *m, int from_int) -{ - /* Read packet data. - */ rxd_t *rxd; - iovec_s_t *iovp; - size_t count, off, left, size; - u8_t *pos; - int i, j, r, batch; - - /* We can deal with only one read request from Inet at a time. */ - assert(from_int || !(state.flags & ATL2_FLAG_READ_PEND)); - - state.task_endpt = m->m_source; + size_t size; /* Are there any packets available at all? */ - if (!(state.flags & ATL2_FLAG_RX_AVAIL)) - goto suspend; + if (!state.rx_avail) + return SUSPEND; - /* Get the first available packet's size. Cut off the CRC. */ + /* Get the first available packet's size. Cut off the CRC. */ rxd = &state.rxd_base[state.rxd_tail]; - count = rxd->hdr & ATL2_RXD_SIZE_MASK; - count -= ETH_CRC_SIZE; + size = rxd->hdr & ATL2_RXD_SIZE_MASK; + size -= ETH_CRC_SIZE; - ATL2_DEBUG(("ATL2: readv: found packet with length %d\n", count)); + ATL2_DEBUG(("ATL2: receiving packet with length %zu\n", size)); + + /* Truncate large packets. */ + if (size > max) + size = max; /* Copy out the packet. */ - off = 0; - left = count; - pos = rxd->data; + netdriver_copyout(data, 0, rxd->data, size); - for (i = 0; i < m->m_net_netdrv_dl_readv_s.count && left > 0; i += batch) { - /* Copy in the next batch. */ - batch = MIN(m->m_net_netdrv_dl_readv_s.count - i, NR_IOREQS); - - r = sys_safecopyfrom(m->m_source, - m->m_net_netdrv_dl_readv_s.grant, off, (vir_bytes) iovec, - batch * sizeof(iovec[0])); - if (r != OK) - panic("vector copy failed: %d", r); - - /* Copy out each element in the batch, until we run out. */ - for (j = 0, iovp = iovec; j < batch && left > 0; j++, iovp++) { - size = MIN(iovp->iov_size, left); - - r = sys_safecopyto(m->m_source, iovp->iov_grant, 0, - (vir_bytes) pos, size); - if (r != OK) - panic("safe copy failed: %d", r); - - pos += size; - left -= size; - } - - off += batch * sizeof(iovec[0]); - } - - /* Not sure what to do here. Inet shouldn't mess this up anyway. */ - if (left > 0) { - printf("ATL2: truncated packet of %d bytes by %d bytes\n", - count, left); - count -= left; - } - - /* We are done with this packet. Move on to the next. */ + /* We are done with this packet. Move on to the next. */ atl2_rx_advance(TRUE /*next*/); - /* We have now successfully received a packet. */ - state.flags &= ~ATL2_FLAG_READ_PEND; - state.flags |= ATL2_FLAG_PACK_RCVD; - state.recv_count = count; - - /* If called from the interrupt handler, the caller will reply. */ - if (!from_int) - atl2_reply(); - - return; - -suspend: - /* No packets are available at this time. If we were not already - * trying to resume receipt, save the read request for later, and tell - * Inet that the request has been suspended. - */ - if (from_int) - return; - - state.flags |= ATL2_FLAG_READ_PEND; - state.read_msg = *m; - - atl2_reply(); + return size; } -/*===========================================================================* - * atl2_writev * - *===========================================================================*/ -static void atl2_writev(const message *m, int from_int) +/* + * Send a packet. + */ +static int +atl2_send(struct netdriver_data * data, size_t size) { - /* Write packet data. - */ - iovec_s_t *iovp; - size_t off, count, left, pos, skip; - vir_bytes size; - u8_t *sizep; - int i, j, r, batch, maxnum; + size_t pos, chunk; + uint8_t *sizep; - /* We can deal with only one write request from Inet at a time. */ - assert(from_int || !(state.flags & ATL2_FLAG_WRITE_PEND)); - - state.task_endpt = m->m_source; - - /* If we are already certain that the packet won't fit, bail out. - * Keep at least some space between TxD head and tail, as it is not - * clear whether the device deals well with the case that they collide. + /* + * If the packet won't fit, bail out. Keep at least some space between + * TxD head and tail, as it is not clear whether the device deals well + * with the case that they collide. */ if (state.txs_num >= ATL2_TXS_COUNT) - goto suspend; - maxnum = ATL2_TXD_BUFSIZE - ETH_MIN_PACK_SIZE - sizeof(u32_t); - if (state.txd_num >= maxnum) - goto suspend; + return SUSPEND; - /* Optimistically try to copy in the data; suspend if it turns out - * that it does not fit. - */ - off = 0; - count = 0; - left = state.txd_num - sizeof(u32_t); + if (state.txd_num + sizeof(uint32_t) + ATL2_ALIGN_32(size) >= + ATL2_TXD_BUFSIZE) + return SUSPEND; + + /* Copy in the packet. */ pos = (state.txd_tail + state.txd_num + - sizeof(u32_t)) % ATL2_TXD_BUFSIZE; - - for (i = 0; i < m->m_net_netdrv_dl_writev_s.count; i += batch) { - /* Copy in the next batch. */ - batch = MIN(m->m_net_netdrv_dl_writev_s.count - i, NR_IOREQS); - - r = sys_safecopyfrom(m->m_source, - m->m_net_netdrv_dl_writev_s.grant, off, (vir_bytes) iovec, - batch * sizeof(iovec[0])); - if (r != OK) - panic("vector copy failed: %d", r); - - /* Copy in each element in the batch. */ - for (j = 0, iovp = iovec; j < batch; j++, iovp++) { - size = iovp->iov_size; - if (size > left) - goto suspend; - - skip = 0; - if (size > ATL2_TXD_BUFSIZE - pos) { - skip = ATL2_TXD_BUFSIZE - pos; - r = sys_safecopyfrom(m->m_source, - iovp->iov_grant, 0, - (vir_bytes) (state.txd_base + pos), - skip); - if (r != OK) - panic("safe copy failed: %d", r); - pos = 0; - } - - r = sys_safecopyfrom(m->m_source, iovp->iov_grant, - skip, (vir_bytes) (state.txd_base + pos), - size - skip); - if (r != OK) - panic("safe copy failed: %d", r); - - pos = (pos + size - skip) % ATL2_TXD_BUFSIZE; - left -= size; - count += size; - } - - off += batch * sizeof(iovec[0]); - } - - assert(count <= ETH_MAX_PACK_SIZE_TAGGED); + sizeof(uint32_t)) % ATL2_TXD_BUFSIZE; + chunk = ATL2_TXD_BUFSIZE - pos; + if (size > chunk) { + netdriver_copyin(data, 0, state.txd_base + pos, chunk); + netdriver_copyin(data, chunk, state.txd_base, size - chunk); + } else + netdriver_copyin(data, 0, state.txd_base + pos, size); /* Write the length to the DWORD right before the packet. */ sizep = state.txd_base + - (state.txd_tail + state.txd_num) % ATL2_TXD_BUFSIZE; - * (u32_t *) sizep = count; + (state.txd_tail + state.txd_num) % ATL2_TXD_BUFSIZE; + *(volatile uint32_t *)sizep = size; /* Update the TxD head. */ - state.txd_num += sizeof(u32_t) + ATL2_ALIGN_32(count); - pos = ATL2_ALIGN_32(pos) % ATL2_TXD_BUFSIZE; - assert((int) pos == - (state.txd_tail + state.txd_num) % ATL2_TXD_BUFSIZE); + state.txd_num += sizeof(uint32_t) + ATL2_ALIGN_32(size); + pos = ATL2_ALIGN_32(pos + size) % ATL2_TXD_BUFSIZE; + assert((int)pos == + (state.txd_tail + state.txd_num) % ATL2_TXD_BUFSIZE); /* Initialize and update the TxS head. */ state.txs_base[(state.txs_tail + state.txs_num) % ATL2_TXS_COUNT] = 0; @@ -937,69 +791,46 @@ static void atl2_writev(const message *m, int from_int) /* Tell the device about our new position. */ __insn_barrier(); - ATL2_WRITE_U32(ATL2_TXD_IDX_REG, pos / sizeof(u32_t)); + ATL2_WRITE_U32(ATL2_TXD_IDX_REG, pos / sizeof(uint32_t)); - /* We have now successfully set up the transmission of a packet. */ - state.flags &= ~ATL2_FLAG_WRITE_PEND; - state.flags |= ATL2_FLAG_PACK_SENT; - - /* If called from the interrupt handler, the caller will reply. */ - if (!from_int) - atl2_reply(); - - return; - -suspend: - /* We cannot transmit the packet at this time. If we were not already - * trying to resume transmission, save the write request for later, - * and tell Inet that the request has been suspended. - */ - if (from_int) - return; - - state.flags |= ATL2_FLAG_WRITE_PEND; - state.write_msg = *m; - - atl2_reply(); + return OK; } -/*===========================================================================* - * atl2_intr * - *===========================================================================*/ -static void atl2_intr(const message *UNUSED(m)) +/* + * Process an interrupt. + */ +static void +atl2_intr(unsigned int __unused mask) { - /* Interrupt received. - */ - u32_t val; - int r, try_write, try_read; + uint32_t val; + int r, try_send, try_recv; /* Clear and disable interrupts. */ val = ATL2_READ_U32(ATL2_ISR_REG); ATL2_WRITE_U32(ATL2_ISR_REG, val | ATL2_ISR_DISABLE); - ATL2_DEBUG(("ATL2: interrupt (0x%08lx)\n", val)); + ATL2_DEBUG(("ATL2: interrupt (0x%08x)\n", val)); /* If an error occurred, reset the card. */ if (val & (ATL2_ISR_DMAR_TIMEOUT | ATL2_ISR_DMAW_TIMEOUT | - ATL2_ISR_PHY_LINKDOWN)) { + ATL2_ISR_PHY_LINKDOWN)) atl2_setup(); - } - try_write = try_read = FALSE; + try_send = try_recv = FALSE; /* Process sent data, and possibly send pending data. */ if (val & ATL2_ISR_TX_EVENT) { if (atl2_tx_advance()) - try_write = (state.flags & ATL2_FLAG_WRITE_PEND); + try_send = TRUE; } /* Receive new data, and possible satisfy a pending receive request. */ if (val & ATL2_ISR_RX_EVENT) { - if (!(state.flags & ATL2_FLAG_RX_AVAIL)) { + if (!state.rx_avail) { atl2_rx_advance(FALSE /*next*/); - try_read = (state.flags & ATL2_FLAG_READ_PEND); + try_recv = TRUE; } } @@ -1009,75 +840,33 @@ static void atl2_intr(const message *UNUSED(m)) if ((r = sys_irqenable(&state.hook_id)) != OK) panic("unable to enable IRQ: %d", r); - /* Attempt to satisfy pending write and read requests. */ - if (try_write) - atl2_writev(&state.write_msg, TRUE /*from_int*/); - if (try_read) - atl2_readv(&state.read_msg, TRUE /*from_int*/); - if (state.flags & (ATL2_FLAG_PACK_SENT | ATL2_FLAG_PACK_RCVD)) - atl2_reply(); + /* Attempt to satisfy pending send and receive requests. */ + if (try_send) + netdriver_send(); + if (try_recv) + netdriver_recv(); } -/*===========================================================================* - * atl2_conf * - *===========================================================================*/ -static void atl2_conf(message *m) +/* + * Copy out statistics. + */ +static void +atl2_stat(eth_stat_t * stat) { - /* Configure the mode of the card. - */ - ether_addr_t addr; - int r; - state.mode = m->m_net_netdrv_dl_conf.mode; - - atl2_set_mode(); - - addr.ea_addr[0] = state.hwaddr[1] >> 8; - addr.ea_addr[1] = state.hwaddr[1] & 0xff; - addr.ea_addr[2] = state.hwaddr[0] >> 24; - addr.ea_addr[3] = (state.hwaddr[0] >> 16) & 0xff; - addr.ea_addr[4] = (state.hwaddr[0] >> 8) & 0xff; - addr.ea_addr[5] = state.hwaddr[0] & 0xff; - - memcpy(m->m_netdrv_net_dl_conf.hw_addr, &addr, - sizeof(m->m_netdrv_net_dl_conf.hw_addr)); - - m->m_type = DL_CONF_REPLY; - m->m_netdrv_net_dl_conf.stat = OK; - - if ((r = ipc_send(m->m_source, m)) != OK) - printf("ATL2: unable to send reply (%d)\n", r); + memcpy(stat, &state.stat, sizeof(*stat)); } -/*===========================================================================* - * atl2_getstat * - *===========================================================================*/ -static void atl2_getstat(message *m) +/* + * Dump link status. + */ +static void +atl2_dump_link(void) { - /* Copy out statistics. - */ - int r; - - sys_safecopyto(m->m_source, m->m_net_netdrv_dl_getstat_s.grant, 0, - (vir_bytes) &state.stat, sizeof(state.stat)); - - m->m_type = DL_STAT_REPLY; - - if ((r = ipc_send(m->m_source, m)) != OK) - printf("ATL2: unable to send reply (%d)\n", r); -} - -/*===========================================================================* - * atl2_dump_link * - *===========================================================================*/ -static void atl2_dump_link(void) -{ - /* Dump link status. - */ - u16_t val; + uint16_t val; int link_up; - /* The link status bit is latched. Read the status register twice. */ + /* The link status bit is latched. Read the status register twice. */ atl2_read_mdio(ATL2_MII_BMSR, &val); if (!atl2_read_mdio(ATL2_MII_BMSR, &val)) return; @@ -1104,13 +893,12 @@ static void atl2_dump_link(void) printf("%s duplex)", (val & ATL2_MII_PSSR_DUPLEX) ? "full" : "half"); } -/*===========================================================================* - * atl2_dump * - *===========================================================================*/ -static void atl2_dump(void) +/* + * Dump statistics. + */ +static void +atl2_dump(void) { - /* Dump statistics. - */ printf("\n"); printf("Attansic L2 statistics:\n"); @@ -1143,151 +931,94 @@ static void atl2_dump(void) printf("TxS tail: %8d\t", state.txs_tail); printf("TxS count: %8d\n", state.txs_num); - printf("flags: 0x%04x\t", state.flags); atl2_dump_link(); printf("\n"); } -/*===========================================================================* - * sef_cb_init_fresh * - *===========================================================================*/ -static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info)) +/* + * Process miscellaneous messages. + */ +static void +atl2_other(const message * m_ptr, int ipc_status) { - /* Initialize the atl2 driver. - */ - int r, devind; - long v; #if ATL2_FKEY - int fkeys, sfkeys; + int sfkeys; + + if (!is_ipc_notify(ipc_status) || m_ptr->m_source != TTY_PROC_NR) + return; + + if (fkey_events(NULL, &sfkeys) == OK && bit_isset(sfkeys, ATL2_FKEY)) + atl2_dump(); +#endif +} + +/* + * Initialize the atl2 driver. + */ +static int +atl2_init(unsigned int instance, ether_addr_t * addr) +{ + int devind; +#if ATL2_FKEY + int r, fkeys, sfkeys; #endif - /* How many matching devices should we skip? */ - v = 0; - (void) env_parse("instance", "d", 0, &v, 0, 255); - instance = (int) v; + memset(&state, 0, sizeof(state)); /* Try to find a recognized device. */ devind = atl2_probe(instance); if (devind < 0) - panic("no matching device found"); + return ENXIO; /* Initialize the device. */ - atl2_init(devind); - - /* Announce we are up! */ - netdriver_announce(); + atl2_init_hw(devind, addr); #if ATL2_FKEY /* Register debug dump function key. */ fkeys = sfkeys = 0; - bit_set(sfkeys, 11); + bit_set(sfkeys, ATL2_FKEY); if ((r = fkey_map(&fkeys, &sfkeys)) != OK) - printf("ATL2: warning, could not map Shift+F11 key (%d)\n", r); + printf("ATL2: warning, could not map Shift+F%u key (%d)\n", + r, ATL2_FKEY); #endif - return(OK); + return OK; } -/*===========================================================================* - * sef_cb_signal_handler * - *===========================================================================*/ -static void sef_cb_signal_handler(int signo) +#if 0 +/* + * Deallocate resources as proof of concept. Currently unused. + */ +static void +atl2_cleanup(void) { - /* In case of a termination signal, shut down this driver. - * Stop the device, and deallocate resources as proof of concept. - */ int r; - /* Only check for termination signal, ignore anything else. */ - if (signo != SIGTERM) return; - - atl2_stop(); - if ((r = sys_irqrmpolicy(&state.hook_id)) != OK) panic("unable to deregister IRQ: %d", r); free_contig(state.txd_base, ATL2_TXD_BUFSIZE); - free_contig(state.txs_base, ATL2_TXS_COUNT * sizeof(u32_t)); + free_contig(state.txs_base, ATL2_TXS_COUNT * sizeof(uint32_t)); free_contig(state.rxd_base_u, - state.rxd_align + ATL2_RXD_COUNT * ATL2_RXD_SIZE); + state.rxd_align + ATL2_RXD_COUNT * ATL2_RXD_SIZE); - vm_unmap_phys(SELF, (void *) state.base, state.size); + vm_unmap_phys(SELF, (void *)state.base, state.size); /* We cannot free the PCI device at this time. */ - - exit(0); } +#endif -/*===========================================================================* - * sef_local_startup * - *===========================================================================*/ -static void sef_local_startup(void) +/* + * The ATL2 ethernet driver. + */ +int +main(int argc, char ** argv) { - /* Register init callbacks. */ - sef_setcb_init_fresh(sef_cb_init_fresh); - sef_setcb_init_lu(sef_cb_init_fresh); - sef_setcb_init_restart(sef_cb_init_fresh); - /* Register live update callbacks. */ - sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready); - sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_workfree); - - /* Register signal callbacks. */ - sef_setcb_signal_handler(sef_cb_signal_handler); - - /* Let SEF perform startup. */ - sef_startup(); -} - -/*===========================================================================* - * main * - *===========================================================================*/ -int main(int argc, char **argv) -{ - /* Driver task. - */ - message m; - int ipc_status; - int r; - - /* Initialize SEF. */ env_setargs(argc, argv); - sef_local_startup(); - while (TRUE) { - if ((r = netdriver_receive(ANY, &m, &ipc_status)) != OK) - panic("netdriver_receive failed: %d", r); + netdriver_task(&atl2_table); - if (is_ipc_notify(ipc_status)) { - switch (m.m_source) { - case HARDWARE: /* interrupt */ - atl2_intr(&m); - - break; - - case TTY_PROC_NR: /* function key */ - atl2_dump(); - - break; - - default: - printf("ATL2: illegal notify from %d\n", - m.m_source); - } - - continue; - } - - /* Process requests from Inet. */ - switch (m.m_type) { - case DL_CONF: atl2_conf(&m); break; - case DL_GETSTAT_S: atl2_getstat(&m); break; - case DL_WRITEV_S: atl2_writev(&m, FALSE); break; - case DL_READV_S: atl2_readv(&m, FALSE); break; - default: - printf("ATL2: illegal message %d from %d\n", - m.m_type, m.m_source); - } - } + return EXIT_SUCCESS; } diff --git a/minix/drivers/net/atl2/atl2.h b/minix/drivers/net/atl2/atl2.h index 85c5e4362..7d53c4741 100644 --- a/minix/drivers/net/atl2/atl2.h +++ b/minix/drivers/net/atl2/atl2.h @@ -179,5 +179,3 @@ #define ATL2_TXS_ABORTCOL 0x04000000 /* collision abort */ #define ATL2_TXS_UNDERRUN 0x08000000 /* buffer underrun */ #define ATL2_TXS_UPDATE 0x80000000 /* updated by device */ - - diff --git a/minix/drivers/net/dec21140A/dec21140A.c b/minix/drivers/net/dec21140A/dec21140A.c index 4ab0d5e40..5d9eec3b5 100644 --- a/minix/drivers/net/dec21140A/dec21140A.c +++ b/minix/drivers/net/dec21140A/dec21140A.c @@ -2,7 +2,7 @@ * dec21041.c * * This file contains an ethernet device driver for DEC 21140A - * fast ethernet controllers as emulated by VirtualPC 2007. It is not + * fast ethernet controllers as emulated by VirtualPC 2007. It is not * intended to support the real card, as much more error checking * and testing would be needed. It supports both bridged and NAT mode. * @@ -12,288 +12,105 @@ #include #include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include "dec21140A.h" - static u32_t io_inl(u16_t); static void io_outl(u16_t, u32_t); -static void do_conf(const message *); -static void do_get_stat_s(message *); -static void do_interrupt(const dpeth_t *); -static void do_reply(dpeth_t *); -static void do_vread_s(const message *, int); -static void do_watchdog(void *); -static void de_update_conf(dpeth_t *); -static int de_probe(dpeth_t *, int skip); -static void de_conf_addr(dpeth_t *); -static void de_first_init(dpeth_t *); +static int do_init(unsigned int, ether_addr_t *); +static void do_stop(void); +static int do_send(struct netdriver_data *, size_t); +static ssize_t do_recv(struct netdriver_data *, size_t); +static void do_stat(eth_stat_t *); +static void do_intr(unsigned int); + +static int de_probe(dpeth_t *, unsigned int skip); +static void de_conf_addr(dpeth_t *, ether_addr_t *); +static void de_init_buf(dpeth_t *); static void de_reset(const dpeth_t *); static void de_hw_conf(const dpeth_t *); static void de_start(const dpeth_t *); -static void de_setup_frame(const dpeth_t *); +static void de_setup_frame(const dpeth_t *, const ether_addr_t *); static u16_t de_read_rom(const dpeth_t *, u8_t, u8_t); -static int de_calc_iov_size(iovec_dat_s_t *); -static void de_next_iov(iovec_dat_s_t *); -static void do_vwrite_s(const message *, int); -static void de_get_userdata_s(int, cp_grant_id_t, vir_bytes, int, void - *); - -/* Error messages */ -static char str_CopyErrMsg[] = "unable to read/write user data"; -static char str_SendErrMsg[] = "send failed"; -static char str_SizeErrMsg[] = "illegal packet size"; -static char str_UmapErrMsg[] = "Unable to sys_umap"; -static char str_BusyErrMsg[] = "Send/Recv failed: busy"; -static char str_StatErrMsg[] = "Unable to send stats"; -static char str_AlignErrMsg[] = "Bad align of buffer/descriptor"; -static char str_DevName[] = "dec21140A:eth#?"; static dpeth_t de_state; static int de_instance; -/* SEF functions and variables. */ -static void sef_local_startup(void); -static int sef_cb_init_fresh(int type, sef_init_info_t *info); +static const struct netdriver de_table = { + .ndr_init = do_init, + .ndr_stop = do_stop, + .ndr_recv = do_recv, + .ndr_send = do_send, + .ndr_stat = do_stat, + .ndr_intr = do_intr +}; -/*===========================================================================* - * main * - *===========================================================================*/ int main(int argc, char *argv[]) { - dpeth_t *dep; - message m; - int ipc_status; - int r; - - /* SEF local startup. */ env_setargs(argc, argv); - sef_local_startup(); - - while (TRUE) - { - if ((r= netdriver_receive(ANY, &m, &ipc_status)) != OK) - panic("netdriver_receive failed: %d", r); - if(is_ipc_notify(ipc_status)) { - switch(_ENDPOINT_P(m.m_source)) { - case CLOCK: - do_watchdog(&m); - break; + netdriver_task(&de_table); - case HARDWARE: - dep = &de_state; - if (dep->de_mode == DEM_ENABLED) { - do_interrupt(dep); - if (dep->de_flags & (DEF_ACK_SEND | DEF_ACK_RECV)) - do_reply(dep); - sys_irqenable(&dep->de_hook); - } - break; - default: - printf("ignoring notify from %d\n", m.m_source); - break; - } - continue; - } - - switch (m.m_type) - { - case DL_WRITEV_S: do_vwrite_s(&m, FALSE); break; - case DL_READV_S: do_vread_s(&m, FALSE); break; - case DL_CONF: do_conf(&m); break; - case DL_GETSTAT_S: do_get_stat_s(&m); break; - - default: - printf("message 0x%x; %d from %d\n", - m.m_type, m.m_type-DL_RQ_BASE, m.m_source); - panic("illegal message: %d", m.m_type); - } - } + return 0; } -/*===========================================================================* - * sef_local_startup * - *===========================================================================*/ -static void sef_local_startup() +static void de_init_hw(dpeth_t *dep, ether_addr_t *addr) { - /* Register init callbacks. */ - sef_setcb_init_fresh(sef_cb_init_fresh); - sef_setcb_init_lu(sef_cb_init_fresh); - sef_setcb_init_restart(sef_cb_init_fresh); + de_reset(dep); + de_conf_addr(dep, addr); + de_init_buf(dep); - /* Register live update callbacks. */ - sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready); - sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_workfree); + /* Set the interrupt handler policy. Request interrupts not to be reenabled + * automatically. Return the IRQ line number when an interrupt occurs. + */ + dep->de_hook = dep->de_irq; + sys_irqsetpolicy(dep->de_irq, 0, &dep->de_hook); + sys_irqenable(&dep->de_hook); - /* Register signal callbacks. */ - sef_setcb_signal_handler(sef_cb_signal_handler_term); - - /* Let SEF perform startup. */ - sef_startup(); + de_reset(dep); + de_hw_conf(dep); + de_setup_frame(dep, addr); + de_start(dep); } -/*===========================================================================* - * sef_cb_init_fresh * - *===========================================================================*/ -static int sef_cb_init_fresh(int type, sef_init_info_t *UNUSED(info)) +static int do_init(unsigned int instance, ether_addr_t *addr) { /* Initialize the DEC 21140A driver. */ - int fkeys, sfkeys; - long v; + dpeth_t *dep; - v = 0; - (void) env_parse("instance", "d", 0, &v, 0, 255); - de_instance = (int) v; + dep = &de_state; + memset(dep, 0, sizeof(*dep)); - /* Request function key for debug dumps */ - fkeys = sfkeys = 0; - bit_set(sfkeys, DE_FKEY); - if ((fkey_map(&fkeys, &sfkeys)) != OK) - printf("%s: error using Shift+F%d key(%d)\n", str_DevName, DE_FKEY, errno); + strlcpy(dep->de_name, "dec21140A:?", sizeof(dep->de_name)); + dep->de_name[strlen(dep->de_name)-1] = '0' + instance; - /* Announce we are up! */ - netdriver_announce(); + de_instance = instance; + + if (!de_probe(dep, instance)) + return ENXIO; + + de_init_hw(dep, addr); return OK; } -static void do_get_stat_s(message * mp) +static void do_stat(eth_stat_t *stat) { - int rc; - dpeth_t *dep; - - dep = &de_state; - - if ((rc = sys_safecopyto(mp->m_source, mp->m_net_netdrv_dl_getstat_s.grant, - 0, (vir_bytes)&dep->de_stat, sizeof(dep->de_stat))) != OK) - panic("%s %d", str_CopyErrMsg, rc); - - mp->m_type = DL_STAT_REPLY; - rc = ipc_send(mp->m_source, mp); - if( rc != OK ) - panic("%s %d", str_StatErrMsg, rc); - return; + memcpy(stat, &de_state.de_stat, sizeof(*stat)); } -static void do_conf(const message * mp) +static int de_probe(dpeth_t *dep, unsigned int skip) { - int r; - dpeth_t *dep; - message reply_mess; - - dep = &de_state; - - strncpy(dep->de_name, str_DevName, strlen(str_DevName)); - dep->de_name[strlen(dep->de_name)-1] = '0' + de_instance; - - if (dep->de_mode == DEM_DISABLED) { - de_update_conf(dep); - pci_init(); - if (dep->de_mode == DEM_ENABLED && !de_probe(dep, de_instance)) { - printf("%s: warning no ethernet card found at 0x%04X\n", - dep->de_name, dep->de_base_port); - dep->de_mode = DEM_DISABLED; - } - } - - r = OK; - - /* 'de_mode' may change if probe routines fail, test again */ - switch (dep->de_mode) { - - case DEM_DISABLED: - r = ENXIO; /* Device is OFF or hardware probe failed */ - break; - - case DEM_ENABLED: - if (dep->de_flags == DEF_EMPTY) { - de_first_init(dep); - dep->de_flags |= DEF_ENABLED; - de_reset(dep); - de_hw_conf(dep); - de_setup_frame(dep); - de_start(dep); - } - - /* TODO CHECK PROMISC AND MULTI */ - dep->de_flags &= NOT(DEF_PROMISC | DEF_MULTI | DEF_BROAD); - if (mp->m_net_netdrv_dl_conf.mode & DL_PROMISC_REQ) - dep->de_flags |= DEF_PROMISC | DEF_MULTI | DEF_BROAD; - if (mp->m_net_netdrv_dl_conf.mode & DL_MULTI_REQ) - dep->de_flags |= DEF_MULTI; - if (mp->m_net_netdrv_dl_conf.mode & DL_BROAD_REQ) - dep->de_flags |= DEF_BROAD; - break; - - case DEM_SINK: - DEBUG(printf("%s running in sink mode\n", str_DevName)); - memset(dep->de_address.ea_addr, 0, sizeof(ether_addr_t)); - de_conf_addr(dep); - break; - - default: break; - } - - reply_mess.m_type = DL_CONF_REPLY; - reply_mess.m_netdrv_net_dl_conf.stat = r; - if(r == OK){ - memcpy(reply_mess.m_netdrv_net_dl_conf.hw_addr, dep->de_address.ea_addr, - sizeof(reply_mess.m_netdrv_net_dl_conf.hw_addr)); - } - - if (ipc_send(mp->m_source, &reply_mess) != OK) - panic("%s %d", str_SendErrMsg, mp->m_source); - - return; -} - -static void do_reply(dpeth_t * dep) -{ - message reply; - int r, flags = DL_NOFLAGS; - - if (dep->de_flags & DEF_ACK_SEND) flags |= DL_PACK_SEND; - if (dep->de_flags & DEF_ACK_RECV) flags |= DL_PACK_RECV; - - reply.m_type = DL_TASK_REPLY; - reply.m_netdrv_net_dl_task.flags = flags; - reply.m_netdrv_net_dl_task.count = dep->de_read_s; - - r = ipc_send(dep->de_client, &reply); - - if(r < 0) - panic("%s %d", str_SendErrMsg, r); - - dep->de_read_s = 0; - dep->de_flags &= NOT(DEF_ACK_SEND | DEF_ACK_RECV); - return; -} - -static void do_watchdog(void *UNUSED(message)) -{ - /* nothing here yet */ - return; -} - -static int de_probe(dpeth_t *dep, int skip) -{ - int i, r, devind; - u16_t vid, did, temp16; + int r, devind; + u16_t vid, did; DEBUG(printf("PROBING...")); - + + pci_init(); + r= pci_first_dev(&devind, &vid, &did); if (r == 0) return FALSE; @@ -314,40 +131,22 @@ static int de_probe(dpeth_t *dep, int skip) panic("de_probe: base address invalid: %d", dep->de_base_port); DEBUG(printf("%s: using I/O address 0x%lx, IRQ %d\n", - dep->de_name, (unsigned long)dep->de_base_port, + dep->de_name, (unsigned long)dep->de_base_port, dep->de_irq)); dep->de_type = pci_attr_r8(devind, PCI_REV); /* device validation. We support only the DEC21140A */ if(dep->de_type != DEC_21140A){ - dep->de_type = DE_TYPE_UNKNOWN; - printf("%s: unsupported device\n", str_DevName); + printf("%s: unsupported card type %x\n", dep->de_name, dep->de_type); return FALSE; } - de_reset(dep); - - DEBUG(printf("Reading SROM...\n")); - - for(i=0;i<(1<srom[i*2] = temp16 & 0xFF; - dep->srom[i*2+1] = temp16 >> 8; - } - - /* TODO: validate SROM content */ - /* acquire MAC addr */ - DEBUG(printf("Using MAC addr= ")); - for(i=0;i<6;i++){ - dep->de_address.ea_addr[i] = dep->srom[i+DE_SROM_EA_OFFSET]; - DEBUG(printf("%02X%c",dep->de_address.ea_addr[i],i!=5?'-':'\n')); - } - DEBUG(printf("probe success\n")); return TRUE; } -static u16_t de_read_rom(const dpeth_t *dep, u8_t addr, u8_t nbAddrBits){ +static u16_t de_read_rom(const dpeth_t *dep, u8_t addr, u8_t nbAddrBits) +{ u16_t retVal = 0; int i; u32_t csr = 0; @@ -356,7 +155,11 @@ static u16_t de_read_rom(const dpeth_t *dep, u8_t addr, u8_t nbAddrBits){ more readable, the following macro is also just to clear up the code a little.*/ - #define EMIT do { io_outl(CSR_ADDR(dep, CSR9), csr | csr2); io_outl(CSR_ADDR(dep, CSR1), 0);} while(0) +#define EMIT \ + do { \ + io_outl(CSR_ADDR(dep, CSR9), csr | csr2); \ + io_outl(CSR_ADDR(dep, CSR1), 0); \ + } while(0) /* init */ csr = 0; EMIT; @@ -404,180 +207,87 @@ static u16_t de_read_rom(const dpeth_t *dep, u8_t addr, u8_t nbAddrBits){ return retVal; } -static void de_update_conf(dpeth_t * dep) +static ssize_t do_recv(struct netdriver_data *data, size_t max) { - static char dpc_fmt[] = "x:d:x"; - char ec_key[16]; - long val; - - strlcpy(ec_key, "DEETH0", sizeof(ec_key)); - ec_key[5] += de_instance; - - dep->de_mode = DEM_ENABLED; - switch (env_parse(ec_key, dpc_fmt, 0, &val, 0x000L, 0x3FFL)) { - case EP_OFF: dep->de_mode = DEM_DISABLED; break; - case EP_ON: dep->de_mode = DEM_SINK; break; - } - dep->de_base_port = 0; - - return; -} - -static void do_vread_s(const message * mp, int from_int) -{ - u8_t *buffer; u32_t size; - int r, ix = 0; - vir_bytes bytes; - dpeth_t *dep = NULL; - de_loc_descr_t *descr = NULL; - iovec_dat_s_t *iovp = NULL; + dpeth_t *dep; + de_loc_descr_t *descr; dep = &de_state; - dep->de_client = mp->m_source; + descr = &dep->descr[DESCR_RECV][dep->cur_descr[DESCR_RECV]]; - if (dep->de_mode == DEM_ENABLED) { + /* check if packet is in the current descr and only there */ + if ((descr->descr->des[DES0] & DES0_OWN) || + !(descr->descr->des[DES0] & DES0_FS) || + !(descr->descr->des[DES0] & DES0_LS)) + return SUSPEND; - descr = &dep->descr[DESCR_RECV][dep->cur_descr[DESCR_RECV]]; + /*TODO: multi-descr msgs...*/ + /* We only support packets contained in a single descriptor. + Setting the descriptor buffer size to less then + ETH_MAX_PACK_SIZE will result in multi-descriptor + packets that we won't be able to handle + */ - /* check if packet is in the current descr and only there */ - if( !( !(descr->descr->des[DES0] & DES0_OWN) && - (descr->descr->des[DES0] & DES0_FS) && - (descr->descr->des[DES0] & DES0_LS) )) - goto suspend; + /* Check for abnormal messages. We assert here + because this driver is for a virtualized + envrionment where we will not get bad packets + */ + assert(!(descr->descr->des[DES0]&DES0_ES)); + assert(!(descr->descr->des[DES0]&DES0_RE)); + /* Copy buffer to user area and clear ownage */ + size = (descr->descr->des[DES0]&DES0_FL)>>DES0_FL_SHIFT; - /*TODO: multi-descr msgs...*/ - /* We only support packets contained in a single descriptor. - Setting the descriptor buffer size to less then - ETH_MAX_PACK_SIZE will result in multi-descriptor - packets that we won't be able to handle - */ - assert(!(descr->descr->des[DES0]&DES0_OWN)); - assert(descr->descr->des[DES0]&DES0_FS); - assert(descr->descr->des[DES0]&DES0_LS); - - /* Check for abnormal messages. We assert here - because this driver is for a virtualized - envrionment where we will not get bad packets - */ - assert(!(descr->descr->des[DES0]&DES0_ES)); - assert(!(descr->descr->des[DES0]&DES0_RE)); - - - /* Setup the iovec entry to allow copying into - client layer - */ - dep->de_read_iovec.iod_proc_nr = mp->m_source; - de_get_userdata_s(mp->m_source, mp->m_net_netdrv_dl_readv_s.grant, 0, - mp->m_net_netdrv_dl_readv_s.count, - dep->de_read_iovec.iod_iovec); - dep->de_read_iovec.iod_iovec_s = mp->m_net_netdrv_dl_readv_s.count; - dep->de_read_iovec.iod_grant = mp->m_net_netdrv_dl_readv_s.grant; - dep->de_read_iovec.iod_iovec_offset = 0; - size = de_calc_iov_size(&dep->de_read_iovec); - if (size < ETH_MAX_PACK_SIZE) - panic("%s %d", str_SizeErrMsg, size); - - /* Copy buffer to user area and clear ownage */ - size = (descr->descr->des[DES0]&DES0_FL)>>DES0_FL_SHIFT; - - /*TODO: Complain to MS */ - /*HACK: VPC2007 returns packet of invalid size. Ethernet standard - specify 46 bytes as the minimum for valid payload. However, this is - artificial in so far as for certain packet types, notably ARP, less - then 46 bytes are needed to contain the full information. In a non - virtualized environment the 46 bytes rule is enforced in order to give - guarantee in the collison detection scheme. Of course, this being a - driver for a VPC2007, we won't have collisions and I can only suppose - MS decided to cut packet size to true minimum, regardless of the - 46 bytes payload standard. Note that this seems to not happen in - bridged mode. Note also, that the card does not return runt or - incomplete frames to us, so this hack is safe - */ - if(size<60){ - memset(&descr->buf1[size], 0, 60-size); - size=60; - } - /* End ugly hack */ - - iovp = &dep->de_read_iovec; - buffer = descr->buf1; - dep->bytes_rx += size; - dep->de_stat.ets_packetR++; - dep->de_read_s = size; - - do { - bytes = iovp->iod_iovec[ix].iov_size; /* Size of buffer */ - if (bytes >= size) - bytes = size; - - r= sys_safecopyto(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_grant, 0, - (vir_bytes)buffer, bytes); - if (r != OK) - panic("%s %d", str_CopyErrMsg, r); - buffer += bytes; - - if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */ - de_next_iov(iovp); - ix = 0; - } - } while ((size -= bytes) > 0); - - descr->descr->des[DES0]=DES0_OWN; - dep->cur_descr[DESCR_RECV]++; - if(dep->cur_descr[DESCR_RECV] >= DE_NB_RECV_DESCR) - dep->cur_descr[DESCR_RECV] = 0; - - DEBUG(printf("Read returned size = %d\n", size)); - - /* Reply information */ - dep->de_flags |= DEF_ACK_RECV; - dep->de_flags &= NOT(DEF_READING); + /* HACK: VPC2007 sends short-sized packets, pad to minimum ethernet length */ + if(size<60){ + memset(&descr->buf1[size], 0, 60-size); + size=60; } - if(!from_int){ - do_reply(dep); - } - return; + /* Truncate large packets */ + if (size > max) + size = max; - suspend: - if(from_int){ - assert(dep->de_flags & DEF_READING); - return; - } + netdriver_copyout(data, 0, descr->buf1, size); - assert(!(dep->de_flags & DEF_READING)); - dep->rx_return_msg = *mp; - dep->de_flags |= DEF_READING; - do_reply(dep); - return; + dep->de_stat.ets_packetR++; + + descr->descr->des[DES0]=DES0_OWN; + dep->cur_descr[DESCR_RECV]++; + if(dep->cur_descr[DESCR_RECV] >= DE_NB_RECV_DESCR) + dep->cur_descr[DESCR_RECV] = 0; + + DEBUG(printf("Read returned size = %d\n", size)); + + return size; } -static void de_conf_addr(dpeth_t * dep) +static void de_conf_addr(dpeth_t *dep, ether_addr_t *addr) { - static char ea_fmt[] = "x:x:x:x:x:x"; - char ea_key[16]; - int ix; - long val; + u16_t temp16; + int i; - strlcpy(ea_key, "DEETH0_EA", sizeof(ea_key)); - ea_key[5] += de_instance; + DEBUG(printf("Reading SROM...\n")); - for (ix = 0; ix < SA_ADDR_LEN; ix++) { - val = dep->de_address.ea_addr[ix]; - if (env_parse(ea_key, ea_fmt, ix, &val, 0x00L, 0xFFL) != EP_SET) - break; - dep->de_address.ea_addr[ix] = val; + for(i=0;i<(1<srom[i*2] = temp16 & 0xFF; + dep->srom[i*2+1] = temp16 >> 8; } - if (ix != 0 && ix != SA_ADDR_LEN) - env_parse(ea_key, "?", 0, &val, 0L, 0L); - return; + /* TODO: validate SROM content */ + /* acquire MAC addr */ + DEBUG(printf("Using MAC addr= ")); + for(i=0;i<6;i++){ + addr->ea_addr[i] = dep->srom[i+DE_SROM_EA_OFFSET]; + DEBUG(printf("%02X%c", addr->ea_addr[i],i!=5?'-':'\n')); + } + DEBUG(printf("probe success\n")); } -static void de_first_init(dpeth_t *dep) +static void de_init_buf(dpeth_t *dep) { int i,j,r; vir_bytes descr_vir = (vir_bytes)dep->sendrecv_descr_buf; @@ -585,7 +295,6 @@ static void de_first_init(dpeth_t *dep) de_loc_descr_t *loc_descr; phys_bytes temp; - for(i=0;i<2;i++){ loc_descr = &dep->descr[i][0]; for(j=0; j < (i==DESCR_RECV ? DE_NB_RECV_DESCR : DE_NB_SEND_DESCR); j++){ @@ -595,7 +304,7 @@ static void de_first_init(dpeth_t *dep) descr_vir += sizeof(de_descr_t); /* assign space for buffer */ - loc_descr->buf1 = (u8_t*)buffer_vir; + loc_descr->buf1 = (u8_t*)buffer_vir; buffer_vir += (i==DESCR_RECV ? DE_RECV_BUF_SIZE : DE_SEND_BUF_SIZE); loc_descr->buf2 = 0; loc_descr++; @@ -610,9 +319,9 @@ static void de_first_init(dpeth_t *dep) temp = (i==DESCR_RECV ? DE_RECV_BUF_SIZE : DE_SEND_BUF_SIZE); for(j=0; j < (i==DESCR_RECV ? DE_NB_RECV_DESCR : DE_NB_SEND_DESCR); j++){ /* translate buffers physical address */ - r = sys_umap(SELF, VM_D, (vir_bytes)loc_descr->buf1, temp, + r = sys_umap(SELF, VM_D, (vir_bytes)loc_descr->buf1, temp, (phys_bytes *) &(loc_descr->descr->des[DES_BUF1])); - if(r != OK) panic("umap failed: %d", r); + if(r != OK) panic("umap failed: %d", r); loc_descr->descr->des[DES_BUF2] = 0; memset(&loc_descr->descr->des[DES0],0,sizeof(u32_t)); loc_descr->descr->des[DES1] = temp; @@ -623,15 +332,15 @@ static void de_first_init(dpeth_t *dep) loc_descr++; } } - + /* record physical location of two first descriptor */ - r = sys_umap(SELF, VM_D, (vir_bytes)dep->descr[DESCR_RECV][0].descr, + r = sys_umap(SELF, VM_D, (vir_bytes)dep->descr[DESCR_RECV][0].descr, sizeof(de_descr_t), &dep->sendrecv_descr_phys_addr[DESCR_RECV]); - if(r != OK) panic("%s %d", str_UmapErrMsg, r); + if(r != OK) panic("sys_umap failed: %d", r); r = sys_umap(SELF, VM_D, (vir_bytes)dep->descr[DESCR_TRAN][0].descr, sizeof(de_descr_t), &dep->sendrecv_descr_phys_addr[DESCR_TRAN]); - if(r != OK) panic("%s %d", str_UmapErrMsg, r); + if(r != OK) panic("sys_umap failed: %d", r); DEBUG(printf("Descr: head tran=[%08X] head recv=[%08X]\n", dep->sendrecv_descr_phys_addr[DESCR_TRAN], @@ -643,58 +352,59 @@ static void de_first_init(dpeth_t *dep) for(j=0;j< (i==DESCR_RECV?DE_NB_RECV_DESCR:DE_NB_SEND_DESCR);j++){ r = sys_umap(SELF, VM_D, (vir_bytes)&(loc_descr->descr), sizeof(de_descr_t), &temp); - if(r != OK) - panic("%s %d", str_UmapErrMsg, r); + if(r != OK) panic("sys_umap failed: %d", r); if( ((loc_descr->descr->des[DES_BUF1] & 0x3) != 0) || ((loc_descr->descr->des[DES_BUF2] & 0x3) != 0) || ((temp&0x3)!=0) ) - panic("%s 0x%lx", str_AlignErrMsg, temp); + panic("alignment error: 0x%lx", temp); loc_descr++; } } - + /* Init default values */ dep->cur_descr[DESCR_TRAN]=1; dep->cur_descr[DESCR_RECV]=0; - dep->bytes_rx = 0; - dep->bytes_tx = 0; - - /* Set the interrupt handler policy. Request interrupts not to be reenabled - * automatically. Return the IRQ line number when an interrupt occurs. - */ - dep->de_hook = dep->de_irq; - sys_irqsetpolicy(dep->de_irq, 0, &dep->de_hook); - sys_irqenable(&dep->de_hook); } -static void do_interrupt(const dpeth_t *dep){ +static void do_intr(unsigned int __unused mask) +{ + dpeth_t *dep; u32_t val; + + dep = &de_state; + val = io_inl(CSR_ADDR(dep, CSR5)); if(val & CSR5_AIS){ panic("Abnormal Int CSR5=: %d", val); } - if( (dep->de_flags & DEF_READING) && (val & CSR5_RI) ){ - do_vread_s(&dep->rx_return_msg, TRUE); - } - - if( (dep->de_flags & DEF_SENDING) && (val & CSR5_TI) ){ - do_vwrite_s(&dep->tx_return_msg, TRUE); - } - + if (val & CSR5_RI) + netdriver_recv(); + + if (val & CSR5_TI) + netdriver_send(); + /* ack and reset interrupts */ io_outl(CSR_ADDR(dep, CSR5), 0xFFFFFFFF); - return; + + sys_irqenable(&dep->de_hook); } -static void de_reset(const dpeth_t *dep){ +static void de_reset(const dpeth_t *dep) +{ io_outl(CSR_ADDR(dep, CSR0), CSR0_SWR); } -static void de_hw_conf(const dpeth_t *dep){ +static void do_stop(void) +{ + de_reset(&de_state); +} + +static void de_hw_conf(const dpeth_t *dep) +{ u32_t val; /* CSR0 - global host bus prop */ @@ -714,18 +424,20 @@ static void de_hw_conf(const dpeth_t *dep){ io_outl(CSR_ADDR(dep, CSR7), val); /* CSR6 - operating mode register */ - val = CSR6_MBO | CSR6_PS | CSR6_FD | CSR6_HBD | + val = CSR6_MBO | CSR6_PS | CSR6_FD | CSR6_HBD | CSR6_PCS | CSR6_SCR | CSR6_TR_00; io_outl(CSR_ADDR(dep, CSR6), val); } -static void de_start(const dpeth_t *dep){ +static void de_start(const dpeth_t *dep) +{ u32_t val; val = io_inl(CSR_ADDR(dep, CSR6)) | CSR6_ST | CSR6_SR; io_outl(CSR_ADDR(dep, CSR6), val); } -static void de_setup_frame(const dpeth_t *dep){ +static void de_setup_frame(const dpeth_t *dep, const ether_addr_t *addr) +{ int i; u32_t val; @@ -739,165 +451,71 @@ static void de_setup_frame(const dpeth_t *dep){ dep->descr[DESCR_TRAN][0].buf1[9] = 0xFF; for(i=1;i<16;i++){ memset(&(dep->descr[DESCR_TRAN][0].buf1[12*i]), 0, 12); - dep->descr[DESCR_TRAN][0].buf1[12*i+0] = dep->de_address.ea_addr[0]; - dep->descr[DESCR_TRAN][0].buf1[12*i+1] = dep->de_address.ea_addr[1]; - dep->descr[DESCR_TRAN][0].buf1[12*i+4] = dep->de_address.ea_addr[2]; - dep->descr[DESCR_TRAN][0].buf1[12*i+5] = dep->de_address.ea_addr[3]; - dep->descr[DESCR_TRAN][0].buf1[12*i+8] = dep->de_address.ea_addr[4]; - dep->descr[DESCR_TRAN][0].buf1[12*i+9] = dep->de_address.ea_addr[5]; + dep->descr[DESCR_TRAN][0].buf1[12*i+0] = addr->ea_addr[0]; + dep->descr[DESCR_TRAN][0].buf1[12*i+1] = addr->ea_addr[1]; + dep->descr[DESCR_TRAN][0].buf1[12*i+4] = addr->ea_addr[2]; + dep->descr[DESCR_TRAN][0].buf1[12*i+5] = addr->ea_addr[3]; + dep->descr[DESCR_TRAN][0].buf1[12*i+8] = addr->ea_addr[4]; + dep->descr[DESCR_TRAN][0].buf1[12*i+9] = addr->ea_addr[5]; } dep->descr[DESCR_TRAN][0].descr->des[DES0] = DES0_OWN; - dep->descr[DESCR_TRAN][0].descr->des[DES1] = DES1_SET | + dep->descr[DESCR_TRAN][0].descr->des[DES1] = DES1_SET | DE_SETUP_FRAME_SIZE | DES1_IC; /* start transmit process to process setup frame */ val = io_inl(CSR_ADDR(dep, CSR6)) | CSR6_ST; - io_outl(CSR_ADDR(dep, CSR6), val); + io_outl(CSR_ADDR(dep, CSR6), val); io_outl(CSR_ADDR(dep, CSR1), 0xFFFFFFFF); - - return; } -static int de_calc_iov_size(iovec_dat_s_t * iovp){ - int size, ix; - size = ix = 0; - - do{ - size += iovp->iod_iovec[ix].iov_size; - if (++ix >= IOVEC_NR) { - de_next_iov(iovp); - ix = 0; - } - } while (ix < iovp->iod_iovec_s); - return size; -} - -static void de_get_userdata_s(int user_proc, cp_grant_id_t grant, - vir_bytes offset, int count, void *loc_addr){ - int rc; - vir_bytes len; - - len = (count > IOVEC_NR ? IOVEC_NR : count) * sizeof(iovec_t); - rc = sys_safecopyfrom(user_proc, grant, 0, (vir_bytes)loc_addr, len); - if (rc != OK) - panic("%s %d", str_CopyErrMsg, rc); - return; -} - -static void de_next_iov(iovec_dat_s_t * iovp){ - - iovp->iod_iovec_s -= IOVEC_NR; - iovp->iod_iovec_offset += IOVEC_NR * sizeof(iovec_t); - de_get_userdata_s(iovp->iod_proc_nr, iovp->iod_grant, iovp->iod_iovec_offset, - iovp->iod_iovec_s, iovp->iod_iovec); - return; -} - -static void do_vwrite_s(const message * mp, int from_int){ - static u8_t setupDone = 0; - int size, r, bytes, ix, totalsize; +static int do_send(struct netdriver_data *data, size_t size) +{ + static int setup_done = 0; dpeth_t *dep; - iovec_dat_s_t *iovp = NULL; de_loc_descr_t *descr = NULL; - u8_t *buffer = NULL; dep = &de_state; - dep->de_client = mp->m_source; + descr = &dep->descr[DESCR_TRAN][dep->cur_descr[DESCR_TRAN]]; - if (dep->de_mode == DEM_ENABLED) { - - if (!from_int && (dep->de_flags & DEF_SENDING)) - panic("%s", str_BusyErrMsg); + if(( descr->descr->des[DES0] & DES0_OWN)!=0) + return SUSPEND; - descr = &dep->descr[DESCR_TRAN][dep->cur_descr[DESCR_TRAN]]; - - if(( descr->descr->des[DES0] & DES0_OWN)!=0) - goto suspend; - - if(!setupDone && (dep->cur_descr[DESCR_TRAN] == 0) ){ - dep->descr[DESCR_TRAN][0].descr->des[DES0] = 0; - setupDone=1; - } - - buffer = descr->buf1; - iovp = &dep->de_write_iovec; - iovp->iod_proc_nr = mp->m_source; - de_get_userdata_s(mp->m_source, mp->m_net_netdrv_dl_writev_s.grant, 0, - mp->m_net_netdrv_dl_writev_s.count, iovp->iod_iovec); - iovp->iod_iovec_s = mp->m_net_netdrv_dl_writev_s.count; - iovp->iod_grant = mp->m_net_netdrv_dl_writev_s.grant; - iovp->iod_iovec_offset = 0; - totalsize = size = de_calc_iov_size(iovp); - if (size < ETH_MIN_PACK_SIZE || size > ETH_MAX_PACK_SIZE) - panic("%s %d", str_SizeErrMsg, size); - - dep->bytes_tx += size; - dep->de_stat.ets_packetT++; - - ix=0; - do { - bytes = iovp->iod_iovec[ix].iov_size; - if (bytes >= size) - bytes = size; - - r= sys_safecopyfrom(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_grant, - 0, (vir_bytes)buffer, bytes); - if (r != OK) - panic("%s %d", str_CopyErrMsg, r); - buffer += bytes; - - if (++ix >= IOVEC_NR) { - de_next_iov(iovp); - ix = 0; - } - } while ((size -= bytes) > 0); - - descr->descr->des[DES1] = (descr->descr->des[DES1]&DES1_ER) | - DES1_FS | DES1_LS | DES1_IC | totalsize; - descr->descr->des[DES0] = DES0_OWN; - - dep->cur_descr[DESCR_TRAN]++; - if(dep->cur_descr[DESCR_TRAN] >= DE_NB_SEND_DESCR) - dep->cur_descr[DESCR_TRAN] = 0; - - io_outl(CSR_ADDR(dep, CSR1), 0xFFFFFFFF); + if(!setup_done && (dep->cur_descr[DESCR_TRAN] == 0) ){ + dep->descr[DESCR_TRAN][0].descr->des[DES0] = 0; + setup_done=1; } - - dep->de_flags |= DEF_ACK_SEND; - if(from_int){ - dep->de_flags &= NOT(DEF_SENDING); - return; - } - do_reply(dep); - return; - suspend: - if(from_int) - panic("should not happen: %d", 0); + netdriver_copyin(data, 0, descr->buf1, size); - dep->de_stat.ets_transDef++; - dep->de_flags |= DEF_SENDING; - dep->de_stat.ets_transDef++; - dep->tx_return_msg = *mp; - do_reply(dep); + descr->descr->des[DES1] = (descr->descr->des[DES1]&DES1_ER) | + DES1_FS | DES1_LS | DES1_IC | size; + descr->descr->des[DES0] = DES0_OWN; + + dep->cur_descr[DESCR_TRAN]++; + if(dep->cur_descr[DESCR_TRAN] >= DE_NB_SEND_DESCR) + dep->cur_descr[DESCR_TRAN] = 0; + + io_outl(CSR_ADDR(dep, CSR1), 0xFFFFFFFF); + + dep->de_stat.ets_packetT++; + + return OK; } -static void warning(const char *type, int err){ - printf("Warning: %s sys_%s failed (%d)\n", str_DevName, type, err); - return; -} - -static u32_t io_inl(u16_t port){ +static u32_t io_inl(u16_t port) +{ u32_t value; int rc; - if ((rc = sys_inl(port, &value)) != OK) warning("inl", rc); + if ((rc = sys_inl(port, &value)) != OK) + panic("sys_inl failed: %d", rc); return value; } -static void io_outl(u16_t port, u32_t value){ +static void io_outl(u16_t port, u32_t value) +{ int rc; - if ((rc = sys_outl(port, value)) != OK) warning("outl", rc); - return; + if ((rc = sys_outl(port, value)) != OK) + panic("sys_outl failed: %d", rc); } diff --git a/minix/drivers/net/dec21140A/dec21140A.h b/minix/drivers/net/dec21140A/dec21140A.h index 6a8b4ea95..74f8af910 100644 --- a/minix/drivers/net/dec21140A/dec21140A.h +++ b/minix/drivers/net/dec21140A/dec21140A.h @@ -11,37 +11,21 @@ Created: 09/01/2009 Nicolas Tittley (first.last @ gmail DOT com) #include -#define DE_FKEY 7 /* Shift+ this value will dump info on console */ - -#define NOT(x) (~(x)) - #if debug == 1 # define DEBUG(statm) statm #else # define DEBUG(statm) #endif - -#define SA_ADDR_LEN sizeof(ether_addr_t) - #define DE_NB_SEND_DESCR 32 #define DE_SEND_BUF_SIZE (ETH_MAX_PACK_SIZE+2) #define DE_NB_RECV_DESCR 32 #define DE_RECV_BUF_SIZE (ETH_MAX_PACK_SIZE+2) -#define IOVEC_NR 16 + #define DE_MIN_BASE_ADDR 0x0400 #define DE_SROM_EA_OFFSET 20 #define DE_SETUP_FRAME_SIZE 192 - -typedef struct iovec_dat_s { - iovec_s_t iod_iovec[IOVEC_NR]; - int iod_iovec_s; - endpoint_t iod_proc_nr; - cp_grant_id_t iod_grant; - vir_bytes iod_iovec_offset; -} iovec_dat_s_t; - typedef struct de_descr { u32_t des[4]; } de_descr_t; @@ -53,9 +37,6 @@ typedef struct de_local_descr { } de_loc_descr_t; typedef struct dpeth { - - message rx_return_msg; /* Holds VREAD message until int */ - message tx_return_msg; /* Holds VWRITE message until int */ char de_name[32]; /* Name of this interface */ port_t de_base_port; /* Base port, for multiple card instance */ int de_irq; /* IRQ line number */ @@ -63,10 +44,7 @@ typedef struct dpeth { int de_type; /* What kind of hardware */ - ether_addr_t de_address; /* Ethernet Address */ eth_stat_t de_stat; /* Stats */ - unsigned long bytes_tx; /* Number of bytes sent */ - unsigned long bytes_rx; /* Number of bytes recv */ /* Space reservation. We will allocate all structures later in the code. here we just make sure we have the space we need at compile time */ @@ -81,42 +59,11 @@ typedef struct dpeth { #define DESCR_RECV 0 #define DESCR_TRAN 1 - int de_flags; /* Send/Receive mode (Configuration) */ - -#define DEF_EMPTY 0x0000 -#define DEF_READING 0x0001 -#define DEF_RECV_BUSY 0x0002 -#define DEF_ACK_RECV 0x0004 -#define DEF_SENDING 0x0010 -#define DEF_XMIT_BUSY 0x0020 -#define DEF_ACK_SEND 0x0040 -#define DEF_PROMISC 0x0100 -#define DEF_MULTI 0x0200 -#define DEF_BROAD 0x0400 -#define DEF_ENABLED 0x2000 -#define DEF_STOPPED 0x4000 - - int de_mode; /* Status of the Interface */ - -#define DEM_DISABLED 0x0000 -#define DEM_SINK 0x0001 -#define DEM_ENABLED 0x0002 - - /* Serial ROM */ #define SROM_BITWIDTH 6 u8_t srom[((1< +#include #include #include diff --git a/minix/drivers/net/dp8390/Makefile b/minix/drivers/net/dp8390/Makefile index 0fcbcc86d..d48227ef7 100644 --- a/minix/drivers/net/dp8390/Makefile +++ b/minix/drivers/net/dp8390/Makefile @@ -2,7 +2,7 @@ PROG= dp8390 SRCS= 3c503.c dp8390.c ne2000.c rtl8029.c wdeth.c -DPADD+= ${LIBNETDRIVER} ${LIBSYS} ${LIBTIMERS} -LDADD+= -lnetdriver -lsys -ltimers +DPADD+= ${LIBNETDRIVER} ${LIBSYS} +LDADD+= -lnetdriver -lsys .include diff --git a/minix/drivers/net/dp8390/dp8390.c b/minix/drivers/net/dp8390/dp8390.c index 3d23db40b..c68d634cb 100644 --- a/minix/drivers/net/dp8390/dp8390.c +++ b/minix/drivers/net/dp8390/dp8390.c @@ -16,14 +16,7 @@ #include #include -#include -#include -#include -#include #include -#include -#include -#include #include #include "assert.h" @@ -70,203 +63,100 @@ static dp_conf_t dp_conf[DP_CONF_NR]= /* Card addresses */ */ #define CR_EXTRA CR_STA -#if ENABLE_PCI +static int do_init(unsigned int instance, ether_addr_t *addr); static void pci_conf(void); -#endif -static void do_vwrite_s(message *mp, int from_int); -static void do_vread_s(message *mp); -static void do_init(message *mp); -static void do_int(dpeth_t *dep); -static void do_getstat_s(message *mp); -static void dp_stop(dpeth_t *dep); +static int do_send(struct netdriver_data *data, size_t size); +static ssize_t do_recv(struct netdriver_data *data, size_t max); +static void do_mode(unsigned int mode); +static void do_stat(eth_stat_t *stat); +static void do_stop(void); static void dp_init(dpeth_t *dep); static void dp_confaddr(dpeth_t *dep); -static void dp_reinit(dpeth_t *dep); static void dp_reset(dpeth_t *dep); -static void dp_check_ints(dpeth_t *dep); -static void dp_recv(dpeth_t *dep); -static void dp_send(dpeth_t *dep); +static void do_intr(unsigned int mask); static void dp_getblock(dpeth_t *dep, int page, size_t offset, size_t size, void *dst); static void dp_pio8_getblock(dpeth_t *dep, int page, size_t offset, size_t size, void *dst); static void dp_pio16_getblock(dpeth_t *dep, int page, size_t offset, size_t size, void *dst); -static int dp_pkt2user_s(dpeth_t *dep, int page, vir_bytes length); -static void dp_user2nic_s(dpeth_t *dep, iovec_dat_s_t *iovp, vir_bytes - offset, int nic_addr, vir_bytes count); -static void dp_pio8_user2nic_s(dpeth_t *dep, iovec_dat_s_t *iovp, - vir_bytes offset, int nic_addr, vir_bytes count); -static void dp_pio16_user2nic_s(dpeth_t *dep, iovec_dat_s_t *iovp, - vir_bytes offset, int nic_addr, vir_bytes count); -static void dp_nic2user_s(dpeth_t *dep, int nic_addr, iovec_dat_s_t - *iovp, vir_bytes offset, vir_bytes count); -static void dp_pio8_nic2user_s(dpeth_t *dep, int nic_addr, iovec_dat_s_t - *iovp, vir_bytes offset, vir_bytes count); -static void dp_pio16_nic2user_s(dpeth_t *dep, int nic_addr, - iovec_dat_s_t *iovp, vir_bytes offset, vir_bytes count); -static void dp_next_iovec_s(iovec_dat_s_t *iovp); +static void dp_pkt2user_s(dpeth_t *dep, struct netdriver_data *data, int page, + size_t length); +static void dp_user2nic_s(dpeth_t *dep, struct netdriver_data *data, + int nic_addr, size_t offset, size_t count); +static void dp_pio8_user2nic_s(dpeth_t *dep, struct netdriver_data *data, + int nic_addr, size_t offset, size_t count); +static void dp_pio16_user2nic_s(dpeth_t *dep, struct netdriver_data *data, + int nic_addr, size_t offset, size_t count); +static void dp_nic2user_s(dpeth_t *dep, struct netdriver_data *data, + int nic_addr, size_t offset, size_t count); +static void dp_pio8_nic2user_s(dpeth_t *dep, struct netdriver_data *data, + int nic_addr, size_t offset, size_t count); +static void dp_pio16_nic2user_s(dpeth_t *dep, struct netdriver_data *data, + int nic_addr, size_t offset, size_t count); static void conf_hw(dpeth_t *dep); static void update_conf(dpeth_t *dep, dp_conf_t *dcp); static void map_hw_buffer(dpeth_t *dep); -static int calc_iovec_size_s(iovec_dat_s_t *iovp); -static void reply(dpeth_t *dep); -static void mess_reply(message *req, message *reply); -static void get_userdata_s(int user_proc, cp_grant_id_t grant, vir_bytes - offset, vir_bytes count, void *loc_addr); -static void put_userdata_s(int user_proc, cp_grant_id_t grant, size_t - count, void *loc_addr); static void insb(port_t port, void *buf, size_t size); static void insw(port_t port, void *buf, size_t size); -static void do_vir_insb(port_t port, int proc, vir_bytes buf, size_t - size); -static void do_vir_insw(port_t port, int proc, vir_bytes buf, size_t - size); -/* SEF functions and variables. */ -static void sef_local_startup(void); -static int sef_cb_init_fresh(int type, sef_init_info_t *info); -static void sef_cb_signal_handler(int signo); - -static void handle_hw_intr(void) -{ - int r, irq; - dpeth_t *dep; - - dep = &de_state; - - if (dep->de_mode != DEM_ENABLED) - return; - assert(dep->de_flags & DEF_ENABLED); - irq= dep->de_irq; - assert(irq >= 0 && irq < NR_IRQ_VECTORS); - if (dep->de_int_pending || 1) - { - dep->de_int_pending= 0; - dp_check_ints(dep); - do_int(dep); - r= sys_irqenable(&dep->de_hook); - if (r != OK) { - panic("unable enable interrupts: %d", r); - } - } -} +static const struct netdriver dp_table = { + .ndr_init = do_init, + .ndr_stop = do_stop, + .ndr_mode = do_mode, + .ndr_recv = do_recv, + .ndr_send = do_send, + .ndr_stat = do_stat, + .ndr_intr = do_intr +}; /*===========================================================================* - * dpeth_task * + * main * *===========================================================================*/ int main(int argc, char *argv[]) { - message m; - int ipc_status; - int r; - - /* SEF local startup. */ env_setargs(argc, argv); - sef_local_startup(); - while (TRUE) - { - if ((r= netdriver_receive(ANY, &m, &ipc_status)) != OK) - panic("dp8390: netdriver_receive failed: %d", r); + netdriver_task(&dp_table); - if (is_ipc_notify(ipc_status)) { - switch (_ENDPOINT_P(m.m_source)) { - case HARDWARE: - handle_hw_intr(); - break; - case CLOCK: - printf("dp8390: notify from CLOCK\n"); - break; - default: - panic("dp8390: illegal notify from: %d", - m.m_source); - } - - /* done, get a new message */ - continue; - } - - switch (m.m_type) - { - case DL_WRITEV_S: do_vwrite_s(&m, FALSE); break; - case DL_READV_S: do_vread_s(&m); break; - case DL_CONF: do_init(&m); break; - case DL_GETSTAT_S: do_getstat_s(&m); break; - default: - panic("dp8390: illegal message: %d", m.m_type); - } - } + return 0; } /*===========================================================================* - * sef_local_startup * + * do_init * *===========================================================================*/ -static void sef_local_startup() -{ - /* Register init callbacks. */ - sef_setcb_init_fresh(sef_cb_init_fresh); - sef_setcb_init_lu(sef_cb_init_fresh); - sef_setcb_init_restart(sef_cb_init_fresh); - - /* Register live update callbacks. */ - sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready); - sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_workfree); - - /* Register signal callbacks. */ - sef_setcb_signal_handler(sef_cb_signal_handler); - - /* Let SEF perform startup. */ - sef_startup(); -} - -/*===========================================================================* - * sef_cb_init_fresh * - *===========================================================================*/ -static int sef_cb_init_fresh(int type, sef_init_info_t *UNUSED(info)) +static int do_init(unsigned int instance, ether_addr_t *addr) { /* Initialize the dp8390 driver. */ dpeth_t *dep; - long v; system_hz = sys_hz(); - if (env_argc < 1) { - panic("A head which at this time has no name"); - } - - v = 0; - (void) env_parse("instance", "d", 0, &v, 0, 255); - de_instance = (int) v; + de_instance = instance; dep = &de_state; + memset(dep, 0, sizeof(*dep)); strlcpy(dep->de_name, "dp8390#0", sizeof(dep->de_name)); dep->de_name[7] += de_instance; - /* Announce we are up! */ - netdriver_announce(); + pci_conf(); /* Configure PCI devices. */ - return(OK); -} + /* This is the default, try to (re)locate the device. */ + conf_hw(dep); -/*===========================================================================* - * sef_cb_signal_handler * - *===========================================================================*/ -static void sef_cb_signal_handler(int signo) -{ - /* Only check for termination signal, ignore anything else. */ - if (signo != SIGTERM) return; + dp_init(dep); - if (de_state.de_mode == DEM_ENABLED) - dp_stop(&de_state); + memcpy(addr, dep->de_address.ea_addr, sizeof(*addr)); + + return OK; } #if 0 /*===========================================================================* * dp8390_dump * *===========================================================================*/ -void dp8390_dump() +void dp8390_dump(void) { dpeth_t *dep; int isr; @@ -274,16 +164,6 @@ void dp8390_dump() dep = &de_state; printf("\n"); -#if XXX - if (dep->de_mode == DEM_DISABLED) - printf("dp8390 instance %d is disabled\n", de_instance); - else if (dep->de_mode == DEM_SINK) - printf("dp8390 instance %d is in sink mode\n", de_instance); -#endif - - if (dep->de_mode != DEM_ENABLED) - return; - printf("dp8390 statistics of instance %d:\n", de_instance); printf("recvErr :%8ld\t", dep->de_stat.ets_recvErr); @@ -314,20 +194,14 @@ void dp8390_dump() } #endif -#if ENABLE_PCI /*===========================================================================* * pci_conf * *===========================================================================*/ -static void pci_conf() +static void pci_conf(void) { char envvar[16]; struct dpeth *dep; int i, pci_instance; - static int first_time= 1; - - if (!first_time) - return; - first_time= 0; dep= &de_state; @@ -347,69 +221,26 @@ static void pci_conf() } if (!rtl_probe(dep, pci_instance)) - dep->de_pci= -1; + panic("no matching PCI device found"); } -#endif /* ENABLE_PCI */ /*===========================================================================* - * do_vwrite_s * + * do_send * *===========================================================================*/ -static void do_vwrite_s(mp, from_int) -message *mp; -int from_int; +static int do_send(struct netdriver_data *data, size_t size) { - int count, size; int sendq_head; dpeth_t *dep; dep= &de_state; - count = mp->m_net_netdrv_dl_writev_s.count; - dep->de_client= mp->m_source; - - if (dep->de_mode == DEM_SINK) - { - assert(!from_int); - dep->de_flags |= DEF_PACK_SEND; - reply(dep); - return; - } - assert(dep->de_mode == DEM_ENABLED); - assert(dep->de_flags & DEF_ENABLED); - if (dep->de_flags & DEF_SEND_AVAIL) - panic("dp8390: send already in progress"); - sendq_head= dep->de_sendq_head; if (dep->de_sendq[sendq_head].sq_filled) - { - if (from_int) - panic("dp8390: should not be sending"); - dep->de_sendmsg= *mp; - dep->de_flags |= DEF_SEND_AVAIL; - reply(dep); - return; - } - assert(!(dep->de_flags & DEF_PACK_SEND)); + return SUSPEND; - get_userdata_s(mp->m_source, mp->m_net_netdrv_dl_writev_s.grant, 0, - (count > IOVEC_NR ? IOVEC_NR : count) * - sizeof(dep->de_write_iovec_s.iod_iovec[0]), - dep->de_write_iovec_s.iod_iovec); - dep->de_write_iovec_s.iod_iovec_s = count; - dep->de_write_iovec_s.iod_proc_nr = mp->m_source; - dep->de_write_iovec_s.iod_grant = mp->m_net_netdrv_dl_writev_s.grant; - dep->de_write_iovec_s.iod_iovec_offset = 0; + (dep->de_user2nicf_s)(dep, data, + dep->de_sendq[sendq_head].sq_sendpage * DP_PAGESIZE, 0, size); - dep->de_tmp_iovec_s = dep->de_write_iovec_s; - size = calc_iovec_size_s(&dep->de_tmp_iovec_s); - - if (size < ETH_MIN_PACK_SIZE || size > ETH_MAX_PACK_SIZE_TAGGED) - { - panic("dp8390: invalid packet size: %d", size); - } - (dep->de_user2nicf_s)(dep, &dep->de_write_iovec_s, 0, - dep->de_sendq[sendq_head].sq_sendpage * DP_PAGESIZE, - size); dep->de_sendq[sendq_head].sq_filled= TRUE; if (dep->de_sendq_tail == sendq_head) { @@ -426,215 +257,65 @@ int from_int; assert(sendq_head < SENDQ_NR); dep->de_sendq_head= sendq_head; - dep->de_flags |= DEF_PACK_SEND; - - /* If the interrupt handler called, don't send a reply. The reply - * will be sent after all interrupts are handled. - */ - if (from_int) - return; - reply(dep); - - assert(dep->de_mode == DEM_ENABLED); - assert(dep->de_flags & DEF_ENABLED); + return OK; } /*===========================================================================* - * do_vread_s * + * do_mode * *===========================================================================*/ -static void do_vread_s(mp) -message *mp; +static void do_mode(unsigned int mode) +{ + dpeth_t *dep; + int dp_rcr_reg; + + dep = &de_state; + + outb_reg0(dep, DP_CR, CR_PS_P0 | CR_EXTRA); + + dp_rcr_reg = 0; + if (mode & NDEV_PROMISC) + dp_rcr_reg |= RCR_AB | RCR_PRO | RCR_AM; + if (mode & NDEV_BROAD) + dp_rcr_reg |= RCR_AB; + if (mode & NDEV_MULTI) + dp_rcr_reg |= RCR_AM; + outb_reg0(dep, DP_RCR, dp_rcr_reg); +} + +/*===========================================================================* + * do_stat * + *===========================================================================*/ +static void do_stat(eth_stat_t *stat) { - int count; - int size; dpeth_t *dep; dep= &de_state; - count = mp->m_net_netdrv_dl_readv_s.count; - dep->de_client= mp->m_source; - if (dep->de_mode == DEM_SINK) - { - reply(dep); - return; - } - assert(dep->de_mode == DEM_ENABLED); - assert(dep->de_flags & DEF_ENABLED); - - if(dep->de_flags & DEF_READING) - panic("dp8390: read already in progress"); - - get_userdata_s(mp->m_source, mp->m_net_netdrv_dl_readv_s.grant, 0, - (count > IOVEC_NR ? IOVEC_NR : count) * - sizeof(dep->de_read_iovec_s.iod_iovec[0]), - dep->de_read_iovec_s.iod_iovec); - dep->de_read_iovec_s.iod_iovec_s = count; - dep->de_read_iovec_s.iod_proc_nr = mp->m_source; - dep->de_read_iovec_s.iod_grant = mp->m_net_netdrv_dl_readv_s.grant; - dep->de_read_iovec_s.iod_iovec_offset = 0; - - dep->de_tmp_iovec_s = dep->de_read_iovec_s; - size= calc_iovec_size_s(&dep->de_tmp_iovec_s); - - if (size < ETH_MAX_PACK_SIZE_TAGGED) - panic("dp8390: wrong packet size: %d", size); - dep->de_flags |= DEF_READING; - - dp_recv(dep); - - if ((dep->de_flags & (DEF_READING|DEF_STOPPED)) == - (DEF_READING|DEF_STOPPED)) - { - /* The chip is stopped, and all arrived packets are - * delivered. - */ - dp_reset(dep); - } - reply(dep); -} - -/*===========================================================================* - * do_init * - *===========================================================================*/ -static void do_init(message *mp) -{ - dpeth_t *dep; - message reply_mess; - -#if ENABLE_PCI - pci_conf(); /* Configure PCI devices. */ -#endif - - dep= &de_state; - - if (dep->de_mode == DEM_DISABLED) - { - /* This is the default, try to (re)locate the device. */ - conf_hw(dep); - if (dep->de_mode == DEM_DISABLED) - { - /* Probe failed, or the device is configured off. */ - reply_mess.m_type = DL_CONF_REPLY; - reply_mess.m_netdrv_net_dl_conf.stat = ENXIO; - mess_reply(mp, &reply_mess); - return; - } - if (dep->de_mode == DEM_ENABLED) - dp_init(dep); - } - - if (dep->de_mode == DEM_SINK) - { - strncpy((char *) dep->de_address.ea_addr, "ZDP", 6); - dep->de_address.ea_addr[5] = de_instance; - dp_confaddr(dep); - reply_mess.m_type = DL_CONF_REPLY; - reply_mess.m_netdrv_net_dl_conf.stat = OK; - memcpy(reply_mess.m_netdrv_net_dl_conf.hw_addr, - dep->de_address.ea_addr, - sizeof(reply_mess.m_netdrv_net_dl_conf.hw_addr)); - mess_reply(mp, &reply_mess); - return; - } - assert(dep->de_mode == DEM_ENABLED); - assert(dep->de_flags & DEF_ENABLED); - - dep->de_flags &= ~(DEF_PROMISC | DEF_MULTI | DEF_BROAD); - - if (mp->m_net_netdrv_dl_conf.mode & DL_PROMISC_REQ) - dep->de_flags |= DEF_PROMISC | DEF_MULTI | DEF_BROAD; - if (mp->m_net_netdrv_dl_conf.mode & DL_MULTI_REQ) - dep->de_flags |= DEF_MULTI; - if (mp->m_net_netdrv_dl_conf.mode & DL_BROAD_REQ) - dep->de_flags |= DEF_BROAD; - - dp_reinit(dep); - - reply_mess.m_type = DL_CONF_REPLY; - reply_mess.m_netdrv_net_dl_conf.stat = OK; - - memcpy(reply_mess.m_netdrv_net_dl_conf.hw_addr, dep->de_address.ea_addr, - sizeof(reply_mess.m_netdrv_net_dl_conf.hw_addr)); - - mess_reply(mp, &reply_mess); -} - -/*===========================================================================* - * do_int * - *===========================================================================*/ -static void do_int(dep) -dpeth_t *dep; -{ - if (dep->de_flags & (DEF_PACK_SEND | DEF_PACK_RECV)) - reply(dep); -} - -/*===========================================================================* - * do_getstat_s * - *===========================================================================*/ -static void do_getstat_s(mp) -message *mp; -{ - int r; - dpeth_t *dep; - - dep= &de_state; - - if (dep->de_mode == DEM_SINK) - { - put_userdata_s(mp->m_source, - mp->m_net_netdrv_dl_getstat_s.grant, - (vir_bytes) sizeof(dep->de_stat), &dep->de_stat); - - mp->m_type= DL_STAT_REPLY; - r= ipc_send(mp->m_source, mp); - if (r != OK) - panic("do_getstat: ipc_send failed: %d", r); - return; - } - assert(dep->de_mode == DEM_ENABLED); - assert(dep->de_flags & DEF_ENABLED); - dep->de_stat.ets_CRCerr += inb_reg0(dep, DP_CNTR0); dep->de_stat.ets_frameAll += inb_reg0(dep, DP_CNTR1); dep->de_stat.ets_missedP += inb_reg0(dep, DP_CNTR2); - put_userdata_s(mp->m_source, mp->m_net_netdrv_dl_getstat_s.grant, - sizeof(dep->de_stat), &dep->de_stat); - - mp->m_type= DL_STAT_REPLY; - r= ipc_send(mp->m_source, mp); - if (r != OK) - panic("do_getstat: ipc_send failed: %d", r); + memcpy(stat, &dep->de_stat, sizeof(*stat)); } /*===========================================================================* - * dp_stop * + * do_stop * *===========================================================================*/ -static void dp_stop(dep) -dpeth_t *dep; +static void do_stop(void) { + dpeth_t *dep; - if (dep->de_mode == DEM_SINK) - return; - assert(dep->de_mode == DEM_ENABLED); - - if (!(dep->de_flags & DEF_ENABLED)) - return; + dep = &de_state; outb_reg0(dep, DP_CR, CR_STP | CR_DM_ABORT); (dep->de_stopf)(dep); - - dep->de_flags= DEF_EMPTY; } /*===========================================================================* * dp_init * *===========================================================================*/ -static void dp_init(dep) -dpeth_t *dep; +static void dp_init(dpeth_t *dep) { - int dp_rcr_reg; int i, r; /* General initialization */ @@ -669,14 +350,7 @@ dpeth_t *dep; outb_reg0(dep, DP_RBCR0, 0); outb_reg0(dep, DP_RBCR1, 0); /* Step 4: */ - dp_rcr_reg = 0; - if (dep->de_flags & DEF_PROMISC) - dp_rcr_reg |= RCR_AB | RCR_PRO | RCR_AM; - if (dep->de_flags & DEF_BROAD) - dp_rcr_reg |= RCR_AB; - if (dep->de_flags & DEF_MULTI) - dp_rcr_reg |= RCR_AM; - outb_reg0(dep, DP_RCR, dp_rcr_reg); + outb_reg0(dep, DP_RCR, 0); /* Step 5: */ outb_reg0(dep, DP_TCR, TCR_INTERNAL); /* Step 6: */ @@ -718,7 +392,6 @@ dpeth_t *dep; inb_reg0(dep, DP_CNTR2); /* Finish the initialization. */ - dep->de_flags |= DEF_ENABLED; for (i= 0; ide_sendq_nr; i++) dep->de_sendq[i].sq_filled= 0; dep->de_sendq_head= 0; @@ -752,16 +425,13 @@ dpeth_t *dep; r= sys_irqenable(&dep->de_hook); if (r != OK) - { - panic("unable enable interrupts: %d", r); - } + panic("unable to enable interrupts: %d", r); } /*===========================================================================* * dp_confaddr * *===========================================================================*/ -static void dp_confaddr(dep) -dpeth_t *dep; +static void dp_confaddr(dpeth_t *dep) { int i; char eakey[16]; @@ -785,31 +455,10 @@ dpeth_t *dep; if (i != 0 && i != 6) env_panic(eakey); /* It's all or nothing */ } -/*===========================================================================* - * dp_reinit * - *===========================================================================*/ -static void dp_reinit(dep) -dpeth_t *dep; -{ - int dp_rcr_reg; - - outb_reg0(dep, DP_CR, CR_PS_P0 | CR_EXTRA); - - dp_rcr_reg = 0; - if (dep->de_flags & DEF_PROMISC) - dp_rcr_reg |= RCR_AB | RCR_PRO | RCR_AM; - if (dep->de_flags & DEF_BROAD) - dp_rcr_reg |= RCR_AB; - if (dep->de_flags & DEF_MULTI) - dp_rcr_reg |= RCR_AM; - outb_reg0(dep, DP_RCR, dp_rcr_reg); -} - /*===========================================================================* * dp_reset * *===========================================================================*/ -static void dp_reset(dep) -dpeth_t *dep; +static void dp_reset(dpeth_t *dep) { int i; @@ -835,21 +484,20 @@ dpeth_t *dep; dep->de_sendq_head= dep->de_sendq_tail= 0; for (i= 0; ide_sendq_nr; i++) dep->de_sendq[i].sq_filled= 0; - dp_send(dep); + netdriver_send(); dep->de_flags &= ~DEF_STOPPED; } /*===========================================================================* - * dp_check_ints * + * do_intr * *===========================================================================*/ -static void dp_check_ints(dep) -dpeth_t *dep; +static void do_intr(unsigned int __unused mask) { + dpeth_t *dep; int isr, tsr; - int size, sendq_tail; + int r, size, sendq_tail; - if (!(dep->de_flags & DEF_ENABLED)) - panic("dp8390: got premature interrupt"); + dep = &de_state; for(;;) { @@ -924,17 +572,12 @@ dpeth_t *dep; outb_reg0(dep, DP_TBCR0, size & 0xff); outb_reg0(dep, DP_CR, CR_TXP | CR_EXTRA); } - if (dep->de_flags & DEF_SEND_AVAIL) - dp_send(dep); + netdriver_send(); } if (isr & ISR_PRX) - { - /* Only call dp_recv if there is a read request */ - if (dep->de_flags & DEF_READING) - dp_recv(dep); - } - + netdriver_recv(); + if (isr & ISR_RXE) dep->de_stat.ets_recvErr++; if (isr & ISR_CNT) { @@ -949,12 +592,6 @@ dpeth_t *dep; { printW(); printf( "%s: got overwrite warning\n", dep->de_name); } #endif - if (dep->de_flags & DEF_READING) - { - printf( -"dp_check_ints: strange: overwrite warning and pending read request\n"); - dp_recv(dep); - } } if (isr & ISR_RDC) { @@ -972,31 +609,29 @@ dpeth_t *dep; "%s: NIC stopped\n", dep->de_name); } #endif dep->de_flags |= DEF_STOPPED; + netdriver_recv(); /* see if we can reset right now */ break; } } - if ((dep->de_flags & (DEF_READING|DEF_STOPPED)) == - (DEF_READING|DEF_STOPPED)) - { - /* The chip is stopped, and all arrived packets are - * delivered. - */ - dp_reset(dep); - } + + if ((r = sys_irqenable(&dep->de_hook)) != OK) + panic("unable enable interrupts: %d", r); } /*===========================================================================* - * dp_recv * + * do_recv * *===========================================================================*/ -static void dp_recv(dep) -dpeth_t *dep; +static ssize_t do_recv(struct netdriver_data *data, size_t max) { + dpeth_t *dep; dp_rcvhdr_t header; unsigned pageno, curr, next; - vir_bytes length; - int packet_processed, r; + size_t length; + int packet_processed; u16_t eth_type; + dep = &de_state; + packet_processed = FALSE; pageno = inb_reg0(dep, DP_BNRY) + 1; if (pageno == dep->de_stoppage) pageno = dep->de_startpage; @@ -1007,7 +642,16 @@ dpeth_t *dep; curr = inb_reg1(dep, DP_CURR); outb_reg0(dep, DP_CR, CR_PS_P0 | CR_EXTRA); - if (curr == pageno) break; + if (curr == pageno) { + if (dep->de_flags & DEF_STOPPED) { + /* The chip is stopped, and all arrived packets + * are delivered. + */ + dp_reset(dep); + } + + return SUSPEND; + } (dep->de_getblockf)(dep, pageno, (size_t)0, sizeof(header), &header); @@ -1017,8 +661,7 @@ dpeth_t *dep; length = (header.dr_rbcl | (header.dr_rbch << 8)) - sizeof(dp_rcvhdr_t); next = header.dr_next; - if (length < ETH_MIN_PACK_SIZE || - length > ETH_MAX_PACK_SIZE_TAGGED) + if (length < ETH_MIN_PACK_SIZE || length > max) { printf("%s: packet with strange length arrived: %d\n", dep->de_name, (int) length); @@ -1038,12 +681,9 @@ dpeth_t *dep; dep->de_stat.ets_fifoOver++; next = curr; } - else if ((header.dr_status & RSR_PRX) && - (dep->de_flags & DEF_ENABLED)) + else if (header.dr_status & RSR_PRX) { - r = dp_pkt2user_s(dep, pageno, length); - if (r != OK) - return; + dp_pkt2user_s(dep, data, pageno, length); packet_processed = TRUE; dep->de_stat.ets_packetR++; @@ -1054,32 +694,16 @@ dpeth_t *dep; outb_reg0(dep, DP_BNRY, next - 1); pageno = next; - } - while (!packet_processed); -} + } while (!packet_processed); -/*===========================================================================* - * dp_send * - *===========================================================================*/ -static void dp_send(dep) -dpeth_t *dep; -{ - if (!(dep->de_flags & DEF_SEND_AVAIL)) - return; - - dep->de_flags &= ~DEF_SEND_AVAIL; - do_vwrite_s(&dep->de_sendmsg, TRUE); + return length; } /*===========================================================================* * dp_getblock * *===========================================================================*/ -static void dp_getblock(dep, page, offset, size, dst) -dpeth_t *dep; -int page; -size_t offset; -size_t size; -void *dst; +static void dp_getblock(dpeth_t *dep, int page, size_t offset, size_t size, + void *dst) { offset = page * DP_PAGESIZE + offset; @@ -1089,12 +713,8 @@ void *dst; /*===========================================================================* * dp_pio8_getblock * *===========================================================================*/ -static void dp_pio8_getblock(dep, page, offset, size, dst) -dpeth_t *dep; -int page; -size_t offset; -size_t size; -void *dst; +static void dp_pio8_getblock(dpeth_t *dep, int page, size_t offset, + size_t size, void *dst) { offset = page * DP_PAGESIZE + offset; outb_reg0(dep, DP_RBCR0, size & 0xFF); @@ -1109,12 +729,8 @@ void *dst; /*===========================================================================* * dp_pio16_getblock * *===========================================================================*/ -static void dp_pio16_getblock(dep, page, offset, size, dst) -dpeth_t *dep; -int page; -size_t offset; -size_t size; -void *dst; +static void dp_pio16_getblock(dpeth_t *dep, int page, size_t offset, + size_t size, void *dst) { offset = page * DP_PAGESIZE + offset; outb_reg0(dep, DP_RBCR0, size & 0xFF); @@ -1130,99 +746,45 @@ void *dst; /*===========================================================================* * dp_pkt2user_s * *===========================================================================*/ -static int dp_pkt2user_s(dpeth_t *dep, int page, vir_bytes length) +static void dp_pkt2user_s(dpeth_t *dep, struct netdriver_data *data, int page, + size_t length) { int last, count; - if (!(dep->de_flags & DEF_READING)) - return EGENERIC; - last = page + (length - 1) / DP_PAGESIZE; if (last >= dep->de_stoppage) { count = (dep->de_stoppage - page) * DP_PAGESIZE - sizeof(dp_rcvhdr_t); - /* Save read_iovec since we need it twice. */ - dep->de_tmp_iovec_s = dep->de_read_iovec_s; - (dep->de_nic2userf_s)(dep, page * DP_PAGESIZE + - sizeof(dp_rcvhdr_t), &dep->de_tmp_iovec_s, 0, count); - (dep->de_nic2userf_s)(dep, dep->de_startpage * DP_PAGESIZE, - &dep->de_read_iovec_s, count, length - count); + (dep->de_nic2userf_s)(dep, data, + page * DP_PAGESIZE + sizeof(dp_rcvhdr_t), 0, count); + (dep->de_nic2userf_s)(dep, data, + dep->de_startpage * DP_PAGESIZE, count, length - count); } else { - (dep->de_nic2userf_s)(dep, page * DP_PAGESIZE + - sizeof(dp_rcvhdr_t), &dep->de_read_iovec_s, 0, length); + (dep->de_nic2userf_s)(dep, data, + page * DP_PAGESIZE + sizeof(dp_rcvhdr_t), 0, length); } - - dep->de_read_s = length; - dep->de_flags |= DEF_PACK_RECV; - dep->de_flags &= ~DEF_READING; - - return OK; } /*===========================================================================* * dp_user2nic_s * *===========================================================================*/ -static void dp_user2nic_s(dep, iovp, offset, nic_addr, count) -dpeth_t *dep; -iovec_dat_s_t *iovp; -vir_bytes offset; -int nic_addr; -vir_bytes count; +static void dp_user2nic_s(dpeth_t *dep, struct netdriver_data *data, + int nic_addr, size_t offset, size_t count) { - vir_bytes vir_hw; - int bytes, i, r; - - vir_hw = (vir_bytes)dep->de_locmem + nic_addr; - - i= 0; - while (count > 0) - { - if (i >= IOVEC_NR) - { - dp_next_iovec_s(iovp); - i= 0; - continue; - } - assert(i < iovp->iod_iovec_s); - if (offset >= iovp->iod_iovec[i].iov_size) - { - offset -= iovp->iod_iovec[i].iov_size; - i++; - continue; - } - bytes = iovp->iod_iovec[i].iov_size - offset; - if (bytes > count) - bytes = count; - - r= sys_safecopyfrom(iovp->iod_proc_nr, - iovp->iod_iovec[i].iov_grant, offset, - vir_hw, bytes); - if (r != OK) { - panic("dp_user2nic_s: sys_safecopyfrom failed: %d", r); - } - - count -= bytes; - vir_hw += bytes; - offset += bytes; - } - assert(count == 0); + netdriver_copyin(data, offset, dep->de_locmem + nic_addr, count); } /*===========================================================================* * dp_pio8_user2nic_s * *===========================================================================*/ -static void dp_pio8_user2nic_s(dep, iovp, offset, nic_addr, count) -dpeth_t *dep; -iovec_dat_s_t *iovp; -vir_bytes offset; -int nic_addr; -vir_bytes count; +static void dp_pio8_user2nic_s(dpeth_t *dep, struct netdriver_data *data, + int nic_addr, size_t offset, size_t count) { - int bytes, i, r; + int i; outb_reg0(dep, DP_ISR, ISR_RDC); @@ -1232,36 +794,7 @@ vir_bytes count; outb_reg0(dep, DP_RSAR1, nic_addr >> 8); outb_reg0(dep, DP_CR, CR_DM_RW | CR_PS_P0 | CR_STA); - i= 0; - while (count > 0) - { - if (i >= IOVEC_NR) - { - dp_next_iovec_s(iovp); - i= 0; - continue; - } - assert(i < iovp->iod_iovec_s); - if (offset >= iovp->iod_iovec[i].iov_size) - { - offset -= iovp->iod_iovec[i].iov_size; - i++; - continue; - } - bytes = iovp->iod_iovec[i].iov_size - offset; - if (bytes > count) - bytes = count; - - r= sys_safe_outsb(dep->de_data_port, iovp->iod_proc_nr, - iovp->iod_iovec[i].iov_grant, offset, bytes); - if (r != OK) { - panic("dp_pio8_user2nic_s: sys_safe_outsb failed: %d", - r); - } - count -= bytes; - offset += bytes; - } - assert(count == 0); + netdriver_portoutb(data, offset, dep->de_data_port, count); for (i= 0; i<100; i++) { @@ -1277,21 +810,13 @@ vir_bytes count; /*===========================================================================* * dp_pio16_user2nic_s * *===========================================================================*/ -static void dp_pio16_user2nic_s(dep, iovp, offset, nic_addr, count) -dpeth_t *dep; -iovec_dat_s_t *iovp; -vir_bytes offset; -int nic_addr; -vir_bytes count; +static void dp_pio16_user2nic_s(dpeth_t *dep, struct netdriver_data *data, + int nic_addr, size_t offset, size_t count) { - vir_bytes ecount; - cp_grant_id_t gid; - int i, r, bytes, user_proc; - u8_t two_bytes[2]; - int odd_byte; + size_t ecount; + int i; ecount= (count+1) & ~1; - odd_byte= 0; outb_reg0(dep, DP_ISR, ISR_RDC); outb_reg0(dep, DP_RBCR0, ecount & 0xFF); @@ -1300,73 +825,7 @@ vir_bytes count; outb_reg0(dep, DP_RSAR1, nic_addr >> 8); outb_reg0(dep, DP_CR, CR_DM_RW | CR_PS_P0 | CR_STA); - i= 0; - while (count > 0) - { - if (i >= IOVEC_NR) - { - dp_next_iovec_s(iovp); - i= 0; - continue; - } - assert(i < iovp->iod_iovec_s); - if (offset >= iovp->iod_iovec[i].iov_size) - { - offset -= iovp->iod_iovec[i].iov_size; - i++; - continue; - } - bytes = iovp->iod_iovec[i].iov_size - offset; - if (bytes > count) - bytes = count; - - user_proc= iovp->iod_proc_nr; - gid= iovp->iod_iovec[i].iov_grant; - if (odd_byte) - { - r= sys_safecopyfrom(user_proc, gid, offset, - (vir_bytes)&two_bytes[1], 1); - if (r != OK) { - panic("dp_pio16_user2nic: sys_safecopyfrom failed: %d", r); - } - outw(dep->de_data_port, *(u16_t *)two_bytes); - count--; - offset++; - bytes--; - odd_byte= 0; - if (!bytes) - continue; - } - ecount= bytes & ~1; - if (ecount != 0) - { - r= sys_safe_outsw(dep->de_data_port, user_proc, - gid, offset, ecount); - if (r != OK) { - panic("dp_pio16_user2nic: sys_safe_outsw failed: %d", r); - } - count -= ecount; - offset += ecount; - bytes -= ecount; - } - if (bytes) - { - assert(bytes == 1); - r= sys_safecopyfrom(user_proc, gid, offset, - (vir_bytes)&two_bytes[0], 1); - if (r != OK) { - panic("dp_pio16_user2nic: sys_safecopyfrom failed: %d", r); - } - count--; - offset++; - bytes--; - odd_byte= 1; - } - } - assert(count == 0); - - if (odd_byte) - outw(dep->de_data_port, *(u16_t *)two_bytes); + netdriver_portoutw(data, offset, dep->de_data_port, count); for (i= 0; i<100; i++) { @@ -1382,118 +841,36 @@ vir_bytes count; /*===========================================================================* * dp_nic2user_s * *===========================================================================*/ -static void dp_nic2user_s(dep, nic_addr, iovp, offset, count) -dpeth_t *dep; -int nic_addr; -iovec_dat_s_t *iovp; -vir_bytes offset; -vir_bytes count; +static void dp_nic2user_s(dpeth_t *dep, struct netdriver_data *data, + int nic_addr, size_t offset, size_t count) { - vir_bytes vir_hw; - int bytes, i, r; - - vir_hw = (vir_bytes)dep->de_locmem + nic_addr; - - i= 0; - while (count > 0) - { - if (i >= IOVEC_NR) - { - dp_next_iovec_s(iovp); - i= 0; - continue; - } - assert(i < iovp->iod_iovec_s); - if (offset >= iovp->iod_iovec[i].iov_size) - { - offset -= iovp->iod_iovec[i].iov_size; - i++; - continue; - } - bytes = iovp->iod_iovec[i].iov_size - offset; - if (bytes > count) - bytes = count; - - r= sys_safecopyto(iovp->iod_proc_nr, - iovp->iod_iovec[i].iov_grant, offset, - vir_hw, bytes); - if (r != OK) - panic("dp_nic2user_s: sys_safecopyto failed: %d", r); - - count -= bytes; - vir_hw += bytes; - offset += bytes; - } - assert(count == 0); + netdriver_copyout(data, offset, dep->de_locmem + nic_addr, count); } /*===========================================================================* * dp_pio8_nic2user_s * *===========================================================================*/ -static void dp_pio8_nic2user_s(dep, nic_addr, iovp, offset, count) -dpeth_t *dep; -int nic_addr; -iovec_dat_s_t *iovp; -vir_bytes offset; -vir_bytes count; +static void dp_pio8_nic2user_s(dpeth_t *dep, struct netdriver_data *data, + int nic_addr, size_t offset, size_t count) { - int bytes, i, r; - outb_reg0(dep, DP_RBCR0, count & 0xFF); outb_reg0(dep, DP_RBCR1, count >> 8); outb_reg0(dep, DP_RSAR0, nic_addr & 0xFF); outb_reg0(dep, DP_RSAR1, nic_addr >> 8); outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA); - i= 0; - while (count > 0) - { - if (i >= IOVEC_NR) - { - dp_next_iovec_s(iovp); - i= 0; - continue; - } - assert(i < iovp->iod_iovec_s); - if (offset >= iovp->iod_iovec[i].iov_size) - { - offset -= iovp->iod_iovec[i].iov_size; - i++; - continue; - } - bytes = iovp->iod_iovec[i].iov_size - offset; - if (bytes > count) - bytes = count; - - r= sys_safe_insb(dep->de_data_port, iovp->iod_proc_nr, - iovp->iod_iovec[i].iov_grant, offset, bytes); - if (r != OK) { - panic("dp_pio8_nic2user_s: sys_safe_insb failed: %d", r); - } - count -= bytes; - offset += bytes; - } - assert(count == 0); + netdriver_portinb(data, offset, dep->de_data_port, count); } /*===========================================================================* * dp_pio16_nic2user_s * *===========================================================================*/ -static void dp_pio16_nic2user_s(dep, nic_addr, iovp, offset, count) -dpeth_t *dep; -int nic_addr; -iovec_dat_s_t *iovp; -vir_bytes offset; -vir_bytes count; +static void dp_pio16_nic2user_s(dpeth_t *dep, struct netdriver_data *data, + int nic_addr, size_t offset, size_t count) { - vir_bytes ecount; - cp_grant_id_t gid; - int i, r, bytes, user_proc; - u8_t two_bytes[2]; - int odd_byte; + size_t ecount; ecount= (count+1) & ~1; - odd_byte= 0; outb_reg0(dep, DP_RBCR0, ecount & 0xFF); outb_reg0(dep, DP_RBCR1, ecount >> 8); @@ -1501,166 +878,49 @@ vir_bytes count; outb_reg0(dep, DP_RSAR1, nic_addr >> 8); outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA); - i= 0; - while (count > 0) - { - if (i >= IOVEC_NR) - { - dp_next_iovec_s(iovp); - i= 0; - continue; - } - assert(i < iovp->iod_iovec_s); - if (offset >= iovp->iod_iovec[i].iov_size) - { - offset -= iovp->iod_iovec[i].iov_size; - i++; - continue; - } - bytes = iovp->iod_iovec[i].iov_size - offset; - if (bytes > count) - bytes = count; - - user_proc= iovp->iod_proc_nr; - gid= iovp->iod_iovec[i].iov_grant; - if (odd_byte) - { - r= sys_safecopyto(user_proc, gid, offset, - (vir_bytes)&two_bytes[1], 1); - if (r != OK) { - panic("dp_pio16_nic2user: sys_safecopyto failed: %d", r); - } - count--; - offset++; - bytes--; - odd_byte= 0; - if (!bytes) - continue; - } - ecount= bytes & ~1; - if (ecount != 0) - { - r= sys_safe_insw(dep->de_data_port, user_proc, gid, - offset, ecount); - if (r != OK) { - panic("dp_pio16_nic2user: sys_safe_insw failed: %d", - r); - } - count -= ecount; - offset += ecount; - bytes -= ecount; - } - if (bytes) - { - assert(bytes == 1); - *(u16_t *)two_bytes= inw(dep->de_data_port); - r= sys_safecopyto(user_proc, gid, offset, - (vir_bytes)&two_bytes[0], 1); - if (r != OK) - { - panic("dp_pio16_nic2user: sys_safecopyto failed: %d", - r); - } - count--; - offset++; - bytes--; - odd_byte= 1; - } - } - assert(count == 0); -} - -/*===========================================================================* - * dp_next_iovec_s * - *===========================================================================*/ -static void dp_next_iovec_s(iovp) -iovec_dat_s_t *iovp; -{ - assert(iovp->iod_iovec_s > IOVEC_NR); - - iovp->iod_iovec_s -= IOVEC_NR; - - iovp->iod_iovec_offset += IOVEC_NR * sizeof(iovec_t); - - get_userdata_s(iovp->iod_proc_nr, iovp->iod_grant, - iovp->iod_iovec_offset, - (iovp->iod_iovec_s > IOVEC_NR ? IOVEC_NR : iovp->iod_iovec_s) * - sizeof(iovp->iod_iovec[0]), iovp->iod_iovec); + netdriver_portinw(data, offset, dep->de_data_port, count); } /*===========================================================================* * conf_hw * *===========================================================================*/ -static void conf_hw(dep) -dpeth_t *dep; +static void conf_hw(dpeth_t *dep) { - static eth_stat_t empty_stat = {0, 0, 0, 0, 0, 0 /* ,... */ }; - int confnr; dp_conf_t *dcp; - dep->de_mode= DEM_DISABLED; /* Superfluous */ - /* Pick a default configuration for this instance. */ confnr= MIN(de_instance, DP_CONF_NR-1); dcp= &dp_conf[confnr]; update_conf(dep, dcp); - if (dep->de_mode != DEM_ENABLED) - return; if (!wdeth_probe(dep) && !ne_probe(dep) && !el2_probe(dep)) - { - printf("%s: No ethernet card found at 0x%x\n", - dep->de_name, dep->de_base_port); - dep->de_mode= DEM_DISABLED; - return; - } + panic("no ethernet card found at 0x%x\n", dep->de_base_port); /* XXX */ if (dep->de_linmem == 0) dep->de_linmem= 0xFFFF0000; - - dep->de_flags = DEF_EMPTY; - dep->de_stat = empty_stat; } /*===========================================================================* * update_conf * *===========================================================================*/ -static void update_conf(dep, dcp) -dpeth_t *dep; -dp_conf_t *dcp; +static void update_conf(dpeth_t *dep, dp_conf_t *dcp) { long v; static char dpc_fmt[] = "x:d:x:x"; char eckey[16]; -#if ENABLE_PCI if (dep->de_pci) { - if (dep->de_pci == 1) - { - /* PCI device is present */ - dep->de_mode= DEM_ENABLED; - } + /* PCI device is present */ return; /* Already configured */ } -#endif strlcpy(eckey, "DPETH0", sizeof(eckey)); eckey[5] += de_instance; /* Get the default settings and modify them from the environment. */ - dep->de_mode= DEM_SINK; v= dcp->dpc_port; - switch (env_parse(eckey, dpc_fmt, 0, &v, 0x0000L, 0xFFFFL)) { - case EP_OFF: - dep->de_mode= DEM_DISABLED; - break; - case EP_ON: - case EP_SET: - dep->de_mode= DEM_ENABLED; /* Might become disabled if - * all probes fail */ - break; - } + (void) env_parse(eckey, dpc_fmt, 0, &v, 0x0000L, 0xFFFFL); dep->de_base_port= v; v= dcp->dpc_irq | DEI_DEFAULT; @@ -1679,8 +939,7 @@ dp_conf_t *dcp; /*===========================================================================* * map_hw_buffer * *===========================================================================*/ -static void map_hw_buffer(dep) -dpeth_t *dep; +static void map_hw_buffer(dpeth_t *dep) { if (dep->de_prog_IO) @@ -1699,108 +958,6 @@ dpeth_t *dep; panic("map_hw_buffer: vm_map_phys failed"); } -/*===========================================================================* - * calc_iovec_size_s * - *===========================================================================*/ -static int calc_iovec_size_s(iovp) -iovec_dat_s_t *iovp; -{ - /* Calculate the size of a request. Note that the iovec_dat - * structure will be unusable after calc_iovec_size_s. - */ - int size; - int i; - - size= 0; - i= 0; - while (i < iovp->iod_iovec_s) - { - if (i >= IOVEC_NR) - { - dp_next_iovec_s(iovp); - i= 0; - continue; - } - size += iovp->iod_iovec[i].iov_size; - i++; - } - return size; -} - -/*===========================================================================* - * reply * - *===========================================================================*/ -static void reply(dep) -dpeth_t *dep; -{ - message reply; - int flags; - int r; - - flags = DL_NOFLAGS; - if (dep->de_flags & DEF_PACK_SEND) - flags |= DL_PACK_SEND; - if (dep->de_flags & DEF_PACK_RECV) - flags |= DL_PACK_RECV; - - reply.m_type = DL_TASK_REPLY; - reply.m_netdrv_net_dl_task.flags = flags; - reply.m_netdrv_net_dl_task.count = dep->de_read_s; - r= ipc_send(dep->de_client, &reply); - - if (r < 0) - panic("dp8390: ipc_send failed: %d", r); - - dep->de_read_s = 0; - dep->de_flags &= ~(DEF_PACK_SEND | DEF_PACK_RECV); -} - -/*===========================================================================* - * mess_reply * - *===========================================================================*/ -static void mess_reply(req, reply_mess) -message *req; -message *reply_mess; -{ - if (ipc_send(req->m_source, reply_mess) != OK) - panic("dp8390: unable to mess_reply"); -} - -/*===========================================================================* - * get_userdata_s * - *===========================================================================*/ -static void get_userdata_s(user_proc, grant, offset, count, loc_addr) -int user_proc; -cp_grant_id_t grant; -vir_bytes offset; -vir_bytes count; -void *loc_addr; -{ - int r; - - r= sys_safecopyfrom(user_proc, grant, offset, - (vir_bytes)loc_addr, count); - if (r != OK) - panic("get_userdata: sys_safecopyfrom failed: %d", r); -} - -/*===========================================================================* - * put_userdata_s * - *===========================================================================*/ -static void put_userdata_s(user_proc, grant, count, loc_addr) -int user_proc; -cp_grant_id_t grant; -size_t count; -void *loc_addr; -{ - int r; - - r= sys_safecopyto(user_proc, grant, 0, (vir_bytes)loc_addr, - count); - if (r != OK) - panic("put_userdata: sys_safecopyto failed: %d", r); -} - u8_t inb(port_t port) { int r; @@ -1845,29 +1002,19 @@ void outw(port_t port, u16_t value) } static void insb(port_t port, void *buf, size_t size) -{ - do_vir_insb(port, SELF, (vir_bytes)buf, size); -} - -static void insw(port_t port, void *buf, size_t size) -{ - do_vir_insw(port, SELF, (vir_bytes)buf, size); -} - -static void do_vir_insb(port_t port, int proc, vir_bytes buf, size_t size) { int r; - r= sys_insb(port, proc, (void *) buf, size); + r= sys_insb(port, SELF, buf, size); if (r != OK) panic("sys_sdevio failed: %d", r); } -static void do_vir_insw(port_t port, int proc, vir_bytes buf, size_t size) +static void insw(port_t port, void *buf, size_t size) { int r; - r= sys_insw(port, proc, (void *) buf, size); + r= sys_insw(port, SELF, buf, size); if (r != OK) panic("sys_sdevio failed: %d", r); } diff --git a/minix/drivers/net/dp8390/dp8390.h b/minix/drivers/net/dp8390/dp8390.h index 342bb632b..ab02f7baf 100644 --- a/minix/drivers/net/dp8390/dp8390.h +++ b/minix/drivers/net/dp8390/dp8390.h @@ -173,45 +173,19 @@ typedef struct dp_rcvhdr struct dpeth; struct iovec_dat; struct iovec_dat_s; -typedef void(*dp_initf_t) (struct dpeth *dep); -typedef void(*dp_stopf_t) (struct dpeth *dep); -typedef void(*dp_user2nicf_t) (struct dpeth *dep, struct iovec_dat - *iovp, vir_bytes offset, int nic_addr, vir_bytes count); -typedef void(*dp_user2nicf_s_t) (struct dpeth *dep, struct iovec_dat_s - *iovp, vir_bytes offset, int nic_addr, vir_bytes count); -typedef void(*dp_nic2userf_t) (struct dpeth *dep, int nic_addr, struct - iovec_dat *iovp, vir_bytes offset, vir_bytes count); -typedef void(*dp_nic2userf_s_t) (struct dpeth *dep, int nic_addr, struct - iovec_dat_s *iovp, vir_bytes offset, vir_bytes count); -#if 0 -typedef void(*dp_getheaderf_t) (struct dpeth *dep, int page, struct - dp_rcvhdr *h, u16_t *eth_type); -#endif -typedef void(*dp_getblock_t) (struct dpeth *dep, int page, size_t +typedef void (*dp_initf_t)(struct dpeth *dep); +typedef void (*dp_stopf_t)(struct dpeth *dep); +typedef void (*dp_user2nicf_s_t)(struct dpeth *dep, + struct netdriver_data *data, int nic_addr, size_t offset, + size_t count); +typedef void (*dp_nic2userf_s_t)(struct dpeth *dep, + struct netdriver_data *data, int nic_addr, size_t offset, + size_t count); +typedef void (*dp_getblock_t)(struct dpeth *dep, int page, size_t offset, size_t size, void *dst); -/* iovectors are handled IOVEC_NR entries at a time. */ -#define IOVEC_NR 16 - typedef int irq_hook_t; -typedef struct iovec_dat -{ - iovec_t iod_iovec[IOVEC_NR]; - int iod_iovec_s; - endpoint_t iod_proc_nr; - vir_bytes iod_iovec_addr; -} iovec_dat_t; - -typedef struct iovec_dat_s -{ - iovec_s_t iod_iovec[IOVEC_NR]; - int iod_iovec_s; - int iod_proc_nr; - cp_grant_id_t iod_grant; - vir_bytes iod_iovec_offset; -} iovec_dat_s_t; - #define SENDQ_NR 2 /* Maximum size of the send queue */ #define SENDQ_PAGES 6 /* 6 * DP_PAGESIZE >= 1514 bytes */ @@ -250,10 +224,8 @@ typedef struct dpeth int de_startpage; int de_stoppage; -#if ENABLE_PCI /* PCI config */ char de_pci; /* TRUE iff PCI device */ -#endif /* Do it yourself send queue */ struct sendq @@ -268,14 +240,7 @@ typedef struct dpeth /* Fields for internal use by the dp8390 driver. */ int de_flags; - int de_mode; eth_stat_t de_stat; - iovec_dat_s_t de_read_iovec_s; - iovec_dat_s_t de_write_iovec_s; - iovec_dat_s_t de_tmp_iovec_s; - vir_bytes de_read_s; - endpoint_t de_client; - message de_sendmsg; dp_user2nicf_s_t de_user2nicf_s; dp_nic2userf_s_t de_nic2userf_s; dp_getblock_t de_getblockf; @@ -283,24 +248,10 @@ typedef struct dpeth #define DEI_DEFAULT 0x8000 -#define DEF_EMPTY 0x000 -#define DEF_PACK_SEND 0x001 -#define DEF_PACK_RECV 0x002 -#define DEF_SEND_AVAIL 0x004 -#define DEF_READING 0x010 -#define DEF_PROMISC 0x040 -#define DEF_MULTI 0x080 -#define DEF_BROAD 0x100 -#define DEF_ENABLED 0x200 -#define DEF_STOPPED 0x400 +#define DEF_EMPTY 0x00 +#define DEF_STOPPED 0x01 -#define DEM_DISABLED 0x0 -#define DEM_SINK 0x1 -#define DEM_ENABLED 0x2 - -#if !__minix_vmd -#define debug 0 /* Standard Minix lacks debug variable */ -#endif +#define debug 0 /* * $PchId: dp8390.h,v 1.10 2005/02/10 17:26:06 philip Exp $ diff --git a/minix/drivers/net/dp8390/local.h b/minix/drivers/net/dp8390/local.h index 3ee5ba3f1..be8a25015 100644 --- a/minix/drivers/net/dp8390/local.h +++ b/minix/drivers/net/dp8390/local.h @@ -5,7 +5,6 @@ local.h #define ENABLE_WDETH 1 #define ENABLE_NE2000 1 #define ENABLE_3C503 1 -#define ENABLE_PCI 1 struct dpeth; diff --git a/minix/drivers/net/dp8390/ne2000.c b/minix/drivers/net/dp8390/ne2000.c index f6d47d4c8..de0ee889d 100644 --- a/minix/drivers/net/dp8390/ne2000.c +++ b/minix/drivers/net/dp8390/ne2000.c @@ -8,12 +8,10 @@ Created: March 15, 1994 by Philip Homburg */ #include +#include #include #include -#if __minix_vmd -#include "config.h" -#endif #include "local.h" #include "dp8390.h" diff --git a/minix/drivers/net/dp8390/rtl8029.c b/minix/drivers/net/dp8390/rtl8029.c index f69453da9..c66f43bae 100644 --- a/minix/drivers/net/dp8390/rtl8029.c +++ b/minix/drivers/net/dp8390/rtl8029.c @@ -7,6 +7,7 @@ Created: April 2000 by Philip Homburg */ #include +#include #include #include @@ -20,8 +21,6 @@ Created: April 2000 by Philip Homburg #include "dp8390.h" #include "rtl8029.h" -#if ENABLE_PCI - static void rtl_init(struct dpeth *dep); #if 0 static u16_t get_ee_word(dpeth_t *dep, int a); @@ -312,8 +311,6 @@ dpeth_t *dep; } #endif -#endif /* ENABLE_PCI */ - /* * $PchId: rtl8029.c,v 1.7 2004/08/03 12:16:58 philip Exp $ */ diff --git a/minix/drivers/net/dp8390/wdeth.c b/minix/drivers/net/dp8390/wdeth.c index 2d21f5af4..e9feb7991 100644 --- a/minix/drivers/net/dp8390/wdeth.c +++ b/minix/drivers/net/dp8390/wdeth.c @@ -5,6 +5,7 @@ Created: March 14, 1994 by Philip Homburg */ #include +#include #include #include @@ -70,9 +71,6 @@ dpeth_t *dep; int we_type; int sendq_nr; - assert(dep->de_mode == DEM_ENABLED); - assert(!(dep->de_flags & DEF_ENABLED)); - dep->de_address.ea_addr[0] = inb_we(dep, EPL_EA0); dep->de_address.ea_addr[1] = inb_we(dep, EPL_EA1); dep->de_address.ea_addr[2] = inb_we(dep, EPL_EA2); diff --git a/minix/drivers/net/dpeth/3c501.c b/minix/drivers/net/dpeth/3c501.c index 14c43bc05..d74600279 100644 --- a/minix/drivers/net/dpeth/3c501.c +++ b/minix/drivers/net/dpeth/3c501.c @@ -10,7 +10,7 @@ */ #include -#include +#include #include #include #include "dp.h" @@ -23,17 +23,17 @@ static unsigned char StationAddress[SA_ADDR_LEN] = {0, 0, 0, 0, 0, 0,}; static buff_t *TxBuff = NULL; /* -** Name: void el1_getstats(dpeth_t *dep) +** Name: el1_getstats ** Function: Reads statistics counters from board. **/ static void el1_getstats(dpeth_t * dep) { - return; /* Nothing to do */ + /* Nothing to do */ } /* -** Name: void el1_reset(dpeth_t *dep) +** Name: el1_reset ** Function: Reset function specific for Etherlink hardware. */ static void el1_reset(dpeth_t * dep) @@ -49,7 +49,6 @@ static void el1_reset(dpeth_t * dep) for (ix = EL1_ADDRESS; ix < SA_ADDR_LEN; ix += 1) outb_el1(dep, ix, StationAddress[ix]); - lock(); /* Enable DMA/Interrupt, gain control of Buffer */ outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS); /* Clear RX packet area */ @@ -60,22 +59,19 @@ static void el1_reset(dpeth_t * dep) inb_el1(dep, EL1_RECV); inb_el1(dep, EL1_XMIT); dep->de_flags &= NOT(DEF_XMIT_BUSY); - unlock(); - return; /* Done */ } /* -** Name: void el1_dumpstats(dpeth_t *dep, int port, vir_bytes size) +** Name: el1_dumpstats ** Function: Dumps counter on screen (support for console display). */ static void el1_dumpstats(dpeth_t * UNUSED(dep)) { - return; } /* -** Name: void el1_mode_init(dpeth_t *dep) +** Name: el1_mode_init ** Function: Initializes receicer mode */ static void el1_mode_init(dpeth_t * dep) @@ -95,125 +91,93 @@ static void el1_mode_init(dpeth_t * dep) } outb_el1(dep, EL1_RECV, dep->de_recv_mode); inb_el1(dep, EL1_RECV); - return; } /* -** Name: void el1_recv(dpeth_t *dep, int from, int size) +** Name: el1_recv ** Function: Receive function. Called from interrupt handler to ** unload recv. buffer or from main (packet to client) */ -static void el1_recv(dpeth_t * dep, int from, int size) +static ssize_t el1_recv(dpeth_t *dep, struct netdriver_data *data, size_t max) { buff_t *rxptr; + size_t size; - while ((dep->de_flags & DEF_READING) && (rxptr = dep->de_recvq_head)) { + if ((rxptr = dep->de_recvq_head) == NULL) + return SUSPEND; - /* Remove buffer from queue and free buffer */ - lock(); - if (dep->de_recvq_tail == dep->de_recvq_head) - dep->de_recvq_head = dep->de_recvq_tail = NULL; - else - dep->de_recvq_head = rxptr->next; - unlock(); + /* Remove buffer from queue and free buffer */ + if (dep->de_recvq_tail == dep->de_recvq_head) + dep->de_recvq_head = dep->de_recvq_tail = NULL; + else + dep->de_recvq_head = rxptr->next; - /* Copy buffer to user area */ - mem2user(dep, rxptr); + /* Copy buffer to user area */ + size = MIN(rxptr->size, max); - /* Reply information */ - dep->de_read_s = rxptr->size; - dep->de_flags |= DEF_ACK_RECV; - dep->de_flags &= NOT(DEF_READING); + netdriver_copyout(data, 0, rxptr->buffer, size); - /* Return buffer to the idle pool */ - free_buff(dep, rxptr); - } - return; + /* Return buffer to the idle pool */ + free_buff(dep, rxptr); + + return size; } /* -** Name: void el1_send(dpeth_t *dep, int from_int, int pktsize) -** Function: Send function. Called from main to transit a packet or -** from interrupt handler when a new packet was queued. +** Name: el1_send +** Function: Send function. */ -static void el1_send(dpeth_t * dep, int from_int, int pktsize) +static int el1_send(dpeth_t *dep, struct netdriver_data *data, size_t size) { buff_t *txbuff; clock_t now; - if (from_int == FALSE) { - - if ((txbuff = alloc_buff(dep, pktsize + sizeof(buff_t))) != NULL) { - - /* Fill transmit buffer from user area */ - txbuff->next = NULL; - txbuff->size = pktsize; - txbuff->client = dep->de_client; - user2mem(dep, txbuff); - } else - panic("out of memory for Tx"); - - } else if ((txbuff = dep->de_xmitq_head) != NULL) { - - /* Get first packet in queue */ - lock(); - if (dep->de_xmitq_tail == dep->de_xmitq_head) - dep->de_xmitq_head = dep->de_xmitq_tail = NULL; - else - dep->de_xmitq_head = txbuff->next; - unlock(); - pktsize = txbuff->size; - - } else - panic("should not be sending "); - - if ((dep->de_flags & DEF_XMIT_BUSY)) { - if (from_int) panic("should not be sending "); + if (dep->de_flags & DEF_XMIT_BUSY) { getticks(&now); if ((now - dep->de_xmit_start) > 4) { /* Transmitter timed out */ DEBUG(printf("3c501: transmitter timed out ... \n")); dep->de_stat.ets_sendErr += 1; dep->de_flags &= NOT(DEF_XMIT_BUSY); - el1_reset(dep); - } - - /* Queue packet */ - lock(); /* Queue packet to receive queue */ - if (dep->de_xmitq_head == NULL) - dep->de_xmitq_head = txbuff; - else - dep->de_xmitq_tail->next = txbuff; - dep->de_xmitq_tail = txbuff; - unlock(); - } else { - /* Save for retransmission */ - TxBuff = txbuff; - dep->de_flags |= (DEF_XMIT_BUSY | DEF_ACK_SEND); - - /* Setup board for packet loading */ - lock(); /* Buffer to processor */ - outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS); - inb_el1(dep, EL1_RECV); /* Clears any spurious interrupt */ - inb_el1(dep, EL1_XMIT); - outw_el1(dep, EL1_RECVPTR, 0); /* Clears RX packet area */ - - /* Loads packet */ - outw_el1(dep, EL1_XMITPTR, (EL1_BFRSIZ - pktsize)); - outsb(dep->de_data_port, SELF, txbuff->buffer, pktsize); - /* Starts transmitter */ - outw_el1(dep, EL1_XMITPTR, (EL1_BFRSIZ - pktsize)); - outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_XMIT); /* There it goes... */ - unlock(); - - getticks(&dep->de_xmit_start); - dep->de_flags &= NOT(DEF_SENDING); + /* Try sending anyway. */ + } else + return SUSPEND; } - return; + + /* Since we may have to retransmit, we need a local copy. */ + if ((txbuff = alloc_buff(dep, size + sizeof(buff_t))) == NULL) + panic("out of memory"); + + /* Fill transmit buffer from user area */ + txbuff->next = NULL; + txbuff->size = size; + + netdriver_copyin(data, 0, txbuff->buffer, size); + + /* Save for retransmission */ + TxBuff = txbuff; + dep->de_flags |= DEF_XMIT_BUSY; + + /* Setup board for packet loading */ + outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS); + inb_el1(dep, EL1_RECV); /* Clears any spurious interrupt */ + inb_el1(dep, EL1_XMIT); + outw_el1(dep, EL1_RECVPTR, 0); /* Clears RX packet area */ + + /* Loads packet */ + outw_el1(dep, EL1_XMITPTR, (EL1_BFRSIZ - size)); + outsb(dep->de_data_port, txbuff->buffer, size); + /* Starts transmitter */ + outw_el1(dep, EL1_XMITPTR, (EL1_BFRSIZ - size)); + outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_XMIT); /* There it goes... */ + + getticks(&dep->de_xmit_start); + + return OK; } /* -** Name: void el1_stop(dpeth_t *dep) +** Name: el1_stop ** Function: Stops board and disable interrupts. */ static void el1_stop(dpeth_t * dep) @@ -225,11 +189,10 @@ static void el1_stop(dpeth_t * dep) outb_el1(dep, EL1_CSR, ECSR_RESET); outb_el1(dep, EL1_CSR, ECSR_SYS); sys_irqdisable(&dep->de_hook); /* Disable interrupt */ - return; } /* -** Name: void el1_interrupt(dpeth_t *dep) +** Name: el1_interrupt ** Function: Interrupt handler. Acknwledges transmit interrupts ** or unloads receive buffer to memory queue. */ @@ -264,7 +227,6 @@ static void el1_interrupt(dpeth_t * dep) } DEBUG(printf("3c501: got xmit interrupt (0x%02X)\n", isr)); el1_reset(dep); - } else { /** if (inw_el1(dep, EL1_XMITPTR) == EL1_BFRSIZ) **/ /* Packet transmitted successfully */ @@ -272,12 +234,9 @@ static void el1_interrupt(dpeth_t * dep) dep->bytes_Tx += (long) (TxBuff->size); free_buff(dep, TxBuff); dep->de_flags &= NOT(DEF_XMIT_BUSY); - if ((dep->de_flags & DEF_SENDING) && dep->de_xmitq_head) { - /* Pending transmit request available in queue */ - el1_send(dep, TRUE, 0); - if (dep->de_flags & (DEF_XMIT_BUSY | DEF_ACK_SEND)) - return; - } + netdriver_send(); + if (dep->de_flags & DEF_XMIT_BUSY) + return; } } else if ((csr & (ECSR_RECV | ECSR_XMTBSY)) == (ECSR_RECV | ECSR_XMTBSY)) { @@ -301,21 +260,20 @@ static void el1_interrupt(dpeth_t * dep) /* Got a good packet. Read it from buffer */ outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS); outw_el1(dep, EL1_XMITPTR, 0); - insb(dep->de_data_port, SELF, rxptr->buffer, pktsize); + insb(dep->de_data_port, rxptr->buffer, pktsize); rxptr->next = NULL; rxptr->size = pktsize; dep->de_stat.ets_packetR += 1; dep->bytes_Rx += (long) pktsize; - lock(); /* Queue packet to receive queue */ + /* Queue packet to receive queue */ if (dep->de_recvq_head == NULL) dep->de_recvq_head = rxptr; else dep->de_recvq_tail->next = rxptr; dep->de_recvq_tail = rxptr; - unlock(); /* Reply to pending Receive requests, if any */ - el1_recv(dep, TRUE, 0); + netdriver_recv(); } } else { /* Nasty condition, should never happen */ DEBUG( @@ -337,11 +295,10 @@ static void el1_interrupt(dpeth_t * dep) /* Be sure that interrupts are cleared */ inb_el1(dep, EL1_RECV); inb_el1(dep, EL1_XMIT); - return; } /* -** Name: void el1_init(dpeth_t *dep) +** Name: el1_init ** Function: Initalizes board hardware and driver data structures. */ static void el1_init(dpeth_t * dep) @@ -376,12 +333,10 @@ static void el1_init(dpeth_t * dep) dep->de_getstatsf = el1_getstats; dep->de_dumpstatsf = el1_dumpstats; dep->de_interruptf = el1_interrupt; - - return; /* Done */ } /* -** Name: int el1_probe(dpeth_t *dep) +** Name: el1_probe ** Function: Checks for presence of the board. */ int el1_probe(dpeth_t * dep) diff --git a/minix/drivers/net/dpeth/3c503.c b/minix/drivers/net/dpeth/3c503.c index e20f1fd94..8b3503e1b 100644 --- a/minix/drivers/net/dpeth/3c503.c +++ b/minix/drivers/net/dpeth/3c503.c @@ -10,6 +10,7 @@ */ #include +#include #include #include #include "dp.h" @@ -20,7 +21,7 @@ #include "3c503.h" /* -** Name: void el2_init(dpeth_t *dep); +** Name: el2_init ** Function: Initalize hardware and data structures. */ static void el2_init(dpeth_t * dep) @@ -97,11 +98,10 @@ static void el2_init(dpeth_t * dep) for (ix = 0; ix < SA_ADDR_LEN; ix += 1) printf("%02X%c", dep->de_address.ea_addr[ix], ix < SA_ADDR_LEN - 1 ? ':' : '\n'); - return; } /* -** Name: void el2_stop(dpeth_t *dep); +** Name: el2_stop ** Function: Stops board by disabling interrupts. */ static void el2_stop(dpeth_t * dep) @@ -109,11 +109,10 @@ static void el2_stop(dpeth_t * dep) outb_el2(dep, EL2_CFGR, ECFGR_IRQOFF); sys_irqdisable(&dep->de_hook); /* disable interrupts */ - return; } /* -** Name: void el2_probe(dpeth_t *dep); +** Name: el2_probe ** Function: Probe for the presence of an EtherLink II card. ** Initialize memory addressing if card detected. */ @@ -132,9 +131,9 @@ int el2_probe(dpeth_t * dep) /* Resets board */ outb_el2(dep, EL2_CNTR, ECNTR_RESET | thin); - milli_delay(1); + micro_delay(1000); outb_el2(dep, EL2_CNTR, thin); - milli_delay(5); + micro_delay(5000); /* Map the address PROM to lower I/O address range */ outb_el2(dep, EL2_CNTR, ECNTR_SAPROM | thin); diff --git a/minix/drivers/net/dpeth/3c509.c b/minix/drivers/net/dpeth/3c509.c index 74e66982a..d1b6dc4c2 100644 --- a/minix/drivers/net/dpeth/3c509.c +++ b/minix/drivers/net/dpeth/3c509.c @@ -10,7 +10,7 @@ */ #include -#include +#include #include #include @@ -25,7 +25,7 @@ static const char *const IfNamesMsg[] = { }; /* -** Name: void el3_update_stats(dpeth_t *dep) +** Name: el3_update_stats ** Function: Reads statistic counters from board ** and updates local counters. */ @@ -52,36 +52,30 @@ static void el3_update_stats(dpeth_t * dep) /* Goes back to operating window and enables statistics */ SetWindow(WNO_Operating); outw_el3(dep, REG_CmdStatus, CMD_StatsEnable); - - return; } /* -** Name: void el3_getstats(dpeth_t *dep) +** Name: el3_getstats ** Function: Reads statistics counters from board. */ static void el3_getstats(dpeth_t * dep) { - lock(); el3_update_stats(dep); - unlock(); - return; } /* -** Name: void el3_dodump(dpeth_t *dep) +** Name: el3_dodump ** Function: Dumps counter on screen (support for console display). */ static void el3_dodump(dpeth_t * dep) { el3_getstats(dep); - return; } /* -** Name: void el3_rx_mode(dpeth_t *dep) +** Name: el3_rx_mode ** Function: Initializes receiver mode */ static void el3_rx_mode(dpeth_t * dep) @@ -95,85 +89,49 @@ static void el3_rx_mode(dpeth_t * dep) outw_el3(dep, REG_CmdStatus, CMD_RxReset); outw_el3(dep, REG_CmdStatus, CMD_SetRxFilter | dep->de_recv_mode); outw_el3(dep, REG_CmdStatus, CMD_RxEnable); - - return; } /* -** Name: void el3_reset(dpeth_t *dep) +** Name: el3_reset ** Function: Reset function specific for Etherlink hardware. */ static void el3_reset(dpeth_t * UNUSED(dep)) { - return; /* Done */ } /* -** Name: void el3_write_fifo(dpeth_t * dep, int pktsize); -** Function: Writes a packet from user area to board. -** Remark: Writing a word/dword at a time may result faster -** but is a lot more complicated. Let's go simpler way. -*/ -static void el3_write_fifo(dpeth_t * dep, int pktsize) -{ - int bytes, ix = 0; - iovec_dat_s_t *iovp = &dep->de_write_iovec; - int r, padding = pktsize; - - do { /* Writes chuncks of packet from user buffers */ - - bytes = iovp->iod_iovec[ix].iov_size; /* Size of buffer */ - if (bytes > pktsize) bytes = pktsize; - /* Writes from user buffer to Tx FIFO */ - r= sys_safe_outsb(dep->de_data_port, iovp->iod_proc_nr, - iovp->iod_iovec[ix].iov_grant, 0, bytes); - if (r != OK) - panic("el3_write_fifo: sys_safe_outsb failed: %d", r); - - if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */ - dp_next_iovec(iovp); - ix = 0; - } - /* Till packet done */ - } while ((pktsize -= bytes) > 0); - while ((padding++ % sizeof(long)) != 0) outb(dep->de_data_port, 0x00); - return; -} - -/* -** Name: void el3_recv(dpeth_t *dep, int fromint, int size) +** Name: el3_recv ** Function: Receive function. Called from interrupt handler or ** from main to unload recv. buffer (packet to client) */ -static void el3_recv(dpeth_t *dep, int fromint, int size) +static ssize_t el3_recv(dpeth_t *dep, struct netdriver_data *data, size_t max) { buff_t *rxptr; + size_t size; - while ((dep->de_flags & DEF_READING) && (rxptr = dep->de_recvq_head)) { + if ((rxptr = dep->de_recvq_head) == NULL) + return SUSPEND; - lock(); /* Remove buffer from queue */ - if (dep->de_recvq_tail == dep->de_recvq_head) - dep->de_recvq_head = dep->de_recvq_tail = NULL; - else - dep->de_recvq_head = rxptr->next; - unlock(); + /* Remove buffer from queue */ + if (dep->de_recvq_tail == dep->de_recvq_head) + dep->de_recvq_head = dep->de_recvq_tail = NULL; + else + dep->de_recvq_head = rxptr->next; - /* Copy buffer to user area and free it */ - mem2user(dep, rxptr); + /* Copy buffer to user area and free it */ + size = MIN(rxptr->size, max); - dep->de_read_s = rxptr->size; - dep->de_flags |= DEF_ACK_RECV; - dep->de_flags &= NOT(DEF_READING); + netdriver_copyout(data, 0, rxptr->buffer, size); - /* Return buffer to the idle pool */ - free_buff(dep, rxptr); - } - return; + /* Return buffer to the idle pool */ + free_buff(dep, rxptr); + + return size; } /* -** Name: void el3_rx_complete(dpeth_t * dep); +** Name: el3_rx_complete ** Function: Upon receiving a packet, provides status checks ** and if packet is OK copies it to local buffer. */ @@ -205,38 +163,36 @@ static void el3_rx_complete(dpeth_t * dep) } else { /* Good packet. Read it from FIFO */ - insb(dep->de_data_port, SELF, rxptr->buffer, pktsize); + insb(dep->de_data_port, rxptr->buffer, pktsize); rxptr->next = NULL; rxptr->size = pktsize; - lock(); /* Queue packet to receive queue */ + /* Queue packet to receive queue */ if (dep->de_recvq_head == NULL) dep->de_recvq_head = rxptr; else dep->de_recvq_tail->next = rxptr; dep->de_recvq_tail = rxptr; - unlock(); /* Reply to pending Receive requests, if any */ - el3_recv(dep, TRUE, pktsize); + netdriver_recv(); } /* Discard top packet from queue */ outw_el3(dep, REG_CmdStatus, CMD_RxDiscard); - - return; } /* -** Name: void el3_send(dpeth_t *dep, int count) +** Name: el3_send ** Function: Send function. Called from main to transit a packet or ** from interrupt handler when Tx FIFO gets available. */ -static void el3_send(dpeth_t * dep, int from_int, int count) +static int el3_send(dpeth_t *dep, struct netdriver_data *data, size_t size) { clock_t now; int ix; short int TxStatus; + size_t padding; getticks(&now); if ((dep->de_flags & DEF_XMIT_BUSY) && @@ -249,41 +205,43 @@ static void el3_send(dpeth_t * dep, int from_int, int count) outw_el3(dep, REG_CmdStatus, CMD_TxEnable); dep->de_flags &= NOT(DEF_XMIT_BUSY); } - if (!(dep->de_flags & DEF_XMIT_BUSY)) { + if (dep->de_flags & DEF_XMIT_BUSY) + return SUSPEND; - /* Writes Transmitter preamble 1st Word (packet len, no ints) */ - outw_el3(dep, REG_TxFIFO, count); - /* Writes Transmitter preamble 2nd Word (all zero) */ - outw_el3(dep, REG_TxFIFO, 0); - /* Writes packet */ - el3_write_fifo(dep, count); + /* Writes Transmitter preamble 1st Word (packet len, no ints) */ + outw_el3(dep, REG_TxFIFO, size); + /* Writes Transmitter preamble 2nd Word (all zero) */ + outw_el3(dep, REG_TxFIFO, 0); + /* Writes packet */ + netdriver_portoutb(data, 0, dep->de_data_port, size); + padding = size; + while ((padding++ % sizeof(long)) != 0) outb(dep->de_data_port, 0x00); - getticks(&dep->de_xmit_start); - dep->de_flags |= (DEF_XMIT_BUSY | DEF_ACK_SEND); - if (inw_el3(dep, REG_TxFree) > ETH_MAX_PACK_SIZE) { - /* Tx has enough room for a packet of maximum size */ - dep->de_flags &= NOT(DEF_XMIT_BUSY | DEF_SENDING); - } else { - /* Interrupt driver when enough room is available */ - outw_el3(dep, REG_CmdStatus, CMD_SetTxAvailable | ETH_MAX_PACK_SIZE); - dep->de_flags &= NOT(DEF_SENDING); - } - - /* Pops Tx status stack */ - for (ix = 4; --ix && (TxStatus = inb_el3(dep, REG_TxStatus)) > 0;) { - if (TxStatus & 0x38) dep->de_stat.ets_sendErr += 1; - if (TxStatus & 0x30) - outw_el3(dep, REG_CmdStatus, CMD_TxReset); - if (TxStatus & 0x3C) - outw_el3(dep, REG_CmdStatus, CMD_TxEnable); - outb_el3(dep, REG_TxStatus, 0); - } + getticks(&dep->de_xmit_start); + dep->de_flags |= DEF_XMIT_BUSY; + if (inw_el3(dep, REG_TxFree) > ETH_MAX_PACK_SIZE) { + /* Tx has enough room for a packet of maximum size */ + dep->de_flags &= NOT(DEF_XMIT_BUSY); + } else { + /* Interrupt driver when enough room is available */ + outw_el3(dep, REG_CmdStatus, CMD_SetTxAvailable | ETH_MAX_PACK_SIZE); } - return; + + /* Pops Tx status stack */ + for (ix = 4; --ix && (TxStatus = inb_el3(dep, REG_TxStatus)) > 0;) { + if (TxStatus & 0x38) dep->de_stat.ets_sendErr += 1; + if (TxStatus & 0x30) + outw_el3(dep, REG_CmdStatus, CMD_TxReset); + if (TxStatus & 0x3C) + outw_el3(dep, REG_CmdStatus, CMD_TxEnable); + outb_el3(dep, REG_TxStatus, 0); + } + + return OK; } /* -** Name: void el3_close(dpeth_t *dep) +** Name: el3_close ** Function: Stops board and makes it ready to shut down. */ static void el3_close(dpeth_t * dep) @@ -296,24 +254,22 @@ static void el3_close(dpeth_t * dep) if (dep->de_if_port == BNC_XCVR) { outw_el3(dep, REG_CmdStatus, CMD_StopIntXcvr); - /* milli_delay(5); */ + /* micro_delay(5000); */ } else if (dep->de_if_port == TP_XCVR) { SetWindow(WNO_Diagnostics); outw_el3(dep, REG_MediaStatus, inw_el3(dep, REG_MediaStatus) & NOT((MediaLBeatEnable | MediaJabberEnable))); - /* milli_delay(5); */ + /* micro_delay(5000); */ } DEBUG(printf("%s: stopping Etherlink ... \n", dep->de_name)); /* Issues a global reset outw_el3(dep, REG_CmdStatus, CMD_GlobalReset); */ sys_irqdisable(&dep->de_hook); /* Disable interrupt */ - - return; } /* -** Name: void el3_interrupt(dpeth_t *dep) +** Name: el3_interrupt ** Function: Interrupt handler. Acknwledges transmit interrupts ** or unloads receive buffer to memory queue. */ @@ -332,8 +288,7 @@ static void el3_interrupt(dpeth_t * dep) DEBUG(printf("3c509: got Tx interrupt, Status=0x%04x\n", isr);) dep->de_flags &= NOT(DEF_XMIT_BUSY); outw_el3(dep, REG_CmdStatus, CMD_Acknowledge | INT_TxAvailable); - if (dep->de_flags & DEF_SENDING) /* Send pending */ - el3_send(dep, TRUE, dep->de_send_s); + netdriver_send(); } if (isr & (INT_AdapterFail | INT_RxEarly | INT_UpdateStats)) { @@ -354,11 +309,10 @@ static void el3_interrupt(dpeth_t * dep) /* Acknowledge interrupt */ outw_el3(dep, REG_CmdStatus, CMD_Acknowledge | (INT_Latch | INT_Requested)); } - return; } /* -** Name: unsigned el3_read_eeprom(port_t port, unsigned address); +** Name: el3_read_eeprom ** Function: Reads the EEPROM at specified address */ static unsigned el3_read_eeprom(port_t port, unsigned address) @@ -368,7 +322,7 @@ static unsigned el3_read_eeprom(port_t port, unsigned address) address |= EL3_READ_EEPROM; outb(port, address); - milli_delay(5); /* Allows EEPROM reads */ + micro_delay(5000); /* Allows EEPROM reads */ for (result = 0, bit = 16; bit > 0; bit -= 1) { result = (result << 1) | (inb(port) & 0x0001); } @@ -376,7 +330,7 @@ static unsigned el3_read_eeprom(port_t port, unsigned address) } /* -** Name: void el3_read_StationAddress(dpeth_t *dep) +** Name: el3_read_StationAddress ** Function: Reads station address from board */ static void el3_read_StationAddress(dpeth_t * dep) @@ -390,11 +344,10 @@ static void el3_read_StationAddress(dpeth_t * dep) dep->de_address.ea_addr[ix++] = (rc >> 8) & 0xFF; dep->de_address.ea_addr[ix++] = rc & 0xFF; } - return; } /* -** Name: void el3_open(dpeth_t *dep) +** Name: el3_open ** Function: Initalizes board hardware and driver data structures. */ static void el3_open(dpeth_t * dep) @@ -440,7 +393,7 @@ static void el3_open(dpeth_t * dep) if (dep->de_if_port == BNC_XCVR) { /* Start internal transceiver for Coaxial cable */ outw_el3(dep, REG_CmdStatus, CMD_StartIntXcvr); - milli_delay(5); + micro_delay(5000); } else if (dep->de_if_port == TP_XCVR) { /* Start internal transceiver for Twisted pair cable */ @@ -497,12 +450,10 @@ static void el3_open(dpeth_t * dep) for (ix = 0; ix < SA_ADDR_LEN; ix += 1) printf("%02X%c", dep->de_address.ea_addr[ix], ix < SA_ADDR_LEN - 1 ? ':' : '\n'); - - return; /* Done */ } /* -** Name: unsigned int el3_checksum(port_t port); +** Name: int el3_checksum ** Function: Reads EEPROM and computes checksum. */ static unsigned short el3_checksum(port_t port) @@ -534,7 +485,7 @@ static unsigned short el3_checksum(port_t port) } /* -** Name: void el3_write_id(port_t port); +** Name: el3_write_id ** Function: Writes the ID sequence to the board. */ static void el3_write_id(port_t port) @@ -548,11 +499,10 @@ static void el3_write_id(port_t port) pattern <<= 1; pattern = (pattern & 0x0100) ? pattern ^ 0xCF : pattern; } - return; } /* -** Name: int el3_probe(dpeth_t *dep) +** Name: el3_probe ** Function: Checks for presence of the board. */ int el3_probe(dpeth_t * dep) @@ -572,10 +522,10 @@ int el3_probe(dpeth_t * dep) el3_write_id(id_port); outb(id_port, EL3_ID_GLOBAL_RESET); /* Reset the board */ - milli_delay(5); /* Technical reference says 162 micro sec. */ + micro_delay(5000); /* Technical reference says 162 micro sec. */ el3_write_id(id_port); outb(id_port, EL3_SET_TAG_REGISTER); - milli_delay(5); + micro_delay(5000); dep->de_id_port = id_port; /* Stores ID port No. */ dep->de_ramsize = /* RAM size is meaningless */ diff --git a/minix/drivers/net/dpeth/8390.c b/minix/drivers/net/dpeth/8390.c index 521a34159..8007d0b0b 100644 --- a/minix/drivers/net/dpeth/8390.c +++ b/minix/drivers/net/dpeth/8390.c @@ -1,4 +1,3 @@ -#include /* ** File: 8390.c May 02, 2000 ** @@ -12,32 +11,18 @@ */ #include -#include +#include #include #include +#include #include "dp.h" #if (ENABLE_DP8390 == 1) -#define PIO16 0 /* NOTE: pio 16 functions missing */ - #include "8390.h" -#if 0 -#define sys_nic2mem(srcOffs,dstProc,dstOffs,length) \ - sys_vircopy(SELF,dep->de_memsegm,(vir_bytes)(srcOffs),\ - (dstProc),D,(vir_bytes)(dstOffs),length) -#endif -#if 0 -#define sys_user2nic_s(srcProc,grant,dstOffs,length) \ - sys_safecopyfrom((srcProc),(grant),0, \ - (vir_bytes)(dstOffs),length,dep->de_memsegm) -#endif - -static char RdmaErrMsg[] = "remote dma failed to complete"; - /* -** Name: void ns_rw_setup(dpeth_t *dep, int mode, int size, u16_t offset); +** Name: ns_rw_setup ** Function: Sets the board for reading/writing. */ static void ns_rw_setup(const dpeth_t *dep, int mode, int size, u16_t offset) @@ -50,11 +35,10 @@ static void ns_rw_setup(const dpeth_t *dep, int mode, int size, u16_t offset) outb_reg0(dep, DP_RSAR1, (offset >> 8) & 0xFF); mode |= (CR_PS_P0 | CR_STA); outb_reg0(dep, DP_CR, mode); - return; } /* -** Name: void ns_start_xmit(dpeth_t *dep, int size, int pageno); +** Name: ns_start_xmit ** Function: Sets the board for for transmitting and fires it. */ static void ns_start_xmit(const dpeth_t * dep, int size, int pageno) @@ -64,110 +48,58 @@ static void ns_start_xmit(const dpeth_t * dep, int size, int pageno) outb_reg0(dep, DP_TBCR1, size >> 8); outb_reg0(dep, DP_TBCR0, size & 0xFF); outb_reg0(dep, DP_CR, CR_NO_DMA | CR_STA | CR_TXP); /* Fires transmission */ - return; } /* -** Name: void mem_getblock(dpeth_t *dep, u16_t offset, -** int size, void *dst) +** Name: mem_getblock ** Function: Reads a block of packet from board (shared memory). */ static void mem_getblock(dpeth_t *dep, u16_t offset, int size, void *dst) { - panic("mem_getblock: not converted to safecopies"); -#if 0 - sys_nic2mem(dep->de_linmem + offset, SELF, dst, size); - return; -#endif + + assert(offset + size <= dep->de_ramsize); + + memcpy(dst, dep->de_locmem + offset, size); } /* -** Name: void mem_nic2user(dpeth_t *dep, int pageno, int pktsize); +** Name: mem_nic2user ** Function: Copies a packet from board to user area (shared memory). */ -static void mem_nic2user(dpeth_t * dep, int pageno, int pktsize) +static void mem_nic2user(dpeth_t *dep, int pageno, struct netdriver_data *data, + size_t size) { - panic("mem_nic2user: not converted to safecopies"); -#if 0 - phys_bytes offset; - iovec_dat_s_t *iovp = &dep->de_read_iovec; - int bytes, ix = 0; - + size_t offset, left; /* Computes shared memory address (skipping receive header) */ offset = pageno * DP_PAGESIZE + sizeof(dp_rcvhdr_t); - do { /* Reads chuncks of packet into user area */ - - bytes = iovp->iod_iovec[ix].iov_size; /* Size of a chunck */ - if (bytes > pktsize) bytes = pktsize; - - /* Reads from board to user area */ - if ((offset + bytes) > (dep->de_stoppage * DP_PAGESIZE)) { - - /* Circular buffer wrap-around */ - bytes = dep->de_stoppage * DP_PAGESIZE - offset; - sys_nic2mem_s(dep->de_linmem + offset, iovp->iod_proc_nr, - iovp->iod_iovec[ix].iov_grant, bytes); - pktsize -= bytes; - phys_user += bytes; - bytes = iovp->iod_iovec[ix].iov_size - bytes; - if (bytes > pktsize) bytes = pktsize; - offset = dep->de_startpage * DP_PAGESIZE; - } - sys_nic2mem_s(dep->de_linmem + offset, iovp->iod_proc_nr, - iovp->iod_iovec[ix].iov_grant, bytes); - offset += bytes; - - if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */ - dp_next_iovec(iovp); - ix = 0; - } - /* Till packet done */ - } while ((pktsize -= bytes) > 0); - return; -#endif + if (offset + size > dep->de_stoppage * DP_PAGESIZE) { + left = dep->de_stoppage * DP_PAGESIZE - offset; + netdriver_copyout(data, 0, dep->de_locmem + offset, left); + offset = dep->de_startpage * DP_PAGESIZE; + netdriver_copyout(data, left, dep->de_locmem + offset, size - left); + } else + netdriver_copyout(data, 0, dep->de_locmem + offset, size); } /* -** Name: void mem_user2nic(dpeth_t *dep, int pageno, int pktsize) +** Name: mem_user2nic ** Function: Copies a packet from user area to board (shared memory). */ -static void mem_user2nic(dpeth_t *dep, int pageno, int pktsize) +static void mem_user2nic(dpeth_t *dep, int pageno, struct netdriver_data *data, + size_t size) { -#if 1 - panic("mem_user2nic: not converted to safecopies"); -#else - phys_bytes offset, phys_user; - iovec_dat_s_t *iovp = &dep->de_write_iovec; - int bytes, ix = 0; + size_t offset; /* Computes shared memory address */ offset = pageno * DP_PAGESIZE; - do { /* Reads chuncks of packet from user area */ - - bytes = iovp->iod_iovec[ix].iov_size; /* Size of chunck */ - if (bytes > pktsize) bytes = pktsize; - - /* Reads from user area to board (shared memory) */ - sys_user2nic_s(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_grant, - dep->de_linmem + offset, bytes); - offset += bytes; - - if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */ - dp_next_iovec(iovp); - ix = 0; - } - /* Till packet done */ - } while ((pktsize -= bytes) > 0); - return; -#endif + netdriver_copyin(data, 0, dep->de_locmem + offset, size); } /* -** Name: void pio_getblock(dpeth_t *dep, u16_t offset, -** int size, void *dst) +** Name: pio_getblock ** Function: Reads a block of packet from board (Prog. I/O). */ static void pio_getblock(dpeth_t *dep, u16_t offset, int size, void *dst) @@ -176,110 +108,72 @@ static void pio_getblock(dpeth_t *dep, u16_t offset, int size, void *dst) /* Sets up board for reading */ ns_rw_setup(dep, CR_DM_RR, size, offset); -#if PIO16 == 0 - insb(dep->de_data_port, SELF, dst, size); -#else - if (dep->de_16bit == TRUE) { + if (dep->de_16bit == TRUE) insw(dep->de_data_port, dst, size); - } else { + else insb(dep->de_data_port, dst, size); - } -#endif - return; } /* -** Name: void pio_nic2user(dpeth_t *dep, int pageno, int pktsize) +** Name: pio_nic2user ** Function: Copies a packet from board to user area (Prog. I/O). */ -static void pio_nic2user(dpeth_t *dep, int pageno, int pktsize) +static void pio_nic2user(dpeth_t *dep, int pageno, struct netdriver_data *data, + size_t size) { - iovec_dat_s_t *iovp = &dep->de_read_iovec; - unsigned offset, iov_offset; int r, bytes, ix = 0; + size_t offset, left; /* Computes memory address (skipping receive header) */ offset = pageno * DP_PAGESIZE + sizeof(dp_rcvhdr_t); - /* Sets up board for reading */ - ns_rw_setup(dep, CR_DM_RR, ((offset + pktsize) > (dep->de_stoppage * DP_PAGESIZE)) ? - (dep->de_stoppage * DP_PAGESIZE) - offset : pktsize, offset); - iov_offset= 0; - do { /* Reads chuncks of packet into user area */ + if (offset + size > dep->de_stoppage * DP_PAGESIZE) { + left = dep->de_stoppage * DP_PAGESIZE - offset; - bytes = iovp->iod_iovec[ix].iov_size; /* Size of a chunck */ - if (bytes > pktsize) bytes = pktsize; + ns_rw_setup(dep, CR_DM_RR, left, offset); - if ((offset + bytes) > (dep->de_stoppage * DP_PAGESIZE)) { + if (dep->de_16bit) + netdriver_portinw(data, 0, dep->de_data_port, left); + else + netdriver_portinb(data, 0, dep->de_data_port, left); - /* Circular buffer wrap-around */ - bytes = dep->de_stoppage * DP_PAGESIZE - offset; - r= sys_safe_insb(dep->de_data_port, iovp->iod_proc_nr, - iovp->iod_iovec[ix].iov_grant, iov_offset, bytes); - if (r != OK) { - panic("pio_nic2user: sys_safe_insb failed: %d", r); - } - pktsize -= bytes; - iov_offset += bytes; - bytes = iovp->iod_iovec[ix].iov_size - bytes; - if (bytes > pktsize) bytes = pktsize; - offset = dep->de_startpage * DP_PAGESIZE; - ns_rw_setup(dep, CR_DM_RR, pktsize, offset); - } - r= sys_safe_insb(dep->de_data_port, iovp->iod_proc_nr, - iovp->iod_iovec[ix].iov_grant, iov_offset, bytes); - if (r != OK) - panic("pio_nic2user: sys_safe_insb failed: %d", r); - offset += bytes; + offset = dep->de_startpage * DP_PAGESIZE; + } else + left = 0; - if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */ - dp_next_iovec(iovp); - ix = 0; - } - iov_offset= 0; - /* Till packet done */ - } while ((pktsize -= bytes) > 0); - return; + ns_rw_setup(dep, CR_DM_RR, size - left, offset); + + if (dep->de_16bit) + netdriver_portinw(data, left, dep->de_data_port, size - left); + else + netdriver_portinb(data, left, dep->de_data_port, size - left); } /* -** Name: void pio_user2nic(dpeth_t *dep, int pageno, int pktsize) +** Name: pio_user2nic ** Function: Copies a packet from user area to board (Prog. I/O). */ -static void pio_user2nic(dpeth_t *dep, int pageno, int pktsize) +static void pio_user2nic(dpeth_t *dep, int pageno, struct netdriver_data *data, + size_t size) { - iovec_dat_s_t *iovp = &dep->de_write_iovec; - int r, bytes, ix = 0; + int ix; /* Sets up board for writing */ - ns_rw_setup(dep, CR_DM_RW, pktsize, pageno * DP_PAGESIZE); - - do { /* Reads chuncks of packet from user area */ + ns_rw_setup(dep, CR_DM_RW, size, pageno * DP_PAGESIZE); - bytes = iovp->iod_iovec[ix].iov_size; /* Size of chunck */ - if (bytes > pktsize) bytes = pktsize; - r= sys_safe_outsb(dep->de_data_port, iovp->iod_proc_nr, - iovp->iod_iovec[ix].iov_grant, 0, bytes); - if (r != OK) - panic("pio_user2nic: sys_safe_outsb failed: %d", r); - - if (++ix >= IOVEC_NR) { /* Next buffer of I/O vector */ - dp_next_iovec(iovp); - ix = 0; - } - /* Till packet done */ - } while ((pktsize -= bytes) > 0); + if (dep->de_16bit) + netdriver_portoutw(data, 0, dep->de_data_port, size); + else + netdriver_portoutb(data, 0, dep->de_data_port, size); for (ix = 0; ix < 100; ix += 1) { if (inb_reg0(dep, DP_ISR) & ISR_RDC) break; } - if (ix == 100) { - panic("%s", RdmaErrMsg); - } - return; + if (ix == 100) + panic("remote dma failed to complete"); } /* -** Name: void ns_stats(dpeth_t * dep) +** Name: ns_stats ** Function: Updates counters reading from device */ static void ns_stats(dpeth_t * dep) @@ -288,22 +182,20 @@ static void ns_stats(dpeth_t * dep) dep->de_stat.ets_CRCerr += inb_reg0(dep, DP_CNTR0); dep->de_stat.ets_recvErr += inb_reg0(dep, DP_CNTR1); dep->de_stat.ets_fifoOver += inb_reg0(dep, DP_CNTR2); - return; } /* -** Name: void ns_dodump(dpeth_t * dep) -** Function: Displays statistics (a request from F5 key). +** Name: ns_dodump +** Function: Displays statistics (a request from a function key). */ static void ns_dodump(dpeth_t * dep) { - ns_stats(dep); /* Forces reading fo counters from board */ - return; + ns_stats(dep); /* Forces reading of counters from board */ } /* -** Name: void ns_reinit(dpeth_t *dep) +** Name: ns_reinit ** Function: Updates receiver configuration. */ static void ns_reinit(dpeth_t * dep) @@ -315,26 +207,24 @@ static void ns_reinit(dpeth_t * dep) if (dep->de_flags & DEF_MULTI) dp_reg |= RCR_AM; outb_reg0(dep, DP_CR, CR_PS_P0); outb_reg0(dep, DP_RCR, dp_reg); - return; } /* -** Name: void ns_send(dpeth_t * dep, int from_int, int size) +** Name: ns_send ** Function: Transfers packet to device and starts sending. */ -static void ns_send(dpeth_t * dep, int from_int, int size) +static int ns_send(dpeth_t *dep, struct netdriver_data *data, size_t size) { int queue; - if (queue = dep->de_sendq_head, dep->de_sendq[queue].sq_filled) { - if (from_int) panic("should not be sending "); - dep->de_send_s = size; - return; - } - (dep->de_user2nicf) (dep, dep->de_sendq[queue].sq_sendpage, size); + queue = dep->de_sendq_head; + if (dep->de_sendq[queue].sq_filled) + return SUSPEND; + + (dep->de_user2nicf)(dep, dep->de_sendq[queue].sq_sendpage, data, size); dep->bytes_Tx += (long) size; dep->de_sendq[queue].sq_filled = TRUE; - dep->de_flags |= (DEF_XMIT_BUSY | DEF_ACK_SEND); + dep->de_flags |= DEF_XMIT_BUSY; if (dep->de_sendq_tail == queue) { /* there it goes.. */ ns_start_xmit(dep, size, dep->de_sendq[queue].sq_sendpage); } else @@ -342,13 +232,12 @@ static void ns_send(dpeth_t * dep, int from_int, int size) if (++queue == dep->de_sendq_nr) queue = 0; dep->de_sendq_head = queue; - dep->de_flags &= NOT(DEF_SENDING); - return; + return OK; } /* -** Name: void ns_reset(dpeth_t *dep) +** Name: ns_reset ** Function: Resets device. */ static void ns_reset(dpeth_t * dep) @@ -359,14 +248,14 @@ static void ns_reset(dpeth_t * dep) outb_reg0(dep, DP_CR, CR_STP | CR_NO_DMA); outb_reg0(dep, DP_RBCR0, 0); outb_reg0(dep, DP_RBCR1, 0); - for (ix = 0; ix < 0x1000 && ((inb_reg0(dep, DP_ISR) & ISR_RST) == 0); ix += 1) + for (ix = 0; ix < 0x1000 && (inb_reg0(dep, DP_ISR) & ISR_RST) == 0; ix += 1) /* Do nothing */ ; outb_reg0(dep, DP_TCR, TCR_1EXTERNAL | TCR_OFST); outb_reg0(dep, DP_CR, CR_STA | CR_NO_DMA); outb_reg0(dep, DP_TCR, TCR_NORMAL | TCR_OFST); /* Acknowledge the ISR_RDC (remote dma) interrupt. */ - for (ix = 0; ix < 0x1000 && ((inb_reg0(dep, DP_ISR) & ISR_RDC) == 0); ix += 1) + for (ix = 0; ix < 0x1000 && (inb_reg0(dep, DP_ISR) & ISR_RDC) == 0; ix += 1) /* Do nothing */ ; outb_reg0(dep, DP_ISR, inb_reg0(dep, DP_ISR) & NOT(ISR_RDC)); @@ -376,19 +265,18 @@ static void ns_reset(dpeth_t * dep) dep->de_sendq_head = dep->de_sendq_tail = 0; for (ix = 0; ix < dep->de_sendq_nr; ix++) dep->de_sendq[ix].sq_filled = FALSE; - ns_send(dep, TRUE, dep->de_send_s); - return; + netdriver_send(); } /* -** Name: void ns_recv(dpeth_t *dep, int fromint, int size) +** Name: ns_recv ** Function: Gets a packet from device */ -static void ns_recv(dpeth_t *dep, int fromint, int size) +static ssize_t ns_recv(dpeth_t *dep, struct netdriver_data *data, size_t max) { dp_rcvhdr_t header; unsigned pageno, curr, next; - vir_bytes length; + size_t length; int packet_processed = FALSE; #ifdef ETH_IGN_PROTO u16_t eth_type; @@ -403,17 +291,21 @@ static void ns_recv(dpeth_t *dep, int fromint, int size) curr = inb_reg1(dep, DP_CURR); outb_reg0(dep, DP_CR, CR_PS_P0 | CR_NO_DMA | CR_STA); - if (curr == pageno) break; + if (curr == pageno) + return SUSPEND; - (dep->de_getblockf) (dep, pageno * DP_PAGESIZE, sizeof(header), &header); + (dep->de_getblockf)(dep, pageno * DP_PAGESIZE, sizeof(header), + &header); #ifdef ETH_IGN_PROTO - (dep->de_getblockf) (dep, pageno * DP_PAGESIZE + sizeof(header) + 2 * sizeof(ether_addr_t), sizeof(eth_type), ð_type); + (dep->de_getblockf)(dep, pageno * DP_PAGESIZE + sizeof(header) + + 2 * sizeof(ether_addr_t), sizeof(eth_type), ð_type); #endif - length = (header.dr_rbcl | (header.dr_rbch << 8)) - sizeof(dp_rcvhdr_t); + length = (header.dr_rbcl | (header.dr_rbch << 8)) - + sizeof(dp_rcvhdr_t); next = header.dr_next; - if (length < ETH_MIN_PACK_SIZE || length > ETH_MAX_PACK_SIZE) { - printf("%s: packet with strange length arrived: %ld\n", + if (length < ETH_MIN_PACK_SIZE || length > max) { + printf("%s: packet with strange length arrived: %zu\n", dep->de_name, length); dep->de_stat.ets_recvErr += 1; next = curr; @@ -422,50 +314,40 @@ static void ns_recv(dpeth_t *dep, int fromint, int size) printf("%s: strange next page\n", dep->de_name); dep->de_stat.ets_recvErr += 1; next = curr; - #ifdef ETH_IGN_PROTO } else if (eth_type == eth_ign_proto) { /* Hack: ignore packets of a given protocol */ static int first = TRUE; if (first) { first = FALSE; - printf("%s: dropping proto %04x packet\n", dep->de_name, ntohs(eth_ign_proto)); + printf("%s: dropping proto %04x packet\n", + dep->de_name, ntohs(eth_ign_proto)); } next = curr; #endif } else if (header.dr_status & RSR_FO) { /* This is very serious, issue a warning and reset buffers */ - printf("%s: fifo overrun, resetting receive buffer\n", dep->de_name); + printf("%s: fifo overrun, resetting receive buffer\n", + dep->de_name); dep->de_stat.ets_fifoOver += 1; next = curr; - } else if ((header.dr_status & RSR_PRX) && (dep->de_flags & DEF_ENABLED)) { - - if (!(dep->de_flags & DEF_READING)) break; - - (dep->de_nic2userf) (dep, pageno, length); - dep->de_read_s = length; - dep->de_flags |= DEF_ACK_RECV; - dep->de_flags &= NOT(DEF_READING); + } else if (header.dr_status & RSR_PRX) { + (dep->de_nic2userf)(dep, pageno, data, length); packet_processed = TRUE; } dep->bytes_Rx += (long) length; dep->de_stat.ets_packetR += 1; - outb_reg0(dep, DP_BNRY, (next == dep->de_startpage ? dep->de_stoppage : next) - 1); + outb_reg0(dep, DP_BNRY, + (next == dep->de_startpage ? dep->de_stoppage : next) - 1); pageno = next; - } while (!packet_processed); -#if 0 - if ((dep->de_flags & (DEF_READING | DEF_STOPPED)) == (DEF_READING | DEF_STOPPED)) - /* The chip is stopped, and all arrived packets delivered */ - (*dep->de_resetf) (dep); - dep->de_flags &= NOT(DEF_STOPPED); -#endif - return; + + return length; } /* -** Name: void ns_interrupt(dpeth_t * dep) +** Name: ns_interrupt ** Function: Handles interrupt. */ static void ns_interrupt(dpeth_t * dep) @@ -487,13 +369,15 @@ static void ns_interrupt(dpeth_t * dep) dep->de_stat.ets_fifoUnder++; } if ((isr & ISR_TXE) || (tsr & (TSR_CRS | TSR_CDH | TSR_OWC))) { - printf("%s: got send Error (0x%02X)\n", dep->de_name, tsr); + printf("%s: got send Error (0x%02X)\n", + dep->de_name, tsr); dep->de_stat.ets_sendErr++; } queue = dep->de_sendq_tail; - if (!(dep->de_sendq[queue].sq_filled)) { /* Hardware bug? */ - printf("%s: transmit interrupt, but not sending\n", dep->de_name); + if (!(dep->de_sendq[queue].sq_filled)) { /* Hardware bug? */ + printf("%s: transmit interrupt, but not sending\n", + dep->de_name); continue; } dep->de_sendq[queue].sq_filled = FALSE; @@ -503,15 +387,14 @@ static void ns_interrupt(dpeth_t * dep) ns_start_xmit(dep, dep->de_sendq[queue].sq_size, dep->de_sendq[queue].sq_sendpage); } - if (dep->de_flags & DEF_SENDING) { - ns_send(dep, TRUE, dep->de_send_s); - } + netdriver_send(); } if (isr & ISR_PRX) { - ns_recv(dep, TRUE, 0); + netdriver_recv(); } if (isr & ISR_RXE) { - printf("%s: got recv Error (0x%04X)\n", dep->de_name, inb_reg0(dep, DP_RSR)); + printf("%s: got recv Error (0x%04X)\n", + dep->de_name, inb_reg0(dep, DP_RSR)); dep->de_stat.ets_recvErr++; } if (isr & ISR_CNT) { @@ -526,26 +409,21 @@ static void ns_interrupt(dpeth_t * dep) /* Nothing to do */ } if (isr & ISR_RST) { - /* This means we got an interrupt but the ethernet - * chip is shutdown. We set the flag DEF_STOPPED, and - * continue processing arrived packets. When the - * receive buffer is empty, we reset the dp8390. */ + /* This means we got an interrupt but the ethernet chip is shut + * down. We reset the chip right away, possibly losing received + * packets in the process. There used to be a more elaborate + * approach of resetting only after all pending packets had + * been accepted, but it was broken and this is simpler anyway. + */ printf("%s: network interface stopped\n", dep->de_name); - dep->de_flags |= DEF_STOPPED; + ns_reset(dep); break; } } - if ((dep->de_flags & (DEF_READING | DEF_STOPPED)) == (DEF_READING | DEF_STOPPED)) { - - /* The chip is stopped, and all arrived packets delivered */ - ns_reset(dep); - dep->de_flags &= NOT(DEF_STOPPED); - } - return; } /* -** Name: void ns_init(dpeth_t *dep) +** Name: ns_init ** Function: Initializes the NS 8390 */ void ns_init(dpeth_t * dep) @@ -555,12 +433,8 @@ void ns_init(dpeth_t * dep) /* NS8390 initialization (as recommended in National Semiconductor specs) */ outb_reg0(dep, DP_CR, CR_PS_P0 | CR_STP | CR_NO_DMA); /* 0x21 */ -#if PIO16 == 0 - outb_reg0(dep, DP_DCR, (DCR_BYTEWIDE | DCR_LTLENDIAN | DCR_8BYTES | DCR_BMS)); -#else outb_reg0(dep, DP_DCR, (((dep->de_16bit) ? DCR_WORDWIDE : DCR_BYTEWIDE) | DCR_LTLENDIAN | DCR_8BYTES | DCR_BMS)); -#endif outb_reg0(dep, DP_RBCR0, 0); outb_reg0(dep, DP_RBCR1, 0); outb_reg0(dep, DP_RCR, RCR_MON); /* Sets Monitor mode */ @@ -609,13 +483,9 @@ void ns_init(dpeth_t * dep) dep->de_nic2userf = mem_nic2user; dep->de_getblockf = mem_getblock; } else { -#if PIO16 == 0 dep->de_user2nicf = pio_user2nic; dep->de_nic2userf = pio_nic2user; dep->de_getblockf = pio_getblock; -#else -#error Missing I/O functions for pio 16 bits -#endif } dep->de_recvf = ns_recv; dep->de_sendf = ns_send; @@ -624,135 +494,8 @@ void ns_init(dpeth_t * dep) dep->de_getstatsf = ns_stats; dep->de_dumpstatsf = ns_dodump; dep->de_interruptf = ns_interrupt; - - return; /* Done */ } -#if PIO16 == 1 - -/* -** Name: void dp_pio16_user2nic(dpeth_t *dep, int pageno, int pktsize) -** Function: Copies a packet from user area to board (Prog. I/O, 16bits). -*/ -static void dp_pio16_user2nic(dpeth_t *dep, int pageno, int pktsize) -{ - u8_t two_bytes[2]; - phys_bytes phys_user, phys_2bytes = vir2phys(two_bytes); - vir_bytes ecount = (pktsize + 1) & NOT(0x0001); - int bytes, ix = 0, odd_byte = 0; - iovec_dat_t *iovp = &dep->de_write_iovec; - - outb_reg0(dep, DP_ISR, ISR_RDC); - dp_read_setup(dep, ecount, pageno * DP_PAGESIZE); - - do { - bytes = iovp->iod_iovec[ix].iov_size; - if (bytes > pktsize) bytes = pktsize; - - phys_user = numap(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_addr, bytes); - if (!phys_user) panic(UmapErrMsg); - - if (odd_byte) { - phys_copy(phys_user, phys_2bytes + 1, (phys_bytes) 1); - out_word(dep->de_data_port, *(u16_t *)two_bytes); - pktsize--; - bytes--; - phys_user++; - odd_byte = 0; - if (!bytes) continue; - } - ecount = bytes & NOT(0x0001); - if (ecount != 0) { - phys_outsw(dep->de_data_port, phys_user, ecount); - pktsize -= ecount; - bytes -= ecount; - phys_user += ecount; - } - if (bytes) { - phys_copy(phys_user, phys_2bytes, (phys_bytes) 1); - pktsize--; - bytes--; - phys_user++; - odd_byte = 1; - } - if (++ix >= IOVEC_NR) { /* Next buffer of I/O vector */ - dp_next_iovec(iovp); - ix = 0; - } - - } while (bytes > 0); - - if (odd_byte) out_word(dep->de_data_port, *(u16_t *) two_bytes); - for (ix = 0; ix < 100; ix++) { - if (inb_reg0(dep, DP_ISR) & ISR_RDC) break; - } - if (ix == 100) { - panic(RdmaErrMsg); - } - return; -} - -/* -** Name: void dp_pio16_nic2user(dpeth_t *dep, int pageno, int pktsize) -** Function: Copies a packet from board to user area (Prog. I/O, 16bits). -*/ -static void dp_pio16_nic2user(dpeth_t * dep, int nic_addr, int count) -{ - phys_bytes phys_user; - vir_bytes ecount; - int bytes, i; - u8_t two_bytes[2]; - phys_bytes phys_2bytes; - int odd_byte; - - ecount = (count + 1) & ~1; - phys_2bytes = vir2phys(two_bytes); - odd_byte = 0; - - dp_read_setup(dep, ecount, nic_addr); - - i = 0; - while (count > 0) { - if (i >= IOVEC_NR) { - dp_next_iovec(iovp); - i = 0; - continue; - } - bytes = iovp->iod_iovec[i].iov_size; - if (bytes > count) bytes = count; - - phys_user = numap(iovp->iod_proc_nr, - iovp->iod_iovec[i].iov_addr, bytes); - if (!phys_user) panic(UmapErrMsg); - if (odd_byte) { - phys_copy(phys_2bytes + 1, phys_user, (phys_bytes) 1); - count--; - bytes--; - phys_user++; - odd_byte = 0; - if (!bytes) continue; - } - ecount = bytes & ~1; - if (ecount != 0) { - phys_insw(dep->de_data_port, phys_user, ecount); - count -= ecount; - bytes -= ecount; - phys_user += ecount; - } - if (bytes) { - *(u16_t *) two_bytes = in_word(dep->de_data_port); - phys_copy(phys_2bytes, phys_user, (phys_bytes) 1); - count--; - bytes--; - phys_user++; - odd_byte = 1; - } - } - return; -} - -#endif /* PIO16 == 1 */ - #endif /* ENABLE_DP8390 */ /** end 8390.c **/ diff --git a/minix/drivers/net/dpeth/Makefile b/minix/drivers/net/dpeth/Makefile index 9c3d2ed15..8bf0cdff6 100644 --- a/minix/drivers/net/dpeth/Makefile +++ b/minix/drivers/net/dpeth/Makefile @@ -5,6 +5,6 @@ SRCS= 3c501.c 3c509.c 3c503.c ne.c wd.c 8390.c devio.c netbuff.c dp.c DPADD+= ${LIBNETDRIVER} ${LIBSYS} LDADD+= -lnetdriver -lsys -CPPFLAGS+= -Ddebug=0 +CPPFLAGS+= -DVERBOSE=0 .include diff --git a/minix/drivers/net/dpeth/devio.c b/minix/drivers/net/dpeth/devio.c index ba8a545c2..1e388b0f2 100644 --- a/minix/drivers/net/dpeth/devio.c +++ b/minix/drivers/net/dpeth/devio.c @@ -3,11 +3,12 @@ ** ** Author: Giovanni Falzoni ** -** This file contains the routines for readind/writing +** This file contains the routines for reading/writing ** from/to the device registers. */ #include +#include #include #include #include "dp.h" @@ -18,11 +19,10 @@ static void warning(const char *type, int err) { printf("Warning: eth#0 sys_%s failed (%d)\n", type, err); - return; } /* -** Name: unsigned int inb(unsigned short int port); +** Name: inb ** Function: Reads a byte from specified i/o port. */ unsigned int inb(unsigned short port) @@ -35,7 +35,7 @@ unsigned int inb(unsigned short port) } /* -** Name: unsigned int inw(unsigned short int port); +** Name: inw ** Function: Reads a word from specified i/o port. */ unsigned int inw(unsigned short port) @@ -48,22 +48,31 @@ unsigned int inw(unsigned short port) } /* -** Name: unsigned int insb(unsigned short int port, int proc_nr, void *buffer, int count); -** Function: Reads a sequence of bytes from specified i/o port to user space buffer. +** Name: insb +** Function: Reads a sequence of bytes from an i/o port. */ -void insb(unsigned short int port, endpoint_t proc_nr, - void *buffer, int count) +void insb(unsigned short int port, void *buffer, int count) { int rc; - if ((rc = sys_insb(port, proc_nr, buffer, count)) != OK) + if ((rc = sys_insb(port, SELF, buffer, count)) != OK) warning("insb", rc); - return; } +/* +** Name: insw +** Function: Reads a sequence of words from an i/o port. +*/ +void insw(unsigned short int port, void *buffer, int count) +{ + int rc; + + if ((rc = sys_insw(port, SELF, buffer, count)) != OK) + warning("insw", rc); +} /* -** Name: void outb(unsigned short int port, unsigned long value); +** Name: outb ** Function: Writes a byte to specified i/o port. */ void outb(unsigned short port, unsigned long value) @@ -71,11 +80,10 @@ void outb(unsigned short port, unsigned long value) int rc; if ((rc = sys_outb(port, value)) != OK) warning("outb", rc); - return; } /* -** Name: void outw(unsigned short int port, unsigned long value); +** Name: outw ** Function: Writes a word to specified i/o port. */ void outw(unsigned short port, unsigned long value) @@ -83,20 +91,18 @@ void outw(unsigned short port, unsigned long value) int rc; if ((rc = sys_outw(port, value)) != OK) warning("outw", rc); - return; } /* -** Name: void outsb(unsigned short int port, int proc_nr, void *buffer, int count); -** Function: Writes a sequence of bytes from user space to specified i/o port. +** Name: outsb +** Function: Writes a sequence of bytes to an i/o port. */ -void outsb(unsigned short port, endpoint_t proc_nr, void *buffer, int count) +void outsb(unsigned short port, void *buffer, int count) { int rc; - if ((rc = sys_outsb(port, proc_nr, buffer, count)) != OK) + if ((rc = sys_outsb(port, SELF, buffer, count)) != OK) warning("outsb", rc); - return; } #else diff --git a/minix/drivers/net/dpeth/dp.c b/minix/drivers/net/dpeth/dp.c index 9ed770fcd..0099dcef1 100644 --- a/minix/drivers/net/dpeth/dp.c +++ b/minix/drivers/net/dpeth/dp.c @@ -14,9 +14,10 @@ #include #include #include -#include #include #include +#include +#include #include "dp.h" @@ -24,7 +25,6 @@ ** Local data */ static dpeth_t de_state; -static int de_instance; typedef struct dp_conf { /* Configuration description structure */ port_t dpc_port; @@ -41,90 +41,43 @@ static dp_conf_t dp_conf[DP_CONF_NR] = { { 0x000, 0, 0x00000, }, }; -static char CopyErrMsg[] = "unable to read/write user data"; -static char RecvErrMsg[] = "netdriver_receive failed"; -static char SendErrMsg[] = "send failed"; -static char SizeErrMsg[] = "illegal packet size"; -static char TypeErrMsg[] = "illegal message type"; -static char DevName[] = "eth#?"; +static int do_init(unsigned int instance, ether_addr_t *addr); +static void do_stop(void); +static void do_mode(unsigned int mode); +static int do_send(struct netdriver_data *data, size_t size); +static ssize_t do_recv(struct netdriver_data *data, size_t max); +static void do_stat(eth_stat_t *stat); +static void do_intr(unsigned int mask); +static void do_other(const message *m_ptr, int ipc_status); + +static const struct netdriver dp_table = { + .ndr_init = do_init, + .ndr_stop = do_stop, + .ndr_mode = do_mode, + .ndr_recv = do_recv, + .ndr_send = do_send, + .ndr_stat = do_stat, + .ndr_intr = do_intr, + .ndr_other = do_other +}; /* -** Name: void reply(dpeth_t *dep, int err, int m_type) -** Function: Fills a reply message and sends it. -*/ -static void reply(dpeth_t * dep) -{ - message reply; - int r, flags; - - flags = DL_NOFLAGS; - if (dep->de_flags & DEF_ACK_SEND) flags |= DL_PACK_SEND; - if (dep->de_flags & DEF_ACK_RECV) flags |= DL_PACK_RECV; - - reply.m_type = DL_TASK_REPLY; - reply.m_netdrv_net_dl_task.flags = flags; - reply.m_netdrv_net_dl_task.count = dep->de_read_s; - - DEBUG(printf("\t reply %d (%lx)\n", reply.m_type, - reply.m_netdrv_net_dl_task.flags)); - - if ((r = ipc_send(dep->de_client, &reply)) != OK) - panic(SendErrMsg, r); - - dep->de_read_s = 0; - dep->de_flags &= NOT(DEF_ACK_SEND | DEF_ACK_RECV); - - return; -} - -/* -** Name: void dp_confaddr(dpeth_t *dep) -** Function: Checks environment for a User defined ethernet address. -*/ -static void dp_confaddr(dpeth_t * dep) -{ - static char ea_fmt[] = "x:x:x:x:x:x"; - char ea_key[16]; - int ix; - long val; - - strlcpy(ea_key, "DPETH0_EA", sizeof(ea_key)); - ea_key[5] += de_instance; - - for (ix = 0; ix < SA_ADDR_LEN; ix++) { - val = dep->de_address.ea_addr[ix]; - if (env_parse(ea_key, ea_fmt, ix, &val, 0x00L, 0xFFL) != EP_SET) - break; - dep->de_address.ea_addr[ix] = val; - } - - if (ix != 0 && ix != SA_ADDR_LEN) - /* It's all or nothing, force a panic */ - env_parse(ea_key, "?", 0, &val, 0L, 0L); - return; -} - -/* -** Name: void update_conf(dpeth_t *dep, dp_conf_t *dcp) +** Name: update_conf ** Function: Gets the default settings from 'dp_conf' table and ** modifies them from the environment. */ -static void update_conf(dpeth_t * dep, const dp_conf_t * dcp) +static void update_conf(dpeth_t * dep, const dp_conf_t * dcp, + unsigned int instance) { static char dpc_fmt[] = "x:d:x"; char ec_key[16]; long val; strlcpy(ec_key, "DPETH0", sizeof(ec_key)); - ec_key[5] += de_instance; + ec_key[5] += instance; - dep->de_mode = DEM_SINK; val = dcp->dpc_port; /* Get I/O port address */ - switch (env_parse(ec_key, dpc_fmt, 0, &val, 0x000L, 0x3FFL)) { - case EP_OFF: dep->de_mode = DEM_DISABLED; break; - case EP_ON: - case EP_SET: dep->de_mode = DEM_ENABLED; break; - } + env_parse(ec_key, dpc_fmt, 0, &val, 0x000L, 0x3FFL); dep->de_base_port = val; val = dcp->dpc_irq | DEI_DEFAULT; /* Get Interrupt line (IRQ) */ @@ -134,15 +87,13 @@ static void update_conf(dpeth_t * dep, const dp_conf_t * dcp) val = dcp->dpc_mem; /* Get shared memory address */ env_parse(ec_key, dpc_fmt, 2, &val, 0L, LONG_MAX); dep->de_linmem = val; - - return; } /* -** Name: void do_dump(message *mp) +** Name: do_dump ** Function: Displays statistics on screen (SFx key from console) */ -static void do_dump(const message *mp) +static void do_dump(void) { dpeth_t *dep; @@ -150,14 +101,12 @@ static void do_dump(const message *mp) printf("\n\n"); - if (dep->de_mode == DEM_DISABLED) return; - printf("%s statistics:\t\t", dep->de_name); /* Network interface status */ - printf("Status: 0x%04x (%d)\n\n", dep->de_flags, dep->de_int_pending); + printf("Status: 0x%04x\n\n", dep->de_flags); - (*dep->de_dumpstatsf) (dep); + (*dep->de_dumpstatsf)(dep); /* Transmitted/received bytes */ printf("Tx bytes:%10ld\t", dep->bytes_Tx); @@ -178,40 +127,31 @@ static void do_dump(const message *mp) /* Transmit collisions/receive CRC errors */ printf("Tx Coll: %8ld\t", dep->de_stat.ets_collision); printf("Rx CRC: %8ld\n", dep->de_stat.ets_CRCerr); - - return; } /* -** Name: void get_userdata_s(int user_proc, vir_bytes user_addr, int count, void *loc_addr) -** Function: Copies data from user area. -*/ -static void get_userdata_s(int user_proc, cp_grant_id_t grant, - vir_bytes offset, int count, void *loc_addr) -{ - int rc; - vir_bytes len; - - len = (count > IOVEC_NR ? IOVEC_NR : count) * sizeof(iovec_t); - if ((rc = sys_safecopyfrom(user_proc, grant, 0, (vir_bytes)loc_addr, len)) != OK) - panic(CopyErrMsg, rc); - return; -} - -/* -** Name: void do_first_init(dpeth_t *dep, dp_conf_t *dcp); +** Name: do_first_init ** Function: Init action to setup task */ static void do_first_init(dpeth_t *dep, const dp_conf_t *dcp) { - dep->de_linmem = 0xFFFF0000; + dep->de_linmem = 0xFFFF0000; /* FIXME: this overrides update_conf, why? */ /* Make sure statisics are cleared */ - memset((void *) &(dep->de_stat), 0, sizeof(eth_stat_t)); + memset(&dep->de_stat, 0, sizeof(dep->de_stat)); /* Device specific initialization */ - (*dep->de_initf) (dep); + (*dep->de_initf)(dep); + + /* Map memory if requested */ + if (dep->de_linmem != 0) { + assert(dep->de_ramsize > 0); + dep->de_locmem = + vm_map_phys(SELF, (void *)dep->de_linmem, dep->de_ramsize); + if (dep->de_locmem == MAP_FAILED) + panic("unable to map memory"); + } /* Set the interrupt handler policy. Request interrupts not to be reenabled * automatically. Return the IRQ line number when an interrupt occurs. @@ -219,402 +159,160 @@ static void do_first_init(dpeth_t *dep, const dp_conf_t *dcp) dep->de_hook = dep->de_irq; if (sys_irqsetpolicy(dep->de_irq, 0 /*IRQ_REENABLE*/, &dep->de_hook) != OK) panic("unable to set IRQ policy"); - dep->de_int_pending = FALSE; sys_irqenable(&dep->de_hook); - - return; } /* -** Name: void do_init(message *mp) +** Name: do_init ** Function: Checks for hardware presence. -** Provides initialization of hardware and data structures +** Initialize hardware and data structures. +** Return status and ethernet address. */ -static void do_init(const message * mp) +static int do_init(unsigned int instance, ether_addr_t *addr) { dpeth_t *dep; dp_conf_t *dcp; - message reply_mess; - int r, confnr; + int confnr, fkeys, sfkeys; dep = &de_state; + strlcpy(dep->de_name, "dpeth#?", sizeof(dep->de_name)); + dep->de_name[4] = '0' + instance; + /* Pick a default configuration for this instance. */ - confnr = MIN(de_instance, DP_CONF_NR-1); + confnr = MIN(instance, DP_CONF_NR-1); dcp = &dp_conf[confnr]; - strlcpy(dep->de_name, DevName, sizeof(dep->de_name)); - dep->de_name[4] = '0' + de_instance; - if (dep->de_mode == DEM_DISABLED) { + update_conf(dep, dcp, instance); - update_conf(dep, dcp); /* First time thru */ - if (dep->de_mode == DEM_ENABLED && - !el1_probe(dep) && /* Probe for 3c501 */ - !wdeth_probe(dep) && /* Probe for WD80x3 */ - !ne_probe(dep) && /* Probe for NEx000 */ - !el2_probe(dep) && /* Probe for 3c503 */ - !el3_probe(dep)) { /* Probe for 3c509 */ - printf("%s: warning no ethernet card found at 0x%04X\n", - dep->de_name, dep->de_base_port); - dep->de_mode = DEM_DISABLED; - } + if (!el1_probe(dep) && /* Probe for 3c501 */ + !wdeth_probe(dep) && /* Probe for WD80x3 */ + !ne_probe(dep) && /* Probe for NEx000 */ + !el2_probe(dep) && /* Probe for 3c503 */ + !el3_probe(dep)) { /* Probe for 3c509 */ + printf("%s: warning no ethernet card found at 0x%04X\n", + dep->de_name, dep->de_base_port); + return ENXIO; } - r = OK; + do_first_init(dep, dcp); - /* 'de_mode' may change if probe routines fail, test again */ - switch (dep->de_mode) { + /* Request function key for debug dumps */ + fkeys = sfkeys = 0; bit_set(sfkeys, 7); + if (fkey_map(&fkeys, &sfkeys) != OK) + printf("%s: couldn't bind Shift+F7 key (%d)\n", dep->de_name, errno); - case DEM_DISABLED: - /* Device is configured OFF or hardware probe failed */ - r = ENXIO; - break; - - case DEM_ENABLED: - /* Device is present and probed */ - if (dep->de_flags == DEF_EMPTY) { - /* These actions only the first time */ - do_first_init(dep, dcp); - dep->de_flags |= DEF_ENABLED; - } - dep->de_flags &= NOT(DEF_PROMISC | DEF_MULTI | DEF_BROAD); - if (mp->m_net_netdrv_dl_conf.mode & DL_PROMISC_REQ) - dep->de_flags |= DEF_PROMISC | DEF_MULTI | DEF_BROAD; - if (mp->m_net_netdrv_dl_conf.mode & DL_MULTI_REQ) - dep->de_flags |= DEF_MULTI; - if (mp->m_net_netdrv_dl_conf.mode & DL_BROAD_REQ) - dep->de_flags |= DEF_BROAD; - (*dep->de_flagsf) (dep); - break; - - case DEM_SINK: - /* Device not present (sink mode) */ - memset(dep->de_address.ea_addr, 0, sizeof(ether_addr_t)); - dp_confaddr(dep); /* Station address from env. */ - break; - - default: break; - } - - reply_mess.m_type = DL_CONF_REPLY; - reply_mess.m_netdrv_net_dl_conf.stat = r; - if (r == OK) - memcpy(reply_mess.m_netdrv_net_dl_conf.hw_addr, dep->de_address.ea_addr, - sizeof(reply_mess.m_netdrv_net_dl_conf.hw_addr)); - DEBUG(printf("\t reply %d\n", reply_mess.m_type)); - if (ipc_send(mp->m_source, &reply_mess) != OK) /* Can't send */ - panic(SendErrMsg, mp->m_source); - - return; + memcpy(addr, dep->de_address.ea_addr, sizeof(*addr)); + return OK; } /* -** Name: void dp_next_iovec(iovec_dat_t *iovp) -** Function: Retrieves data from next iovec element. +** Name: de_mode +** Function: Sets packet receipt mode. */ -void dp_next_iovec(iovec_dat_s_t * iovp) +static void do_mode(unsigned int mode) { - - iovp->iod_iovec_s -= IOVEC_NR; - iovp->iod_iovec_offset += IOVEC_NR * sizeof(iovec_t); - get_userdata_s(iovp->iod_proc_nr, iovp->iod_grant, iovp->iod_iovec_offset, - iovp->iod_iovec_s, iovp->iod_iovec); - return; -} - -/* -** Name: int calc_iovec_size(iovec_dat_t *iovp) -** Function: Compute the size of a request. -*/ -static int calc_iovec_size(iovec_dat_s_t * iovp) -{ - int size, ix; - - size = ix = 0; - do { - size += iovp->iod_iovec[ix].iov_size; - if (++ix >= IOVEC_NR) { - dp_next_iovec(iovp); - ix = 0; - } - - /* Till all vectors added */ - } while (ix < iovp->iod_iovec_s); - return size; -} - -/* -** Name: void do_vwrite_s(message *mp) -** Function: -*/ -static void do_vwrite_s(const message * mp) -{ - int size; dpeth_t *dep; dep = &de_state; - dep->de_client = mp->m_source; - - if (dep->de_mode == DEM_ENABLED) { - - if (dep->de_flags & DEF_SENDING) /* Is sending in progress? */ - panic("send already in progress "); - - dep->de_write_iovec.iod_proc_nr = mp->m_source; - get_userdata_s(mp->m_source, mp->m_net_netdrv_dl_writev_s.grant, 0, - mp->m_net_netdrv_dl_writev_s.count, dep->de_write_iovec.iod_iovec); - dep->de_write_iovec.iod_iovec_s = mp->m_net_netdrv_dl_writev_s.count; - dep->de_write_iovec.iod_grant = mp->m_net_netdrv_dl_writev_s.grant; - dep->de_write_iovec.iod_iovec_offset = 0; - size = calc_iovec_size(&dep->de_write_iovec); - if (size < ETH_MIN_PACK_SIZE || size > ETH_MAX_PACK_SIZE) - panic(SizeErrMsg, size); - - dep->de_flags |= DEF_SENDING; - (*dep->de_sendf) (dep, FALSE, size); - - } else if (dep->de_mode == DEM_SINK) - dep->de_flags |= DEF_ACK_SEND; - - reply(dep); - return; + dep->de_flags &= NOT(DEF_PROMISC | DEF_MULTI | DEF_BROAD); + if (mode & NDEV_PROMISC) + dep->de_flags |= DEF_PROMISC | DEF_MULTI | DEF_BROAD; + if (mode & NDEV_MULTI) + dep->de_flags |= DEF_MULTI; + if (mode & NDEV_BROAD) + dep->de_flags |= DEF_BROAD; + (*dep->de_flagsf)(dep); } /* -** Name: void do_vread_s(message *mp, int vectored) -** Function: +** Name: do_send +** Function: Send a packet, if possible. */ -static void do_vread_s(const message * mp) +static int do_send(struct netdriver_data *data, size_t size) { - int size; dpeth_t *dep; dep = &de_state; - dep->de_client = mp->m_source; - - if (dep->de_mode == DEM_ENABLED) { - - if (dep->de_flags & DEF_READING) /* Reading in progress */ - panic("read already in progress"); - - dep->de_read_iovec.iod_proc_nr = mp->m_source; - get_userdata_s(mp->m_source, mp->m_net_netdrv_dl_readv_s.grant, 0, - mp->m_net_netdrv_dl_readv_s.count, dep->de_read_iovec.iod_iovec); - dep->de_read_iovec.iod_iovec_s = mp->m_net_netdrv_dl_readv_s.count; - dep->de_read_iovec.iod_grant = mp->m_net_netdrv_dl_readv_s.grant; - dep->de_read_iovec.iod_iovec_offset = 0; - size = calc_iovec_size(&dep->de_read_iovec); - if (size < ETH_MAX_PACK_SIZE) panic(SizeErrMsg, size); - - dep->de_flags |= DEF_READING; - (*dep->de_recvf) (dep, FALSE, size); -#if 0 - if ((dep->de_flags & (DEF_READING | DEF_STOPPED)) == (DEF_READING | DEF_STOPPED)) - /* The chip is stopped, and all arrived packets delivered */ - (*dep->de_resetf) (dep); - dep->de_flags &= NOT(DEF_STOPPED); -#endif - } - reply(dep); - return; + return (*dep->de_sendf)(dep, data, size); } /* -** Name: void do_getstat_s(message *mp) +** Name: do_recv +** Function: Receive a packet, if possible. +*/ +static ssize_t do_recv(struct netdriver_data *data, size_t max) +{ + dpeth_t *dep; + + dep = &de_state; + + return (*dep->de_recvf)(dep, data, max); +} + +/* +** Name: do_stat ** Function: Reports device statistics. */ -static void do_getstat_s(const message * mp) +static void do_stat(eth_stat_t *stat) { - int rc; - dpeth_t *dep; - message reply_mess; - dep = &de_state; - - if (dep->de_mode == DEM_ENABLED) (*dep->de_getstatsf) (dep); - if ((rc = sys_safecopyto(mp->m_source, mp->m_net_netdrv_dl_getstat_s.grant, 0, - (vir_bytes)&dep->de_stat, - (vir_bytes)sizeof(dep->de_stat))) != OK) - panic(CopyErrMsg, rc); - - reply_mess.m_type = DL_STAT_REPLY; - rc= ipc_send(mp->m_source, &reply_mess); - if (rc != OK) - panic("do_getname: ipc_send failed: %d", rc); - return; + memcpy(stat, &de_state.de_stat, sizeof(*stat)); } /* -** Name: void dp_stop(dpeth_t *dep) +** Name: do_stop ** Function: Stops network interface. */ -static void dp_stop(dpeth_t * dep) +static void do_stop(void) { + dpeth_t *dep; - if (dep->de_mode == DEM_ENABLED && (dep->de_flags & DEF_ENABLED)) { + dep = &de_state; - /* Stop device */ - (dep->de_stopf) (dep); - dep->de_flags = DEF_EMPTY; - dep->de_mode = DEM_DISABLED; - } - return; + /* Stop device */ + (dep->de_stopf)(dep); } -static void do_watchdog(const void *UNUSED(message)) -{ - - DEBUG(printf("\t no reply")); - return; -} - -static void handle_hw_intr(void) +/* +** Name: do_intr +** Function; Handles interrupts. +*/ +static void do_intr(unsigned int __unused mask) { dpeth_t *dep; dep = &de_state; /* If device is enabled and interrupt pending */ - if (dep->de_mode == DEM_ENABLED) { - dep->de_int_pending = TRUE; - (*dep->de_interruptf) (dep); - if (dep->de_flags & (DEF_ACK_SEND | DEF_ACK_RECV)) - reply(dep); - dep->de_int_pending = FALSE; - sys_irqenable(&dep->de_hook); - } + (*dep->de_interruptf)(dep); + sys_irqenable(&dep->de_hook); } -/* SEF functions and variables. */ -static void sef_local_startup(void); -static int sef_cb_init_fresh(int type, sef_init_info_t *info); -static void sef_cb_signal_handler(int signo); +/* +** Name: do_other +** Function: Processes miscellaneous messages. +*/ +static void do_other(const message *m_ptr, int ipc_status) +{ + + if (is_ipc_notify(ipc_status) && m_ptr->m_source == TTY_PROC_NR) + do_dump(); +} /* -** Name: int dpeth_task(void) +** Name: main ** Function: Main entry for dp task */ int main(int argc, char **argv) { - message m; - int ipc_status; - int rc; - /* SEF local startup. */ env_setargs(argc, argv); - sef_local_startup(); - while (TRUE) { - if ((rc = netdriver_receive(ANY, &m, &ipc_status)) != OK){ - panic(RecvErrMsg, rc); - } + netdriver_task(&dp_table); - DEBUG(printf("eth: got message %d, ", m.m_type)); - - if (is_ipc_notify(ipc_status)) { - switch(_ENDPOINT_P(m.m_source)) { - case CLOCK: - /* to be defined */ - do_watchdog(&m); - break; - case HARDWARE: - /* Interrupt from device */ - handle_hw_intr(); - break; - case TTY_PROC_NR: - /* Function key pressed */ - do_dump(&m); - break; - default: - /* Invalid message type */ - panic(TypeErrMsg, m.m_type); - break; - } - /* message processed, get another one */ - continue; - } - - switch (m.m_type) { - case DL_WRITEV_S: /* Write message to device */ - do_vwrite_s(&m); - break; - case DL_READV_S: /* Read message from device */ - do_vread_s(&m); - break; - case DL_CONF: /* Initialize device */ - do_init(&m); - break; - case DL_GETSTAT_S: /* Get device statistics */ - do_getstat_s(&m); - break; - default: /* Invalid message type */ - panic(TypeErrMsg, m.m_type); - break; - } - } - return OK; /* Never reached, but keeps compiler happy */ + return 0; } - -/*===========================================================================* - * sef_local_startup * - *===========================================================================*/ -static void sef_local_startup() -{ - /* Register init callbacks. */ - sef_setcb_init_fresh(sef_cb_init_fresh); - sef_setcb_init_lu(sef_cb_init_fresh); - sef_setcb_init_restart(sef_cb_init_fresh); - - /* Register live update callbacks. */ - sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready); - sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_workfree); - - /* Register signal callbacks. */ - sef_setcb_signal_handler(sef_cb_signal_handler); - - /* Let SEF perform startup. */ - sef_startup(); -} - -/*===========================================================================* - * sef_cb_init_fresh * - *===========================================================================*/ -static int sef_cb_init_fresh(int type, sef_init_info_t *UNUSED(info)) -{ -/* Initialize the dpeth driver. */ - int fkeys, sfkeys; - long v; - - /* Request function key for debug dumps */ - fkeys = sfkeys = 0; bit_set(sfkeys, 8); - if ((fkey_map(&fkeys, &sfkeys)) != OK) - printf("%s: couldn't program Shift+F8 key (%d)\n", DevName, errno); - - v = 0; - (void) env_parse("instance", "d", 0, &v, 0, 255); - de_instance = (int) v; - - /* Announce we are up! */ - netdriver_announce(); - - return(OK); -} - -/*===========================================================================* - * sef_cb_signal_handler * - *===========================================================================*/ -static void sef_cb_signal_handler(int signo) -{ - /* Only check for termination signal, ignore anything else. */ - if (signo != SIGTERM) return; - - if (de_state.de_mode == DEM_ENABLED) - dp_stop(&de_state); - - exit(0); -} - -/** dp.c **/ diff --git a/minix/drivers/net/dpeth/dp.h b/minix/drivers/net/dpeth/dp.h index d36b5ea99..6a0b56f0e 100644 --- a/minix/drivers/net/dpeth/dp.h +++ b/minix/drivers/net/dpeth/dp.h @@ -51,7 +51,7 @@ #define NOT(x) (~(x)) -#if debug == 1 +#if VERBOSE == 1 # define DEBUG(statm) statm #else # define DEBUG(statm) @@ -70,26 +70,19 @@ typedef struct _buff_t { /* Receive/Transmit buffer header */ } buff_t; struct dpeth; -struct iovec_dat; -typedef void (*dp_eth_t) (struct dpeth *); -typedef void (*dp_send_recv_t) (struct dpeth *, int, int); +typedef void (*dp_eth_t)(struct dpeth *); +typedef int (*dp_send_t)(struct dpeth *, struct netdriver_data *, size_t); +typedef ssize_t (*dp_recv_t)(struct dpeth *, struct netdriver_data *, size_t); #if ENABLE_DP8390 == 1 -typedef void (*dp_user2nicf_t) (struct dpeth *, int, int); -typedef void (*dp_nic2userf_t) (struct dpeth *, int, int); -typedef void (*dp_getblock_t) (struct dpeth *, u16_t, int, void *); +typedef void (*dp_user2nicf_t)(struct dpeth *, int, struct netdriver_data *, + size_t); +typedef void (*dp_nic2userf_t)(struct dpeth *, int, struct netdriver_data *, + size_t); +typedef void (*dp_getblock_t)(struct dpeth *, u16_t, int, void *); #endif #define SENDQ_NR 2 /* Size of the send queue */ -#define IOVEC_NR 16 /* Number of IOVEC entries at a time */ - -typedef struct iovec_dat_s { - iovec_s_t iod_iovec[IOVEC_NR]; - int iod_iovec_s; - endpoint_t iod_proc_nr; - cp_grant_id_t iod_grant; - vir_bytes iod_iovec_offset; -} iovec_dat_s_t; typedef struct dpeth { /* The de_base_port field is the starting point of the probe. The @@ -109,7 +102,6 @@ typedef struct dpeth { port_t de_data_port; /* For boards using Prog. I/O for xmit/recv */ int de_irq; - int de_int_pending; int de_hook; /* interrupt hook at kernel */ char de_name[8]; @@ -117,7 +109,7 @@ typedef struct dpeth { #define DEI_DEFAULT 0x8000 phys_bytes de_linmem; /* For boards using shared memory */ - vir_bytes de_memoffs; + char *de_locmem; /* Locally mapped (virtual) address */ int de_ramsize; /* Size of on board memory */ int de_offset_page; /* Offset of shared memory page */ @@ -129,8 +121,8 @@ typedef struct dpeth { dp_eth_t de_getstatsf; dp_eth_t de_dumpstatsf; dp_eth_t de_interruptf; - dp_send_recv_t de_recvf; - dp_send_recv_t de_sendf; + dp_recv_t de_recvf; + dp_send_t de_sendf; ether_addr_t de_address; /* Ethernet Address */ eth_stat_t de_stat; /* Ethernet Statistics */ @@ -141,35 +133,12 @@ typedef struct dpeth { int de_flags; /* Send/Receive mode (Configuration) */ -#define DEF_EMPTY 0x0000 -#define DEF_READING 0x0001 -#define DEF_RECV_BUSY 0x0002 -#define DEF_ACK_RECV 0x0004 -#define DEF_SENDING 0x0010 -#define DEF_XMIT_BUSY 0x0020 -#define DEF_ACK_SEND 0x0040 -#define DEF_PROMISC 0x0100 -#define DEF_MULTI 0x0200 -#define DEF_BROAD 0x0400 -#define DEF_ENABLED 0x2000 -#define DEF_STOPPED 0x4000 +#define DEF_EMPTY 0x00 +#define DEF_XMIT_BUSY 0x01 +#define DEF_PROMISC 0x02 +#define DEF_MULTI 0x04 +#define DEF_BROAD 0x08 - int de_mode; /* Status of the Interface */ - -#define DEM_DISABLED 0x0000 -#define DEM_SINK 0x0001 -#define DEM_ENABLED 0x0002 - - /* Temporary storage for RECV/SEND requests */ - iovec_dat_s_t de_read_iovec; - iovec_dat_s_t de_write_iovec; - vir_bytes de_read_s; - vir_bytes de_send_s; - int de_client; -/* - message de_sendmsg; - iovec_dat_t de_tmp_iovec; -*/ #if ENABLE_DP8390 == 1 /* For use by NS DP8390 driver */ port_t de_dp8390_port; @@ -203,8 +172,6 @@ typedef struct dpeth { /* For use by 3Com Etherlink (3c501 and 3c509) driver */ buff_t *de_recvq_head; buff_t *de_recvq_tail; - buff_t *de_xmitq_head; - buff_t *de_xmitq_tail; u16_t de_recv_mode; clock_t de_xmit_start; #endif @@ -215,29 +182,23 @@ typedef struct dpeth { * Function definitions */ -/* dp.c */ -void dp_next_iovec(iovec_dat_s_t * iovp); - /* devio.c */ #if defined USE_IOPL #include #else unsigned int inb(unsigned short int); unsigned int inw(unsigned short int); -void insb(unsigned short int, endpoint_t, void *, int); -void insw(unsigned short int, int, void *, int); +void insb(unsigned short int, void *, int); +void insw(unsigned short int, void *, int); void outb(unsigned short int, unsigned long); void outw(unsigned short int, unsigned long); -void outsb(unsigned short int, endpoint_t, void *, int); -void outsw(unsigned short int, int, void *, int); +void outsb(unsigned short int, void *, int); #endif /* netbuff.c */ void *alloc_buff(dpeth_t *, int); void free_buff(dpeth_t *, void *); void init_buff(dpeth_t *, buff_t **); -void mem2user(dpeth_t *, buff_t *); -void user2mem(dpeth_t *, buff_t *); /* 3c501.c */ #if ENABLE_3C501 == 1 @@ -274,8 +235,4 @@ int wdeth_probe(dpeth_t * dep); #define wdeth_probe(x) (0) #endif -#define lock() (++dep->de_int_pending,sys_irqdisable(&dep->de_hook)) -#define unlock() do{int i=(--dep->de_int_pending)?0:sys_irqenable(&dep->de_hook);(void) i;}while(0) -#define milli_delay(t) tickdelay(1) - /** dp.h **/ diff --git a/minix/drivers/net/dpeth/ne.c b/minix/drivers/net/dpeth/ne.c index ea6cbe6b1..4b8add035 100644 --- a/minix/drivers/net/dpeth/ne.c +++ b/minix/drivers/net/dpeth/ne.c @@ -13,6 +13,7 @@ */ #include +#include #include #include #include "dp.h" @@ -23,7 +24,7 @@ #include "ne.h" /* -** Name: void ne_reset(dpeth_t * dep); +** Name: ne_reset ** Function: Resets the board and checks if reset cycle completes */ static int ne_reset(dpeth_t * dep) @@ -34,13 +35,13 @@ static int ne_reset(dpeth_t * dep) outb_ne(dep, NE_RESET, inb_ne(dep, NE_RESET)); do { if (++count > 10) return FALSE; /* 20 mSecs. timeout */ - milli_delay(2); + micro_delay(2000); } while ((inb_ne(dep, DP_ISR) & ISR_RST) == 0); return TRUE; } /* -** Name: void ne_close(dpeth_t * dep); +** Name: ne_close ** Function: Stops the board by resetting it and masking interrupts. */ static void ne_close(dpeth_t * dep) @@ -49,11 +50,10 @@ static void ne_close(dpeth_t * dep) (void)ne_reset(dep); outb_ne(dep, DP_ISR, 0xFF); sys_irqdisable(&dep->de_hook); - return; } /* -** Name: void ne_init(dpeth_t * dep); +** Name: ne_init ** Function: Initialize the board making it ready to work. */ static void ne_init(dpeth_t * dep) @@ -90,12 +90,12 @@ static void ne_init(dpeth_t * dep) dep->de_ramsize / 1024, dep->de_base_port, dep->de_irq); for (ix = 0; ix < SA_ADDR_LEN; ix += 1) - printf("%02X%c", dep->de_address.ea_addr[ix], ix < SA_ADDR_LEN - 1 ? ':' : '\n'); - return; + printf("%02X%c", dep->de_address.ea_addr[ix], + ix < SA_ADDR_LEN - 1 ? ':' : '\n'); } /* -** Name: int ne_probe(dpeth_t * dep); +** Name: ne_probe ** Function: Probe for the presence of a NE*000 card by testing ** whether the board is reachable through the dp8390. ** Note that the NE1000 is an 8bit card and has a memory diff --git a/minix/drivers/net/dpeth/netbuff.c b/minix/drivers/net/dpeth/netbuff.c index e190048d3..955c466e7 100644 --- a/minix/drivers/net/dpeth/netbuff.c +++ b/minix/drivers/net/dpeth/netbuff.c @@ -8,6 +8,7 @@ */ #include +#include #include #include #include "dp.h" @@ -18,7 +19,7 @@ static m_hdr_t *allocptr = NULL; static char tx_rx_buff[8192]; /* -** Name: void *alloc_buff(dpeth_t *dep, int size) +** Name: alloc_buff ** Function: Allocates a buffer from the common pool. */ void *alloc_buff(dpeth_t *dep, int size) @@ -26,7 +27,6 @@ void *alloc_buff(dpeth_t *dep, int size) m_hdr_t *ptr, *wrk = allocptr; int units = ((size + sizeof(m_hdr_t) - 1) / sizeof(m_hdr_t)) + 1; - lock(); for (ptr = wrk->next;; wrk = ptr, ptr = ptr->next) { if (ptr->size >= units) { /* Memory is available, carve requested size from pool */ @@ -39,24 +39,22 @@ void *alloc_buff(dpeth_t *dep, int size) ptr->size = units; } allocptr = wrk; - unlock(); return ptr + 1; } if (ptr == allocptr) break; } - unlock(); return NULL; /* No memory available */ } /* -** Name: void free_buff(dpeth_t *dep, void *blk) +** Name: free_buff ** Function: Returns a buffer to the common pool. */ void free_buff(dpeth_t *dep, void *blk) { m_hdr_t *wrk, *ptr = (m_hdr_t *) blk - 1; - lock(); /* Scan linked list for the correct place */ + /* Scan linked list for the correct place */ for (wrk = allocptr; !(ptr > wrk && ptr < wrk->next); wrk = wrk->next) if (wrk >= wrk->next && (ptr > wrk || ptr < wrk->next)) break; @@ -72,12 +70,10 @@ void free_buff(dpeth_t *dep, void *blk) } else wrk->next = ptr; allocptr = wrk; /* Point allocptr to block just released */ - unlock(); - return; } /* -** Name: void init_buff(dpeth_t *dep, buff_t **tx_buff) +** Name: init_buff ** Function: Initalizes driver data structures. */ void init_buff(dpeth_t *dep, buff_t **tx_buff) @@ -98,69 +94,6 @@ void init_buff(dpeth_t *dep, buff_t **tx_buff) (*tx_buff)->size = 0; } } - return; /* Done */ -} - -/* -** Name: void mem2user(dpeth_t *dep, buff_t *rxbuff); -** Function: Copies a packet from local buffer to user area. -*/ -void mem2user(dpeth_t *dep, buff_t *rxbuff) -{ - int bytes, ix = 0; - iovec_dat_s_t *iovp = &dep->de_read_iovec; - int r, pktsize = rxbuff->size; - char *buffer = rxbuff->buffer; - - do { /* Reads chuncks of packet into user buffers */ - - bytes = iovp->iod_iovec[ix].iov_size; /* Size of buffer */ - if (bytes > pktsize) bytes = pktsize; - - /* Reads from Rx buffer to user area */ - r= sys_safecopyto(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_grant, 0, - (vir_bytes)buffer, bytes); - if (r != OK) - panic("mem2user: sys_safecopyto failed: %d", r); - buffer += bytes; - - if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */ - dp_next_iovec(iovp); - ix = 0; - } - /* Till packet done */ - } while ((pktsize -= bytes) > 0); - return; -} - -/* -** Name: void user2mem(dpeth_t *dep, buff_t *txbuff) -** Function: Copies a packet from user area to local buffer. -*/ -void user2mem(dpeth_t *dep, buff_t *txbuff) -{ - int bytes, ix = 0; - iovec_dat_s_t *iovp = &dep->de_write_iovec; - int r, pktsize = txbuff->size; - char *buffer = txbuff->buffer; - - do { /* Reads chuncks of packet from user buffers */ - - bytes = iovp->iod_iovec[ix].iov_size; /* Size of buffer */ - if (bytes > pktsize) bytes = pktsize; - r= sys_safecopyfrom(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_grant, - 0, (vir_bytes)buffer, bytes); - if (r != OK) - panic("user2mem: sys_safecopyfrom failed: %d", r); - buffer += bytes; - - if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */ - dp_next_iovec(iovp); - ix = 0; - } - /* Till packet done */ - } while ((pktsize -= bytes) > 0); - return; } #endif /* HAVE_BUFFERS */ diff --git a/minix/drivers/net/dpeth/wd.c b/minix/drivers/net/dpeth/wd.c index 1ce57fdd9..2e3d5d1df 100644 --- a/minix/drivers/net/dpeth/wd.c +++ b/minix/drivers/net/dpeth/wd.c @@ -13,6 +13,7 @@ */ #include +#include #include #include #include "dp.h" @@ -43,8 +44,7 @@ static int we_ultra(dpeth_t * dep); /*===========================================================================* * wdeth_probe * *===========================================================================*/ -int wdeth_probe(dep) -dpeth_t *dep; +int wdeth_probe(dpeth_t *dep) { int sum; @@ -67,8 +67,7 @@ dpeth_t *dep; /*===========================================================================* * we_init * *===========================================================================*/ -static void we_init(dep) -dpeth_t *dep; +static void we_init(dpeth_t *dep) { int i, int_indx, int_nr; int tlb, rambit, revision; @@ -212,8 +211,7 @@ dpeth_t *dep; /*===========================================================================* * we_stop * *===========================================================================*/ -static void we_stop(dep) -dpeth_t *dep; +static void we_stop(dpeth_t *dep) { if (dep->de_16bit) outb_we(dep, EPL_LAAR, E_LAAR_A19 | E_LAAR_LAN16E); @@ -226,8 +224,7 @@ dpeth_t *dep; /*===========================================================================* * we_aliasing * *===========================================================================*/ -static int we_aliasing(dep) -dpeth_t *dep; +static int we_aliasing(dpeth_t *dep) { /* Determine whether wd8003 hardware performs register aliasing. This implies * an old WD8003E board. */ @@ -243,8 +240,7 @@ dpeth_t *dep; /*===========================================================================* * we_interface_chip * *===========================================================================*/ -static int we_interface_chip(dep) -dpeth_t *dep; +static int we_interface_chip(dpeth_t *dep) { /* Determine if the board has an interface chip. */ @@ -258,8 +254,7 @@ dpeth_t *dep; /*===========================================================================* * we_16bitboard * *===========================================================================*/ -static int we_16bitboard(dep) -dpeth_t *dep; +static int we_16bitboard(dpeth_t *dep) { /* Determine whether the board is capable of doing 16 bit memory moves. * If the 16 bit enable bit is unchangable by software we'll assume an @@ -286,8 +281,7 @@ dpeth_t *dep; /*===========================================================================* * we_16bitslot * *===========================================================================*/ -static int we_16bitslot(dep) -dpeth_t *dep; +static int we_16bitslot(dpeth_t *dep) { /* Determine if the 16 bit board in plugged into a 16 bit slot. */ @@ -297,8 +291,7 @@ dpeth_t *dep; /*===========================================================================* * we_ultra * *===========================================================================*/ -static int we_ultra(dep) -dpeth_t *dep; +static int we_ultra(dpeth_t *dep) { /* Determine if we has an '790 chip. */ u8_t tlb; diff --git a/minix/drivers/net/e1000/Makefile b/minix/drivers/net/e1000/Makefile index a21331d34..ce5945683 100644 --- a/minix/drivers/net/e1000/Makefile +++ b/minix/drivers/net/e1000/Makefile @@ -6,7 +6,7 @@ FILES=$(PROG).conf FILESNAME=$(PROG) FILESDIR= /etc/system.conf.d -DPADD+= ${LIBNETDRIVER} ${LIBSYS} ${LIBTIMERS} -LDADD+= -lnetdriver -lsys -ltimers +DPADD+= ${LIBNETDRIVER} ${LIBSYS} +LDADD+= -lnetdriver -lsys .include diff --git a/minix/drivers/net/e1000/e1000.c b/minix/drivers/net/e1000/e1000.c index 64cbf1720..72b7e3baf 100644 --- a/minix/drivers/net/e1000/e1000.c +++ b/minix/drivers/net/e1000/e1000.c @@ -1,19 +1,8 @@ -/** - * @file e1000.c - * - * @brief This file contains a device driver for Intel Pro/1000 - * Gigabit Ethernet Controllers. - */ +/* A device driver for Intel Pro/1000 Gigabit Ethernet Controllers. */ #include #include -#include -#include -#include #include -#include -#include -#include #include #include "assert.h" #include "e1000.h" @@ -21,1188 +10,836 @@ #include "e1000_reg.h" #include "e1000_pci.h" -static int e1000_instance; -static e1000_t e1000_state; - -static void e1000_init(message *mp); -static void e1000_init_pci(void); +static int e1000_init(unsigned int instance, ether_addr_t *addr); +static void e1000_stop(void); +static int e1000_send(struct netdriver_data *data, size_t size); +static ssize_t e1000_recv(struct netdriver_data *data, size_t max); +static void e1000_stat(eth_stat_t *stat); +static void e1000_intr(unsigned int mask); static int e1000_probe(e1000_t *e, int skip); -static int e1000_init_hw(e1000_t *e); -static void e1000_init_addr(e1000_t *e); -static void e1000_init_buf(e1000_t *e); -static void e1000_reset_hw(e1000_t *e); -static void e1000_writev_s(message *mp, int from_int); -static void e1000_readv_s(message *mp, int from_int); -static void e1000_getstat_s(message *mp); -static void e1000_interrupt(message *mp); -static int e1000_link_changed(e1000_t *e); -static void e1000_stop(e1000_t *e); +static void e1000_init_hw(e1000_t *e, ether_addr_t *addr); static uint32_t e1000_reg_read(e1000_t *e, uint32_t reg); static void e1000_reg_write(e1000_t *e, uint32_t reg, uint32_t value); static void e1000_reg_set(e1000_t *e, uint32_t reg, uint32_t value); static void e1000_reg_unset(e1000_t *e, uint32_t reg, uint32_t value); -static u16_t eeprom_eerd(void *e, int reg); -static u16_t eeprom_ich(void *e, int reg); +static u16_t eeprom_eerd(e1000_t *e, int reg); +static u16_t eeprom_ich(e1000_t *e, int reg); static int eeprom_ich_init(e1000_t *e); -static int eeprom_ich_cycle(const e1000_t *e, u32_t timeout); -static void reply(e1000_t *e); -static void mess_reply(message *req, message *reply); +static int eeprom_ich_cycle(e1000_t *e, u32_t timeout); -/* SEF functions and variables. */ -static void sef_local_startup(void); -static int sef_cb_init_fresh(int type, sef_init_info_t *info); -static void sef_cb_signal_handler(int signo); +static int e1000_instance; +static e1000_t e1000_state; -/*===========================================================================* - * main * - *===========================================================================*/ -int main(int argc, char *argv[]) +static const struct netdriver e1000_table = { + .ndr_init = e1000_init, + .ndr_stop = e1000_stop, + .ndr_recv = e1000_recv, + .ndr_send = e1000_send, + .ndr_stat = e1000_stat, + .ndr_intr = e1000_intr, +}; + +/* + * The e1000 driver. + */ +int +main(int argc, char * argv[]) { - message m; - int ipc_status; - int r; - /* SEF local startup. */ - env_setargs(argc, argv); - sef_local_startup(); + env_setargs(argc, argv); - /* - * Enter the main driver loop. - */ - while (TRUE) - { - if ((r= netdriver_receive(ANY, &m, &ipc_status)) != OK) - { - panic("netdriver_receive failed: %d", r); - } + /* Let the netdriver library take control. */ + netdriver_task(&e1000_table); - if (is_ipc_notify(ipc_status)) - { - switch (_ENDPOINT_P(m.m_source)) - { - case HARDWARE: - e1000_interrupt(&m); - break; - - case CLOCK: - break; - } - continue; - } - switch (m.m_type) - { - case DL_WRITEV_S: e1000_writev_s(&m, FALSE); break; - case DL_READV_S: e1000_readv_s(&m, FALSE); break; - case DL_CONF: e1000_init(&m); break; - case DL_GETSTAT_S: e1000_getstat_s(&m); break; - default: - panic("illegal message: %d", m.m_type); - } - } + return 0; } -/*===========================================================================* - * sef_local_startup * - *===========================================================================*/ -static void sef_local_startup() +/* + * Initialize the e1000 driver and device. + */ +static int +e1000_init(unsigned int instance, ether_addr_t * addr) { - /* Register init callbacks. */ - sef_setcb_init_fresh(sef_cb_init_fresh); - sef_setcb_init_lu(sef_cb_init_fresh); - sef_setcb_init_restart(sef_cb_init_fresh); + e1000_t *e; + int r; - /* Register live update callbacks. */ - sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready); - sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_workfree); + e1000_instance = instance; - /* Register signal callbacks. */ - sef_setcb_signal_handler(sef_cb_signal_handler); + /* Clear state. */ + memset(&e1000_state, 0, sizeof(e1000_state)); - /* Let SEF perform startup. */ - sef_startup(); + e = &e1000_state; + strlcpy(e->name, "e1000#0", sizeof(e->name)); + e->name[6] += instance; + + /* Perform calibration. */ + if ((r = tsc_calibrate()) != OK) + panic("tsc_calibrate failed: %d", r); + + /* See if we can find a matching device. */ + if (!e1000_probe(e, instance)) + return ENXIO; + + /* Initialize the hardware, and return its ethernet address. */ + e1000_init_hw(e, addr); + + return OK; } -/*===========================================================================* - * sef_cb_init_fresh * - *===========================================================================*/ -static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info)) +/* + * Map flash memory. This step is optional. + */ +static void +e1000_map_flash(e1000_t * e, int devind, int did) { -/* Initialize the e1000 driver. */ - long v; - int r; + u32_t flash_addr, gfpreg, sector_base_addr; + size_t flash_size; - v = 0; - (void) env_parse("instance", "d", 0, &v, 0, 255); - e1000_instance = (int) v; + /* The flash memory is pointed to by BAR2. It may not be present. */ + if ((flash_addr = pci_attr_r32(devind, PCI_BAR_2)) == 0) + return; - /* Clear state. */ - memset(&e1000_state, 0, sizeof(e1000_state)); + /* The default flash size. */ + flash_size = 0x10000; - /* Perform calibration. */ - if((r = tsc_calibrate()) != OK) - { - panic("tsc_calibrate failed: %d", r); - } - - /* Announce we are up! */ - netdriver_announce(); - - return(OK); -} - -/*===========================================================================* - * sef_cb_signal_handler * - *===========================================================================*/ -static void sef_cb_signal_handler(int signo) -{ - e1000_t *e; - e = &e1000_state; - - E1000_DEBUG(3, ("%s: got signal\n", e->name)); - - /* Only check for termination signal, ignore anything else. */ - if (signo != SIGTERM) return; - - e1000_stop(e); -} - -/*===========================================================================* - * e1000_init * - *===========================================================================*/ -static void e1000_init(message *mp) -{ - static int first_time = 1; - message reply_mess; - e1000_t *e; - - E1000_DEBUG(3, ("e1000: init()\n")); - - /* Configure PCI devices, if needed. */ - if (first_time) - { - first_time = 0; - e1000_init_pci(); - } - e = &e1000_state; - - /* Initialize hardware, if needed. */ - if (!(e->status & E1000_ENABLED) && !(e1000_init_hw(e))) - { - reply_mess.m_type = DL_CONF_REPLY; - reply_mess.m_netdrv_net_dl_conf.stat = ENXIO; - mess_reply(mp, &reply_mess); - return; - } - /* Reply back to INET. */ - reply_mess.m_type = DL_CONF_REPLY; - reply_mess.m_netdrv_net_dl_conf.stat = OK; - memcpy(reply_mess.m_netdrv_net_dl_conf.hw_addr, e->address.ea_addr, - sizeof(reply_mess.m_netdrv_net_dl_conf.hw_addr)); - mess_reply(mp, &reply_mess); -} - -/*===========================================================================* - * e1000_int_pci * - *===========================================================================*/ -static void e1000_init_pci() -{ - e1000_t *e; - - /* Initialize the PCI bus. */ - pci_init(); - - /* Try to detect e1000's. */ - e = &e1000_state; - strlcpy(e->name, "e1000#0", sizeof(e->name)); - e->name[6] += e1000_instance; - e1000_probe(e, e1000_instance); -} - -/*===========================================================================* - * e1000_probe * - *===========================================================================*/ -static int e1000_probe(e1000_t *e, int skip) -{ - int r, devind, ioflag; - u16_t vid, did, cr; - u32_t status[2]; - u32_t base, size; - u32_t gfpreg, sector_base_addr; - char *dname; - - E1000_DEBUG(3, ("%s: probe()\n", e->name)); - - /* - * Attempt to iterate the PCI bus. Start at the beginning. - */ - if ((r = pci_first_dev(&devind, &vid, &did)) == 0) - { - return FALSE; - } - /* Loop devices on the PCI bus. */ - while (skip--) - { - E1000_DEBUG(3, ("%s: probe() devind %d vid 0x%x did 0x%x\n", - e->name, devind, vid, did)); - - if (!(r = pci_next_dev(&devind, &vid, &did))) - { - return FALSE; - } - } - /* - * Successfully detected an Intel Pro/1000 on the PCI bus. - */ - e->status |= E1000_DETECTED; - e->eeprom_read = eeprom_eerd; - - /* - * Set card specific properties. - */ - switch (did) - { - case E1000_DEV_ID_ICH10_D_BM_LM: - case E1000_DEV_ID_ICH10_R_BM_LF: - e->eeprom_read = eeprom_ich; - break; - - case E1000_DEV_ID_82540EM: + switch (did) { + case E1000_DEV_ID_82540EM: case E1000_DEV_ID_82545EM: - e->eeprom_done_bit = (1 << 4); - e->eeprom_addr_off = 8; - break; + case E1000_DEV_ID_82540EP: + return; /* don't even try */ + + /* 82566/82567/82562V series support mapping 4kB of flash memory. */ + case E1000_DEV_ID_ICH10_D_BM_LM: + case E1000_DEV_ID_ICH10_R_BM_LF: + flash_size = 0x1000; + break; + } + + e->flash = vm_map_phys(SELF, (void *)flash_addr, flash_size); + if (e->flash == MAP_FAILED) + panic("e1000: couldn't map in flash"); + + /* sector_base_addr is a "sector"-aligned address (4096 bytes). */ + gfpreg = E1000_READ_FLASH_REG(e, ICH_FLASH_GFPREG); + sector_base_addr = gfpreg & FLASH_GFPREG_BASE_MASK; + + /* flash_base_addr is byte-aligned. */ + e->flash_base_addr = sector_base_addr << FLASH_SECTOR_ADDR_SHIFT; +} + +/* + * Find a matching device. Return TRUE on success. + */ +static int +e1000_probe(e1000_t * e, int skip) +{ + int r, devind, ioflag; + u16_t vid, did, cr; + u32_t status; + u32_t base, size; + char *dname; + + E1000_DEBUG(3, ("%s: probe()\n", e->name)); + + /* Initialize communication to the PCI driver. */ + pci_init(); + + /* Attempt to iterate the PCI bus. Start at the beginning. */ + if ((r = pci_first_dev(&devind, &vid, &did)) == 0) + return FALSE; + + /* Loop devices on the PCI bus. */ + while (skip--) { + E1000_DEBUG(3, ("%s: probe() devind %d vid 0x%x did 0x%x\n", + e->name, devind, vid, did)); + + if (!(r = pci_next_dev(&devind, &vid, &did))) + return FALSE; + } + + /* We found a matching card. Set card-specific properties. */ + e->eeprom_read = eeprom_eerd; + + switch (did) { + case E1000_DEV_ID_ICH10_D_BM_LM: + case E1000_DEV_ID_ICH10_R_BM_LF: + e->eeprom_read = eeprom_ich; + break; + + case E1000_DEV_ID_82540EM: + case E1000_DEV_ID_82545EM: + e->eeprom_done_bit = (1 << 4); + e->eeprom_addr_off = 8; + break; default: - e->eeprom_done_bit = (1 << 1); - e->eeprom_addr_off = 2; - break; - } + e->eeprom_done_bit = (1 << 1); + e->eeprom_addr_off = 2; + break; + } - /* Inform the user about the new card. */ - if (!(dname = pci_dev_name(vid, did))) - { - dname = "Intel Pro/1000 Gigabit Ethernet Card"; - } - E1000_DEBUG(1, ("%s: %s (%04x/%04x/%02x) at %s\n", - e->name, dname, vid, did, e->revision, - pci_slot_name(devind))); + /* Inform the user about the new card. */ + if (!(dname = pci_dev_name(vid, did))) + dname = "Intel Pro/1000 Gigabit Ethernet Card"; + E1000_DEBUG(1, ("%s: %s (%04x/%04x) at %s\n", + e->name, dname, vid, did, pci_slot_name(devind))); - /* Reserve PCI resources found. */ - if ((r = pci_reserve_ok(devind)) != OK) - { - panic("failed to reserve PCI device: %d", r); - } - /* Read PCI configuration. */ - e->irq = pci_attr_r8(devind, PCI_ILR); + /* Reserve PCI resources found. */ + pci_reserve(devind); - if ((r = pci_get_bar(devind, PCI_BAR, &base, &size, &ioflag)) != OK) - panic("failed to get PCI BAR (%d)", r); - if (ioflag) panic("PCI BAR is not for memory"); + /* Read PCI configuration. */ + e->irq = pci_attr_r8(devind, PCI_ILR); - e->regs = vm_map_phys(SELF, (void *) base, size); - if (e->regs == (u8_t *) -1) { + if ((r = pci_get_bar(devind, PCI_BAR, &base, &size, &ioflag)) != OK) + panic("failed to get PCI BAR: %d", r); + if (ioflag) + panic("PCI BAR is not for memory"); + + if ((e->regs = vm_map_phys(SELF, (void *)base, size)) == MAP_FAILED) panic("failed to map hardware registers from PCI"); - } - /* FIXME: enable DMA bus mastering if necessary. This is disabled by - * default on VMware. Eventually, the PCI driver should deal with this. - */ - cr = pci_attr_r16(devind, PCI_CR); - if (!(cr & PCI_CR_MAST_EN)) + /* Enable DMA bus mastering if necessary. */ + cr = pci_attr_r16(devind, PCI_CR); + if (!(cr & PCI_CR_MAST_EN)) pci_attr_w16(devind, PCI_CR, cr | PCI_CR_MAST_EN); - /* Optionally map flash memory. */ - if (did != E1000_DEV_ID_82540EM && - did != E1000_DEV_ID_82545EM && - did != E1000_DEV_ID_82540EP && - pci_attr_r32(devind, PCI_BAR_2)) - { - size_t flash_size; + /* Optionally map flash memory. */ + e1000_map_flash(e, devind, did); - /* 82566/82567/82562V series support mapping 4kB of flash memory */ - switch(did) - { - case E1000_DEV_ID_ICH10_D_BM_LM: - case E1000_DEV_ID_ICH10_R_BM_LF: - flash_size = 0x1000; - break; - default: - flash_size = 0x10000; - } + /* Output debug information. */ + status = e1000_reg_read(e, E1000_REG_STATUS); + E1000_DEBUG(3, ("%s: MEM at %p, IRQ %d\n", e->name, e->regs, e->irq)); + E1000_DEBUG(3, ("%s: link %s, %s duplex\n", e->name, + status & 3 ? "up" : "down", status & 1 ? "full" : "half")); - if ((e->flash = vm_map_phys(SELF, - (void *) pci_attr_r32(devind, PCI_BAR_2), - flash_size)) == MAP_FAILED) { - panic("e1000: couldn't map in flash."); - } - - gfpreg = E1000_READ_FLASH_REG(e, ICH_FLASH_GFPREG); - /* - * sector_base_addr is a "sector"-aligned address (4096 bytes) - */ - sector_base_addr = gfpreg & FLASH_GFPREG_BASE_MASK; - - /* flash_base_addr is byte-aligned */ - e->flash_base_addr = sector_base_addr << FLASH_SECTOR_ADDR_SHIFT; - } - /* - * Output debug information. - */ - status[0] = e1000_reg_read(e, E1000_REG_STATUS); - E1000_DEBUG(3, ("%s: MEM at %p, IRQ %d\n", - e->name, e->regs, e->irq)); - E1000_DEBUG(3, ("%s: link %s, %s duplex\n", - e->name, status[0] & 3 ? "up" : "down", - status[0] & 1 ? "full" : "half")); - return TRUE; + return TRUE; } -/*===========================================================================* - * e1000_init_hw * - *===========================================================================*/ -static int e1000_init_hw(e) -e1000_t *e; +/* + * Reset the card. + */ +static void +e1000_reset_hw(e1000_t * e) { - int r, i; - e->status |= E1000_ENABLED; - e->irq_hook = e->irq; + /* Assert a Device Reset signal. */ + e1000_reg_set(e, E1000_REG_CTRL, E1000_REG_CTRL_RST); - /* - * Set the interrupt handler and policy. Do not automatically - * re-enable interrupts. Return the IRQ line number on interrupts. - */ - if ((r = sys_irqsetpolicy(e->irq, 0, &e->irq_hook)) != OK) - { - panic("sys_irqsetpolicy failed: %d", r); - } - if ((r = sys_irqenable(&e->irq_hook)) != OK) - { - panic("sys_irqenable failed: %d", r); - } - /* Reset hardware. */ - e1000_reset_hw(e); - - /* - * Initialize appropriately, according to section 14.3 General Configuration - * of Intel's Gigabit Ethernet Controllers Software Developer's Manual. - */ - e1000_reg_set(e, E1000_REG_CTRL, E1000_REG_CTRL_ASDE | E1000_REG_CTRL_SLU); - e1000_reg_unset(e, E1000_REG_CTRL, E1000_REG_CTRL_LRST); - e1000_reg_unset(e, E1000_REG_CTRL, E1000_REG_CTRL_PHY_RST); - e1000_reg_unset(e, E1000_REG_CTRL, E1000_REG_CTRL_ILOS); - e1000_reg_write(e, E1000_REG_FCAL, 0); - e1000_reg_write(e, E1000_REG_FCAH, 0); - e1000_reg_write(e, E1000_REG_FCT, 0); - e1000_reg_write(e, E1000_REG_FCTTV, 0); - e1000_reg_unset(e, E1000_REG_CTRL, E1000_REG_CTRL_VME); - - /* Clear Multicast Table Array (MTA). */ - for (i = 0; i < 128; i++) - { - e1000_reg_write(e, E1000_REG_MTA + i, 0); - } - /* Initialize statistics registers. */ - for (i = 0; i < 64; i++) - { - e1000_reg_write(e, E1000_REG_CRCERRS + (i * 4), 0); - } - /* - * Aquire MAC address and setup RX/TX buffers. - */ - e1000_init_addr(e); - e1000_init_buf(e); - - /* Enable interrupts. */ - e1000_reg_set(e, E1000_REG_IMS, E1000_REG_IMS_LSC | - E1000_REG_IMS_RXO | - E1000_REG_IMS_RXT | - E1000_REG_IMS_TXQE | - E1000_REG_IMS_TXDW); - return TRUE; + /* Wait one microsecond. */ + tickdelay(1); } -/*===========================================================================* - * e1000_init_addr * - *===========================================================================*/ -static void e1000_init_addr(e) -e1000_t *e; +/* + * Initialize and return the card's ethernet address. + */ +static void +e1000_init_addr(e1000_t * e, ether_addr_t * addr) { - static char eakey[]= E1000_ENVVAR "#_EA"; - static char eafmt[]= "x:x:x:x:x:x"; - u16_t word; - int i; - long v; + static char eakey[] = E1000_ENVVAR "#_EA"; + static char eafmt[] = "x:x:x:x:x:x"; + u16_t word; + int i; + long v; - /* - * Do we have a user defined ethernet address? - */ - eakey[sizeof(E1000_ENVVAR)-1] = '0' + e1000_instance; + /* Do we have a user defined ethernet address? */ + eakey[sizeof(E1000_ENVVAR)-1] = '0' + e1000_instance; - for (i= 0; i < 6; i++) - { - if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET) - break; - else - e->address.ea_addr[i]= v; - } - /* - * If that fails, read Ethernet Address from EEPROM. - */ - if (i != 6) - { - for (i = 0; i < 3; i++) - { - word = e->eeprom_read(e, i); - e->address.ea_addr[(i * 2)] = (word & 0xff); - e->address.ea_addr[(i * 2) + 1] = (word & 0xff00) >> 8; + for (i = 0; i < 6; i++) { + if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET) + break; + else + addr->ea_addr[i] = v; } - } - /* - * Set Receive Address. - */ - e1000_reg_write(e, E1000_REG_RAL, *(u32_t *)(&e->address.ea_addr[0])); - e1000_reg_write(e, E1000_REG_RAH, *(u16_t *)(&e->address.ea_addr[4])); - e1000_reg_set(e, E1000_REG_RAH, E1000_REG_RAH_AV); - e1000_reg_set(e, E1000_REG_RCTL, E1000_REG_RCTL_MPE); - E1000_DEBUG(3, ("%s: Ethernet Address %x:%x:%x:%x:%x:%x\n", e->name, - e->address.ea_addr[0], e->address.ea_addr[1], - e->address.ea_addr[2], e->address.ea_addr[3], - e->address.ea_addr[4], e->address.ea_addr[5])); + /* If that fails, read Ethernet Address from EEPROM. */ + if (i != 6) { + for (i = 0; i < 3; i++) { + word = e->eeprom_read(e, i); + addr->ea_addr[i * 2] = (word & 0x00ff); + addr->ea_addr[i * 2 + 1] = (word & 0xff00) >> 8; + } + } + + /* Set Receive Address. */ + e1000_reg_write(e, E1000_REG_RAL, *(u32_t *)(&addr->ea_addr[0])); + e1000_reg_write(e, E1000_REG_RAH, *(u16_t *)(&addr->ea_addr[4])); + e1000_reg_set(e, E1000_REG_RAH, E1000_REG_RAH_AV); + e1000_reg_set(e, E1000_REG_RCTL, E1000_REG_RCTL_MPE); + + E1000_DEBUG(3, ("%s: Ethernet Address %x:%x:%x:%x:%x:%x\n", e->name, + addr->ea_addr[0], addr->ea_addr[1], addr->ea_addr[2], + addr->ea_addr[3], addr->ea_addr[4], addr->ea_addr[5])); } -/*===========================================================================* - * e1000_init_buf * - *===========================================================================*/ -static void e1000_init_buf(e) -e1000_t *e; +/* + * Initialize receive and transmit buffers. + */ +static void +e1000_init_buf(e1000_t * e) { - phys_bytes rx_buff_p; - phys_bytes tx_buff_p; - int i; + phys_bytes rx_desc_p, rx_buff_p; + phys_bytes tx_desc_p, tx_buff_p; + int i; - /* Number of descriptors. */ - e->rx_desc_count = E1000_RXDESC_NR; - e->tx_desc_count = E1000_TXDESC_NR; + /* Number of descriptors. */ + e->rx_desc_count = E1000_RXDESC_NR; + e->tx_desc_count = E1000_TXDESC_NR; - /* - * First, allocate the receive descriptors. - */ - if (!e->rx_desc) - { - if ((e->rx_desc = alloc_contig(sizeof(e1000_rx_desc_t) * - e->rx_desc_count, AC_ALIGN4K, - &e->rx_desc_p)) == NULL) { + /* Allocate receive descriptors. */ + if ((e->rx_desc = alloc_contig(sizeof(e1000_rx_desc_t) * + e->rx_desc_count, AC_ALIGN4K, &rx_desc_p)) == NULL) panic("failed to allocate RX descriptors"); - } - memset(e->rx_desc, 0, sizeof(e1000_rx_desc_t) * e->rx_desc_count); - /* - * Allocate 2048-byte buffers. - */ + memset(e->rx_desc, 0, sizeof(e1000_rx_desc_t) * e->rx_desc_count); + + /* Allocate receive buffers. */ e->rx_buffer_size = E1000_RXDESC_NR * E1000_IOBUF_SIZE; - - /* Attempt to allocate. */ - if ((e->rx_buffer = alloc_contig(e->rx_buffer_size, - AC_ALIGN4K, &rx_buff_p)) == NULL) - { - panic("failed to allocate RX buffers"); - } - /* Setup receive descriptors. */ + + if ((e->rx_buffer = alloc_contig(e->rx_buffer_size, AC_ALIGN4K, + &rx_buff_p)) == NULL) + panic("failed to allocate RX buffers"); + + /* Set up receive descriptors. */ for (i = 0; i < E1000_RXDESC_NR; i++) - { - e->rx_desc[i].buffer = rx_buff_p + (i * E1000_IOBUF_SIZE); - } - } - /* - * Then, allocate transmit descriptors. - */ - if (!e->tx_desc) - { - if ((e->tx_desc = alloc_contig(sizeof(e1000_tx_desc_t) * - e->tx_desc_count, AC_ALIGN4K, - &e->tx_desc_p)) == NULL) { + e->rx_desc[i].buffer = rx_buff_p + i * E1000_IOBUF_SIZE; + + /* Allocate transmit descriptors. */ + if ((e->tx_desc = alloc_contig(sizeof(e1000_tx_desc_t) * + e->tx_desc_count, AC_ALIGN4K, &tx_desc_p)) == NULL) panic("failed to allocate TX descriptors"); - } - memset(e->tx_desc, 0, sizeof(e1000_tx_desc_t) * e->tx_desc_count); - /* - * Allocate 2048-byte buffers. - */ + memset(e->tx_desc, 0, sizeof(e1000_tx_desc_t) * e->tx_desc_count); + + /* Allocate transmit buffers. */ e->tx_buffer_size = E1000_TXDESC_NR * E1000_IOBUF_SIZE; - - /* Attempt to allocate. */ - if ((e->tx_buffer = alloc_contig(e->tx_buffer_size, - AC_ALIGN4K, &tx_buff_p)) == NULL) - { - panic("failed to allocate TX buffers"); - } - /* Setup transmit descriptors. */ + + if ((e->tx_buffer = alloc_contig(e->tx_buffer_size, AC_ALIGN4K, + &tx_buff_p)) == NULL) + panic("failed to allocate TX buffers"); + + /* Set up transmit descriptors. */ for (i = 0; i < E1000_TXDESC_NR; i++) - { - e->tx_desc[i].buffer = tx_buff_p + (i * E1000_IOBUF_SIZE); - } - } - /* - * Setup the receive ring registers. - */ - e1000_reg_write(e, E1000_REG_RDBAL, e->rx_desc_p); - e1000_reg_write(e, E1000_REG_RDBAH, 0); - e1000_reg_write(e, E1000_REG_RDLEN, e->rx_desc_count * - sizeof(e1000_rx_desc_t)); - e1000_reg_write(e, E1000_REG_RDH, 0); - e1000_reg_write(e, E1000_REG_RDT, e->rx_desc_count - 1); - e1000_reg_unset(e, E1000_REG_RCTL, E1000_REG_RCTL_BSIZE); - e1000_reg_set(e, E1000_REG_RCTL, E1000_REG_RCTL_EN); - - /* - * Setup the transmit ring registers. - */ - e1000_reg_write(e, E1000_REG_TDBAL, e->tx_desc_p); - e1000_reg_write(e, E1000_REG_TDBAH, 0); - e1000_reg_write(e, E1000_REG_TDLEN, e->tx_desc_count * - sizeof(e1000_tx_desc_t)); - e1000_reg_write(e, E1000_REG_TDH, 0); - e1000_reg_write(e, E1000_REG_TDT, 0); - e1000_reg_set( e, E1000_REG_TCTL, E1000_REG_TCTL_EN | E1000_REG_TCTL_PSP); + e->tx_desc[i].buffer = tx_buff_p + i * E1000_IOBUF_SIZE; + + /* Set up the receive ring registers. */ + e1000_reg_write(e, E1000_REG_RDBAL, rx_desc_p); + e1000_reg_write(e, E1000_REG_RDBAH, 0); + e1000_reg_write(e, E1000_REG_RDLEN, + e->rx_desc_count * sizeof(e1000_rx_desc_t)); + e1000_reg_write(e, E1000_REG_RDH, 0); + e1000_reg_write(e, E1000_REG_RDT, e->rx_desc_count - 1); + e1000_reg_unset(e, E1000_REG_RCTL, E1000_REG_RCTL_BSIZE); + e1000_reg_set(e, E1000_REG_RCTL, E1000_REG_RCTL_EN); + + /* Set up the transmit ring registers. */ + e1000_reg_write(e, E1000_REG_TDBAL, tx_desc_p); + e1000_reg_write(e, E1000_REG_TDBAH, 0); + e1000_reg_write(e, E1000_REG_TDLEN, + e->tx_desc_count * sizeof(e1000_tx_desc_t)); + e1000_reg_write(e, E1000_REG_TDH, 0); + e1000_reg_write(e, E1000_REG_TDT, 0); + e1000_reg_set(e, E1000_REG_TCTL, + E1000_REG_TCTL_EN | E1000_REG_TCTL_PSP); } -/*===========================================================================* - * e1000_reset_hw * - *===========================================================================*/ -static void e1000_reset_hw(e) -e1000_t *e; +/* + * Initialize the hardware. Return the ethernet address. + */ +static void +e1000_init_hw(e1000_t * e, ether_addr_t * addr) { - /* Assert a Device Reset signal. */ - e1000_reg_set(e, E1000_REG_CTRL, E1000_REG_CTRL_RST); + int r, i; - /* Wait one microsecond. */ - tickdelay(1); -} - -/*===========================================================================* - * e1000_writev_s * - *===========================================================================*/ -static void e1000_writev_s(mp, from_int) -message *mp; -int from_int; -{ - e1000_t *e = &e1000_state; - e1000_tx_desc_t *desc; - iovec_s_t iovec[E1000_IOVEC_NR]; - int r, head, tail, i, bytes = 0, size; - - E1000_DEBUG(3, ("e1000: writev_s(%p,%d)\n", mp, from_int)); - - /* Are we called from the interrupt handler? */ - if (!from_int) - { - /* We cannot write twice simultaneously. - assert(!(e->status & E1000_WRITING)); */ - - /* Copy write message. */ - e->tx_message = *mp; - e->client = mp->m_source; - e->status |= E1000_WRITING; - - /* Must be a sane vector count. */ - assert(e->tx_message.m_net_netdrv_dl_writev_s.count > 0); - assert(e->tx_message.m_net_netdrv_dl_writev_s.count < E1000_IOVEC_NR); + e->irq_hook = e->irq; /* - * Copy the I/O vector table. + * Set the interrupt handler and policy. Do not automatically + * reenable interrupts. Return the IRQ line number on interrupts. */ - if ((r = sys_safecopyfrom(e->tx_message.m_source, - e->tx_message.m_net_netdrv_dl_writev_s.grant, 0, - (vir_bytes) iovec, - e->tx_message.m_net_netdrv_dl_writev_s.count * - sizeof(iovec_s_t))) != OK) - { - panic("sys_safecopyfrom() failed: %d", r); - } - /* Find the head, tail and current descriptors. */ - head = e1000_reg_read(e, E1000_REG_TDH); - tail = e1000_reg_read(e, E1000_REG_TDT); + if ((r = sys_irqsetpolicy(e->irq, 0, &e->irq_hook)) != OK) + panic("sys_irqsetpolicy failed: %d", r); + if ((r = sys_irqenable(&e->irq_hook)) != OK) + panic("sys_irqenable failed: %d", r); + + /* Reset hardware. */ + e1000_reset_hw(e); + + /* + * Initialize appropriately, according to section 14.3 General + * Configuration of Intel's Gigabit Ethernet Controllers Software + * Developer's Manual. + */ + e1000_reg_set(e, E1000_REG_CTRL, + E1000_REG_CTRL_ASDE | E1000_REG_CTRL_SLU); + e1000_reg_unset(e, E1000_REG_CTRL, E1000_REG_CTRL_LRST); + e1000_reg_unset(e, E1000_REG_CTRL, E1000_REG_CTRL_PHY_RST); + e1000_reg_unset(e, E1000_REG_CTRL, E1000_REG_CTRL_ILOS); + e1000_reg_write(e, E1000_REG_FCAL, 0); + e1000_reg_write(e, E1000_REG_FCAH, 0); + e1000_reg_write(e, E1000_REG_FCT, 0); + e1000_reg_write(e, E1000_REG_FCTTV, 0); + e1000_reg_unset(e, E1000_REG_CTRL, E1000_REG_CTRL_VME); + + /* Clear Multicast Table Array (MTA). */ + for (i = 0; i < 128; i++) + e1000_reg_write(e, E1000_REG_MTA + i * 4, 0); + + /* Initialize statistics registers. */ + for (i = 0; i < 64; i++) + e1000_reg_write(e, E1000_REG_CRCERRS + i * 4, 0); + + /* Acquire MAC address and set up RX/TX buffers. */ + e1000_init_addr(e, addr); + e1000_init_buf(e); + + /* Enable interrupts. */ + e1000_reg_set(e, E1000_REG_IMS, E1000_REG_IMS_LSC | E1000_REG_IMS_RXO | + E1000_REG_IMS_RXT | E1000_REG_IMS_TXQE | E1000_REG_IMS_TXDW); +} + +/* + * Try to send a packet. + */ +static int +e1000_send(struct netdriver_data * data, size_t size) +{ + e1000_t *e; + e1000_tx_desc_t *desc; + unsigned int head, tail, next; + char *ptr; + + e = &e1000_state; + + if (size > E1000_IOBUF_SIZE) + panic("packet too large to send"); + + /* + * The queue tail must not advance to the point that it is equal to the + * queue head, since this condition indicates that the queue is empty. + */ + head = e1000_reg_read(e, E1000_REG_TDH); + tail = e1000_reg_read(e, E1000_REG_TDT); + next = (tail + 1) % e->tx_desc_count; + + if (next == head) + return SUSPEND; + + /* The descriptor to use is the one pointed to by the current tail. */ desc = &e->tx_desc[tail]; - - E1000_DEBUG(4, ("%s: head=%d, tail=%d\n", - e->name, head, tail)); - /* Loop vector elements. */ - for (i = 0; i < e->tx_message.m_net_netdrv_dl_writev_s.count; i++) - { - size = iovec[i].iov_size < (E1000_IOBUF_SIZE - bytes) ? - iovec[i].iov_size : (E1000_IOBUF_SIZE - bytes); + /* Copy the packet from the caller. */ + ptr = e->tx_buffer + tail * E1000_IOBUF_SIZE; - E1000_DEBUG(4, ("iovec[%d] = %d\n", i, size)); + netdriver_copyin(data, 0, ptr, size); - /* Copy bytes to TX queue buffers. */ - if ((r = sys_safecopyfrom(e->tx_message.m_source, - iovec[i].iov_grant, 0, - (vir_bytes) e->tx_buffer + - (tail * E1000_IOBUF_SIZE), - size)) != OK) - { - panic("sys_safecopyfrom() failed: %d", r); - } - /* Mark this descriptor ready. */ - desc->status = 0; - desc->command = 0; - desc->length = size; + /* Mark this descriptor ready. */ + desc->status = 0; + desc->length = size; + desc->command = E1000_TX_CMD_EOP | E1000_TX_CMD_FCS | E1000_TX_CMD_RS; - /* Marks End-of-Packet. */ - if (i == e->tx_message.m_net_netdrv_dl_writev_s.count - 1) - { - desc->command = E1000_TX_CMD_EOP | - E1000_TX_CMD_FCS | - E1000_TX_CMD_RS; - } - /* Move to next descriptor. */ - tail = (tail + 1) % e->tx_desc_count; - bytes += size; - desc = &e->tx_desc[tail]; - } - /* Increment tail. Start transmission. */ - e1000_reg_write(e, E1000_REG_TDT, tail); + /* Increment tail. Start transmission. */ + e1000_reg_write(e, E1000_REG_TDT, next); - E1000_DEBUG(2, ("e1000: wrote %d byte packet\n", bytes)); - } - else - { - e->status |= E1000_TRANSMIT; - } - reply(e); + return OK; } -/*===========================================================================* - * e1000_readv_s * - *===========================================================================*/ -static void e1000_readv_s(mp, from_int) -message *mp; -int from_int; +/* + * Try to receive a packet. + */ +static ssize_t +e1000_recv(struct netdriver_data * data, size_t max) { - e1000_t *e = &e1000_state; - e1000_rx_desc_t *desc; - iovec_s_t iovec[E1000_IOVEC_NR]; - int i, r, head, tail, cur, bytes = 0, size; + e1000_t *e; + e1000_rx_desc_t *desc; + unsigned int head, tail, cur; + char *ptr; + size_t size; - E1000_DEBUG(3, ("e1000: readv_s(%p,%d)\n", mp, from_int)); + e = &e1000_state; - /* Are we called from the interrupt handler? */ - if (!from_int) - { - e->rx_message = *mp; - e->client = mp->m_source; - e->status |= E1000_READING; - e->rx_size = 0; - - assert(e->rx_message.m_net_netdrv_dl_readv_s.count > 0); - assert(e->rx_message.m_net_netdrv_dl_readv_s.count < E1000_IOVEC_NR); - } - if (e->status & E1000_READING) - { - /* - * Copy the I/O vector table first. - */ - if ((r = sys_safecopyfrom(e->rx_message.m_source, - e->rx_message.m_net_netdrv_dl_readv_s.grant, 0, - (vir_bytes) iovec, - e->rx_message.m_net_netdrv_dl_readv_s.count * - sizeof(iovec_s_t))) != OK) - { - panic("sys_safecopyfrom() failed: %d", r); - } - /* Find the head, tail and current descriptors. */ + /* If the queue head and tail are equal, the queue is empty. */ head = e1000_reg_read(e, E1000_REG_RDH); tail = e1000_reg_read(e, E1000_REG_RDT); - cur = (tail + 1) % e->rx_desc_count; + + E1000_DEBUG(4, ("%s: head=%u, tail=%u\n", e->name, head, tail)); + + if (head == tail) + return SUSPEND; + + /* Has a packet been received? */ + cur = (tail + 1) % e->rx_desc_count; desc = &e->rx_desc[cur]; - + + if (!(desc->status & E1000_RX_STATUS_DONE)) + return SUSPEND; + /* - * Only handle one packet at a time. + * HACK: we expect all packets to fit in a single receive buffer. + * Eventually, some sort of support to deal with packets spanning + * multiple receive descriptors should be added. For now, we panic, + * so that we can continue after the restart; this is already an + * improvement over freezing (the old behavior of this driver). */ + size = desc->length; + if (!(desc->status & E1000_RX_STATUS_EOP)) - { - reply(e); - return; - } - E1000_DEBUG(4, ("%s: head=%x, tail=%d\n", - e->name, head, tail)); + panic("received packet too large"); - /* - * Copy to vector elements. - */ - for (i = 0; i < e->rx_message.m_net_netdrv_dl_readv_s.count && - bytes < desc->length; i++) - { - size = iovec[i].iov_size < (desc->length - bytes) ? - iovec[i].iov_size : (desc->length - bytes); - - E1000_DEBUG(4, ("iovec[%d] = %lu[%d]\n", - i, iovec[i].iov_size, size)); + /* Copy the packet to the caller. */ + ptr = e->rx_buffer + cur * E1000_IOBUF_SIZE; - if ((r = sys_safecopyto(e->rx_message.m_source, iovec[i].iov_grant, - 0, (vir_bytes) e->rx_buffer + bytes + - (cur * E1000_IOBUF_SIZE), - size)) != OK) - { - panic("sys_safecopyto() failed: %d", r); - } - bytes += size; - } + if (size > max) + size = max; + + netdriver_copyout(data, 0, ptr, size); + + /* Reset the descriptor. */ desc->status = 0; - /* - * Update state. - */ - e->rx_size = bytes; - e->status |= E1000_RECEIVED; - E1000_DEBUG(2, ("e1000: got %d byte packet\n", e->rx_size)); - /* Increment tail. */ - e1000_reg_write(e, E1000_REG_RDT, (tail + 1) % e->rx_desc_count); - } - reply(e); + e1000_reg_write(e, E1000_REG_RDT, cur); + + /* Return the size of the received packet. */ + return size; } -/*===========================================================================* - * e1000_getstat_s * - *===========================================================================*/ -static void e1000_getstat_s(mp) -message *mp; +/* + * Return statistics. + */ +static void +e1000_stat(eth_stat_t * stat) { - int r; - eth_stat_t stats; - e1000_t *e = &e1000_state; + e1000_t *e = &e1000_state; - E1000_DEBUG(3, ("e1000: getstat_s()\n")); + E1000_DEBUG(3, ("e1000: stat()\n")); - stats.ets_recvErr = e1000_reg_read(e, E1000_REG_RXERRC); - stats.ets_sendErr = 0; - stats.ets_OVW = 0; - stats.ets_CRCerr = e1000_reg_read(e, E1000_REG_CRCERRS); - stats.ets_frameAll = 0; - stats.ets_missedP = e1000_reg_read(e, E1000_REG_MPC); - stats.ets_packetR = e1000_reg_read(e, E1000_REG_TPR); - stats.ets_packetT = e1000_reg_read(e, E1000_REG_TPT); - stats.ets_collision = e1000_reg_read(e, E1000_REG_COLC); - stats.ets_transAb = 0; - stats.ets_carrSense = 0; - stats.ets_fifoUnder = 0; - stats.ets_fifoOver = 0; - stats.ets_CDheartbeat = 0; - stats.ets_OWC = 0; - - sys_safecopyto(mp->m_source, mp->m_net_netdrv_dl_getstat_s.grant, 0, - (vir_bytes)&stats, sizeof(stats)); - mp->m_type = DL_STAT_REPLY; - if((r=ipc_send(mp->m_source, mp)) != OK) - panic("e1000_getstat: ipc_send() failed: %d", r); + stat->ets_recvErr = e1000_reg_read(e, E1000_REG_RXERRC); + stat->ets_sendErr = 0; + stat->ets_OVW = 0; + stat->ets_CRCerr = e1000_reg_read(e, E1000_REG_CRCERRS); + stat->ets_frameAll = 0; + stat->ets_missedP = e1000_reg_read(e, E1000_REG_MPC); + stat->ets_packetR = e1000_reg_read(e, E1000_REG_TPR); + stat->ets_packetT = e1000_reg_read(e, E1000_REG_TPT); + stat->ets_collision = e1000_reg_read(e, E1000_REG_COLC); + stat->ets_transAb = 0; + stat->ets_carrSense = 0; + stat->ets_fifoUnder = 0; + stat->ets_fifoOver = 0; + stat->ets_CDheartbeat = 0; + stat->ets_OWC = 0; } -/*===========================================================================* - * e1000_interrupt * - *===========================================================================*/ -static void e1000_interrupt(mp) -message *mp; +/* + * Link status has changed. Nothing to do for now. + */ +static void +e1000_link_changed(e1000_t * e) { - e1000_t *e; - u32_t cause; - E1000_DEBUG(3, ("e1000: interrupt\n")); - - /* - * Check the card for interrupt reason(s). - */ - e = &e1000_state; - - /* Re-enable interrupts. */ - if (sys_irqenable(&e->irq_hook) != OK) - { - panic("failed to re-enable IRQ"); - } - - /* Read the Interrupt Cause Read register. */ - if ((cause = e1000_reg_read(e, E1000_REG_ICR))) - { - if (cause & E1000_REG_ICR_LSC) - e1000_link_changed(e); - - if (cause & (E1000_REG_ICR_RXO | E1000_REG_ICR_RXT)) - e1000_readv_s(&e->rx_message, TRUE); - - if ((cause & E1000_REG_ICR_TXQE) || - (cause & E1000_REG_ICR_TXDW)) - e1000_writev_s(&e->tx_message, TRUE); - } + E1000_DEBUG(4, ("%s: link_changed()\n", e->name)); } -/*===========================================================================* - * e1000_link_changed * - *===========================================================================*/ -static int e1000_link_changed(e) -e1000_t *e; +/* + * Handle an interrupt. + */ +static void +e1000_intr(unsigned int __unused mask) { - E1000_DEBUG(4, ("%s: link_changed()\n", e->name)); - return FALSE; + e1000_t *e; + u32_t cause; + + E1000_DEBUG(3, ("e1000: interrupt\n")); + + e = &e1000_state; + + /* Reenable interrupts. */ + if (sys_irqenable(&e->irq_hook) != OK) + panic("failed to re-enable IRQ"); + + /* Read the Interrupt Cause Read register. */ + if ((cause = e1000_reg_read(e, E1000_REG_ICR)) != 0) { + if (cause & E1000_REG_ICR_LSC) + e1000_link_changed(e); + + if (cause & (E1000_REG_ICR_RXO | E1000_REG_ICR_RXT)) + netdriver_recv(); + + if (cause & (E1000_REG_ICR_TXQE | E1000_REG_ICR_TXDW)) + netdriver_send(); + } } -/*===========================================================================* - * e1000_stop * - *===========================================================================*/ -static void e1000_stop(e) -e1000_t *e; +/* + * Stop the card. + */ +static void +e1000_stop(void) { - E1000_DEBUG(3, ("%s: stop()\n", e->name)); + e1000_t *e; - e1000_reset_hw(e); + e = &e1000_state; - exit(EXIT_SUCCESS); + E1000_DEBUG(3, ("%s: stop()\n", e->name)); + + e1000_reset_hw(e); } -/*===========================================================================* - * e1000_reg_read * - *===========================================================================*/ -static uint32_t e1000_reg_read(e, reg) -e1000_t *e; -uint32_t reg; +/* + * Read from a register. + */ +static uint32_t +e1000_reg_read(e1000_t * e, uint32_t reg) { - uint32_t value; + uint32_t value; - /* Assume a sane register. */ - assert(reg < 0x1ffff); + /* Assume a sane register. */ + assert(reg < 0x1ffff); - /* Read from memory mapped register. */ - value = *(volatile u32_t *)(e->regs + reg); + /* Read from memory mapped register. */ + value = *(volatile uint32_t *)(e->regs + reg); - /* Return the result. */ - return value; + /* Return the result. */ + return value; } -/*===========================================================================* - * e1000_reg_write * - *===========================================================================*/ -static void e1000_reg_write(e, reg, value) -e1000_t *e; -uint32_t reg; -uint32_t value; +/* + * Write to a register. + */ +static void +e1000_reg_write(e1000_t * e, uint32_t reg, uint32_t value) { - /* Assume a sane register. */ - assert(reg < 0x1ffff); - - /* Write to memory mapped register. */ - *(volatile u32_t *)(e->regs + reg) = value; + + /* Assume a sane register. */ + assert(reg < 0x1ffff); + + /* Write to memory mapped register. */ + *(volatile u32_t *)(e->regs + reg) = value; } -/*===========================================================================* - * e1000_reg_set * - *===========================================================================*/ -static void e1000_reg_set(e, reg, value) -e1000_t *e; -uint32_t reg; -uint32_t value; +/* + * Set bits in a register. + */ +static void +e1000_reg_set(e1000_t * e, uint32_t reg, uint32_t value) { - uint32_t data; + uint32_t data; - /* First read the current value. */ - data = e1000_reg_read(e, reg); - - /* Set value, and write back. */ - e1000_reg_write(e, reg, data | value); + /* First read the current value. */ + data = e1000_reg_read(e, reg); + + /* Set bits, and write back. */ + e1000_reg_write(e, reg, data | value); } -/*===========================================================================* - * e1000_reg_unset * - *===========================================================================*/ -static void e1000_reg_unset(e, reg, value) -e1000_t *e; -uint32_t reg; -uint32_t value; +/* + * Clear bits in a register. + */ +static void +e1000_reg_unset(e1000_t * e, uint32_t reg, uint32_t value) { - uint32_t data; + uint32_t data; - /* First read the current value. */ - data = e1000_reg_read(e, reg); - - /* Unset value, and write back. */ - e1000_reg_write(e, reg, data & ~value); + /* First read the current value. */ + data = e1000_reg_read(e, reg); + + /* Unset bits, and write back. */ + e1000_reg_write(e, reg, data & ~value); } - -/*===========================================================================* - * eeprom_eerd * - *===========================================================================*/ -static u16_t eeprom_eerd(v, reg) -void *v; -int reg; +/* + * Read from EEPROM. + */ +static u16_t +eeprom_eerd(e1000_t * e, int reg) { - e1000_t *e = (e1000_t *) v; - u32_t data; + u32_t data; - /* Request EEPROM read. */ - e1000_reg_write(e, E1000_REG_EERD, - (reg << e->eeprom_addr_off) | (E1000_REG_EERD_START)); + /* Request EEPROM read. */ + e1000_reg_write(e, E1000_REG_EERD, + (reg << e->eeprom_addr_off) | (E1000_REG_EERD_START)); - /* Wait until ready. */ - while (!((data = (e1000_reg_read(e, E1000_REG_EERD))) & e->eeprom_done_bit)); + /* Wait until ready. */ + while (!((data = (e1000_reg_read(e, E1000_REG_EERD))) & + e->eeprom_done_bit)); - return data >> 16; + return data >> 16; } -/*===========================================================================* - * eeprom_ich_init * - *===========================================================================*/ -static int eeprom_ich_init(e) -e1000_t *e; +/* + * Initialize ICH8 flash. + */ +static int +eeprom_ich_init(e1000_t * e) { - union ich8_hws_flash_status hsfsts; - int ret_val = -1; - int i = 0; + union ich8_hws_flash_status hsfsts; + int ret_val = -1; + int i = 0; - hsfsts.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFSTS); + hsfsts.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFSTS); - /* Check if the flash descriptor is valid */ - if (hsfsts.hsf_status.fldesvalid == 0) - { - E1000_DEBUG(3, ("Flash descriptor invalid. " - "SW Sequencing must be used.")); - goto out; - } - /* Clear FCERR and DAEL in hw status by writing 1 */ - hsfsts.hsf_status.flcerr = 1; - hsfsts.hsf_status.dael = 1; - - E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFSTS, hsfsts.regval); - - /* - * Either we should have a hardware SPI cycle in progress - * bit to check against, in order to start a new cycle or - * FDONE bit should be changed in the hardware so that it - * is 1 after hardware reset, which can then be used as an - * indication whether a cycle is in progress or has been - * completed. - */ - if (hsfsts.hsf_status.flcinprog == 0) - { - /* - * There is no cycle running at present, - * so we can start a cycle. - * Begin by setting Flash Cycle Done. - */ - hsfsts.hsf_status.flcdone = 1; - E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFSTS, hsfsts.regval); - ret_val = 0; - } - else - { - /* - * Otherwise poll for sometime so the current - * cycle has a chance to end before giving up. - */ - for (i = 0; i < ICH_FLASH_READ_COMMAND_TIMEOUT; i++) - { - hsfsts.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFSTS); - - if (hsfsts.hsf_status.flcinprog == 0) - { - ret_val = 0; - break; - } - tickdelay(1); - } - if (ret_val == 0) - { - /* - * Successful in waiting for previous cycle to timeout, - * now set the Flash Cycle Done. - */ - hsfsts.hsf_status.flcdone = 1; - E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFSTS, - hsfsts.regval); - } - else - { - E1000_DEBUG(3, ("Flash controller busy, cannot get access")); - } - } -out: - return ret_val; + /* Check if the flash descriptor is valid */ + if (hsfsts.hsf_status.fldesvalid == 0) { + E1000_DEBUG(3, ("Flash descriptor invalid. " + "SW Sequencing must be used.")); + return ret_val; + } + + /* Clear FCERR and DAEL in hw status by writing 1 */ + hsfsts.hsf_status.flcerr = 1; + hsfsts.hsf_status.dael = 1; + + E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFSTS, hsfsts.regval); + + /* + * Either we should have a hardware SPI cycle in progress bit to check + * against, in order to start a new cycle or FDONE bit should be + * changed in the hardware so that it is 1 after hardware reset, which + * can then be used as an indication whether a cycle is in progress or + * has been completed. + */ + if (hsfsts.hsf_status.flcinprog == 0) { + /* + * There is no cycle running at present, so we can start a + * cycle. Begin by setting Flash Cycle Done. + */ + hsfsts.hsf_status.flcdone = 1; + E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFSTS, hsfsts.regval); + ret_val = 0; + } else { + /* + * Otherwise poll for sometime so the current cycle has a + * chance to end before giving up. + */ + for (i = 0; i < ICH_FLASH_READ_COMMAND_TIMEOUT; i++) { + hsfsts.regval = E1000_READ_FLASH_REG16(e, + ICH_FLASH_HSFSTS); + + if (hsfsts.hsf_status.flcinprog == 0) { + ret_val = 0; + break; + } + tickdelay(1); + } + if (ret_val == 0) { + /* + * Successful in waiting for previous cycle to timeout, + * now set the Flash Cycle Done. + */ + hsfsts.hsf_status.flcdone = 1; + E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFSTS, + hsfsts.regval); + } else { + E1000_DEBUG(3, + ("Flash controller busy, cannot get access")); + } + } + + return ret_val; } -/*===========================================================================* - * eeprom_ich_cycle * - *===========================================================================*/ -static int eeprom_ich_cycle(const e1000_t *e, u32_t timeout) +/* + * Start ICH8 flash cycle. + */ +static int +eeprom_ich_cycle(e1000_t * e, u32_t timeout) { - union ich8_hws_flash_ctrl hsflctl; - union ich8_hws_flash_status hsfsts; - int ret_val = -1; - u32_t i = 0; + union ich8_hws_flash_ctrl hsflctl; + union ich8_hws_flash_status hsfsts; + int ret_val = -1; + u32_t i = 0; - E1000_DEBUG(3, ("e1000_flash_cycle_ich8lan")); + E1000_DEBUG(3, ("e1000_flash_cycle_ich8lan")); - /* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */ - hsflctl.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFCTL); - hsflctl.hsf_ctrl.flcgo = 1; - E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFCTL, hsflctl.regval); - - /* wait till FDONE bit is set to 1 */ - do - { - hsfsts.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFSTS); - if (hsfsts.hsf_status.flcdone == 1) - break; - tickdelay(1); - } - while (i++ < timeout); - - if (hsfsts.hsf_status.flcdone == 1 && hsfsts.hsf_status.flcerr == 0) - ret_val = 0; - - return ret_val; + /* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */ + hsflctl.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFCTL); + hsflctl.hsf_ctrl.flcgo = 1; + E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFCTL, hsflctl.regval); + + /* Wait till the FDONE bit is set to 1 */ + do { + hsfsts.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFSTS); + if (hsfsts.hsf_status.flcdone == 1) + break; + tickdelay(1); + } while (i++ < timeout); + + if (hsfsts.hsf_status.flcdone == 1 && hsfsts.hsf_status.flcerr == 0) + ret_val = 0; + + return ret_val; } -/*===========================================================================* - * eeprom_ich * - *===========================================================================*/ -static u16_t eeprom_ich(v, reg) -void *v; -int reg; +/* + * Read from ICH8 flash. + */ +static u16_t +eeprom_ich(e1000_t * e, int reg) { - union ich8_hws_flash_status hsfsts; - union ich8_hws_flash_ctrl hsflctl; - u32_t flash_linear_addr; - u32_t flash_data = 0; - int ret_val = -1; - u8_t count = 0; - e1000_t *e = (e1000_t *) v; - u16_t data = 0; - - E1000_DEBUG(3, ("e1000_read_flash_data_ich8lan")); - - if (reg > ICH_FLASH_LINEAR_ADDR_MASK) - goto out; + union ich8_hws_flash_status hsfsts; + union ich8_hws_flash_ctrl hsflctl; + u32_t flash_linear_addr; + u32_t flash_data = 0; + int ret_val = -1; + u8_t count = 0; + u16_t data = 0; - reg *= sizeof(u16_t); - flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & reg) + - e->flash_base_addr; + E1000_DEBUG(3, ("e1000_read_flash_data_ich8lan")); - do { - tickdelay(1); - - /* Steps */ - ret_val = eeprom_ich_init(e); - if (ret_val != 0) - break; + if (reg > ICH_FLASH_LINEAR_ADDR_MASK) + return data; - hsflctl.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFCTL); - /* 0b/1b corresponds to 1 or 2 byte size, respectively. */ - hsflctl.hsf_ctrl.fldbcount = 1; - hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ; - E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFCTL, hsflctl.regval); - E1000_WRITE_FLASH_REG(e, ICH_FLASH_FADDR, flash_linear_addr); + reg *= sizeof(u16_t); + flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & reg) + + e->flash_base_addr; - ret_val = eeprom_ich_cycle(v, ICH_FLASH_READ_COMMAND_TIMEOUT); - - /* - * Check if FCERR is set to 1, if set to 1, clear it - * and try the whole sequence a few more times, else - * read in (shift in) the Flash Data0, the order is - * least significant byte first msb to lsb - */ - if (ret_val == 0) - { - flash_data = E1000_READ_FLASH_REG(e, ICH_FLASH_FDATA0); - data = (u16_t)(flash_data & 0x0000FFFF); - break; - } - else - { - /* - * If we've gotten here, then things are probably - * completely hosed, but if the error condition is - * detected, it won't hurt to give it another try... - * ICH_FLASH_CYCLE_REPEAT_COUNT times. - */ - hsfsts.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFSTS); - - if (hsfsts.hsf_status.flcerr == 1) - { - /* Repeat for some time before giving up. */ - continue; - } - else if (hsfsts.hsf_status.flcdone == 0) - { - E1000_DEBUG(3, ("Timeout error - flash cycle " - "did not complete.")); - break; - } - } - } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT); + do { + tickdelay(1); -out: - return data; -} - -/*===========================================================================* - * reply * - *===========================================================================*/ -static void reply(e) -e1000_t *e; -{ - message msg; - int r; - - /* Only reply to client for read/write request. */ - if (!(e->status & E1000_READING || - e->status & E1000_WRITING)) - { - return; - } - /* Construct reply message. */ - msg.m_type = DL_TASK_REPLY; - msg.m_netdrv_net_dl_task.flags = DL_NOFLAGS; - msg.m_netdrv_net_dl_task.count = 0; - - /* Did we successfully receive packet(s)? */ - if (e->status & E1000_READING && - e->status & E1000_RECEIVED) - { - msg.m_netdrv_net_dl_task.flags |= DL_PACK_RECV; - msg.m_netdrv_net_dl_task.count = - e->rx_size >= ETH_MIN_PACK_SIZE ? - e->rx_size : ETH_MIN_PACK_SIZE; - - /* Clear flags. */ - e->status &= ~(E1000_READING | E1000_RECEIVED); - } - /* Did we successfully transmit packet(s)? */ - if (e->status & E1000_TRANSMIT && - e->status & E1000_WRITING) - { - msg.m_netdrv_net_dl_task.flags |= DL_PACK_SEND; - - /* Clear flags. */ - e->status &= ~(E1000_WRITING | E1000_TRANSMIT); - } - - /* Acknowledge to INET. */ - if ((r = ipc_send(e->client, &msg)) != OK) - { - panic("ipc_send() failed: %d", r); - } -} - -/*===========================================================================* - * mess_reply * - *===========================================================================*/ -static void mess_reply(req, reply_mess) -message *req; -message *reply_mess; -{ - if (ipc_send(req->m_source, reply_mess) != OK) - { - panic("unable to send reply message"); - } + /* Steps */ + ret_val = eeprom_ich_init(e); + if (ret_val != 0) + break; + + hsflctl.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFCTL); + /* 0b/1b corresponds to 1 or 2 byte size, respectively. */ + hsflctl.hsf_ctrl.fldbcount = 1; + hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ; + E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFCTL, hsflctl.regval); + E1000_WRITE_FLASH_REG(e, ICH_FLASH_FADDR, flash_linear_addr); + + ret_val = eeprom_ich_cycle(e, ICH_FLASH_READ_COMMAND_TIMEOUT); + + /* + * Check if FCERR is set to 1, if set to 1, clear it and try + * the whole sequence a few more times, else read in (shift in) + * the Flash Data0, the order is least significant byte first + * msb to lsb. + */ + if (ret_val == 0) { + flash_data = E1000_READ_FLASH_REG(e, ICH_FLASH_FDATA0); + data = (u16_t)(flash_data & 0x0000FFFF); + break; + } else { + /* + * If we've gotten here, then things are probably + * completely hosed, but if the error condition is + * detected, it won't hurt to give it another try... + * ICH_FLASH_CYCLE_REPEAT_COUNT times. + */ + hsfsts.regval = E1000_READ_FLASH_REG16(e, + ICH_FLASH_HSFSTS); + + if (hsfsts.hsf_status.flcerr == 1) { + /* Repeat for some time before giving up. */ + continue; + } else if (hsfsts.hsf_status.flcdone == 0) { + E1000_DEBUG(3, ("Timeout error - flash cycle " + "did not complete.")); + break; + } + } + } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT); + + return data; } diff --git a/minix/drivers/net/e1000/e1000.h b/minix/drivers/net/e1000/e1000.h index d1e26dd72..f97b437e7 100644 --- a/minix/drivers/net/e1000/e1000.h +++ b/minix/drivers/net/e1000/e1000.h @@ -18,13 +18,6 @@ #ifndef __E1000_H #define __E1000_H -#include -#include -#include -#include -#include -#include -#include #include "e1000_hw.h" /** @@ -38,14 +31,11 @@ /** Number of transmit descriptors per card. */ #define E1000_TXDESC_NR 256 -/** Number of I/O vectors to use. */ -#define E1000_IOVEC_NR 16 - /** Size of each I/O buffer per descriptor. */ #define E1000_IOBUF_SIZE 2048 /** Debug verbosity. */ -#define E1000_VERBOSE 1 +#define E1000_VERBOSE 0 /** MAC address override variable. */ #define E1000_ENVVAR "E1000ETH" @@ -59,24 +49,6 @@ * @{ */ -/** Card has been detected on the PCI bus. */ -#define E1000_DETECTED (1 << 0) - -/** Card is enabled. */ -#define E1000_ENABLED (1 << 1) - -/** Client has requested to receive packets. */ -#define E1000_READING (1 << 2) - -/** Client has requested to write packets. */ -#define E1000_WRITING (1 << 3) - -/** Received some packets on the card. */ -#define E1000_RECEIVED (1 << 4) - -/** Transmitted some packets on the card. */ -#define E1000_TRANSMIT (1 << 5) - /** * @} */ @@ -141,36 +113,25 @@ typedef struct e1000 { char name[8]; /**< String containing the device name. */ - int status; /**< Describes the card's current state. */ int irq; /**< Interrupt Request Vector. */ int irq_hook; /**< Interrupt Request Vector Hook. */ - int revision; /**< Hardware Revision Number. */ u8_t *regs; /**< Memory mapped hardware registers. */ u8_t *flash; /**< Optional flash memory. */ u32_t flash_base_addr; /**< Flash base address. */ - ether_addr_t address; /**< Ethernet MAC address. */ - u16_t (*eeprom_read)(void *, int reg); /**< Function to read - the EEPROM. */ + u16_t (*eeprom_read)(struct e1000 *, int reg); + /**< Function to read the EEPROM. */ int eeprom_done_bit; /**< Offset of the EERD.DONE bit. */ int eeprom_addr_off; /**< Offset of the EERD.ADDR field. */ e1000_rx_desc_t *rx_desc; /**< Receive Descriptor table. */ - phys_bytes rx_desc_p; /**< Physical Receive Descriptor Address. */ int rx_desc_count; /**< Number of Receive Descriptors. */ char *rx_buffer; /**< Receive buffer returned by malloc(). */ int rx_buffer_size; /**< Size of the receive buffer. */ e1000_tx_desc_t *tx_desc; /**< Transmit Descriptor table. */ - phys_bytes tx_desc_p; /**< Physical Transmit Descriptor Address. */ int tx_desc_count; /**< Number of Transmit Descriptors. */ char *tx_buffer; /**< Transmit buffer returned by malloc(). */ int tx_buffer_size; /**< Size of the transmit buffer. */ - - int client; /**< Process ID being served by e1000. */ - message rx_message; /**< Read message received from client. */ - message tx_message; /**< Write message received from client. */ - size_t rx_size; /**< Size of one packet received. */ -} -e1000_t; +} e1000_t; #endif /* __E1000_H */ diff --git a/minix/drivers/net/fxp/Makefile b/minix/drivers/net/fxp/Makefile index 48cd2a49e..5425dec40 100644 --- a/minix/drivers/net/fxp/Makefile +++ b/minix/drivers/net/fxp/Makefile @@ -6,7 +6,7 @@ FILES=$(PROG).conf FILESNAME=$(PROG) FILESDIR= /etc/system.conf.d -DPADD+= ${LIBNETDRIVER} ${LIBSYS} ${LIBTIMERS} -LDADD+= -lnetdriver -lsys -ltimers +DPADD+= ${LIBNETDRIVER} ${LIBSYS} +LDADD+= -lnetdriver -lsys .include diff --git a/minix/drivers/net/fxp/fxp.c b/minix/drivers/net/fxp/fxp.c index 90ec370b6..48d4bdcb5 100644 --- a/minix/drivers/net/fxp/fxp.c +++ b/minix/drivers/net/fxp/fxp.c @@ -1,7 +1,7 @@ /* * fxp.c * - * This file contains an ethernet device driver for Intel 82557, 82558, + * This file contains an ethernet device driver for Intel 82557, 82558, * 82559, 82550, and 82562 fast ethernet controllers. * * Created: Nov 2004 by Philip Homburg @@ -10,21 +10,10 @@ #include #include -#include -#include -#include -#include #include #include -#include +#include -#include - -#define debug 0 -#define RAND_UPDATE /**/ -#define printW() ((void)0) - -#include "assert.h" #include "fxp.h" #include "mii.h" @@ -34,17 +23,11 @@ /* Number of transmit buffers */ #define N_TX_BUF 4 -/* I/O vectors are handled IOVEC_NR entries at a time. */ -#define IOVEC_NR 16 - /* Configuration */ #define FXP_ENVVAR "FXPETH" typedef int irq_hook_t; -/* ignore interrupt for the moment */ -#define interrupt(x) do { } while(0) - static union tmpbuf { char pad[4096]; @@ -55,12 +38,8 @@ static union tmpbuf typedef struct fxp { port_t fxp_base_port; - int fxp_mode; int fxp_got_int; int fxp_send_int; - int fxp_flags; - int fxp_client; - int fxp_features; /* Needed? */ int fxp_irq; int fxp_type; /* What kind of hardware */ int fxp_ms_regs; /* Master/slave registers */ @@ -69,7 +48,6 @@ typedef struct fxp int fxp_need_reset; /* Rx */ - vir_bytes fxp_read_s; int fxp_rx_nbuf; int fxp_rx_bufsize; struct rfd *fxp_rx_buf; @@ -93,42 +71,13 @@ typedef struct fxp /* Link status */ int fxp_report_link; int fxp_link_up; - int fxp_mii_busy; u16_t fxp_mii_scr; - /* PCI related */ - int fxp_seen; /* TRUE iff device available */ - - /* 'large' items */ irq_hook_t fxp_hook; - ether_addr_t fxp_address; - message fxp_rx_mess; - message fxp_tx_mess; struct sc fxp_stat; u8_t fxp_conf_bytes[CC_BYTES_NR]; char fxp_name[sizeof("fxp#n")]; - iovec_t fxp_iovec[IOVEC_NR]; - iovec_s_t fxp_iovec_s[IOVEC_NR]; -} -fxp_t; - -/* fxp_mode */ -#define FM_DISABLED 0x0 -#define FM_ENABLED 0x1 - -/* fxp_flags */ -#define FF_EMPTY 0x000 -#define FF_PACK_SENT 0x001 -#define FF_PACK_RECV 0x002 -#define FF_SEND_AVAIL 0x004 -#define FF_READING 0x010 -#define FF_PROMISC 0x040 -#define FF_MULTI 0x080 -#define FF_BROAD 0x100 -#define FF_ENABLED 0x200 - -/* fxp_features */ -#define FFE_NONE 0x0 +} fxp_t; /* fxp_type */ #define FT_UNKNOWN 0x0 @@ -141,40 +90,35 @@ static int fxp_instance; static fxp_t *fxp_state; -static minix_timer_t fxp_watchdog; - -static u32_t system_hz; - #define fxp_inb(port, offset) (do_inb((port) + (offset))) #define fxp_inl(port, offset) (do_inl((port) + (offset))) #define fxp_outb(port, offset, value) (do_outb((port) + (offset), (value))) #define fxp_outl(port, offset, value) (do_outl((port) + (offset), (value))) -static void fxp_init(message *mp); -static void fxp_pci_conf(void); +static int fxp_init(unsigned int instance, ether_addr_t *addr); +static void fxp_intr(unsigned int __unused mask); +static void fxp_stop(void); static int fxp_probe(fxp_t *fp, int skip); static void fxp_conf_hw(fxp_t *fp); -static void fxp_init_hw(fxp_t *fp); +static void fxp_init_hw(fxp_t *fp, ether_addr_t *addr); static void fxp_init_buf(fxp_t *fp); static void fxp_reset_hw(fxp_t *fp); -static void fxp_confaddr(fxp_t *fp); -static void fxp_rec_mode(fxp_t *fp); -static void fxp_writev_s(const message *mp, int from_int); -static void fxp_readv_s(message *mp, int from_int); +static void fxp_confaddr(fxp_t *fp, ether_addr_t *addr); +static void fxp_mode(unsigned int mode); +static int fxp_send(struct netdriver_data *data, size_t size); +static ssize_t fxp_recv(struct netdriver_data *data, size_t max); static void fxp_do_conf(fxp_t *fp); static void fxp_cu_ptr_cmd(fxp_t *fp, int cmd, phys_bytes bus_addr, int check_idle); static void fxp_ru_ptr_cmd(fxp_t *fp, int cmd, phys_bytes bus_addr, int check_idle); static void fxp_restart_ru(fxp_t *fp); -static void fxp_getstat_s(message *mp); +static void fxp_stat(eth_stat_t *stat); static void fxp_handler(fxp_t *fp); static void fxp_check_ints(fxp_t *fp); -static void fxp_watchdog_f(minix_timer_t *tp); +static void fxp_alarm(clock_t stamp); static int fxp_link_changed(fxp_t *fp); static void fxp_report_link(fxp_t *fp); -static void reply(fxp_t *fp); -static void mess_reply(message *req, message *reply); static u16_t eeprom_read(fxp_t *fp, int reg); static void eeprom_addrsize(fxp_t *fp); static u16_t mii_read(fxp_t *fp, int reg); @@ -182,240 +126,110 @@ static u8_t do_inb(port_t port); static u32_t do_inl(port_t port); static void do_outb(port_t port, u8_t v); static void do_outl(port_t port, u32_t v); -static void tell_dev(vir_bytes start, size_t size, int pci_bus, int +static void tell_iommu(vir_bytes start, size_t size, int pci_bus, int pci_dev, int pci_func); -static void handle_hw_intr(void) -{ - int r; - fxp_t *fp; - - fp= fxp_state; - - if (fp->fxp_mode != FM_ENABLED) - return; - fxp_handler(fp); - - r= sys_irqenable(&fp->fxp_hook); - if (r != OK) { - panic("unable enable interrupts: %d", r); - } - - if (!fp->fxp_got_int) - return; - fp->fxp_got_int= 0; - assert(fp->fxp_flags & FF_ENABLED); - fxp_check_ints(fp); -} - -/* SEF functions and variables. */ -static void sef_local_startup(void); -static int sef_cb_init_fresh(int type, sef_init_info_t *info); -static void sef_cb_signal_handler(int signo); +static const struct netdriver fxp_table = { + .ndr_init = fxp_init, + .ndr_stop = fxp_stop, + .ndr_mode = fxp_mode, + .ndr_recv = fxp_recv, + .ndr_send = fxp_send, + .ndr_stat = fxp_stat, + .ndr_intr = fxp_intr, + .ndr_alarm = fxp_alarm, +}; /*===========================================================================* * main * *===========================================================================*/ int main(int argc, char *argv[]) { - message m; - int ipc_status; - int r; - - /* SEF local startup. */ env_setargs(argc, argv); - sef_local_startup(); - while (TRUE) - { - if ((r= netdriver_receive(ANY, &m, &ipc_status)) != OK) - panic("netdriver_receive failed: %d", r); + netdriver_task(&fxp_table); - if (is_ipc_notify(ipc_status)) { - switch (_ENDPOINT_P(m.m_source)) { - case HARDWARE: - handle_hw_intr(); - break; - case CLOCK: - expire_timers(m.m_notify.timestamp); - break; - default: - panic(" illegal notify from: %d", m.m_source); - } - - /* get new message */ - continue; - } - - switch (m.m_type) - { - case DL_WRITEV_S: fxp_writev_s(&m, FALSE); break; - case DL_READV_S: fxp_readv_s(&m, FALSE); break; - case DL_CONF: fxp_init(&m); break; - case DL_GETSTAT_S: fxp_getstat_s(&m); break; - default: - panic(" illegal message: %d", m.m_type); - } - } + return 0; } /*===========================================================================* - * sef_local_startup * + * fxp_intr * *===========================================================================*/ -static void sef_local_startup() +static void fxp_intr(unsigned int __unused mask) { - /* Register init callbacks. */ - sef_setcb_init_fresh(sef_cb_init_fresh); - sef_setcb_init_lu(sef_cb_init_fresh); - sef_setcb_init_restart(sef_cb_init_fresh); - - /* Register live update callbacks. */ - sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready); - sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_workfree); - - /* Register signal callbacks. */ - sef_setcb_signal_handler(sef_cb_signal_handler); - - /* Let SEF perform startup. */ - sef_startup(); -} - -/*===========================================================================* - * sef_cb_init_fresh * - *===========================================================================*/ -static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info)) -{ -/* Initialize the fxp driver. */ - long v; int r; - vir_bytes ft; + fxp_t *fp; - system_hz = sys_hz(); + fp= fxp_state; - v = 0; - (void) env_parse("instance", "d", 0, &v, 0, 255); - fxp_instance = (int) v; + fxp_handler(fp); - ft = sizeof(*fxp_state); + if ((r = sys_irqenable(&fp->fxp_hook)) != OK) + panic("unable to enable interrupts: %d", r); - if(!(fxp_state = alloc_contig(ft, 0, NULL))) - panic("couldn't allocate table: %d", ENOMEM); - - memset(fxp_state, 0, ft); - - if((r=tsc_calibrate()) != OK) - panic("tsc_calibrate failed: %d", r); - - /* Announce we are up! */ - netdriver_announce(); - - return(OK); + if (!fp->fxp_got_int) + return; + fp->fxp_got_int= 0; + fxp_check_ints(fp); } /*===========================================================================* - * sef_cb_signal_handler * + * fxp_stop * *===========================================================================*/ -static void sef_cb_signal_handler(int signo) +static void fxp_stop(void) { port_t port; fxp_t *fp; - /* Only check for termination signal, ignore anything else. */ - if (signo != SIGTERM) return; - fp= fxp_state; - if (fp->fxp_mode == FM_ENABLED && (fp->fxp_flags & FF_ENABLED)) { - port= fp->fxp_base_port; + port= fp->fxp_base_port; - /* Reset device */ - if (debug) - printf("%s: resetting device\n", fp->fxp_name); - fxp_outl(port, CSR_PORT, CP_CMD_SOFT_RESET); - } + /* Stop device */ +#if VERBOSE + printf("%s: stopping device\n", fp->fxp_name); +#endif - exit(0); + fxp_outl(port, CSR_PORT, CP_CMD_SOFT_RESET); } /*===========================================================================* * fxp_init * *===========================================================================*/ -static void fxp_init(mp) -message *mp; -{ - static int first_time= 1; - - fxp_t *fp; - message reply_mess; - - if (first_time) - { - first_time= 0; - fxp_pci_conf(); /* Configure PCI devices. */ - - init_timer(&fxp_watchdog); - set_timer(&fxp_watchdog, system_hz, fxp_watchdog_f, 0); - } - - fp= fxp_state; - if (fp->fxp_mode == FM_DISABLED) - { - /* This is the default, try to (re)locate the device. */ - fxp_conf_hw(fp); - if (fp->fxp_mode == FM_DISABLED) - { - /* Probe failed, or the device is configured off. */ - reply_mess.m_type= DL_CONF_REPLY; - reply_mess.m_netdrv_net_dl_conf.stat= ENXIO; - mess_reply(mp, &reply_mess); - return; - } - if (fp->fxp_mode == FM_ENABLED) - fxp_init_hw(fp); - fxp_report_link(fp); - } - - assert(fp->fxp_mode == FM_ENABLED); - assert(fp->fxp_flags & FF_ENABLED); - - fp->fxp_flags &= ~(FF_PROMISC | FF_MULTI | FF_BROAD); - - if (mp->m_net_netdrv_dl_conf.mode & DL_PROMISC_REQ) - fp->fxp_flags |= FF_PROMISC; - if (mp->m_net_netdrv_dl_conf.mode & DL_MULTI_REQ) - fp->fxp_flags |= FF_MULTI; - if (mp->m_net_netdrv_dl_conf.mode & DL_BROAD_REQ) - fp->fxp_flags |= FF_BROAD; - - fxp_rec_mode(fp); - - reply_mess.m_type = DL_CONF_REPLY; - reply_mess.m_netdrv_net_dl_conf.stat = OK; - memcpy(reply_mess.m_netdrv_net_dl_conf.hw_addr, - fp->fxp_address.ea_addr, - sizeof(reply_mess.m_netdrv_net_dl_conf.hw_addr)); - - mess_reply(mp, &reply_mess); -} - -/*===========================================================================* - * fxp_pci_conf * - *===========================================================================*/ -static void fxp_pci_conf() +static int fxp_init(unsigned int instance, ether_addr_t *addr) { fxp_t *fp; + int r; + + fxp_instance = instance; + + if (!(fxp_state = alloc_contig(sizeof(*fxp_state), 0, NULL))) + panic("couldn't allocate table"); fp= fxp_state; + memset(fp, 0, sizeof(*fp)); + strlcpy(fp->fxp_name, "fxp#0", sizeof(fp->fxp_name)); fp->fxp_name[4] += fxp_instance; - fp->fxp_seen= FALSE; - fp->fxp_features= FFE_NONE; - pci_init(); + if ((r = tsc_calibrate()) != OK) + panic("tsc_calibrate failed: %d", r); - if (fxp_probe(fp, fxp_instance)) - fp->fxp_seen= TRUE; + /* Configure PCI device. */ + if (!fxp_probe(fp, fxp_instance)) + return ENXIO; + + fxp_conf_hw(fp); + + fxp_init_hw(fp, addr); + fxp_report_link(fp); + + /* Set watchdog timer. */ + if ((r = sys_setalarm(sys_hz(), 0)) != OK) + panic("unable to set watchdog alarm"); + + return OK; } /*===========================================================================* @@ -424,7 +238,7 @@ static void fxp_pci_conf() static int fxp_probe(fxp_t *fp, int skip) { int r, devind; - u16_t vid, did; + u16_t vid, did, cr; u32_t bar; u8_t ilr, rev; char *str; @@ -432,6 +246,8 @@ static int fxp_probe(fxp_t *fp, int skip) char *dname; #endif + pci_init(); + r= pci_first_dev(&devind, &vid, &did); if (r == 0) return FALSE; @@ -452,6 +268,11 @@ static int fxp_probe(fxp_t *fp, int skip) #endif pci_reserve(devind); + /* Enable bus mastering if necessary. */ + cr = pci_attr_r16(devind, PCI_CR); + if (!(cr & PCI_CR_MAST_EN)) + pci_attr_w16(devind, PCI_CR, cr | PCI_CR_MAST_EN); + bar= pci_attr_r32(devind, PCI_BAR_2) & 0xffffffe0; if (bar < 0x400) { panic("fxp_probe: base address is not properly configured"); @@ -460,11 +281,10 @@ static int fxp_probe(fxp_t *fp, int skip) ilr= pci_attr_r8(devind, PCI_ILR); fp->fxp_irq= ilr; - if (debug) - { - printf("%s: using I/O address 0x%lx, IRQ %d\n", - fp->fxp_name, (unsigned long)bar, ilr); - } +#if VERBOSE + printf("%s: using I/O address 0x%lx, IRQ %d\n", + fp->fxp_name, (unsigned long)bar, ilr); +#endif rev= pci_attr_r8(devind, PCI_REV); str= NULL; @@ -541,23 +361,12 @@ static void fxp_conf_hw(fxp_t *fp) int i; #endif - fp->fxp_mode= FM_DISABLED; /* Superfluous */ - - if (!fp->fxp_seen) - return; - - /* PCI device is present */ - fp->fxp_mode= FM_ENABLED; - - fp->fxp_flags= FF_EMPTY; fp->fxp_got_int= 0; fp->fxp_send_int= 0; fp->fxp_ee_addrlen= 0; /* Unknown */ fp->fxp_need_reset= 0; fp->fxp_report_link= 0; fp->fxp_link_up= -1; /* Unknown */ - fp->fxp_mii_busy= 0; - fp->fxp_read_s= 0; fp->fxp_rx_need_restart= 0; fp->fxp_need_conf= 0; fp->fxp_tx_head= 0; @@ -636,10 +445,9 @@ static void fxp_conf_hw(fxp_t *fp) /*===========================================================================* * fxp_init_hw * *===========================================================================*/ -static void fxp_init_hw(fp) -fxp_t *fp; +static void fxp_init_hw(fxp_t *fp, ether_addr_t *addr) { - int i, r, isr; + int r, isr; port_t port; phys_bytes bus_addr; @@ -647,10 +455,7 @@ fxp_t *fp; fxp_init_buf(fp); - fp->fxp_flags = FF_EMPTY; - fp->fxp_flags |= FF_ENABLED; - - /* Set the interrupt handler and policy. Do not automatically + /* Set the interrupt handler and policy. Do not automatically * reenable interrupts. Return the IRQ line number on interrupts. */ fp->fxp_hook = fp->fxp_irq; @@ -685,16 +490,7 @@ fxp_t *fp; fxp_ru_ptr_cmd(fp, SC_RU_START, fp->fxp_rx_busaddr, TRUE /* check idle */); - fxp_confaddr(fp); - if (debug) - { - printf("%s: Ethernet address ", fp->fxp_name); - for (i= 0; i < 6; i++) - { - printf("%x%c", fp->fxp_address.ea_addr[i], - i < 5 ? ':' : '\n'); - } - } + fxp_confaddr(fp, addr); } /*===========================================================================* @@ -724,13 +520,13 @@ fxp_t *fp; tot_bufsize += 4096 - (tot_bufsize % 4096); alloc_bufsize= tot_bufsize; alloc_buf= alloc_contig(alloc_bufsize, AC_ALIGN4K, &ph); - if (alloc_buf == NULL) { - panic("fxp_init_buf: unable to alloc_contig size: %d", alloc_bufsize); - } + if (alloc_buf == NULL) + panic("fxp_init_buf: unable to alloc_contig size: %d", + alloc_bufsize); buf= (phys_bytes)alloc_buf; - tell_dev((vir_bytes)buf, tot_bufsize, 0, 0, 0); + tell_iommu((vir_bytes)buf, tot_bufsize, 0, 0, 0); tmpbufp= (union tmpbuf *)buf; @@ -797,7 +593,7 @@ fxp_t *fp; txp->tx_tthresh= fp->fxp_tx_threshold; txp->tx_ntbd= 0; } - fp->fxp_tx_idle= 1; + fp->fxp_tx_idle= TRUE; } /*===========================================================================* @@ -828,7 +624,7 @@ fxp_t *fp; /*===========================================================================* * fxp_confaddr * *===========================================================================*/ -static void fxp_confaddr(fxp_t *fp) +static void fxp_confaddr(fxp_t *fp, ether_addr_t *addr) { static char eakey[]= FXP_ENVVAR "#_EA"; static char eafmt[]= "x:x:x:x:x:x"; @@ -843,7 +639,7 @@ static void fxp_confaddr(fxp_t *fp) { if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET) break; - fp->fxp_address.ea_addr[i]= v; + addr->ea_addr[i]= v; } if (i != 0 && i != 6) env_panic(eakey); /* It's all or nothing */ @@ -854,8 +650,8 @@ static void fxp_confaddr(fxp_t *fp) for (i= 0; i<3; i++) { v= eeprom_read(fp, i); - fp->fxp_address.ea_addr[i*2]= (v & 0xff); - fp->fxp_address.ea_addr[i*2+1]= ((v >> 8) & 0xff); + addr->ea_addr[i*2]= (v & 0xff); + addr->ea_addr[i*2+1]= ((v >> 8) & 0xff); } } @@ -863,7 +659,7 @@ static void fxp_confaddr(fxp_t *fp) tmpbufp->ias.ias_status= 0; tmpbufp->ias.ias_command= CBL_C_EL | CBL_AIS; tmpbufp->ias.ias_linkaddr= 0; - memcpy(tmpbufp->ias.ias_ethaddr, fp->fxp_address.ea_addr, + memcpy(tmpbufp->ias.ias_ethaddr, addr->ea_addr, sizeof(tmpbufp->ias.ias_ethaddr)); r= sys_umap(SELF, VM_D, (vir_bytes)&tmpbufp->ias, (phys_bytes)sizeof(tmpbufp->ias), &bus_addr); @@ -883,30 +679,30 @@ static void fxp_confaddr(fxp_t *fp) #if VERBOSE printf("%s: hardware ethernet address: ", fp->fxp_name); for (i= 0; i<6; i++) - { - printf("%02x%s", fp->fxp_address.ea_addr[i], - i < 5 ? ":" : ""); - } + printf("%02x%s", addr->ea_addr[i], i < 5 ? ":" : ""); printf("\n"); #endif } /*===========================================================================* - * fxp_rec_mode * + * fxp_mode * *===========================================================================*/ -static void fxp_rec_mode(fp) -fxp_t *fp; +static void fxp_mode(unsigned int mode) { + fxp_t *fp; + + fp = fxp_state; + fp->fxp_conf_bytes[0]= CC_BYTES_NR; /* Just to be sure */ fp->fxp_conf_bytes[15] &= ~(CCB15_BD|CCB15_PM); fp->fxp_conf_bytes[21] &= ~CCB21_MA; - if (fp->fxp_flags & FF_PROMISC) + if (mode & NDEV_PROMISC) fp->fxp_conf_bytes[15] |= CCB15_PM; - if (fp->fxp_flags & FF_MULTI) + if (mode & NDEV_MULTI) fp->fxp_conf_bytes[21] |= CCB21_MA; - if (!(fp->fxp_flags & (FF_BROAD|FF_MULTI|FF_PROMISC))) + if (!(mode & (NDEV_BROAD|NDEV_MULTI|NDEV_PROMISC))) fp->fxp_conf_bytes[15] |= CCB15_BD; /* Queue request if not idle */ @@ -922,35 +718,18 @@ fxp_t *fp; } /*===========================================================================* - * fxp_writev_s * + * fxp_send * *===========================================================================*/ -static void fxp_writev_s(const message *mp, int from_int) +static int fxp_send(struct netdriver_data *data, size_t size) { - endpoint_t iov_endpt; - cp_grant_id_t iov_grant; - vir_bytes iov_offset; - int i, j, n, o, r, s, count, size, prev_head; + int prev_head; int fxp_tx_nbuf, fxp_tx_head; u16_t tx_command; fxp_t *fp; - iovec_s_t *iovp; struct tx *txp, *prev_txp; fp= fxp_state; - count = mp->m_net_netdrv_dl_writev_s.count; - fp->fxp_client= mp->m_source; - - assert(fp->fxp_mode == FM_ENABLED); - assert(fp->fxp_flags & FF_ENABLED); - - if (from_int) - { - assert(fp->fxp_flags & FF_SEND_AVAIL); - fp->fxp_flags &= ~FF_SEND_AVAIL; - fp->fxp_tx_alive= TRUE; - } - if (fp->fxp_tx_idle) { txp= fp->fxp_tx_buf; @@ -958,7 +737,7 @@ static void fxp_writev_s(const message *mp, int from_int) prev_txp= NULL; /* lint */ } else - { + { fxp_tx_nbuf= fp->fxp_tx_nbuf; prev_head= fp->fxp_tx_head; fxp_tx_head= prev_head+1; @@ -969,54 +748,15 @@ static void fxp_writev_s(const message *mp, int from_int) if (fxp_tx_head == fp->fxp_tx_tail) { /* Send queue is full */ - assert(!(fp->fxp_flags & FF_SEND_AVAIL)); - fp->fxp_flags |= FF_SEND_AVAIL; - goto suspend; + return SUSPEND; } prev_txp= &fp->fxp_tx_buf[prev_head]; txp= &fp->fxp_tx_buf[fxp_tx_head]; } - assert(!(fp->fxp_flags & FF_SEND_AVAIL)); - assert(!(fp->fxp_flags & FF_PACK_SENT)); - - iov_endpt= mp->m_source; - iov_grant= mp->m_net_netdrv_dl_writev_s.grant; - - size= 0; - o= 0; - iov_offset= 0; - for (i= 0; ifxp_iovec_s[0])) - { - n= IOVEC_NR; - if (i+n > count) - n= count-i; - r= sys_safecopyfrom(iov_endpt, iov_grant, iov_offset, - (vir_bytes)fp->fxp_iovec_s, - n * sizeof(fp->fxp_iovec_s[0])); - if (r != OK) - panic("fxp_writev: sys_safecopyfrom failed: %d", r); - - for (j= 0, iovp= fp->fxp_iovec_s; jiov_size; - if (size + s > ETH_MAX_PACK_SIZE_TAGGED) { - panic("fxp_writev: invalid packet size: %d", size + s); - } - - r= sys_safecopyfrom(iov_endpt, iovp->iov_grant, - 0, (vir_bytes)(txp->tx_buf+o), s); - if (r != OK) { - panic("fxp_writev_s: sys_safecopyfrom failed: %d", r); - } - size += s; - o += s; - } - } - if (size < ETH_MIN_PACK_SIZE) - panic("fxp_writev: invalid packet size: %d", size); + /* Copy in the packet data */ + netdriver_copyin(data, 0, txp->tx_buf, size); txp->tx_status= 0; txp->tx_command= TXC_EL | CBL_XMIT; @@ -1026,7 +766,7 @@ static void fxp_writev_s(const message *mp, int from_int) txp->tx_ntbd= 0; if (fp->fxp_tx_idle) { - fp->fxp_tx_idle= 0; + fp->fxp_tx_idle= FALSE; fp->fxp_tx_head= fp->fxp_tx_tail= 0; fxp_cu_ptr_cmd(fp, SC_CU_START, fp->fxp_tx_busaddr, @@ -1041,62 +781,63 @@ static void fxp_writev_s(const message *mp, int from_int) fp->fxp_tx_head= fxp_tx_head; } - fp->fxp_flags |= FF_PACK_SENT; - - /* If the interrupt handler called, don't send a reply. The reply - * will be sent after all interrupts are handled. - */ - if (from_int) - return; - reply(fp); - return; - -suspend: - if (from_int) - panic("fxp: should not be sending"); - - fp->fxp_tx_mess= *mp; - reply(fp); + return OK; } /*===========================================================================* - * fxp_readv_s * + * fxp_check_restart * *===========================================================================*/ -static void fxp_readv_s(mp, from_int) -message *mp; -int from_int; +static void fxp_check_restart(fxp_t *fp) { - int i, j, n, o, r, s, count, size, fxp_rx_head, fxp_rx_nbuf; - endpoint_t iov_endpt; - cp_grant_id_t iov_grant; + port_t port; + u8_t scb_status; + + if (!fp->fxp_rx_need_restart) + return; + + fp->fxp_rx_need_restart= 0; + + /* Check the status of the RU */ + port= fp->fxp_base_port; + scb_status= fxp_inb(port, SCB_STATUS); + if ((scb_status & SS_RUS_MASK) != SS_RU_NORES) + { + /* Race condition? */ + printf("fxp_check_restart: restart race: 0x%x\n", scb_status); + assert((scb_status & SS_RUS_MASK) == SS_RU_READY); + } + else + { + fxp_restart_ru(fp); + } +} + +/*===========================================================================* + * fxp_recv * + *===========================================================================*/ +static ssize_t fxp_recv(struct netdriver_data *data, size_t max) +{ + int fxp_rx_head, fxp_rx_nbuf; port_t port; unsigned packlen; - vir_bytes iov_offset; u16_t rfd_status; u16_t rfd_res; - u8_t scb_status; fxp_t *fp; - iovec_s_t *iovp; struct rfd *rfdp, *prev_rfdp; fp= fxp_state; - count = mp->m_net_netdrv_dl_readv_s.count; - fp->fxp_client= mp->m_source; - - assert(fp->fxp_mode == FM_ENABLED); - assert(fp->fxp_flags & FF_ENABLED); - port= fp->fxp_base_port; fxp_rx_head= fp->fxp_rx_head; rfdp= &fp->fxp_rx_buf[fxp_rx_head]; rfd_status= rfdp->rfd_status; - if (!(rfd_status & RFDS_C)) - { + if (!(rfd_status & RFDS_C)) { /* Receive buffer is empty, suspend */ - goto suspend; + fxp_check_restart(fp); + + return SUSPEND; } if (!(rfd_status & RFDS_OK)) @@ -1107,7 +848,7 @@ int from_int; else { assert(!(rfd_status & (RFDS_CRCERR | RFDS_ALIGNERR | - RFDS_OUTOFBUF | RFDS_DMAOVR | RFDS_TOOSHORT | + RFDS_OUTOFBUF | RFDS_DMAOVR | RFDS_TOOSHORT | RFDS_RXERR))); } rfd_res= rfdp->rfd_res; @@ -1116,55 +857,11 @@ int from_int; packlen= rfd_res & RFDSZ_SIZE; - iov_endpt = mp->m_source; - iov_grant = mp->m_net_netdrv_dl_readv_s.grant; + /* Copy out the packet data */ + if (packlen > max) + packlen = max; - size= 0; - o= 0; - iov_offset= 0; - for (i= 0; ifxp_iovec_s[0])) - { - n= IOVEC_NR; - if (i+n > count) - n= count-i; - r= sys_safecopyfrom(iov_endpt, iov_grant, iov_offset, - (vir_bytes)fp->fxp_iovec_s, - n * sizeof(fp->fxp_iovec_s[0])); - if (r != OK) - panic("fxp_readv_s: sys_safecopyfrom failed: %d", r); - - for (j= 0, iovp= fp->fxp_iovec_s; jiov_size; - if (size + s > packlen) - { - assert(packlen > size); - s= packlen-size; - } - - r= sys_safecopyto(iov_endpt, iovp->iov_grant, - 0, (vir_bytes)(rfdp->rfd_buf+o), s); - if (r != OK) - { - panic("fxp_readv: sys_safecopyto failed: %d", r); - } - - size += s; - if (size == packlen) - break; - o += s; - } - if (size == packlen) - break; - } - if (size < packlen) - { - assert(0); - } - - fp->fxp_read_s= packlen; - fp->fxp_flags= (fp->fxp_flags & ~FF_READING) | FF_PACK_RECV; + netdriver_copyout(data, 0, rfdp->rfd_buf, packlen); /* Re-init the current buffer */ rfdp->rfd_status= 0; @@ -1190,43 +887,7 @@ int from_int; assert(fxp_rx_head < fxp_rx_nbuf); fp->fxp_rx_head= fxp_rx_head; - if (!from_int) - reply(fp); - - return; - -suspend: - if (fp->fxp_rx_need_restart) - { - fp->fxp_rx_need_restart= 0; - - /* Check the status of the RU */ - scb_status= fxp_inb(port, SCB_STATUS); - if ((scb_status & SS_RUS_MASK) != SS_RU_NORES) - { - /* Race condition? */ - printf("fxp_readv: restart race: 0x%x\n", - scb_status); - assert((scb_status & SS_RUS_MASK) == SS_RU_READY); - } - else - { - fxp_restart_ru(fp); - } - } - if (from_int) - { - assert(fp->fxp_flags & FF_READING); - - /* No need to store any state */ - return; - } - - fp->fxp_rx_mess= *mp; - assert(!(fp->fxp_flags & FF_READING)); - fp->fxp_flags |= FF_READING; - - reply(fp); + return packlen; } /*===========================================================================* @@ -1373,20 +1034,15 @@ fxp_t *fp; } /*===========================================================================* - * fxp_getstat_s * + * fxp_stat * *===========================================================================*/ -static void fxp_getstat_s(message *mp) +static void fxp_stat(eth_stat_t *stat) { - int r; fxp_t *fp; u32_t *p; - eth_stat_t stats; fp= fxp_state; - assert(fp->fxp_mode == FM_ENABLED); - assert(fp->fxp_flags & FF_ENABLED); - p= &fp->fxp_stat.sc_tx_fcp; *p= 0; @@ -1399,45 +1055,35 @@ static void fxp_getstat_s(message *mp) SPIN_UNTIL(*p != 0, 1000); if (*p == 0) - panic("fxp_getstat: CU command failed to complete"); + panic("fxp_stat: CU command failed to complete"); if (*p != SCM_DSC) - panic("fxp_getstat: bad magic"); + panic("fxp_stat: bad magic"); - stats.ets_recvErr= + stat->ets_recvErr= fp->fxp_stat.sc_rx_crc + fp->fxp_stat.sc_rx_align + fp->fxp_stat.sc_rx_resource + fp->fxp_stat.sc_rx_overrun + fp->fxp_stat.sc_rx_cd + fp->fxp_stat.sc_rx_short; - stats.ets_sendErr= + stat->ets_sendErr= fp->fxp_stat.sc_tx_maxcol + fp->fxp_stat.sc_tx_latecol + fp->fxp_stat.sc_tx_crs; - stats.ets_OVW= fp->fxp_stat.sc_rx_overrun; - stats.ets_CRCerr= fp->fxp_stat.sc_rx_crc; - stats.ets_frameAll= fp->fxp_stat.sc_rx_align; - stats.ets_missedP= fp->fxp_stat.sc_rx_resource; - stats.ets_packetR= fp->fxp_stat.sc_rx_good; - stats.ets_packetT= fp->fxp_stat.sc_tx_good; - stats.ets_transDef= fp->fxp_stat.sc_tx_defered; - stats.ets_collision= fp->fxp_stat.sc_tx_totcol; - stats.ets_transAb= fp->fxp_stat.sc_tx_maxcol; - stats.ets_carrSense= fp->fxp_stat.sc_tx_crs; - stats.ets_fifoUnder= fp->fxp_stat.sc_tx_underrun; - stats.ets_fifoOver= fp->fxp_stat.sc_rx_overrun; - stats.ets_CDheartbeat= 0; - stats.ets_OWC= fp->fxp_stat.sc_tx_latecol; - - r= sys_safecopyto(mp->m_source, mp->m_net_netdrv_dl_getstat_s.grant, 0, - (vir_bytes)&stats, sizeof(stats)); - if (r != OK) - panic("fxp_getstat_s: sys_safecopyto failed: %d", r); - - mp->m_type= DL_STAT_REPLY; - r= ipc_send(mp->m_source, mp); - if (r != OK) - panic("fxp_getstat_s: ipc_send failed: %d", r); + stat->ets_OVW= fp->fxp_stat.sc_rx_overrun; + stat->ets_CRCerr= fp->fxp_stat.sc_rx_crc; + stat->ets_frameAll= fp->fxp_stat.sc_rx_align; + stat->ets_missedP= fp->fxp_stat.sc_rx_resource; + stat->ets_packetR= fp->fxp_stat.sc_rx_good; + stat->ets_packetT= fp->fxp_stat.sc_tx_good; + stat->ets_transDef= fp->fxp_stat.sc_tx_defered; + stat->ets_collision= fp->fxp_stat.sc_tx_totcol; + stat->ets_transAb= fp->fxp_stat.sc_tx_maxcol; + stat->ets_carrSense= fp->fxp_stat.sc_tx_crs; + stat->ets_fifoUnder= fp->fxp_stat.sc_tx_underrun; + stat->ets_fifoOver= fp->fxp_stat.sc_rx_overrun; + stat->ets_CDheartbeat= 0; + stat->ets_OWC= fp->fxp_stat.sc_tx_latecol; } /*===========================================================================* @@ -1448,8 +1094,6 @@ static void fxp_handler(fxp_t *fp) int port; u16_t isr; - RAND_UPDATE - port= fp->fxp_base_port; /* Ack interrupt */ @@ -1460,11 +1104,7 @@ static void fxp_handler(fxp_t *fp) { isr &= ~SIS_FR; - if (!fp->fxp_got_int && (fp->fxp_flags & FF_READING)) - { - fp->fxp_got_int= TRUE; - interrupt(fxp_tasknr); - } + fp->fxp_got_int= TRUE; } if (isr & SIS_CNA) { @@ -1472,18 +1112,14 @@ static void fxp_handler(fxp_t *fp) if (!fp->fxp_tx_idle) { fp->fxp_send_int= TRUE; - if (!fp->fxp_got_int) - { - fp->fxp_got_int= TRUE; - interrupt(fxp_tasknr); - } + fp->fxp_got_int= TRUE; } } if (isr & SIS_RNR) { isr &= ~SIS_RNR; - /* Assume that receive buffer is full of packets. fxp_readv + /* Assume that receive buffer is full of packets. fxp_recv * will restart the RU. */ fp->fxp_rx_need_restart= 1; @@ -1500,7 +1136,7 @@ static void fxp_handler(fxp_t *fp) *===========================================================================*/ static void fxp_check_ints(fxp_t *fp) { - int n, fxp_flags, prev_tail; + int n, prev_tail; int fxp_tx_tail, fxp_tx_nbuf, fxp_tx_threshold; port_t port; u32_t busaddr; @@ -1508,17 +1144,8 @@ static void fxp_check_ints(fxp_t *fp) u8_t scb_status; struct tx *txp; - fxp_flags= fp->fxp_flags; + netdriver_recv(); - if (fxp_flags & FF_READING) - { - if (!(fp->fxp_rx_buf[fp->fxp_rx_head].rfd_status & RFDS_C)) - ; /* Nothing */ - else - { - fxp_readv_s(&fp->fxp_rx_mess, TRUE /* from int */); - } - } if (fp->fxp_tx_idle) ; /* Nothing to do */ else if (fp->fxp_send_int) @@ -1552,7 +1179,7 @@ static void fxp_check_ints(fxp_t *fp) if (txp->tx_command & TXC_EL) { - fp->fxp_tx_idle= 1; + fp->fxp_tx_idle= TRUE; break; } @@ -1585,7 +1212,7 @@ static void fxp_check_ints(fxp_t *fp) if (!fp->fxp_tx_idle) { fp->fxp_tx_tail= fxp_tx_tail; - + /* Check the status of the CU */ port= fp->fxp_base_port; scb_status= fxp_inb(port, SCB_STATUS); @@ -1610,51 +1237,37 @@ static void fxp_check_ints(fxp_t *fp) } } - if (fp->fxp_flags & FF_SEND_AVAIL) - { - fxp_writev_s(&fp->fxp_tx_mess, - TRUE /* from int */); - } + fp->fxp_tx_alive = TRUE; + + netdriver_send(); } - + } if (fp->fxp_report_link) fxp_report_link(fp); - - if (fp->fxp_flags & (FF_PACK_SENT | FF_PACK_RECV)) - reply(fp); } /*===========================================================================* - * fxp_watchdog_f * + * fxp_alarm * *===========================================================================*/ -static void fxp_watchdog_f(tp) -minix_timer_t *tp; +static void fxp_alarm(clock_t __unused stamp) { fxp_t *fp; - set_timer(&fxp_watchdog, system_hz, fxp_watchdog_f, 0); + sys_setalarm(sys_hz(), 0); fp= fxp_state; - if (fp->fxp_mode != FM_ENABLED) - return; - /* Handle race condition, MII interface might be busy */ - if(!fp->fxp_mii_busy) - { - /* Check the link status. */ - if (fxp_link_changed(fp)) - { + /* Check the link status. */ + if (fxp_link_changed(fp)) { #if VERBOSE - printf("fxp_watchdog_f: link changed\n"); + printf("fxp_alarm: link changed\n"); #endif - fp->fxp_report_link= TRUE; - fp->fxp_got_int= TRUE; - interrupt(fxp_tasknr); - } + fp->fxp_report_link= TRUE; + fxp_check_ints(fp); } - - if (!(fp->fxp_flags & FF_SEND_AVAIL)) + + if (fp->fxp_tx_idle) { /* Assume that an idle system is alive */ fp->fxp_tx_alive= TRUE; @@ -1666,16 +1279,15 @@ minix_timer_t *tp; return; } + /* XXX this flag is never actually checked! */ fp->fxp_need_reset= TRUE; - fp->fxp_got_int= TRUE; - interrupt(fxp_tasknr); + fxp_check_ints(fp); } /*===========================================================================* * fxp_link_changed * *===========================================================================*/ -static int fxp_link_changed(fp) -fxp_t *fp; +static int fxp_link_changed(fxp_t *fp) { u16_t scr; @@ -1690,7 +1302,7 @@ fxp_t *fp; *===========================================================================*/ static void fxp_report_link(fxp_t *fp) { - u16_t mii_ctrl, mii_status, mii_id1, mii_id2, + u16_t mii_ctrl, mii_status, mii_id1, mii_id2, mii_ana, mii_anlpa, mii_ane, mii_extstat, mii_ms_ctrl, mii_ms_status, scr; u32_t oui; @@ -1738,13 +1350,13 @@ static void fxp_report_link(fxp_t *fp) return; } - oui= (mii_id1 << MII_PH_OUI_H_C_SHIFT) | + oui= (mii_id1 << MII_PH_OUI_H_C_SHIFT) | ((mii_id2 & MII_PL_OUI_L_MASK) >> MII_PL_OUI_L_SHIFT); model= ((mii_id2 & MII_PL_MODEL_MASK) >> MII_PL_MODEL_SHIFT); rev= (mii_id2 & MII_PL_REV_MASK); #if VERBOSE - printf("OUI 0x%06lx, Model 0x%02x, Revision 0x%x\n", oui, model, rev); + printf("OUI 0x%06x, Model 0x%02x, Revision 0x%x\n", oui, model, rev); #endif if (mii_ctrl & (MII_CTRL_LB|MII_CTRL_PD|MII_CTRL_ISO)) @@ -1789,8 +1401,7 @@ static void fxp_report_link(fxp_t *fp) return; } - if (!debug) goto resspeed; - +#if VERBOSE printf("%s: ", fp->fxp_name); mii_print_stat_speed(mii_status, mii_extstat); printf("\n"); @@ -1911,62 +1522,20 @@ static void fxp_report_link(fxp_t *fp) } printf("\n"); } - resspeed: +#endif + #if VERBOSE printf("%s: link up, %d Mbps, %s duplex\n", fp->fxp_name, (scr & MII_SCR_100) ? 100 : 10, (scr & MII_SCR_FD) ? "full" : "half"); #endif - ; -} - -/*===========================================================================* - * reply * - *===========================================================================*/ -static void reply(fp) -fxp_t *fp; -{ - message reply; - int flags; - int r; - - flags = DL_NOFLAGS; - if (fp->fxp_flags & FF_PACK_SENT) - flags |= DL_PACK_SEND; - if (fp->fxp_flags & FF_PACK_RECV) - flags |= DL_PACK_RECV; - - reply.m_type = DL_TASK_REPLY; - reply.m_netdrv_net_dl_task.flags = flags; - reply.m_netdrv_net_dl_task.count = fp->fxp_read_s; - - r= ipc_send(fp->fxp_client, &reply); - - if (r < 0) - panic("fxp: ipc_send failed: %d", r); - - fp->fxp_read_s = 0; - fp->fxp_flags &= ~(FF_PACK_SENT | FF_PACK_RECV); -} - -/*===========================================================================* - * mess_reply * - *===========================================================================*/ -static void mess_reply(req, reply_mess) -message *req; -message *reply_mess; -{ - if (ipc_send(req->m_source, reply_mess) != OK) - panic("fxp: unable to mess_reply"); } /*===========================================================================* * eeprom_read * *===========================================================================*/ -static u16_t eeprom_read(fp, reg) -fxp_t *fp; -int reg; +static u16_t eeprom_read(fxp_t *fp, int reg) { port_t port; u16_t v; @@ -1990,10 +1559,10 @@ int reg; fxp_outb(port, CSR_EEPROM, CE_EECS | b); /* bit */ fxp_outb(port, CSR_EEPROM, CE_EECS | b | CE_EESK); /* Clock */ micro_delay(EESK_PERIOD/2+1); - fxp_outb(port, CSR_EEPROM, CE_EECS | b); + fxp_outb(port, CSR_EEPROM, CE_EECS | b); micro_delay(EESK_PERIOD/2+1); } - + v= reg; for (i= alen-1; i >= 0; i--) { @@ -2001,7 +1570,7 @@ int reg; fxp_outb(port, CSR_EEPROM, CE_EECS | b); /* bit */ fxp_outb(port, CSR_EEPROM, CE_EECS | b | CE_EESK); /* Clock */ micro_delay(EESK_PERIOD/2+1); - fxp_outb(port, CSR_EEPROM, CE_EECS | b); + fxp_outb(port, CSR_EEPROM, CE_EECS | b); micro_delay(EESK_PERIOD/2+1); } @@ -2012,7 +1581,7 @@ int reg; micro_delay(EESK_PERIOD/2+1); b= !!(fxp_inb(port, CSR_EEPROM) & CE_EEDO); v= (v << 1) | b; - fxp_outb(port, CSR_EEPROM, CE_EECS ); + fxp_outb(port, CSR_EEPROM, CE_EECS ); micro_delay(EESK_PERIOD/2+1); } fxp_outb(port, CSR_EEPROM, 0); /* Disable EEPROM */ @@ -2024,8 +1593,7 @@ int reg; /*===========================================================================* * eeprom_addrsize * *===========================================================================*/ -static void eeprom_addrsize(fp) -fxp_t *fp; +static void eeprom_addrsize(fxp_t *fp) { port_t port; u16_t v; @@ -2042,7 +1610,7 @@ fxp_t *fp; fxp_outb(port, CSR_EEPROM, CE_EECS | b); /* bit */ fxp_outb(port, CSR_EEPROM, CE_EECS | b | CE_EESK); /* Clock */ micro_delay(EESK_PERIOD/2+1); - fxp_outb(port, CSR_EEPROM, CE_EECS | b); + fxp_outb(port, CSR_EEPROM, CE_EECS | b); micro_delay(EESK_PERIOD/2+1); } @@ -2052,7 +1620,7 @@ fxp_t *fp; fxp_outb(port, CSR_EEPROM, CE_EECS | b); /* bit */ fxp_outb(port, CSR_EEPROM, CE_EECS | b | CE_EESK); /* Clock */ micro_delay(EESK_PERIOD/2+1); - fxp_outb(port, CSR_EEPROM, CE_EECS | b); + fxp_outb(port, CSR_EEPROM, CE_EECS | b); micro_delay(EESK_PERIOD/2+1); v= fxp_inb(port, CSR_EEPROM); if (!(v & CE_EEDO)) @@ -2067,7 +1635,7 @@ fxp_t *fp; { fxp_outb(port, CSR_EEPROM, CE_EECS | CE_EESK); /* Clock */ micro_delay(EESK_PERIOD/2+1); - fxp_outb(port, CSR_EEPROM, CE_EECS ); + fxp_outb(port, CSR_EEPROM, CE_EECS ); micro_delay(EESK_PERIOD/2+1); } fxp_outb(port, CSR_EEPROM, 0); /* Disable EEPROM */ @@ -2082,9 +1650,7 @@ fxp_t *fp; /*===========================================================================* * mii_read * *===========================================================================*/ -static u16_t mii_read(fp, reg) -fxp_t *fp; -int reg; +static u16_t mii_read(fxp_t *fp, int reg) { spin_t spin; port_t port; @@ -2092,9 +1658,6 @@ int reg; port= fp->fxp_base_port; - assert(!fp->fxp_mii_busy); - fp->fxp_mii_busy++; - if (!(fxp_inl(port, CSR_MDI_CTL) & CM_READY)) panic("mii_read: MDI not ready"); fxp_outl(port, CSR_MDI_CTL, CM_READ | (1 << CM_PHYADDR_SHIFT) | @@ -2110,9 +1673,6 @@ int reg; if (!(v & CM_READY)) panic("mii_read: MDI not ready after command"); - fp->fxp_mii_busy--; - assert(!fp->fxp_mii_busy); - return v & CM_DATA_MASK; } @@ -2156,12 +1716,9 @@ static void do_outl(port_t port, u32_t value) panic("sys_outl failed: %d", r); } -static void tell_dev(buf, size, pci_bus, pci_dev, pci_func) -vir_bytes buf; -size_t size; -int pci_bus; -int pci_dev; -int pci_func; +/* TODO: obviously this needs a lot of work. */ +static void tell_iommu(vir_bytes buf, size_t size, int pci_bus, int pci_dev, + int pci_func) { int r; endpoint_t dev_e; @@ -2171,9 +1728,8 @@ int pci_func; if (r != OK) { #if 0 - printf( - "fxp`tell_dev: ds_retrieve_label_endpt failed for 'amddev': %d\n", - r); + printf("fxp`tell_iommu: ds_retrieve_label_endpt failed " + "for 'amddev': %d\n", r); #endif return; } @@ -2188,13 +1744,13 @@ int pci_func; r= ipc_sendrec(dev_e, &m); if (r != OK) { - printf("fxp`tell_dev: ipc_sendrec to %d failed: %d\n", + printf("fxp`tell_iommu: ipc_sendrec to %d failed: %d\n", dev_e, r); return; } if (m.m_type != OK) { - printf("fxp`tell_dev: dma map request failed: %d\n", + printf("fxp`tell_iommu: dma map request failed: %d\n", m.m_type); return; } @@ -2203,4 +1759,3 @@ int pci_func; /* * $PchId: fxp.c,v 1.4 2005/01/31 22:10:37 philip Exp $ */ - diff --git a/minix/drivers/net/lan8710a/Makefile b/minix/drivers/net/lan8710a/Makefile index 79d790d5e..a3387079f 100644 --- a/minix/drivers/net/lan8710a/Makefile +++ b/minix/drivers/net/lan8710a/Makefile @@ -6,7 +6,7 @@ FILES=$(PROG).conf FILESNAME=$(PROG) FILESDIR= /etc/system.conf.d -DPADD+= ${LIBNETDRIVER} ${LIBSYS} ${LIBTIMERS} -LDADD+= -lnetdriver -lsys -ltimers +DPADD+= ${LIBNETDRIVER} ${LIBSYS} +LDADD+= -lnetdriver -lsys .include diff --git a/minix/drivers/net/lan8710a/lan8710a.c b/minix/drivers/net/lan8710a/lan8710a.c index 9eac5d698..eb5ecbdea 100644 --- a/minix/drivers/net/lan8710a/lan8710a.c +++ b/minix/drivers/net/lan8710a/lan8710a.c @@ -1,31 +1,28 @@ #include #include -#include -#include -#include #include +#include #include "assert.h" #include "lan8710a.h" #include "lan8710a_reg.h" /* Local functions */ -static void lan8710a_readv_s(message *m, int from_int); -static void lan8710a_writev_s(message *m, int from_int); -static void lan8710a_conf(message *m); -static void lan8710a_getstat(message *m); - -static void lan8710a_init(void); -static void lan8710a_enable_interrupt(int interrupt); -static void lan8710a_interrupt(message *m); -static void lan8710a_map_regs(void); +static int lan8710a_init(unsigned int instance, ether_addr_t *addr); static void lan8710a_stop(void); +static ssize_t lan8710a_recv(struct netdriver_data *data, size_t max); +static int lan8710a_send(struct netdriver_data *data, size_t size); +static void lan8710a_stat(eth_stat_t *stat); +static void lan8710a_intr(unsigned int mask); + +static void lan8710a_enable_interrupt(int interrupt); +static void lan8710a_map_regs(void); static void lan8710a_dma_config_tx(u8_t desc_idx); static void lan8710a_dma_reset_init(void); -static void lan8710a_init_addr(void); +static void lan8710a_init_addr(ether_addr_t *addr); static void lan8710a_init_desc(void); static void lan8710a_init_mdio(void); -static int lan8710a_init_hw(void); -static void lan8710a_reset_hw(); +static int lan8710a_init_hw(ether_addr_t *addr); +static void lan8710a_reset_hw(void); static void lan8710a_phy_write(u32_t reg, u32_t value); static u32_t lan8710a_phy_read(u32_t reg); @@ -35,16 +32,17 @@ static void lan8710a_reg_write(volatile u32_t *reg, u32_t value); static void lan8710a_reg_set(volatile u32_t *reg, u32_t value); static void lan8710a_reg_unset(volatile u32_t *reg, u32_t value); -static void mess_reply(message *req, message *reply); -static void reply(lan8710a_t *e); - /* Local variables */ static lan8710a_t lan8710a_state; -/* SEF functions and variables. */ -static void sef_local_startup(void); -static int sef_cb_init_fresh(int type, sef_init_info_t *info); -static void sef_cb_signal_handler(int signal); +static const struct netdriver lan8710a_table = { + .ndr_init = lan8710a_init, + .ndr_stop = lan8710a_stop, + .ndr_recv = lan8710a_recv, + .ndr_send = lan8710a_send, + .ndr_stat = lan8710a_stat, + .ndr_intr = lan8710a_intr +}; /*============================================================================* * main * @@ -52,122 +50,45 @@ static void sef_cb_signal_handler(int signal); int main(int argc, char *argv[]) { - - /* Local variables */ - message m; - int r; - int ipc_status; - struct machine machine ; + struct machine machine; + + env_setargs(argc, argv); sys_getmachine(&machine); - if ( BOARD_IS_BB(machine.board_id)) { + if (BOARD_IS_BB(machine.board_id)) + netdriver_task(&lan8710a_table); - /* SEF local startup */ - env_setargs(argc, argv); - sef_local_startup(); - - /* Main driver loop */ - for (;;) { - r = netdriver_receive(ANY, &m, &ipc_status); - if (r != OK) { - panic("netdriver_receive failed: %d", r); - } - - if (is_ipc_notify(ipc_status)) { - switch (_ENDPOINT_P(m.m_source)) { - case HARDWARE: - lan8710a_interrupt(&m); - break; - } - } else { - switch (m.m_type) { - case DL_WRITEV_S: - lan8710a_writev_s(&m, FALSE); - break; - case DL_READV_S: - lan8710a_readv_s(&m, FALSE); - break; - case DL_CONF: - lan8710a_conf(&m); - break; - case DL_GETSTAT_S: - lan8710a_getstat(&m); - break; - default: - panic("Illegal message: %d", m.m_type); - } - } - } - } return EXIT_SUCCESS; } /*============================================================================* - * sef_local_startup * - *============================================================================*/ -static void -sef_local_startup() -{ - /* Register init callbacks. */ - sef_setcb_init_fresh(sef_cb_init_fresh); - sef_setcb_init_lu(sef_cb_init_fresh); - sef_setcb_init_restart(sef_cb_init_fresh); - - /* Register live update callbacks. */ - sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready); - sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_workfree); - - /* Register signal callbacks. */ - sef_setcb_signal_handler(sef_cb_signal_handler); - - /* Let SEF perform startup. */ - sef_startup(); -} - -/*============================================================================* - * sef_cb_init_fresh * + * lan8710a_init * *============================================================================*/ static int -sef_cb_init_fresh(int UNUSED( type), sef_init_info_t *UNUSED( info)) +lan8710a_init(unsigned int instance, ether_addr_t * addr) { /* Initialize the ethernet driver. */ - long v = 0; /* Clear state. */ memset(&lan8710a_state, 0, sizeof(lan8710a_state)); + strlcpy(lan8710a_state.name, "lan8710a#0", LAN8710A_NAME_LEN); + lan8710a_state.name[9] += instance; + lan8710a_state.instance = instance; + /* Initialize driver. */ - lan8710a_init(); + lan8710a_map_regs(); - /* Get instance of ethernet device */ - env_parse("instance", "d", 0, &v, 0, 255); - lan8710a_state.instance = (int) v; - - /* Announce we are up! */ - netdriver_announce(); + lan8710a_init_hw(addr); return OK; } -/*============================================================================* - * sef_cb_signal_handler * - *============================================================================*/ -static void -sef_cb_signal_handler(int signal) -{ - /* Only check for termination signal, ignore anything else. */ - if (signal != SIGTERM) - return; - - lan8710a_stop(); -} - /*============================================================================* * lan8710a_enable_interrupt * *============================================================================*/ static void -lan8710a_enable_interrupt(interrupt) -u8_t interrupt; +lan8710a_enable_interrupt(int interrupt) { int r; @@ -182,14 +103,13 @@ u8_t interrupt; } } } + /*============================================================================* - * lan8710a_interrupt * + * lan8710a_intr * *============================================================================*/ static void -lan8710a_interrupt(m) -message *m; +lan8710a_intr(unsigned int mask) { - lan8710a_t *e = &lan8710a_state; u32_t dma_status; /* Check the card for interrupt reason(s). */ @@ -201,7 +121,7 @@ message *m; if (rx_stat) { cp = lan8710a_reg_read(CPDMA_STRAM_RX_CP(0)); - lan8710a_readv_s(&(e->rx_message), TRUE); + netdriver_recv(); lan8710a_reg_write(CPDMA_STRAM_RX_CP(0), cp); lan8710a_reg_write(CPDMA_EOI_VECTOR, RX_INT); @@ -212,7 +132,7 @@ message *m; /* Disabling channels, where Tx interrupt occurred */ lan8710a_reg_set(CPDMA_TX_INTMASK_CLEAR, tx_stat); - lan8710a_writev_s(&(e->tx_message), TRUE); + netdriver_send(); lan8710a_reg_write(CPDMA_STRAM_TX_CP(0), cp); lan8710a_reg_write(CPDMA_EOI_VECTOR, TX_INT); @@ -226,61 +146,19 @@ message *m; } /* Re-enable Rx interrupt. */ - if(m->m_notify.interrupts & (1 << RX_INT)) + if (mask & (1 << RX_INT)) lan8710a_enable_interrupt(RX_INT); /* Re-enable Tx interrupt. */ - if(m->m_notify.interrupts & (1 << TX_INT)) + if (mask & (1 << TX_INT)) lan8710a_enable_interrupt(TX_INT); } -/*============================================================================* - * lan8710a_conf * - *============================================================================*/ -static void -lan8710a_conf(m) -message *m; -{ - message reply; - - if (!(lan8710a_state.status & LAN8710A_ENABLED) && - !(lan8710a_init_hw())) { - reply.m_type = DL_CONF_REPLY; - reply.m_netdrv_net_dl_conf.stat = ENXIO; - mess_reply(m, &reply); - return; - } - /* Reply back to INET. */ - reply.m_type = DL_CONF_REPLY; - reply.m_netdrv_net_dl_conf.stat = OK; - memcpy(reply.m_netdrv_net_dl_conf.hw_addr, - lan8710a_state.address.ea_addr, - sizeof(reply.m_netdrv_net_dl_conf.hw_addr)); - mess_reply(m, &reply); -} - -/*============================================================================* - * lan8710a_init * - *============================================================================*/ -static void -lan8710a_init(void) -{ - lan8710a_map_regs(); - strlcpy(lan8710a_state.name, "lan8710a#0", LAN8710A_NAME_LEN); - lan8710a_state.name[9] += lan8710a_state.instance; - lan8710a_state.status |= LAN8710A_DETECTED; - - if (!(lan8710a_state.status & LAN8710A_ENABLED) && - !(lan8710a_init_hw())) { - return; - } -} - /*============================================================================* * lan8710a_init_addr * *============================================================================*/ static void -lan8710a_init_addr(void) +lan8710a_init_addr(ether_addr_t * addr) { static char eakey[]= LAN8710A_ENVVAR "#_EA"; static char eafmt[]= "x:x:x:x:x:x"; @@ -296,22 +174,20 @@ lan8710a_init_addr(void) if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET) break; else - lan8710a_state.address.ea_addr[i] = v; - } - if (i != 6) { - lan8710a_state.address.ea_addr[0] = - (lan8710a_reg_read(CTRL_MAC_ID0_HI) & 0xFF); - lan8710a_state.address.ea_addr[1] = - ((lan8710a_reg_read(CTRL_MAC_ID0_HI) & 0xFF00) >> 8); - lan8710a_state.address.ea_addr[2] = - ((lan8710a_reg_read(CTRL_MAC_ID0_HI) & 0xFF0000) >> 16); - lan8710a_state.address.ea_addr[3] = - ((lan8710a_reg_read(CTRL_MAC_ID0_HI) & 0xFF000000) >> 24); - lan8710a_state.address.ea_addr[4] = - (lan8710a_reg_read(CTRL_MAC_ID0_LO) & 0xFF); - lan8710a_state.address.ea_addr[5] = - ((lan8710a_reg_read(CTRL_MAC_ID0_LO) & 0xFF00) >> 8); + addr->ea_addr[i] = v; } + if (i == 6) + return; + + /* + * No; get the address from the chip itself. + */ + addr->ea_addr[0] = lan8710a_reg_read(CTRL_MAC_ID0_HI) & 0xFF; + addr->ea_addr[1] = (lan8710a_reg_read(CTRL_MAC_ID0_HI) >> 8) & 0xFF; + addr->ea_addr[2] = (lan8710a_reg_read(CTRL_MAC_ID0_HI) >> 16) & 0xFF; + addr->ea_addr[3] = (lan8710a_reg_read(CTRL_MAC_ID0_HI) >> 24) & 0xFF; + addr->ea_addr[4] = lan8710a_reg_read(CTRL_MAC_ID0_LO) & 0xFF; + addr->ea_addr[5] = (lan8710a_reg_read(CTRL_MAC_ID0_LO) >> 8) & 0xFF; } /*============================================================================* @@ -411,40 +287,28 @@ lan8710a_map_regs(void) } /*============================================================================* - * lan8710a_getstat * + * lan8710a_stat * *============================================================================*/ static void -lan8710a_getstat(mp) -message *mp; +lan8710a_stat(eth_stat_t * stat) { - int r; - eth_stat_t stats; - - stats.ets_recvErr = lan8710a_reg_read(CPSW_STAT_RX_CRC_ERR) + stat->ets_recvErr = lan8710a_reg_read(CPSW_STAT_RX_CRC_ERR) + lan8710a_reg_read(CPSW_STAT_RX_AGNCD_ERR) + lan8710a_reg_read(CPSW_STAT_RX_OVERSIZE); - stats.ets_sendErr = 0; - stats.ets_OVW = 0; - stats.ets_CRCerr = lan8710a_reg_read(CPSW_STAT_RX_CRC_ERR); - stats.ets_frameAll = lan8710a_reg_read(CPSW_STAT_RX_AGNCD_ERR); - stats.ets_missedP = 0; - stats.ets_packetR = lan8710a_reg_read(CPSW_STAT_RX_GOOD); - stats.ets_packetT = lan8710a_reg_read(CPSW_STAT_TX_GOOD); - stats.ets_collision = lan8710a_reg_read(CPSW_STAT_COLLISIONS); - stats.ets_transAb = 0; - stats.ets_carrSense = lan8710a_reg_read(CPSW_STAT_CARR_SENS_ERR); - stats.ets_fifoUnder = lan8710a_reg_read(CPSW_STAT_TX_UNDERRUN); - stats.ets_fifoOver = lan8710a_reg_read(CPSW_STAT_RX_OVERRUN); - stats.ets_CDheartbeat = 0; - stats.ets_OWC = 0; - - sys_safecopyto(mp->m_source, mp->m_net_netdrv_dl_getstat_s.grant, 0, - (vir_bytes)&stats, sizeof(stats)); - mp->m_type = DL_STAT_REPLY; - - if ((r=ipc_send(mp->m_source, mp)) != OK) { - panic("lan8710a_getstat: ipc_send() failed: %d", r); - } + stat->ets_sendErr = 0; + stat->ets_OVW = 0; + stat->ets_CRCerr = lan8710a_reg_read(CPSW_STAT_RX_CRC_ERR); + stat->ets_frameAll = lan8710a_reg_read(CPSW_STAT_RX_AGNCD_ERR); + stat->ets_missedP = 0; + stat->ets_packetR = lan8710a_reg_read(CPSW_STAT_RX_GOOD); + stat->ets_packetT = lan8710a_reg_read(CPSW_STAT_TX_GOOD); + stat->ets_collision = lan8710a_reg_read(CPSW_STAT_COLLISIONS); + stat->ets_transAb = 0; + stat->ets_carrSense = lan8710a_reg_read(CPSW_STAT_CARR_SENS_ERR); + stat->ets_fifoUnder = lan8710a_reg_read(CPSW_STAT_TX_UNDERRUN); + stat->ets_fifoOver = lan8710a_reg_read(CPSW_STAT_RX_OVERRUN); + stat->ets_CDheartbeat = 0; + stat->ets_OWC = 0; } /*============================================================================* @@ -455,17 +319,13 @@ lan8710a_stop(void) { /* Reset hardware. */ lan8710a_reset_hw(); - - /* Exit driver. */ - exit(EXIT_SUCCESS); } /*============================================================================* * lan8710a_dma_config_tx * *============================================================================*/ static void -lan8710a_dma_config_tx(desc_idx) -u8_t desc_idx; +lan8710a_dma_config_tx(u8_t desc_idx) { phys_bytes phys_addr; int i; @@ -585,12 +445,10 @@ lan8710a_init_desc(void) * lan8710a_init_hw * *============================================================================*/ static int -lan8710a_init_hw(void) +lan8710a_init_hw(ether_addr_t * addr) { int r, i; - lan8710a_state.status |= LAN8710A_ENABLED; - /* * Set the interrupt handler and policy. Do not automatically * re-enable interrupts. Return the IRQ line number on interrupts. @@ -757,7 +615,7 @@ lan8710a_init_hw(void) lan8710a_init_mdio(); /* Getting MAC Address */ - lan8710a_init_addr(); + lan8710a_init_addr(addr); /* Initialize descriptors */ lan8710a_init_desc(); @@ -825,244 +683,145 @@ lan8710a_init_mdio(void) } /*============================================================================* - * lan8710a_writev_s * + * lan8710a_send * *============================================================================*/ -static void -lan8710a_writev_s(mp, from_int) -message *mp; -int from_int; +static int +lan8710a_send(struct netdriver_data * data, size_t size) { - iovec_s_t iovec[LAN8710A_IOVEC_NR]; lan8710a_t *e = &lan8710a_state; lan8710a_desc_t *p_tx_desc; - u8_t *p_buf; - int r, size, buf_data_len, i; + u8_t *buf; - /* Are we called from the interrupt handler? */ - if (!from_int) { - /* We cannot write twice simultaneously. */ - assert(!(e->status & LAN8710A_WRITING)); + /* setup descriptors */ + p_tx_desc = &(e->tx_desc[e->tx_desc_idx]); - /* Copy write message. */ - e->tx_message = *mp; - e->client = mp->m_source; - e->status |= LAN8710A_WRITING; + /* + * Check if descriptor is available for host and suspend if not. + */ + if (LAN8710A_DESC_FLAG_OWN & p_tx_desc->pkt_len_flags) + return SUSPEND; - /* verify vector count */ - assert(mp->m_net_netdrv_dl_writev_s.count > 0); - assert(mp->m_net_netdrv_dl_writev_s.count < LAN8710A_IOVEC_NR); + /* Drop packets that exceed the size of our transmission buffer. */ + if (size > LAN8710A_IOBUF_SIZE) { + printf("%s: dropping large packet (%zu)\n", e->name, size); - /* - * Copy the I/O vector table. - */ - if ((r = sys_safecopyfrom(mp->m_source, - mp->m_net_netdrv_dl_writev_s.grant, 0, - (vir_bytes) iovec, - mp->m_net_netdrv_dl_writev_s.count * - sizeof(iovec_s_t))) != OK) { - panic("sys_safecopyfrom() failed: %d", r); - } - /* setup descriptors */ - p_tx_desc = &(e->tx_desc[e->tx_desc_idx]); - - /* - * Check if descriptor is available for host - * and drop the packet if not. - */ - if (LAN8710A_DESC_FLAG_OWN & p_tx_desc->pkt_len_flags) { - panic("No available transmit descriptor."); - } - - /* virtual address of buffer */ - p_buf = e->p_tx_buf + e->tx_desc_idx * LAN8710A_IOBUF_SIZE; - buf_data_len = 0; - for (i = 0; i < mp->m_net_netdrv_dl_writev_s.count; i++) { - if ((buf_data_len + iovec[i].iov_size) - > LAN8710A_IOBUF_SIZE) { - panic("packet too long"); - } - - /* copy data to buffer */ - size = iovec[i].iov_size - < (LAN8710A_IOBUF_SIZE - buf_data_len) ? - iovec[i].iov_size - : (LAN8710A_IOBUF_SIZE - buf_data_len); - - /* Copy bytes to TX queue buffers. */ - if ((r = sys_safecopyfrom(mp->m_source, - iovec[i].iov_grant, 0, - (vir_bytes) p_buf, size)) != OK) { - panic("sys_safecopyfrom() failed: %d", r); - } - p_buf += size; - buf_data_len += size; - } - - /* set descriptor length */ - p_tx_desc->buffer_length_off = buf_data_len; - /* set flags */ - p_tx_desc->pkt_len_flags = (LAN8710A_DESC_FLAG_OWN | - LAN8710A_DESC_FLAG_SOP | - LAN8710A_DESC_FLAG_EOP | - TX_DESC_TO_PORT1 | - TX_DESC_TO_PORT_EN); - p_tx_desc->pkt_len_flags |= buf_data_len; - - /* setup DMA transfer */ - lan8710a_dma_config_tx(e->tx_desc_idx); - - e->tx_desc_idx++; - if (LAN8710A_NUM_TX_DESC == e->tx_desc_idx) { - e->tx_desc_idx = 0; - } - } else { - e->status |= LAN8710A_TRANSMIT; + return OK; } - reply(e); + + /* virtual address of buffer */ + buf = e->p_tx_buf + e->tx_desc_idx * LAN8710A_IOBUF_SIZE; + + netdriver_copyin(data, 0, buf, size); + + /* set descriptor length */ + p_tx_desc->buffer_length_off = size; + /* set flags */ + p_tx_desc->pkt_len_flags = (LAN8710A_DESC_FLAG_OWN | + LAN8710A_DESC_FLAG_SOP | + LAN8710A_DESC_FLAG_EOP | + TX_DESC_TO_PORT1 | + TX_DESC_TO_PORT_EN); + p_tx_desc->pkt_len_flags |= size; + + /* setup DMA transfer */ + lan8710a_dma_config_tx(e->tx_desc_idx); + + e->tx_desc_idx++; + if (LAN8710A_NUM_TX_DESC == e->tx_desc_idx) + e->tx_desc_idx = 0; + + return OK; } /*============================================================================* - * lan8710a_readv_s * + * lan8710a_recv * *============================================================================*/ -static void -lan8710a_readv_s(mp, from_int) -message *mp; -int from_int; +static ssize_t +lan8710a_recv(struct netdriver_data * data, size_t max) { - iovec_s_t iovec[LAN8710A_IOVEC_NR]; lan8710a_t *e = &lan8710a_state; lan8710a_desc_t *p_rx_desc; - u32_t flags; - u8_t *p_buf; - u16_t pkt_data_len; - u16_t buf_bytes, buf_len; - int i, r, size; + u32_t flags; + u8_t *buf; + size_t off, size, chunk; - /* Are we called from the interrupt handler? */ - if (!from_int) { - e->rx_message = *mp; - e->client = mp->m_source; - e->status |= LAN8710A_READING; - e->rx_size = 0; + /* + * Only handle one packet at a time. + */ + p_rx_desc = &(e->rx_desc[e->rx_desc_idx]); + /* find next OWN descriptor with SOP flag */ + while ((0 == (LAN8710A_DESC_FLAG_SOP & p_rx_desc->pkt_len_flags)) && + (0 == (LAN8710A_DESC_FLAG_OWN & p_rx_desc->pkt_len_flags))) { + p_rx_desc->buffer_length_off = LAN8710A_IOBUF_SIZE; + /* set ownership of current descriptor to EMAC */ + p_rx_desc->pkt_len_flags = LAN8710A_DESC_FLAG_OWN; - assert(e->rx_message.m_net_netdrv_dl_readv_s.count > 0); - assert(e->rx_message.m_net_netdrv_dl_readv_s.count < LAN8710A_IOVEC_NR); - } - if (e->status & LAN8710A_READING) { - /* - * Copy the I/O vector table first. - */ - if ((r = sys_safecopyfrom(e->rx_message.m_source, - e->rx_message.m_net_netdrv_dl_readv_s.grant, 0, - (vir_bytes) iovec, - e->rx_message.m_net_netdrv_dl_readv_s.count * - sizeof(iovec_s_t))) != OK) { - panic("sys_safecopyfrom() failed: %d", r); - } - - /* - * Only handle one packet at a time. - */ + e->rx_desc_idx++; + if (LAN8710A_NUM_RX_DESC == e->rx_desc_idx) + e->rx_desc_idx = 0; p_rx_desc = &(e->rx_desc[e->rx_desc_idx]); - /* find next OWN descriptor with SOP flag */ - while ((0 == (LAN8710A_DESC_FLAG_SOP & - p_rx_desc->pkt_len_flags)) && - (0 == (LAN8710A_DESC_FLAG_OWN & - p_rx_desc->pkt_len_flags))) { - p_rx_desc->buffer_length_off = LAN8710A_IOBUF_SIZE; - /* set ownership of current descriptor to EMAC */ - p_rx_desc->pkt_len_flags = LAN8710A_DESC_FLAG_OWN; - - e->rx_desc_idx++; - if (LAN8710A_NUM_RX_DESC == e->rx_desc_idx) - e->rx_desc_idx = 0; - p_rx_desc = &(e->rx_desc[e->rx_desc_idx]); - } - if (0 == (LAN8710A_DESC_FLAG_SOP & p_rx_desc->pkt_len_flags)) { - /* SOP was not found */ - reply(e); - return; - } - - /* - * Copy to vector elements. - */ - pkt_data_len = 0; - buf_bytes = 0; - p_buf = e->p_rx_buf + e->rx_desc_idx * LAN8710A_IOBUF_SIZE; - for (i = 0; i < e->rx_message.m_net_netdrv_dl_readv_s.count; i++) { - buf_len = p_rx_desc->buffer_length_off & 0xFFFF; - if (buf_bytes == buf_len) { - /* Whole buffer move to the next descriptor */ - p_rx_desc->buffer_length_off = - LAN8710A_IOBUF_SIZE; - /* set ownership of current desc to EMAC */ - p_rx_desc->pkt_len_flags = - LAN8710A_DESC_FLAG_OWN; - buf_bytes = 0; - - e->rx_desc_idx++; - if (LAN8710A_NUM_RX_DESC == e->rx_desc_idx) - e->rx_desc_idx = 0; - p_rx_desc = &(e->rx_desc[e->rx_desc_idx]); - p_buf = e->p_rx_buf + (e->rx_desc_idx * - LAN8710A_IOBUF_SIZE) + - (p_rx_desc->buffer_length_off >> 16); - buf_len = p_rx_desc->buffer_length_off & 0xFFFF; - } - size = iovec[i].iov_size < (buf_len - buf_bytes) ? - iovec[i].iov_size : - (buf_len - buf_bytes); - - if ((r = sys_safecopyto(e->rx_message.m_source, - iovec[i].iov_grant, 0, - (vir_bytes) p_buf, - size)) != OK) { - panic("sys_safecopyto() failed: %d", r); - } - p_buf += size; - buf_bytes += size; - pkt_data_len += size; - - /* if EOP flag is set -> stop processing */ - if ((LAN8710A_DESC_FLAG_EOP & p_rx_desc->pkt_len_flags) && - (buf_bytes == buf_len)) { - /* end of packet */ - break; - } - } - do { - /* reset owned descriptors up to EOP flag */ - flags = p_rx_desc->pkt_len_flags; - p_rx_desc->buffer_length_off = LAN8710A_IOBUF_SIZE; - /* set ownership of current descriptor to EMAC */ - p_rx_desc->pkt_len_flags = LAN8710A_DESC_FLAG_OWN; - - e->rx_desc_idx++; - if (LAN8710A_NUM_RX_DESC == e->rx_desc_idx) - e->rx_desc_idx = 0; - - p_rx_desc = &(e->rx_desc[e->rx_desc_idx]); - } - while (0 == (flags & LAN8710A_DESC_FLAG_EOP)); - - /* - * Update state. - */ - e->status |= LAN8710A_RECEIVED; - e->rx_size = pkt_data_len; - } - reply(e); + + if (0 == (LAN8710A_DESC_FLAG_SOP & p_rx_desc->pkt_len_flags)) { + /* SOP was not found */ + return SUSPEND; + } + + /* + * Copy data from descriptors, from SOP to EOP inclusive. + * TODO: make sure that the presence of a SOP slot implies the presence + * of an EOP slot, because we are not checking for ownership below.. + */ + size = 0; + off = 0; + + for (;;) { + buf = e->p_rx_buf + e->rx_desc_idx * LAN8710A_IOBUF_SIZE + off; + chunk = p_rx_desc->buffer_length_off & 0xFFFF; + + /* Truncate packets that are too large. */ + if (chunk > max - size) + chunk = max - size; + + if (chunk > 0) { + netdriver_copyout(data, size, buf, chunk); + + size += chunk; + } + + flags = p_rx_desc->pkt_len_flags; + + /* Whole buffer move to the next descriptor */ + p_rx_desc->buffer_length_off = LAN8710A_IOBUF_SIZE; + /* set ownership of current desc to EMAC */ + p_rx_desc->pkt_len_flags = LAN8710A_DESC_FLAG_OWN; + + e->rx_desc_idx++; + if (LAN8710A_NUM_RX_DESC == e->rx_desc_idx) + e->rx_desc_idx = 0; + p_rx_desc = &(e->rx_desc[e->rx_desc_idx]); + + /* if EOP flag is set -> stop processing */ + if (flags & LAN8710A_DESC_FLAG_EOP) + break; + + /* + * TODO: the upper 16 bits of buffer_length_off are used *only* + * for descriptors *after* the first one; I'm retaining this + * behavior because I don't have the chip's spec, but it may be + * better to simplify/correct this behavior. --David + */ + off = p_rx_desc->buffer_length_off >> 16; + } + + return size; } /*============================================================================* * lan8710a_phy_write * *============================================================================*/ static void -lan8710a_phy_write(reg, value) -u32_t reg; -u32_t value; +lan8710a_phy_write(u32_t reg, u32_t value) { if (!(lan8710a_reg_read(MDIOUSERACCESS0) & MDIO_GO)) { /* Clearing MDIOUSERACCESS0 register */ @@ -1073,7 +832,8 @@ u32_t value; lan8710a_reg_set(MDIOUSERACCESS0, lan8710a_state.phy_address << MDIO_PHYADR); /* Data written only 16 bits. */ - lan8710a_reg_set(MDIOUSERACCESS0, (value & 0xFFFF) << MDIO_DATA); + lan8710a_reg_set(MDIOUSERACCESS0, + (value & 0xFFFF) << MDIO_DATA); lan8710a_reg_set(MDIOUSERACCESS0, MDIO_GO); /* Waiting for writing completion */ @@ -1085,8 +845,7 @@ u32_t value; * lan8710a_phy_read * *============================================================================*/ static u32_t -lan8710a_phy_read(reg) -u32_t reg; +lan8710a_phy_read(u32_t reg) { u32_t value = 0xFFFFFFFF; @@ -1116,7 +875,7 @@ u32_t reg; * lan8710a_reset_hw * *============================================================================*/ static void -lan8710a_reset_hw() +lan8710a_reset_hw(void) { /* Assert a Device Reset signal. */ lan8710a_phy_write(LAN8710A_CTRL_REG, LAN8710A_SOFT_RESET); @@ -1129,8 +888,7 @@ lan8710a_reset_hw() * lan8710a_reg_read * *============================================================================*/ static u32_t -lan8710a_reg_read(reg) -volatile u32_t *reg; +lan8710a_reg_read(volatile u32_t *reg) { u32_t value; @@ -1145,9 +903,7 @@ volatile u32_t *reg; * lan8710a_reg_write * *============================================================================*/ static void -lan8710a_reg_write(reg, value) -volatile u32_t *reg; -u32_t value; +lan8710a_reg_write(volatile u32_t *reg, u32_t value) { /* Write to memory mapped register. */ *reg = value; @@ -1157,9 +913,7 @@ u32_t value; * lan8710a_reg_set * *============================================================================*/ static void -lan8710a_reg_set(reg, value) -volatile u32_t *reg; -u32_t value; +lan8710a_reg_set(volatile u32_t *reg, u32_t value) { u32_t data; @@ -1174,9 +928,7 @@ u32_t value; * lan8710a_reg_unset * *============================================================================*/ static void -lan8710a_reg_unset(reg, value) -volatile u32_t *reg; -u32_t value; +lan8710a_reg_unset(volatile u32_t *reg, u32_t value) { u32_t data; @@ -1186,61 +938,3 @@ u32_t value; /* Unset value, and write back. */ lan8710a_reg_write(reg, data & ~value); } - -/*============================================================================* - * mess_reply * - *============================================================================*/ -static void -mess_reply(req, reply) -message *req;message *reply; -{ - if (ipc_send(req->m_source, reply) != OK) { - panic("unable to send reply message"); - } -} - -/*============================================================================* - * reply * - *============================================================================*/ -static void -reply(e) -lan8710a_t *e; -{ - message msg; - int r; - - /* Only reply to client for read/write request. */ - if (!(e->status & LAN8710A_READING || - e->status & LAN8710A_WRITING)) { - return; - } - /* Construct reply message. */ - msg.m_type = DL_TASK_REPLY; - msg.m_netdrv_net_dl_task.flags = DL_NOFLAGS; - msg.m_netdrv_net_dl_task.count = 0; - - /* Did we successfully receive packet(s)? */ - if (e->status & LAN8710A_READING && - e->status & LAN8710A_RECEIVED) { - msg.m_netdrv_net_dl_task.flags |= DL_PACK_RECV; - msg.m_netdrv_net_dl_task.count = - e->rx_size >= ETH_MIN_PACK_SIZE ? - e->rx_size : ETH_MIN_PACK_SIZE; - - /* Clear flags. */ - e->status &= ~(LAN8710A_READING | LAN8710A_RECEIVED); - } - /* Did we successfully transmit packet(s)? */ - if (e->status & LAN8710A_TRANSMIT && - e->status & LAN8710A_WRITING) { - msg.m_netdrv_net_dl_task.flags |= DL_PACK_SEND; - - /* Clear flags. */ - e->status &= ~(LAN8710A_WRITING | LAN8710A_TRANSMIT); - } - - /* Acknowledge to INET. */ - if ((r = ipc_send(e->client, &msg) != OK)) { - panic("ipc_send() failed: %d", r); - } -} diff --git a/minix/drivers/net/lan8710a/lan8710a.h b/minix/drivers/net/lan8710a/lan8710a.h index 214df87cc..3dca3a787 100644 --- a/minix/drivers/net/lan8710a/lan8710a.h +++ b/minix/drivers/net/lan8710a/lan8710a.h @@ -16,26 +16,9 @@ #define LAN8710A_DEBUG_PRINT(args) #endif -#ifndef ERR - #define ERR (-1) /* general error flag */ -#endif -#ifndef OK - #define OK 0 /* general OK flag */ -#endif - -#define MAP_FAILED ((void *) -1) /* mmap() failed */ - /* Ethernet driver defines */ #define LAN8710A_NAME_LEN (11) -/* Ethernet driver states */ -#define LAN8710A_DETECTED (1 << 0) -#define LAN8710A_ENABLED (1 << 1) -#define LAN8710A_READING (1 << 2) -#define LAN8710A_WRITING (1 << 3) -#define LAN8710A_RECEIVED (1 << 4) -#define LAN8710A_TRANSMIT (1 << 5) - /* Descriptors flags */ #define LAN8710A_DESC_FLAG_OWN (1 << 29) /* ownership flag */ #define LAN8710A_DESC_FLAG_SOP (1 << 31) /* start of packet flag */ @@ -58,9 +41,6 @@ /** Number of receive descriptors */ #define LAN8710A_NUM_RX_DESC (255) -/** Number of I/O vectors to use. */ -#define LAN8710A_IOVEC_NR (16) - /** Size of each I/O buffer per descriptor. */ #define LAN8710A_IOBUF_SIZE (1520) @@ -89,11 +69,9 @@ typedef struct lan8710a_t phys_bytes rx_desc_phy; phys_bytes tx_desc_phy; char name[LAN8710A_NAME_LEN]; - int status; int irq_rx_hook; /* Rx interrupt Request Vector Hook. */ int irq_tx_hook; /* Tx interrupt Request Vector Hook. */ int instance; - ether_addr_t address; /* Ethernet MAC address. */ u8_t *regs; u32_t phy_address; u8_t *p_rx_buf; /* pointer to the buffer with receive frames */ @@ -101,10 +79,6 @@ typedef struct lan8710a_t u16_t tx_desc_idx; /* index of the next transmit desciptor */ u16_t rx_desc_idx; /* index of the next receive desciptor */ - int client; - message tx_message; - message rx_message; - unsigned int rx_size; /* register mapping */ vir_bytes regs_cp_per; diff --git a/minix/drivers/net/lance/lance.c b/minix/drivers/net/lance/lance.c index cf86f9d9e..b63d40029 100644 --- a/minix/drivers/net/lance/lance.c +++ b/minix/drivers/net/lance/lance.c @@ -4,38 +4,6 @@ * This file contains a ethernet device driver for AMD LANCE based ethernet * cards. * - * The valid messages and their parameters are: - * - * m_type DL_COUNT DL_MODE DL_GRANT - * |--------------+----------+---------+---------| - * | DL_WRITEV_S | count | | grant | - * |--------------|----------|---------|---------| - * | DL_READV_S | count | | grant | - * |--------------|----------|---------|---------| - * | DL_CONF | | mode | | - * |--------------|----------|---------|---------| - * | DL_GETSTAT_S | | | grant | - * |--------------|----------|---------|---------| - * | hardware int | | | | - * |--------------|----------|---------|---------| - * - * The messages sent are: - * - * m_type DL_COUNT DL_FLAGS - * |---------------+----------+---------| - * | DL_TASK_REPLY | rd-count | flags | - * |---------------|----------|---------| - * - * m_type - * |---------------| - * | DL_STAT_REPLY | - * |---------------| - * - * m_type DL_STAT DL_ADDR - * |---------------+---------+---------------| - * | DL_CONF_REPLY | code | ethernet addr | - * |---------------|---------|---------------| - * * Created: Jul 27, 2002 by Kazuya Kodama * Adapted for Minix 3: Sep 05, 2005 by Joren l'Ami */ @@ -58,58 +26,21 @@ #include "lance.h" -static ether_card_t ec_state; -static int ec_instance; - -/* Configuration */ -typedef struct ec_conf -{ - port_t ec_port; - int ec_irq; - phys_bytes ec_mem; -} ec_conf_t; - -/* We hardly use these. Just "LANCE0=on/off" "LANCE1=on/off" mean. */ -#define EC_CONF_NR 3 -ec_conf_t ec_conf[EC_CONF_NR]= /* Card addresses */ -{ - /* I/O port, IRQ, Buffer address. */ - { 0x1000, 9, 0x00000, }, - { 0xD000, 15, 0x00000, }, - { 0x0000, 0, 0x00000, }, -}; - -/* General */ -static void do_init(message *mp); -static void ec_init(ether_card_t *ec); -static void ec_confaddr(ether_card_t *ec); +static int do_init(unsigned int instance, ether_addr_t *addr); +static void ec_confaddr(ether_addr_t *addr); static void ec_reinit(ether_card_t *ec); -static void ec_check_ints(ether_card_t *ec); -static void conf_hw(ether_card_t *ec); -static void update_conf(ether_card_t *ec, ec_conf_t *ecp); -static void mess_reply(message *req, message *reply); -static void do_int(ether_card_t *ec); -static void reply(ether_card_t *ec); static void ec_reset(ether_card_t *ec); -static void ec_send(ether_card_t *ec); -static void ec_recv(ether_card_t *ec); -static void do_vwrite_s(message *mp, int from_int); -static void do_vread_s(const message *mp); -static void ec_user2nic(ether_card_t *dep, iovec_dat_t *iovp, vir_bytes - offset, int nic_addr, vir_bytes count); -static void ec_nic2user(ether_card_t *ec, int nic_addr, iovec_dat_t - *iovp, vir_bytes offset, vir_bytes count); -static int calc_iovec_size(iovec_dat_t *iovp); -static void ec_next_iovec(iovec_dat_t *iovp); -static void do_getstat_s(message *mp); -static void lance_stop(ether_card_t *ec); - +static void do_intr(unsigned int mask); +static void do_mode(unsigned int mode); +static int do_send(struct netdriver_data *data, size_t size); +static ssize_t do_recv(struct netdriver_data *data, size_t max); +static void do_stat(eth_stat_t *stat); +static void do_stop(void); static void lance_dump(void); -static void getAddressing(int devind, ether_card_t *ec); - -/* probe+init LANCE cards */ -static int lance_probe(ether_card_t *ec, int skip); -static void lance_init_card(ether_card_t *ec); +static void do_other(const message *m_ptr, int ipc_status); +static void get_addressing(int devind, ether_card_t *ec); +static int lance_probe(ether_card_t *ec, unsigned int skip); +static void lance_init_hw(ether_card_t *ec, ether_addr_t *addr); /* Accesses Lance Control and Status Registers */ static u8_t in_byte(port_t port); @@ -118,28 +49,12 @@ static void out_word(port_t port, u16_t value); static u16_t read_csr(port_t ioaddr, u16_t csrno); static void write_csr(port_t ioaddr, u16_t csrno, u16_t value); +static ether_card_t ec_state; +static int ec_instance; + /* --- LANCE --- */ /* General */ -typedef unsigned long Address; - -#define virt_to_bus(x) (vir2phys((unsigned long)x)) -unsigned long vir2phys( unsigned long x ) -{ - int r; - unsigned long value; - - if ( (r=sys_umap( SELF, VM_D, x, 4, &value )) != OK ) { - printf("lance: umap of 0x%lx failed\n",x ); - panic("sys_umap failed: %d", r); - } - - return value; -} - -/* DMA limitations */ -#define DMA_ADDR_MASK 0xFFFFFF /* mask to verify DMA address is 24-bit */ - -#define CORRECT_DMA_MEM() ( (virt_to_bus(lance_buf + sizeof(struct lance_interface)) & ~DMA_ADDR_MASK) == 0 ) +typedef uint32_t Address; #define ETH_FRAME_LEN 1518 @@ -240,153 +155,33 @@ static char *lance_buf = NULL; static int rx_slot_nr = 0; /* Rx-slot number */ static int tx_slot_nr = 0; /* Tx-slot number */ static int cur_tx_slot_nr = 0; /* Tx-slot number */ +static phys_bytes tx_ring_base[TX_RING_SIZE]; /* Tx-slot physical address */ static char isstored[TX_RING_SIZE]; /* Tx-slot in-use */ -phys_bytes lance_buf_phys; - -/* SEF functions and variables. */ -static void sef_local_startup(void); -static int sef_cb_init_fresh(int type, sef_init_info_t *info); -static void sef_cb_signal_handler(int signo); +static const struct netdriver lance_table = { + .ndr_init = do_init, + .ndr_stop = do_stop, + .ndr_mode = do_mode, + .ndr_recv = do_recv, + .ndr_send = do_send, + .ndr_stat = do_stat, + .ndr_intr = do_intr, + .ndr_other = do_other, +}; /*===========================================================================* * main * *===========================================================================*/ -int main( int argc, char **argv ) +int main(int argc, char **argv) { - message m; - int ipc_status; - int r; - ether_card_t *ec; - /* SEF local startup. */ env_setargs(argc, argv); - sef_local_startup(); - ec= &ec_state; - - while (TRUE) - { - if (ec->ec_irq != 0) - sys_irqenable(&ec->ec_hook); - - if ((r= netdriver_receive(ANY, &m, &ipc_status)) != OK) - panic("netdriver_receive failed: %d", r); - - if (ec->ec_irq != 0) - sys_irqdisable(&ec->ec_hook); - - if (is_ipc_notify(ipc_status)) { - switch(_ENDPOINT_P(m.m_source)) { - case TTY_PROC_NR: - lance_dump(); - break; - case HARDWARE: - if (ec->mode == EC_ENABLED) - { - ec->ec_int_pending = 0; - ec_check_ints(ec); - do_int(ec); - } - break; - default: - panic("illegal notify source: %d", m.m_source); - } - - /* get next message */ - continue; - } - - switch (m.m_type) - { - case DL_WRITEV_S: - do_vwrite_s(&m, FALSE); - break; - case DL_READV_S: - do_vread_s(&m); - break; - case DL_CONF: - do_init(&m); - break; - case DL_GETSTAT_S: - do_getstat_s(&m); - break; - default: - panic("illegal message: %d", m.m_type); - } - } + netdriver_task(&lance_table); return 0; } -/*===========================================================================* - * sef_local_startup * - *===========================================================================*/ -static void sef_local_startup() -{ - /* Register init callbacks. */ - sef_setcb_init_fresh(sef_cb_init_fresh); - sef_setcb_init_lu(sef_cb_init_fresh); - sef_setcb_init_restart(sef_cb_init_fresh); - - /* Register live update callbacks. */ - sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready); - sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_workfree); - - /* Register signal callbacks. */ - sef_setcb_signal_handler(sef_cb_signal_handler); - - /* Let SEF perform startup. */ - sef_startup(); -} - -/*===========================================================================* - * sef_cb_init_fresh * - *===========================================================================*/ -static int sef_cb_init_fresh(int type, sef_init_info_t *UNUSED(info)) -{ -/* Initialize the lance driver. */ - long v; -#if LANCE_FKEY - int r, fkeys, sfkeys; -#endif - -#if LANCE_FKEY - fkeys = sfkeys = 0; - bit_set( sfkeys, 7 ); - if ( (r = fkey_map(&fkeys, &sfkeys)) != OK ) - printf("Warning: lance couldn't observe Shift+F7 key: %d\n",r); -#endif - - v = 0; - (void) env_parse("instance", "d", 0, &v, 0, 255); - ec_instance = (int) v; - - /* Announce we are up! */ - netdriver_announce(); - - return OK; -} - -/*===========================================================================* - * sef_cb_signal_handler * - *===========================================================================*/ -static void sef_cb_signal_handler(int signo) -{ - - /* Only check for termination signal, ignore anything else. */ - if (signo != SIGTERM) return; - - if (ec_state.mode == EC_ENABLED) - lance_stop(&ec_state); - -#if VERBOSE - printf("LANCE driver stopped.\n"); -#endif - - exit(0); -} - /*===========================================================================* * lance_dump * *===========================================================================*/ @@ -395,41 +190,34 @@ static void lance_dump() ether_card_t *ec; int isr, csr; unsigned short ioaddr; - + printf("\n"); ec = &ec_state; - if (ec->mode == EC_DISABLED) - printf("lance instance %d is disabled\n", ec_instance); - else if (ec->mode == EC_SINK) - printf("lance instance %d is in sink mode\n", ec_instance); - if (ec->mode != EC_ENABLED) - return; - printf("lance statistics of instance %d:\n", ec_instance); - + printf("recvErr :%8ld\t", ec->eth_stat.ets_recvErr); printf("sendErr :%8ld\t", ec->eth_stat.ets_sendErr); printf("OVW :%8ld\n", ec->eth_stat.ets_OVW); - + printf("CRCerr :%8ld\t", ec->eth_stat.ets_CRCerr); printf("frameAll :%8ld\t", ec->eth_stat.ets_frameAll); printf("missedP :%8ld\n", ec->eth_stat.ets_missedP); - + printf("packetR :%8ld\t", ec->eth_stat.ets_packetR); printf("packetT :%8ld\t", ec->eth_stat.ets_packetT); printf("transDef :%8ld\n", ec->eth_stat.ets_transDef); - + printf("collision :%8ld\t", ec->eth_stat.ets_collision); printf("transAb :%8ld\t", ec->eth_stat.ets_transAb); printf("carrSense :%8ld\n", ec->eth_stat.ets_carrSense); - + printf("fifoUnder :%8ld\t", ec->eth_stat.ets_fifoUnder); printf("fifoOver :%8ld\t", ec->eth_stat.ets_fifoOver); printf("CDheartbeat:%8ld\n", ec->eth_stat.ets_CDheartbeat); - + printf("OWC :%8ld\t", ec->eth_stat.ets_OWC); - + ioaddr = ec->ec_port; isr = read_csr(ioaddr, LANCE_CSR0); printf("isr = 0x%x, flags = 0x%x\n", isr, @@ -450,261 +238,19 @@ static void lance_dump() } /*===========================================================================* - * do_init * + * do_other * *===========================================================================*/ -static void do_init(mp) -message *mp; +static void do_other(const message *m_ptr, int ipc_status) { - ether_card_t *ec; - message reply_mess; - pci_init(); - - if(!lance_buf && !(lance_buf = alloc_contig(LANCE_BUF_SIZE, AC_ALIGN4K|AC_LOWER16M, &lance_buf_phys))) { - panic("alloc_contig failed: %d", LANCE_BUF_SIZE); - } - - ec= &ec_state; - strlcpy(ec->port_name, "lance#0", sizeof(ec->port_name)); - ec->port_name[6] += ec_instance; - - if (ec->mode == EC_DISABLED) - { - /* This is the default, try to (re)locate the device. */ - /* only try to enable if memory is correct for DMA */ - if ( CORRECT_DMA_MEM() ) - { - conf_hw(ec); - } - else - { - printf("LANCE: DMA denied because address out of range\n" ); - } - - if (ec->mode == EC_DISABLED) - { - /* Probe failed, or the device is configured off. */ - reply_mess.m_type= DL_CONF_REPLY; - reply_mess.m_netdrv_net_dl_conf.stat = ENXIO; - mess_reply(mp, &reply_mess); - return; - } - if (ec->mode == EC_ENABLED) - ec_init(ec); - } - - if (ec->mode == EC_SINK) - { - ec->mac_address.ea_addr[0] = - ec->mac_address.ea_addr[1] = - ec->mac_address.ea_addr[2] = - ec->mac_address.ea_addr[3] = - ec->mac_address.ea_addr[4] = - ec->mac_address.ea_addr[5] = 0; - ec_confaddr(ec); - reply_mess.m_type = DL_CONF_REPLY; - reply_mess.m_netdrv_net_dl_conf.stat = OK; - memcpy(reply_mess.m_netdrv_net_dl_conf.hw_addr, ec->mac_address.ea_addr, - sizeof(reply_mess.m_netdrv_net_dl_conf.hw_addr)); - mess_reply(mp, &reply_mess); - return; - } - assert(ec->mode == EC_ENABLED); - assert(ec->flags & ECF_ENABLED); - - ec->flags &= ~(ECF_PROMISC | ECF_MULTI | ECF_BROAD); - - if (mp->m_net_netdrv_dl_conf.mode & DL_PROMISC_REQ) - ec->flags |= ECF_PROMISC | ECF_MULTI | ECF_BROAD; - if (mp->m_net_netdrv_dl_conf.mode & DL_MULTI_REQ) - ec->flags |= ECF_MULTI; - if (mp->m_net_netdrv_dl_conf.mode & DL_BROAD_REQ) - ec->flags |= ECF_BROAD; - - ec_reinit(ec); - - reply_mess.m_type = DL_CONF_REPLY; - reply_mess.m_netdrv_net_dl_conf.stat = OK; - memcpy(reply_mess.m_netdrv_net_dl_conf.hw_addr, ec->mac_address.ea_addr, - sizeof(reply_mess.m_netdrv_net_dl_conf.hw_addr)); - - mess_reply(mp, &reply_mess); + if (is_ipc_notify(ipc_status) && m_ptr->m_source == TTY_PROC_NR) + lance_dump(); } - -/*===========================================================================* - * do_int * - *===========================================================================*/ -static void do_int(ec) -ether_card_t *ec; -{ - if (ec->flags & (ECF_PACK_SEND | ECF_PACK_RECV)) - reply(ec); -} - - -/*===========================================================================* - * conf_hw * - *===========================================================================*/ -static void conf_hw(ec) -ether_card_t *ec; -{ - static eth_stat_t empty_stat = {0, 0, 0, 0, 0, 0 /* ,... */ }; - - int confnr; - ec_conf_t *ecp; - - ec->mode= EC_DISABLED; /* Superfluous */ - - /* Pick a default configuration. This hardly matters anymore. */ - confnr= MIN(ec_instance, EC_CONF_NR-1); - - ecp= &ec_conf[confnr]; - update_conf(ec, ecp); - if (ec->mode != EC_ENABLED) - return; - - if (!lance_probe(ec, ec_instance)) - { - printf("%s: No ethernet card found on PCI-BIOS info.\n", - ec->port_name); - ec->mode= EC_DISABLED; - return; - } - - /* XXX */ if (ec->ec_linmem == 0) ec->ec_linmem= 0xFFFF0000; - - ec->flags = ECF_EMPTY; - ec->eth_stat = empty_stat; -} - - -/*===========================================================================* - * update_conf * - *===========================================================================*/ -static void update_conf(ec, ecp) -ether_card_t *ec; -ec_conf_t *ecp; -{ - long v; - char eckey[16]; - static char ec_fmt[] = "x:d:x:x"; - - /* Get the default settings and modify them from the environment. */ - strlcpy(eckey, "LANCE0", sizeof(eckey)); - eckey[5] += ec_instance; - ec->mode= EC_SINK; - v= ecp->ec_port; - switch (env_parse(eckey, ec_fmt, 0, &v, 0x0000L, 0xFFFFL)) - { - case EP_OFF: - ec->mode= EC_DISABLED; - break; - case EP_ON: - case EP_SET: - default: - ec->mode= EC_ENABLED; /* Might become disabled if - * all probes fail */ - break; - } - - ec->ec_port= v; - - v= ecp->ec_irq | DEI_DEFAULT; - (void) env_parse(eckey, ec_fmt, 1, &v, 0L, (long) NR_IRQ_VECTORS - 1); - ec->ec_irq= v; - - v= ecp->ec_mem; - (void) env_parse(eckey, ec_fmt, 2, &v, 0L, 0xFFFFFL); - ec->ec_linmem= v; - - v= 0; - (void) env_parse(eckey, ec_fmt, 3, &v, 0x2000L, 0x8000L); - ec->ec_ramsize= v; -} - - -/*===========================================================================* - * ec_init * - *===========================================================================*/ -static void ec_init(ec) -ether_card_t *ec; -{ - int r; -#if VERBOSE - int i; -#endif - - /* General initialization */ - ec->flags = ECF_EMPTY; - lance_init_card(ec); /* Get mac_address, etc ...*/ - - ec_confaddr(ec); - -#if VERBOSE - printf("%s: Ethernet address ", ec->port_name); - for (i= 0; i < 6; i++) - printf("%x%c", ec->mac_address.ea_addr[i], - i < 5 ? ':' : '\n'); -#endif - - /* Finish the initialization */ - ec->flags |= ECF_ENABLED; - - /* Set the interrupt handler */ - ec->ec_hook = ec->ec_irq; - if ((r=sys_irqsetpolicy(ec->ec_irq, 0, &ec->ec_hook)) != OK) - printf("lance: error, couldn't set IRQ policy: %d\n", r); - - return; -} - - -/*===========================================================================* - * reply * - *===========================================================================*/ -static void reply(ec) -ether_card_t *ec; -{ - message reply; - int flags,r; - - flags = DL_NOFLAGS; - if (ec->flags & ECF_PACK_SEND) - flags |= DL_PACK_SEND; - if (ec->flags & ECF_PACK_RECV) - flags |= DL_PACK_RECV; - - reply.m_type = DL_TASK_REPLY; - reply.m_netdrv_net_dl_task.flags = flags; - reply.m_netdrv_net_dl_task.count = ec->read_s; - - r = ipc_send(ec->client, &reply); - if (r < 0) - panic("ipc_send failed: %d", r); - - ec->read_s = 0; - ec->flags &= ~(ECF_PACK_SEND | ECF_PACK_RECV); -} - - -/*===========================================================================* - * mess_reply * - *===========================================================================*/ -static void mess_reply(req, reply_mess) -message *req; -message *reply_mess; -{ - if (ipc_send(req->m_source, reply_mess) != OK) - panic("unable to mess_reply"); -} - - /*===========================================================================* * ec_confaddr * *===========================================================================*/ -static void ec_confaddr(ec) -ether_card_t *ec; +static void ec_confaddr(ether_addr_t *addr) { int i; char eakey[16]; @@ -717,25 +263,68 @@ ether_card_t *ec; for (i = 0; i < 6; i++) { - v= ec->mac_address.ea_addr[i]; + v= addr->ea_addr[i]; if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET) break; - ec->mac_address.ea_addr[i]= v; + addr->ea_addr[i]= v; } - + if (i != 0 && i != 6) { /* It's all or nothing; force a panic. */ - (void) env_parse(eakey, "?", 0, &v, 0L, 0L); + panic("invalid ethernet address supplied"); } } +/*===========================================================================* + * do_init * + *===========================================================================*/ +static int do_init(unsigned int instance, ether_addr_t *addr) +{ +/* Initialize the lance driver. */ + ether_card_t *ec; +#if VERBOSE + int i, r; +#endif +#if LANCE_FKEY + int fkeys, sfkeys; +#endif + +#if LANCE_FKEY + fkeys = sfkeys = 0; + bit_set( sfkeys, 7 ); + if ( (r = fkey_map(&fkeys, &sfkeys)) != OK ) + printf("Warning: lance couldn't observe Shift+F7 key: %d\n",r); +#endif + + ec_instance = instance; + + /* Initialize the driver state. */ + ec= &ec_state; + memset(ec, 0, sizeof(*ec)); + strlcpy(ec->port_name, "lance#0", sizeof(ec->port_name)); + ec->port_name[6] += instance; + + /* See if there is a matching card. */ + if (!lance_probe(ec, instance)) + return ENXIO; + + /* Initialize the hardware. */ + lance_init_hw(ec, addr); + +#if VERBOSE + printf("%s: Ethernet address ", ec->port_name); + for (i= 0; i < 6; i++) + printf("%x%c", addr->ea_addr[i], i < 5 ? ':' : '\n'); +#endif + + return OK; +} /*===========================================================================* * ec_reinit * *===========================================================================*/ -static void ec_reinit(ec) -ether_card_t *ec; +static void ec_reinit(ether_card_t *ec) { int i; unsigned short ioaddr = ec->ec_port; @@ -784,18 +373,39 @@ ether_card_t *ec; } /*===========================================================================* - * ec_check_ints * + * do_mode * *===========================================================================*/ -static void ec_check_ints(ec) -ether_card_t *ec; +static void do_mode(unsigned int mode) { - int must_restart = 0; - int check,status; - int isr = 0x0000; - unsigned short ioaddr = ec->ec_port; + ether_card_t *ec; - if (!(ec->flags & ECF_ENABLED)) - panic("got premature interrupt"); + ec = &ec_state; + + ec->flags &= ~(ECF_PROMISC | ECF_MULTI | ECF_BROAD); + + if (mode & NDEV_PROMISC) + ec->flags |= ECF_PROMISC | ECF_MULTI | ECF_BROAD; + if (mode & NDEV_MULTI) + ec->flags |= ECF_MULTI; + if (mode & NDEV_BROAD) + ec->flags |= ECF_BROAD; + + ec_reinit(ec); +} + +/*===========================================================================* + * do_intr * + *===========================================================================*/ +static void do_intr(unsigned int __unused mask) +{ + ether_card_t *ec; + int must_restart = 0; + int r, check, status; + int isr = 0x0000; + unsigned short ioaddr; + + ec = &ec_state; + ioaddr = ec->ec_port; for (;;) { @@ -812,8 +422,6 @@ ether_card_t *ec; LANCE_CSR0_BABL|LANCE_CSR0_CERR|LANCE_CSR0_MISS|LANCE_CSR0_MERR |LANCE_CSR0_IDON|LANCE_CSR0_IENA); -#define ISR_RST 0x0000 - if ((isr & (LANCE_CSR0_TINT|LANCE_CSR0_RINT|LANCE_CSR0_MISS |LANCE_CSR0_BABL|LANCE_CSR0_ERR)) == 0x0000) { @@ -847,18 +455,18 @@ ether_card_t *ec; /* status check: restart if needed. */ status = lp->tx_ring[cur_tx_slot_nr].u.base; - /* ??? */ + /* did an error (UFLO, LCOL, LCAR, RTRY) occur? */ if (status & 0x40000000) { status = lp->tx_ring[cur_tx_slot_nr].misc; ec->eth_stat.ets_sendErr++; - if (status & 0x0400) + if (status & 0x0400) /* RTRY */ ec->eth_stat.ets_transAb++; - if (status & 0x0800) + if (status & 0x0800) /* LCAR */ ec->eth_stat.ets_carrSense++; - if (status & 0x1000) + if (status & 0x1000) /* LCOL */ ec->eth_stat.ets_OWC++; - if (status & 0x4000) + if (status & 0x4000) /* UFLO */ { ec->eth_stat.ets_fifoUnder++; must_restart=1; @@ -896,55 +504,43 @@ ether_card_t *ec; } /* we set a buffered message in the slot if it exists. */ /* and transmit it, if needed. */ - if (ec->flags & ECF_SEND_AVAIL) - ec_send(ec); + if (!must_restart) + netdriver_send(); } if (isr & LANCE_CSR0_RINT) { #if VERBOSE printf("RX INT\n"); #endif - ec_recv(ec); + netdriver_recv(); } - if (isr & ISR_RST) - { - ec->flags = ECF_STOPPED; -#if VERBOSE - printf("ISR_RST\n"); -#endif - break; - } - - /* ??? cf. lance driver on linux */ if (must_restart == 1) { #if VERBOSE printf("ETH: restarting...\n"); #endif - /* stop */ - write_csr(ioaddr, LANCE_CSR0, LANCE_CSR0_STOP); - /* start */ - write_csr(ioaddr, LANCE_CSR0, LANCE_CSR0_STRT); + + ec_reset(ec); } } - if ((ec->flags & (ECF_READING|ECF_STOPPED)) == (ECF_READING|ECF_STOPPED)) - { -#if VERBOSE - printf("ETH: resetting...\n"); -#endif - ec_reset(ec); - } + /* reenable interrupts */ + if ((r = sys_irqenable(&ec->ec_hook)) != OK) + panic("couldn't enable interrupt: %d", r); } /*===========================================================================* * ec_reset * *===========================================================================*/ -static void ec_reset(ec) -ether_card_t *ec; +static void ec_reset(ether_card_t *ec) { - /* Stop/start the chip, and clear all RX,TX-slots */ + /* Stop/start the chip, and clear all RX,TX-slots. The spec says this type + * of reset should be done on MERR, UFLO, and TX BUFF errors. For now it is + * called only for UFLO and TX BUFF (which causes UFLO). MERR is not (yet?) + * handled. Also note that the PCnet spec says that the LANCE chip does not + * require resetting Rx/Tx, but PCnet does. We intend to support both here. + */ unsigned short ioaddr = ec->ec_port; int i; @@ -969,185 +565,101 @@ ether_card_t *ec; lp->rx_ring[i].u.addr[3] |= 0x80; } - /* store a buffered message on the slot if exists */ - ec_send(ec); - ec->flags &= ~ECF_STOPPED; + /* store a buffered message on the slot if it exists */ + netdriver_send(); } /*===========================================================================* - * ec_send * + * do_recv * *===========================================================================*/ -static void ec_send(ec) -ether_card_t *ec; +static ssize_t do_recv(struct netdriver_data *data, size_t max) { - /* from ec_check_ints() or ec_reset(). */ - /* this function proccesses the buffered message. (slot/transmit) */ - if (!(ec->flags & ECF_SEND_AVAIL)) - return; - - ec->flags &= ~ECF_SEND_AVAIL; - switch(ec->sendmsg.m_type) - { - case DL_WRITEV_S: do_vwrite_s(&ec->sendmsg, TRUE); break; - default: - panic("wrong type: %d", ec->sendmsg.m_type); - break; - } -} - -/*===========================================================================* - * do_vread_s * - *===========================================================================*/ -static void do_vread_s(const message *mp) -{ - int count, r; ether_card_t *ec; - - ec= &ec_state; - - ec->client= mp->m_source; - count = mp->m_net_netdrv_dl_readv_s.count; - - r = sys_safecopyfrom(mp->m_source, mp->m_net_netdrv_dl_readv_s.grant, 0, - (vir_bytes)ec->read_iovec.iod_iovec, - (count > IOVEC_NR ? IOVEC_NR : count) * - sizeof(iovec_s_t)); - if (r != OK) - panic("do_vread_s: sys_safecopyfrom failed: %d", r); - ec->read_iovec.iod_iovec_s = count; - ec->read_iovec.iod_proc_nr = mp->m_source; - ec->read_iovec.iod_grant = mp->m_net_netdrv_dl_readv_s.grant; - ec->read_iovec.iod_iovec_offset = 0; - - ec->tmp_iovec = ec->read_iovec; - - ec->flags |= ECF_READING; - - ec_recv(ec); - - if ((ec->flags & (ECF_READING|ECF_STOPPED)) == (ECF_READING|ECF_STOPPED)) - ec_reset(ec); - reply(ec); -} - -/*===========================================================================* - * ec_recv * - *===========================================================================*/ -static void ec_recv(ec) -ether_card_t *ec; -{ vir_bytes length; int packet_processed; int status; - unsigned short ioaddr = ec->ec_port; + unsigned short ioaddr; - if ((ec->flags & ECF_READING)==0) - return; - if (!(ec->flags & ECF_ENABLED)) - return; + ec = &ec_state; + ioaddr = ec->ec_port; /* we check all the received slots until find a properly received packet */ packet_processed = FALSE; while (!packet_processed) { status = lp->rx_ring[rx_slot_nr].u.base >> 24; - if ( (status & 0x80) == 0x00 ) + + /* is the slot marked as ready? */ + if ( (status & 0x80) != 0x00 ) + return SUSPEND; /* no */ + + /* did an error occur? */ + if (status != 0x03) { - status = lp->rx_ring[rx_slot_nr].u.base >> 24; - - /* ??? */ - if (status != 0x03) - { - if (status & 0x01) - ec->eth_stat.ets_recvErr++; - if (status & 0x04) - ec->eth_stat.ets_fifoOver++; - if (status & 0x08) - ec->eth_stat.ets_CRCerr++; - if (status & 0x10) - ec->eth_stat.ets_OVW++; - if (status & 0x20) - ec->eth_stat.ets_frameAll++; - length = 0; - } - else - { - ec->eth_stat.ets_packetR++; - length = lp->rx_ring[rx_slot_nr].msg_length; - } - if (length > 0) - { - ec_nic2user(ec, (int)(lp->rbuf[rx_slot_nr]), - &ec->read_iovec, 0, length); - - ec->read_s = length; - ec->flags |= ECF_PACK_RECV; - ec->flags &= ~ECF_READING; - packet_processed = TRUE; - } - /* set up this slot again, and we move to the next slot */ - lp->rx_ring[rx_slot_nr].buf_length = -ETH_FRAME_LEN; - lp->rx_ring[rx_slot_nr].u.addr[3] |= 0x80; - - write_csr(ioaddr, LANCE_CSR0, - LANCE_CSR0_BABL|LANCE_CSR0_CERR|LANCE_CSR0_MISS - |LANCE_CSR0_MERR|LANCE_CSR0_IDON|LANCE_CSR0_IENA); - - rx_slot_nr = (rx_slot_nr + 1) & RX_RING_MOD_MASK; + if (status & 0x01) + ec->eth_stat.ets_recvErr++; + if (status & 0x04) + ec->eth_stat.ets_fifoOver++; + if (status & 0x08) + ec->eth_stat.ets_CRCerr++; + if (status & 0x10) + ec->eth_stat.ets_OVW++; + if (status & 0x20) + ec->eth_stat.ets_frameAll++; + length = 0; } else - break; + { + ec->eth_stat.ets_packetR++; + length = lp->rx_ring[rx_slot_nr].msg_length; + } + + /* do we now have a valid packet? */ + if (length > 0) + { + if (length > max) + length = max; + netdriver_copyout(data, 0, lp->rbuf[rx_slot_nr], length); + packet_processed = TRUE; + } + + /* set up this slot again, and we move to the next slot */ + lp->rx_ring[rx_slot_nr].buf_length = -ETH_FRAME_LEN; + lp->rx_ring[rx_slot_nr].u.addr[3] |= 0x80; + + write_csr(ioaddr, LANCE_CSR0, + LANCE_CSR0_BABL|LANCE_CSR0_CERR|LANCE_CSR0_MISS + |LANCE_CSR0_MERR|LANCE_CSR0_IDON|LANCE_CSR0_IENA); + + rx_slot_nr = (rx_slot_nr + 1) & RX_RING_MOD_MASK; } + + /* return the length of the packet we have received */ + return length; } /*===========================================================================* - * do_vwrite_s * + * do_send * *===========================================================================*/ -static void do_vwrite_s(mp, from_int) -message *mp; -int from_int; +static int do_send(struct netdriver_data *data, size_t size) { - int count, check, r; + int check; ether_card_t *ec; unsigned short ioaddr; ec = &ec_state; - ec->client= mp->m_source; - count = mp->m_net_netdrv_dl_writev_s.count; - + /* if all slots are used, this request must be deferred */ if (isstored[tx_slot_nr]==1) - { - /* all slots are used, so this message is buffered */ - ec->sendmsg= *mp; - ec->flags |= ECF_SEND_AVAIL; - reply(ec); - return; - } + return SUSPEND; - /* convert the message to write_iovec */ - r = sys_safecopyfrom(mp->m_source, mp->m_net_netdrv_dl_writev_s.grant, 0, - (vir_bytes)ec->write_iovec.iod_iovec, - (count > IOVEC_NR ? IOVEC_NR : count) * - sizeof(iovec_s_t)); - if (r != OK) - panic("do_vwrite_s: sys_safecopyfrom failed: %d", r); - ec->write_iovec.iod_iovec_s = count; - ec->write_iovec.iod_proc_nr = mp->m_source; - ec->write_iovec.iod_grant = mp->m_net_netdrv_dl_writev_s.grant; - ec->write_iovec.iod_iovec_offset = 0; + /* copy the packet to the slot on DMA address */ + netdriver_copyin(data, 0, lp->tbuf[tx_slot_nr], size); - ec->tmp_iovec = ec->write_iovec; - ec->write_s = calc_iovec_size(&ec->tmp_iovec); - - /* copy write_iovec to the slot on DMA address */ - ec_user2nic(ec, &ec->write_iovec, 0, - (int)(lp->tbuf[tx_slot_nr]), ec->write_s); /* set-up for transmitting, and transmit it if needed. */ - lp->tx_ring[tx_slot_nr].buf_length = -ec->write_s; + lp->tx_ring[tx_slot_nr].buf_length = -size; lp->tx_ring[tx_slot_nr].misc = 0x0; - lp->tx_ring[tx_slot_nr].u.base - = virt_to_bus(lp->tbuf[tx_slot_nr]) & 0xffffff; + lp->tx_ring[tx_slot_nr].u.base = tx_ring_base[tx_slot_nr]; isstored[tx_slot_nr]=1; if (cur_tx_slot_nr == tx_slot_nr) check=1; @@ -1161,198 +673,44 @@ int from_int; lp->tx_ring[cur_tx_slot_nr].u.addr[3] = 0x83; write_csr(ioaddr, LANCE_CSR0, LANCE_CSR0_IENA|LANCE_CSR0_TDMD); } - - ec->flags |= ECF_PACK_SEND; - /* reply by calling do_int() if this function is called from interrupt. */ - if (from_int) - return; - reply(ec); -} - - -/*===========================================================================* - * ec_user2nic * - *===========================================================================*/ -static void ec_user2nic(ec, iovp, offset, nic_addr, count) -ether_card_t *ec; -iovec_dat_t *iovp; -vir_bytes offset; -int nic_addr; -vir_bytes count; -{ - int bytes, i, r; - - i= 0; - while (count > 0) - { - if (i >= IOVEC_NR) - { - ec_next_iovec(iovp); - i= 0; - continue; - } - if (offset >= iovp->iod_iovec[i].iov_size) - { - offset -= iovp->iod_iovec[i].iov_size; - i++; - continue; - } - bytes = iovp->iod_iovec[i].iov_size - offset; - if (bytes > count) - bytes = count; - - if ( (r=sys_safecopyfrom(iovp->iod_proc_nr, - iovp->iod_iovec[i].iov_grant, offset, - nic_addr, bytes )) != OK ) - panic("ec_user2nic: sys_safecopyfrom failed: %d", r); - - count -= bytes; - nic_addr += bytes; - offset += bytes; - } + return OK; } /*===========================================================================* - * ec_nic2user * + * do_stat * *===========================================================================*/ -static void ec_nic2user(ec, nic_addr, iovp, offset, count) -ether_card_t *ec; -int nic_addr; -iovec_dat_t *iovp; -vir_bytes offset; -vir_bytes count; +static void do_stat(eth_stat_t *stat) { - int bytes, i, r; - i= 0; - while (count > 0) - { - if (i >= IOVEC_NR) - { - ec_next_iovec(iovp); - i= 0; - continue; - } - if (offset >= iovp->iod_iovec[i].iov_size) - { - offset -= iovp->iod_iovec[i].iov_size; - i++; - continue; - } - bytes = iovp->iod_iovec[i].iov_size - offset; - if (bytes > count) - bytes = count; - if ( (r=sys_safecopyto( iovp->iod_proc_nr, iovp->iod_iovec[i].iov_grant, - offset, nic_addr, bytes )) != OK ) - panic("ec_nic2user: sys_safecopyto failed: %d", r); - - count -= bytes; - nic_addr += bytes; - offset += bytes; - } -} - - -/*===========================================================================* - * calc_iovec_size * - *===========================================================================*/ -static int calc_iovec_size(iovec_dat_t *iovp) -{ - int size,i; - - size = i = 0; - - while (i < iovp->iod_iovec_s) - { - if (i >= IOVEC_NR) - { - ec_next_iovec(iovp); - i= 0; - continue; - } - size += iovp->iod_iovec[i].iov_size; - i++; - } - - return size; + memcpy(stat, &ec_state.eth_stat, sizeof(*stat)); } /*===========================================================================* - * ec_next_iovec * + * do_stop * *===========================================================================*/ -static void ec_next_iovec(iovp) -iovec_dat_t *iovp; +static void do_stop(void) { - int r; - - iovp->iod_iovec_s -= IOVEC_NR; - iovp->iod_iovec_offset += IOVEC_NR * sizeof(iovec_s_t); - - r = sys_safecopyfrom(iovp->iod_proc_nr, iovp->iod_grant, - iovp->iod_iovec_offset, - (vir_bytes)iovp->iod_iovec, - (iovp->iod_iovec_s > IOVEC_NR ? - IOVEC_NR : iovp->iod_iovec_s) * - sizeof(iovec_s_t)); - if (r != OK) - panic("ec_next_iovec: sys_safecopyfrom failed: %d", r); -} - - -/*===========================================================================* - * do_getstat_s * - *===========================================================================*/ -static void do_getstat_s(mp) -message *mp; -{ - int r; ether_card_t *ec; - - ec= &ec_state; - - r = sys_safecopyto(mp->m_source, mp->m_net_netdrv_dl_getstat_s.grant, 0, - (vir_bytes)&ec->eth_stat, sizeof(ec->eth_stat)); - - if (r != OK) - panic("do_getstat_s: sys_safecopyto failed: %d", r); - - mp->m_type= DL_STAT_REPLY; - r= ipc_send(mp->m_source, mp); - if (r != OK) - panic("do_getstat_s: send failed: %d", r); -} - -/*===========================================================================* - * lance_stop * - *===========================================================================*/ -static void lance_stop(ec) -ether_card_t *ec; -{ unsigned short ioaddr; - if (!(ec->flags & ECF_ENABLED)) - return; + ec = &ec_state; ioaddr = ec->ec_port; - + /* stop */ write_csr(ioaddr, LANCE_CSR0, LANCE_CSR0_STOP); /* Reset */ in_word(ioaddr+LANCE_RESET); - - ec->flags = ECF_EMPTY; } /*===========================================================================* - * getAddressing * + * get_addressing * *===========================================================================*/ -static void getAddressing(devind, ec) -int devind; -ether_card_t *ec; +static void get_addressing(int devind, ether_card_t *ec) { - unsigned int membase, ioaddr; + unsigned int ioaddr; int reg, irq; for (reg = PCI_BAR; reg <= PCI_BAR_6; reg += 4) @@ -1363,25 +721,20 @@ ether_card_t *ec; continue; /* Strip the I/O address out of the returned value */ ioaddr &= PCI_BAR_IO_MASK; - /* Get the memory base address */ - membase = pci_attr_r32(devind, PCI_BAR_2); - /* KK: Get the IRQ number */ - irq = pci_attr_r8(devind, PCI_IPR); - if (irq) - irq = pci_attr_r8(devind, PCI_ILR); - - ec->ec_linmem = membase; ec->ec_port = ioaddr; - ec->ec_irq = irq; } + + /* KK: Get the IRQ number */ + irq = pci_attr_r8(devind, PCI_IPR); + if (irq) + irq = pci_attr_r8(devind, PCI_ILR); + ec->ec_irq = irq; } /*===========================================================================* * lance_probe * *===========================================================================*/ -static int lance_probe(ec, skip) -ether_card_t *ec; -int skip; +static int lance_probe(ether_card_t *ec, unsigned int skip) { unsigned short pci_cmd; unsigned short ioaddr; @@ -1389,6 +742,8 @@ int skip; int devind, r; u16_t vid, did; + pci_init(); + r= pci_first_dev(&devind, &vid, &did); if (r == 0) return 0; @@ -1402,8 +757,7 @@ int skip; pci_reserve(devind); - getAddressing(devind, ec); - + get_addressing(devind, ec); /* ===== Bus Master ? ===== */ pci_cmd = pci_attr_r32(devind, PCI_CR); @@ -1420,7 +774,7 @@ int skip; if (read_csr(ioaddr, LANCE_CSR0) != LANCE_CSR0_STOP) { - ec->mode=EC_DISABLED; + return 0; } /* Probe Chip Version */ @@ -1434,7 +788,7 @@ int skip; if ((chip_version & 0xfff) != 0x3) { - ec->mode=EC_DISABLED; + return 0; } chip_version = (chip_version >> 12) & 0xffff; for (lance_version = 1; chip_table[lance_version].id_number != 0; @@ -1453,18 +807,38 @@ int skip; } /*===========================================================================* - * lance_init_card * + * virt_to_bus * *===========================================================================*/ -static void lance_init_card(ec) -ether_card_t *ec; +static phys_bytes virt_to_bus(void *ptr) { - int i; - Address l = (vir_bytes)lance_buf; + phys_bytes value; + int r; + + if ((r = sys_umap(SELF, VM_D, (vir_bytes)ptr, 4, &value)) != OK) + panic("sys_umap failed: %d", r); + + return value; +} + +/*===========================================================================* + * lance_init_hw * + *===========================================================================*/ +static void lance_init_hw(ether_card_t *ec, ether_addr_t *addr) +{ + phys_bytes lance_buf_phys; + int i, r; + Address l; unsigned short ioaddr = ec->ec_port; /* ============= setup init_block(cf. lance_probe1) ================ */ /* make sure data structure is 8-byte aligned and below 16MB (for DMA) */ + /* Allocate memory */ + if ((lance_buf = alloc_contig(LANCE_BUF_SIZE, AC_ALIGN4K|AC_LOWER16M, + &lance_buf_phys)) == NULL) + panic("alloc_contig failed: %d", LANCE_BUF_SIZE); + + l = (vir_bytes)lance_buf; lp = (struct lance_interface *)l; /* disable Tx and Rx */ @@ -1485,7 +859,10 @@ ether_card_t *ec; /* ============= Get MAC address (cf. lance_probe1) ================ */ for (i = 0; i < 6; ++i) - ec->mac_address.ea_addr[i]=in_byte(ioaddr+LANCE_ETH_ADDR+i); + addr->ea_addr[i]=in_byte(ioaddr+LANCE_ETH_ADDR+i); + + /* Allow the user to override the hardware address. */ + ec_confaddr(addr); /* ============ (re)start init_block(cf. lance_reset) =============== */ /* Reset the LANCE */ @@ -1494,7 +871,7 @@ ether_card_t *ec; /* ----- Re-initialize the LANCE ----- */ /* Set station address */ for (i = 0; i < 6; ++i) - lp->init_block.phys_addr[i] = ec->mac_address.ea_addr[i]; + lp->init_block.phys_addr[i] = addr->ea_addr[i]; /* Preset the receive ring headers */ for (i=0; itx_ring[i].u.base = 0; + tx_ring_base[i] = virt_to_bus(lp->tbuf[i]) & 0xffffff; isstored[i] = 0; } /* enable Rx and Tx */ @@ -1553,11 +931,16 @@ ether_card_t *ec; } } + /* Set the interrupt handler */ + ec->ec_hook = ec->ec_irq; + if ((r=sys_irqsetpolicy(ec->ec_irq, 0, &ec->ec_hook)) != OK) + panic("couldn't set IRQ policy: %d", r); + if ((r = sys_irqenable(&ec->ec_hook)) != OK) + panic("couldn't enable interrupt: %d", r); + /* start && enable interrupt */ write_csr(ioaddr, LANCE_CSR0, LANCE_CSR0_IDON|LANCE_CSR0_IENA|LANCE_CSR0_STRT); - - return; } /*===========================================================================* diff --git a/minix/drivers/net/lance/lance.h b/minix/drivers/net/lance/lance.h index 6b79a35a7..5a1b3e5dc 100644 --- a/minix/drivers/net/lance/lance.h +++ b/minix/drivers/net/lance/lance.h @@ -1,39 +1,8 @@ -/* macros for 'mode' */ -#define EC_DISABLED 0x0 -#define EC_SINK 0x1 -#define EC_ENABLED 0x2 - /* macros for 'flags' */ -#define ECF_EMPTY 0x000 -#define ECF_PACK_SEND 0x001 -#define ECF_PACK_RECV 0x002 -#define ECF_SEND_AVAIL 0x004 -#define ECF_READING 0x010 -#define ECF_PROMISC 0x040 -#define ECF_MULTI 0x080 -#define ECF_BROAD 0x100 -#define ECF_ENABLED 0x200 -#define ECF_STOPPED 0x400 - -/* === macros for ether cards (our generalized version) === */ -#define EC_ISR_RINT 0x0001 -#define EC_ISR_WINT 0x0002 -#define EC_ISR_RERR 0x0010 -#define EC_ISR_WERR 0x0020 -#define EC_ISR_ERR 0x0040 -#define EC_ISR_RST 0x0100 - -/* IOVEC */ -#define IOVEC_NR 16 -typedef struct iovec_dat -{ - iovec_s_t iod_iovec[IOVEC_NR]; - int iod_iovec_s; - endpoint_t iod_proc_nr; - cp_grant_id_t iod_grant; - vir_bytes iod_iovec_offset; -} iovec_dat_t; +#define ECF_PROMISC 0x01 +#define ECF_MULTI 0x02 +#define ECF_BROAD 0x04 /* ====== ethernet card info. ====== */ typedef struct ether_card @@ -41,35 +10,14 @@ typedef struct ether_card /* ####### MINIX style ####### */ char port_name[sizeof("lance#n")]; int flags; - int mode; - int transfer_mode; eth_stat_t eth_stat; - iovec_dat_t read_iovec; - iovec_dat_t write_iovec; - iovec_dat_t tmp_iovec; - vir_bytes write_s; - vir_bytes read_s; - int client; - message sendmsg; /* ######## device info. ####### */ port_t ec_port; - phys_bytes ec_linmem; int ec_irq; - int ec_int_pending; int ec_hook; - - int ec_ramsize; - - /* Addrassing */ - u16_t ec_memseg; - vir_bytes ec_memoff; - - ether_addr_t mac_address; } ether_card_t; -#define DEI_DEFAULT 0x8000 - /* * NOTE: Not all the CSRs are defined. Just the ones that were deemed * necessary or potentially useful. diff --git a/minix/drivers/net/orinoco/Makefile b/minix/drivers/net/orinoco/Makefile index 172e7d319..a71e040a0 100644 --- a/minix/drivers/net/orinoco/Makefile +++ b/minix/drivers/net/orinoco/Makefile @@ -2,8 +2,8 @@ PROG= orinoco SRCS= orinoco.c hermes.c -DPADD+= ${LIBNETDRIVER} ${LIBSYS} ${LIBTIMERS} -LDADD+= -lnetdriver -lsys -ltimers +DPADD+= ${LIBNETDRIVER} ${LIBSYS} +LDADD+= -lnetdriver -lsys CPPFLAGS.orinoco.c+= -I${NETBSDSRCDIR}/minix diff --git a/minix/drivers/net/orinoco/orinoco.c b/minix/drivers/net/orinoco/orinoco.c index b6632f080..fd71ffa2a 100644 --- a/minix/drivers/net/orinoco/orinoco.c +++ b/minix/drivers/net/orinoco/orinoco.c @@ -2,52 +2,26 @@ * orinoco.c * * This file contains a wireless device driver for Prism based wireless - * cards. + * cards. * - * Created by Stevens Le Blond + * Created by Stevens Le Blond * and Michael Valkering * */ #include #include -#include -#include -#include -#include -#include #include #include -#include -#include -#include "kernel/const.h" -#include "kernel/config.h" -#include "kernel/type.h" +#include #define VERBOSE 1 /* display message during init */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include "assert.h" #include "hermes.h" #include "hermes_rid.h" #include "orinoco.h" -#define ERR -1 - -#define debug 0 - #define OR_M_ENABLED 1 #define OR_M_DISABLED 0 #define OR_F_EMPTY 0 @@ -71,7 +45,6 @@ #define ETH_HLEN 14 static t_or or_state; -static int or_instance; struct ethhdr { u8_t h_dest[ETH_ALEN]; @@ -110,7 +83,7 @@ static const long channel_frequency[] = { #define NUM_CHANNELS (sizeof(channel_frequency) / sizeof(channel_frequency[0])) -/* This tables gives the actual meanings of the bitrate IDs returned by the +/* This tables gives the actual meanings of the bitrate IDs returned by the * firmware. Not used yet */ struct { int bitrate; /* in 100s of kilobits */ @@ -129,46 +102,39 @@ struct { #define BITRATE_TABLE_SIZE (sizeof(bitrate_table) / sizeof(bitrate_table[0])) - -static void or_writev_s(message * mp, int from_int); -static void or_readv_s(message * mp, int from_int); -static void reply(t_or * orp); -static int or_probe(t_or *, int skip); +static void or_other(const message *m_ptr, int ipc_status); +static void or_stop(void); +static int or_probe(t_or *, unsigned int skip); static void or_ev_info(t_or *); -static void or_init(message *); -static void or_pci_conf(void); -static void or_init_struct(t_or *); -static void map_hw_buffer(t_or *); -static void or_init_hw(t_or *); +static int or_init(unsigned int instance, ether_addr_t *addr); +static void or_init_struct(t_or *, unsigned int); +static void or_init_hw(t_or *, ether_addr_t *); static void or_check_ints(t_or *); static void or_writerids(hermes_t *, t_or *); -static void or_readrids(hermes_t *, t_or *); -static void or_rec_mode(t_or *); -static void mess_reply(message *, message *); +static void or_readrids(hermes_t *, t_or *, ether_addr_t *); static u32_t or_get_bar(int devind, t_or * orp); -static void or_getstat_s(message * mp); +static void or_stat(eth_stat_t *stat); static void print_linkstatus(t_or * orp, u16_t status); +static ssize_t or_recv(struct netdriver_data *data, size_t max); static int or_get_recvd_packet(t_or *orp, u16_t rxfid, u8_t *databuf); static void or_reset(void); -static void or_watchdog_f(minix_timer_t *tp); +static void or_alarm(clock_t stamp); +static int or_send(struct netdriver_data *data, size_t size); static void setup_wepkey(t_or *orp, char *wepkey0); -static void do_hard_int(void); -static void check_int_events(void); +static void or_intr(unsigned int mask); static void or_handler(t_or *orp); -static void or_dump(message *m); +static void or_dump(void); -/* The message used in the main loop is made global, so that rl_watchdog_f() - * can change its message type to fake an interrupt message. - */ -static message m; -static int int_event_check; /* set to TRUE if events arrived */ - -static u32_t system_hz; - -/* SEF functions and variables. */ -static void sef_local_startup(void); -static int sef_cb_init_fresh(int type, sef_init_info_t *info); -static void sef_cb_signal_handler(int signo); +static const struct netdriver or_table = { + .ndr_init = or_init, + .ndr_stop = or_stop, + .ndr_recv = or_recv, + .ndr_send = or_send, + .ndr_stat = or_stat, + .ndr_intr = or_intr, + .ndr_alarm = or_alarm, + .ndr_other = or_other +}; /***************************************************************************** * main * @@ -176,164 +142,62 @@ static void sef_cb_signal_handler(int signo); * * * The main function of the driver, receiving and processing messages * *****************************************************************************/ -int main(int argc, char *argv[]) { - int r; - int ipc_status; - - /* SEF local startup. */ +int main(int argc, char *argv[]) +{ env_setargs(argc, argv); - sef_local_startup(); - while (TRUE) { - if ((r = netdriver_receive (ANY, &m, &ipc_status)) != OK) - panic("orinoco: netdriver_receive failed"); + netdriver_task(&or_table); - if (is_ipc_notify(ipc_status)) { - switch (_ENDPOINT_P(m.m_source)) { - case CLOCK: - or_watchdog_f(NULL); - break; - case HARDWARE: - do_hard_int(); - if (int_event_check) - check_int_events(); - break ; - case TTY_PROC_NR: - or_dump(&m); - break; - default: - panic("orinoco: illegal notify from: %d", - m.m_source); - } - - /* done, get new message */ - continue; - } - - switch (m.m_type) { - case DL_WRITEV_S: - or_writev_s (&m, FALSE); - break; - case DL_READV_S: - or_readv_s (&m, FALSE); - break; - case DL_CONF: - or_init (&m); - break; - case DL_GETSTAT_S: - or_getstat_s (&m); - break; - default: - panic("orinoco: illegal message: %d", m.m_type); - } - } -} - -/*===========================================================================* - * sef_local_startup * - *===========================================================================*/ -static void sef_local_startup() -{ - /* Register init callbacks. */ - sef_setcb_init_fresh(sef_cb_init_fresh); - sef_setcb_init_lu(sef_cb_init_fresh); - sef_setcb_init_restart(sef_cb_init_fresh); - - /* Register live update callbacks. */ - sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready); - sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_workfree); - - /* Register signal callbacks. */ - sef_setcb_signal_handler(sef_cb_signal_handler); - - /* Let SEF perform startup. */ - sef_startup(); -} - -/*===========================================================================* - * sef_cb_init_fresh * - *===========================================================================*/ -static int sef_cb_init_fresh(int type, sef_init_info_t *info) -{ -/* Initialize the orinoco driver. */ - long v; - int fkeys, sfkeys, r; - - system_hz = sys_hz(); - - v = 0; - (void) env_parse("instance", "d", 0, &v, 0, 255); - or_instance = (int) v; - - /* Observe some function key for debug dumps. */ - fkeys = sfkeys = 0; bit_set(sfkeys, 11); - if ((r=fkey_map(&fkeys, &sfkeys)) != OK) - printf("Warning: orinoco couldn't observe F-key(s): %d\n",r); - - /* Announce we are up! */ - netdriver_announce(); - - return(OK); -} - -/*===========================================================================* - * sef_cb_signal_handler * - *===========================================================================*/ -static void sef_cb_signal_handler(int signo) -{ - t_or *orp; - - /* Only check for termination signal, ignore anything else. */ - if (signo != SIGTERM) return; - - orp = &or_state; - - if (orp->or_mode == OR_M_ENABLED) { - /* TODO: send a signal to the card to shut it down */ - } - exit(0); + return 0; } /***************************************************************************** - * check_int_events * + * or_other * * * - * If a hard interrupt message came in, call the or_check_ints for the right * - * card * + * * + * Process miscellaneous messages * *****************************************************************************/ -static void check_int_events(void) { - t_or *orp; - - /* the interrupt message doesn't contain information about the port, try - * to find it */ - orp = &or_state; - - if (orp->or_mode != OR_M_ENABLED) - return; - if (!orp->or_got_int) - return; - orp->or_got_int = 0; - assert (orp->or_flags & OR_F_ENABLED); - or_check_ints (orp); - +static void or_other(const message *m_ptr, int ipc_status) +{ + if (is_ipc_notify(ipc_status) && m_ptr->m_source == TTY_PROC_NR) + or_dump(); } /***************************************************************************** - * do_hard_int * + * or_stop * + * * + * Stop the card * + *****************************************************************************/ +static void or_stop(void) +{ + t_or *orp; + + orp = &or_state; + + /* TODO: send a signal to the card to shut it down */ +} + +/***************************************************************************** + * or_intr * * * * Process the interrupts which the card generated * *****************************************************************************/ -static void do_hard_int(void) +static void or_intr(unsigned int __unused mask) { + t_or *orp; int s; + orp = &or_state; + /* Run interrupt handler at driver level. */ - or_handler(&or_state); + or_handler(orp); /* Reenable interrupts for this hook. */ - if ((s=sys_irqenable(&or_state.or_hook_id)) != OK) { - printf("orinoco: error, couldn't enable"); - printf(" interrupts: %d\n", s); - } + if ((s=sys_irqenable(&orp->or_hook_id)) != OK) + printf("orinoco: error, couldn't enable interrupts: %d\n", s); + + /* Perform tasks based on the flagged conditions. */ + or_check_ints(orp); } /***************************************************************************** @@ -342,42 +206,36 @@ static void do_hard_int(void) * Sometime the card gets screwed, behaving erratically. Solution: reset the * * card. This is actually largely redoing the initialization * *****************************************************************************/ -static void or_reset() { - static clock_t last_reset, now; +static void or_reset(void) +{ + static clock_t last_reset, now; t_or *orp; int i, r; if (OK != (r = getticks(&now))) panic("orinoco: getuptime() failed: %d", r); - if(now - last_reset < system_hz * 10) { + if(now - last_reset < sys_hz() * 10) { printf("Resetting card too often. Going to reset driver\n"); exit(1); } last_reset = now; - + orp = &or_state; - if(orp->or_mode == OR_M_DISABLED) - printf("orinoco instance %d is disabled\n", or_instance); - - if(orp->or_mode != OR_M_ENABLED) { - return; - } - - orp->or_need_reset = 0; - or_init_hw(orp); + orp->or_need_reset = FALSE; + or_init_hw(orp, NULL); orp->rx_last = orp->rx_first = 0; for(i = 0; i < NR_RX_BUFS; i++) { orp->rx_length[0] = 0; } - if(orp->or_flags & OR_F_SEND_AVAIL) { - orp->or_tx.ret_busy = FALSE; - orp->or_send_int = TRUE; - } + if (orp->or_tx.ret_busy) + orp->or_tx_busy--; + orp->or_tx.ret_busy = FALSE; + orp->or_send_int = TRUE; } /***************************************************************************** @@ -386,24 +244,17 @@ static void or_reset() { * Dump interesting information about the card on F-key pressed. * * Not implemented yet * *****************************************************************************/ -static void or_dump (message *m) - { +static void or_dump(void) +{ t_or *orp; int sfkeys; orp = &or_state; - if(orp->or_mode == OR_M_DISABLED) { - printf("%s is disabled\n", orp->or_name); - } - - if(orp->or_mode != OR_M_ENABLED) - return; - if(OK != fkey_events(NULL, &sfkeys)) { printf("Contacting the TTY failed\n"); } - + if(bit_isset(sfkeys, 11)) { print_linkstatus(orp, orp->last_linkstatus); } @@ -412,88 +263,34 @@ static void or_dump (message *m) /***************************************************************************** * or_init * * * - * The main initialization function, called when a DL_INIT message comes in. * + * The main initialization function, called at startup. * *****************************************************************************/ -static void or_init (message * mp) { +static int or_init(unsigned int instance, ether_addr_t *addr) +{ + int fkeys, sfkeys, r; t_or *orp; - message reply; - static int first_time = 1; - - if (first_time) { - first_time = 0; - or_pci_conf (); /* Configure PCI devices. */ - - /* Use a synchronous alarm instead of a watchdog timer. */ - sys_setalarm(system_hz, 0); - } orp = &or_state; - if (orp->or_mode == OR_M_DISABLED) { - /* Initialize the orp structure */ - or_init_struct (orp); - if (orp->or_mode == OR_M_DISABLED) { - reply.m_type = DL_CONF_REPLY; - reply.m_netdrv_net_dl_conf.stat = ENXIO; - mess_reply (mp, &reply); - return; - } - if (orp->or_mode == OR_M_ENABLED) { - /* initialize card, hardware/firmware */ - orp->or_flags |= OR_F_ENABLED; - or_init_hw (orp); - } - } + /* Initialize the orp structure */ + or_init_struct(orp, instance); - assert (orp->or_mode == OR_M_ENABLED); - assert (orp->or_flags & OR_F_ENABLED); - - /* Not supported by the driver yet, but set a couple of options: - * multicasting, promiscuity, broadcasting, depending on the users - * needs */ - orp->or_flags &= ~(OR_F_PROMISC | OR_F_MULTI | OR_F_BROAD); - if (mp->m_net_netdrv_dl_conf.mode & DL_PROMISC_REQ) - orp->or_flags |= OR_F_PROMISC; - if (mp->m_net_netdrv_dl_conf.mode & DL_MULTI_REQ) - orp->or_flags |= OR_F_MULTI; - if (mp->m_net_netdrv_dl_conf.mode & DL_BROAD_REQ) - orp->or_flags |= OR_F_BROAD; - - or_rec_mode (orp); - - /* reply the caller that the configuration succeeded */ - reply.m_type = DL_CONF_REPLY; - reply.m_netdrv_net_dl_conf.stat = OK; - memcpy(reply.m_netdrv_net_dl_conf.hw_addr, orp->or_address.ea_addr, - sizeof(reply.m_netdrv_net_dl_conf.hw_addr)); - mess_reply (mp, &reply); -} - -/***************************************************************************** - * or_pci_conf * - * * - * Configure the pci related issues of the card, e.g. finding out where the * - * card is in the pci configuration, it's assigned irq, etc. This can be * - * done if the boot monitor is provided with information, or the pci bus * - * can be searched (at the end: or_probe function) * - *****************************************************************************/ -static void or_pci_conf () { - t_or *orp; - - /* extract information from the boot monitor about the pci - * configuration if provided */ - orp = &or_state; - - strncpy (orp->or_name, OR_NAME, sizeof(OR_NAME)); - orp->or_name[sizeof(OR_NAME) - 2] = or_instance + '0'; - orp->or_seen = FALSE; - - /* Initialize the pci bus, bridges and cards, if not yet done */ - pci_init (); - /* Try to find out where the card is in the pci bus */ - if (or_probe (orp, or_instance)) - orp->or_seen = TRUE; + if (!or_probe(orp, instance)) + return ENXIO; + + /* initialize card, hardware/firmware */ + or_init_hw(orp, addr); + + /* Use a synchronous alarm instead of a watchdog timer. */ + sys_setalarm(sys_hz(), 0); + + /* Observe some function key for debug dumps. */ + fkeys = sfkeys = 0; bit_set(sfkeys, 11); + if ((r=fkey_map(&fkeys, &sfkeys)) != OK) + printf("Warning: orinoco couldn't observe F-key(s): %d\n",r); + + return OK; } /***************************************************************************** @@ -502,7 +299,7 @@ static void or_pci_conf () { * Try to find the card based on information provided by pci and get irq and * * bar * *****************************************************************************/ -static int or_probe (t_or * orp, int skip) +static int or_probe(t_or * orp, unsigned int skip) { u8_t ilr; u32_t bar; @@ -510,88 +307,51 @@ static int or_probe (t_or * orp, int skip) u16_t vid, did; int r, devind; + pci_init(); + /* Start looking from the beginning */ - r = pci_first_dev (&devind, &vid, &did); + r = pci_first_dev(&devind, &vid, &did); if (r == 0) - return (0); + return FALSE; /* Skip as many instances as requested */ while (skip--) { - r = pci_next_dev (&devind, &vid, &did); + r = pci_next_dev(&devind, &vid, &did); if (!r) - return (0); + return FALSE; } /* Get the name as advertised by pci */ - dname = pci_dev_name (vid, did); + dname = pci_dev_name(vid, did); if (!dname) dname = "unknown device"; - printf ("%s: %s (%04x/%04x) at %s\n", - orp->or_name, dname, vid, did, pci_slot_name (devind)); + printf("%s: %s (%04x/%04x) at %s\n", + orp->or_name, dname, vid, did, pci_slot_name(devind)); - pci_reserve (devind); + pci_reserve(devind); - orp->devind = devind; /* Get the irq */ - ilr = pci_attr_r8 (devind, PCI_ILR); + ilr = pci_attr_r8(devind, PCI_ILR); orp->or_irq = ilr; - /* Get the base address */ - bar = or_get_bar (devind, orp); - orp->or_base_port = bar; + /* Map registers into memory */ + bar = or_get_bar(devind, orp); + + orp->hw.locmem = vm_map_phys(SELF, (void *)bar, PAGE_SIZE); + if (orp->hw.locmem == MAP_FAILED) + panic("or_probe: vm_map_phys failed"); - map_hw_buffer(orp); return TRUE; } -/***************************************************************************** - * map_hw_buffer * - * * - * Map the memory mapped registers into user space memory * - *****************************************************************************/ -static void map_hw_buffer(t_or *orp) -{ - int r; - size_t o, size; - char *buf, *abuf; - hermes_t *hw = &(orp->hw); - - /* This way, the buffer will be at least PAGE_SIZE big: see - * calculation with the offset */ - size = 2 * PAGE_SIZE; - - buf = (char *)malloc(size); - if(buf == NULL) - panic("map_hw_buffer: cannot malloc size: %d", size); - - /* Let the mapped memory by PAGE_SIZE aligned */ - o = PAGE_SIZE - ((vir_bytes)buf % PAGE_SIZE); - abuf = buf + o; - -#if 0 - r = sys_vm_map(SELF, 1, (vir_bytes)abuf, - 1 * PAGE_SIZE, (phys_bytes)orp->or_base_port); -#else - r = ENOSYS; -#endif - - if(r!=OK) - panic("map_hw_buffer: sys_vm_map failed: %d", r); - - - hw->locmem = abuf; -} - - - /***************************************************************************** * or_get_bar * * * - * Get the base address from pci (from Base Address Register) and find out * + * Get the base address from pci (from Base Address Register) and find out * * whether the card is memory mapped or in I/O space. Currently, only * * memmory mapped is supported. * *****************************************************************************/ -static u32_t or_get_bar (int devind, t_or * orp) +static u32_t or_get_bar(int devind, t_or * orp) { u32_t bar; int is_iospace; @@ -599,11 +359,11 @@ static u32_t or_get_bar (int devind, t_or * orp) /* bit 1 off the PCI_BAR register indicates whether the cards registers * are mapped in io-space or shared memory */ - is_iospace = pci_attr_r32 (devind, PCI_BAR) & 1; + is_iospace = pci_attr_r32(devind, PCI_BAR) & 1; if (is_iospace) { /* read where the base address is in I/O space */ - bar = pci_attr_r32 (devind, PCI_BAR) & 0xffffffe0; + bar = pci_attr_r32(devind, PCI_BAR) & 0xffffffe0; if ((bar & 0x3ff) >= 0x100 - 32 || bar < 0x400) panic("base address isn't properly configured"); @@ -613,33 +373,32 @@ static u32_t or_get_bar (int devind, t_or * orp) hermes_struct_init (hw, bar, is_iospace, HERMES_16BIT_REGSPACING); - if (debug) { - printf ("%s: using I/O space address 0x%x, IRQ %d\n", - orp->or_name, bar, orp->or_irq); - } +#if VERBOSE + printf ("%s: using I/O space address 0x%x, IRQ %d\n", + orp->or_name, bar, orp->or_irq); +#endif panic("Not implemented yet"); - /* Although we are able to find the desired bar and irq for an - * I/O spaced card, we haven't implemented the right register + /* Although we are able to find the desired bar and irq for an + * I/O spaced card, we haven't implemented the right register * accessing functions. This wouldn't be difficult, but we were * not able to test them. Therefore, give an alert here */ return bar; } else { /* read where the base address is in shared memory */ - bar = pci_attr_r32 (devind, PCI_BAR) & 0xfffffff0; + bar = pci_attr_r32(devind, PCI_BAR) & 0xfffffff0; /* maybe some checking whether the address is legal... */ - /* Memory mapped registers are 2 bytes wide, aligned on 4 + /* Memory mapped registers are 2 bytes wide, aligned on 4 * bytes */ hermes_struct_init (hw, bar, is_iospace, HERMES_32BIT_REGSPACING); - if (debug){ - printf ("%s: using shared memory address", - orp->or_name); - printf (" 0x%x, IRQ %d\n", bar, orp->or_irq); - } +#if VERBOSE + printf ("%s: using shared memory address", orp->or_name); + printf (" 0x%x, IRQ %d\n", bar, orp->or_irq); +#endif return bar; @@ -651,62 +410,44 @@ static u32_t or_get_bar (int devind, t_or * orp) * * * Set the orinoco structure to default values * *****************************************************************************/ -static void or_init_struct (t_or * orp) +static void or_init_struct(t_or * orp, unsigned int instance) { - int i = 0; - static eth_stat_t empty_stat = { 0, 0, 0, 0, 0, 0 }; + int i; - orp->or_mode = OR_M_DISABLED; + memset(orp, 0, sizeof(*orp)); - if (orp->or_seen) - orp->or_mode = OR_M_ENABLED; + strlcpy(orp->or_name, OR_NAME, sizeof(orp->or_name)); + orp->or_name[sizeof(OR_NAME) - 2] = instance + '0'; - if (orp->or_mode != OR_M_ENABLED) - return; - - orp->or_got_int = 0; orp->or_link_up = -1; - orp->or_send_int = 0; - orp->or_clear_rx = 0; - orp->or_tx_alive = 0; - orp->or_need_reset = 0; - orp->or_read_s = 0; - orp->or_tx_head = 0; - orp->or_tx_tail = 0; - orp->connected = 0; - - orp->or_tx.ret_busy = FALSE; orp->or_tx.or_txfid = NO_FID; for(i = 0; i < NR_RX_BUFS; i++) { orp->rxfid[i] = NO_FID; orp->rx_length[i] = 0; } - orp->rx_current = 0; - orp->rx_first = 0; - orp->rx_last = 0; - - orp->or_stat = empty_stat; - orp->or_flags = OR_F_EMPTY; /* Keep an administration in the driver whether the internal buffer is in use. That's what ret_busy is for */ orp->or_tx.ret_busy = FALSE; + orp->or_tx_busy = 0; orp->or_nicbuf_size = IEEE802_11_FRAME_LEN + ETH_HLEN; - } /***************************************************************************** * or_init_hw * * * * Initialize hardware and prepare for intercepting the interrupts. At the * - * end, the card is up and running * + * end, the card is up and running. May be called multiple times. * *****************************************************************************/ -static void or_init_hw (t_or * orp) +static void or_init_hw(t_or * orp, ether_addr_t * addr) { - int i, err, s; +#if VERBOSE + int i; +#endif + int err, s; hermes_t *hw = &(orp->hw); static int first_time = TRUE; @@ -720,19 +461,19 @@ static void or_init_hw (t_or * orp) printf ("error value of hermes_init(): %d\n", err); } - /* Get the MAC address (which is a data item in the card)*/ - or_readrids (hw, orp); + if (first_time) { + /* Get the MAC address (which is a data item in the card)*/ + or_readrids(hw, orp, addr); + } /* Write a few rids to the card, e.g. WEP key*/ or_writerids (hw, orp); - if (debug) { - printf ("%s: Ethernet address ", orp->or_name); - for (i = 0; i < 6; i++) { - printf ("%x%c", orp->or_address.ea_addr[i], - i < 5 ? ':' : '\n'); - } - } +#if VERBOSE + printf ("%s: Ethernet address ", orp->or_name); + for (i = 0; i < 6; i++) + printf("%x%c", addr->ea_addr[i], i < 5 ? ':' : '\n'); +#endif /* Prepare internal TX buffer in the card */ err = hermes_allocate (hw, @@ -745,8 +486,8 @@ static void or_init_hw (t_or * orp) /* Establish event handle */ if(first_time) { - orp->or_hook_id = orp->or_irq; - if ((s=sys_irqsetpolicy(orp->or_irq, 0, + orp->or_hook_id = orp->or_irq; + if ((s=sys_irqsetpolicy(orp->or_irq, 0, &orp->or_hook_id)) != OK) printf("orinoco: couldn't set IRQ policy: %d\n", s); @@ -760,12 +501,10 @@ static void or_init_hw (t_or * orp) /* Enable operation */ err = hermes_docmd_wait (hw, HERMES_CMD_ENABLE, 0, NULL); - if (err) { - printf ("%s: Error %d enabling MAC port\n", orp->or_name, err); - } + if (err) + printf("%s: Error %d enabling MAC port\n", orp->or_name, err); } - /***************************************************************************** * or_readrids * * * @@ -773,17 +512,17 @@ static void or_init_hw (t_or * orp) * is a data item in the firmware, some configuration variable. * * In our case, we are mostly interested in the MAC address for now * *****************************************************************************/ - -static void or_readrids (hermes_t * hw, t_or * orp) +static void or_readrids(hermes_t * hw, t_or * orp, ether_addr_t * addr) { - /* Read the MAC address */ - int err = hermes_read_ltv (hw, USER_BAP, HERMES_RID_CNFOWNMACADDR, - ETH_ALEN, NULL, &orp->or_address); - if (err) { - printf ("%s: failed to read MAC address!\n", orp->or_name); - return; - } + int err; + assert(addr != NULL); + + /* Read the MAC address */ + err = hermes_read_ltv (hw, USER_BAP, HERMES_RID_CNFOWNMACADDR, + ETH_ALEN, NULL, addr); + if (err) + printf("%s: failed to read MAC address!\n", orp->or_name); } /***************************************************************************** @@ -792,18 +531,15 @@ static void or_readrids (hermes_t * hw, t_or * orp) * Write some default rids to the card. A rid (resource identifier) * * is a data item in the firmware, some configuration variable, e.g. WEP key * *****************************************************************************/ -static void or_writerids (hermes_t * hw, t_or * orp) +static void or_writerids(hermes_t * hw, t_or * orp) { int err; struct hermes_idstring idbuf; - u16_t port_type; static char essid[IW_ESSID_MAX_SIZE + 1]; static char wepkey0[LARGE_KEY_LENGTH + 1]; /* Set the MAC port */ - port_type = 1; - err = hermes_write_wordrec (hw, USER_BAP, HERMES_RID_CNFPORTTYPE, - port_type); + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE, 1); if (err) { printf ("%s: Error %d setting port type\n", orp->or_name, err); return; @@ -827,7 +563,7 @@ static void or_writerids (hermes_t * hw, t_or * orp) HERMES_BYTES_TO_RECLEN (strlen (essid) + 2), &idbuf); if (err) { - printf ("%s: Error %d setting DESIREDSSID\n", + printf ("%s: Error %d setting DESIREDSSID\n", orp->or_name, err); return; } @@ -858,7 +594,8 @@ static void or_writerids (hermes_t * hw, t_or * orp) * It appears that there is a severe bug in setting up WEP. If the driver * * doesnt function properly, please turn WEP off. * *****************************************************************************/ -static void setup_wepkey(t_or *orp, char *wepkey0) { +static void setup_wepkey(t_or *orp, char *wepkey0) +{ int default_key = 0, err = 0; hermes_t *hw = &(orp->hw); @@ -867,40 +604,30 @@ static void setup_wepkey(t_or *orp, char *wepkey0) { default_key); if (err) printf ("%s: Error %d setting the default WEP-key entry\n", - orp->or_name, err); - - err = hermes_write_ltv (hw, USER_BAP, + orp->or_name, err); + + err = hermes_write_ltv (hw, USER_BAP, HERMES_RID_CNFDEFAULTKEY0, HERMES_BYTES_TO_RECLEN(LARGE_KEY_LENGTH), wepkey0); - if (err) + if (err) printf ("%s: Error %d setting the WEP-key0\n", - orp->or_name, err); - - err = hermes_write_wordrec (hw, USER_BAP, + orp->or_name, err); + + err = hermes_write_wordrec (hw, USER_BAP, HERMES_RID_CNFAUTHENTICATION, HERMES_AUTH_OPEN); if (err) printf ("%s: Error %d setting the authentication flag\n", - orp->or_name, err); + orp->or_name, err); - err = hermes_write_wordrec (hw, USER_BAP, + err = hermes_write_wordrec (hw, USER_BAP, HERMES_RID_CNFWEPFLAGS_INTERSIL, HERMES_WEP_PRIVACY_INVOKED); if (err) printf ("%s: Error %d setting the master wep setting flag\n", - orp->or_name, err); - -} + orp->or_name, err); - -/***************************************************************************** - * or_rec_mode * - * * - * Set the desired receive mode, e.g. promiscuous mode. Not implemented yet * - *****************************************************************************/ -static void or_rec_mode (t_or * orp) { - /* TODO */ } /***************************************************************************** @@ -910,12 +637,12 @@ static void or_rec_mode (t_or * orp) { * like EV_INFO and EV_RX have to be handled before an acknowledgement for * * the event is returned to the card. See also the documentation * *****************************************************************************/ -static void or_handler (t_or *orp) +static void or_handler(t_or *orp) { int length; u16_t evstat, events, fid; hermes_t *hw = &(orp->hw); - + beginning: /* Retrieve which kind of event happened */ evstat = hermes_read_reg (hw, HERMES_EVSTAT); @@ -940,8 +667,8 @@ beginning: if (events & HERMES_EV_INFDROP) { events &= ~(HERMES_EV_INFDROP); } - - /* This AP-only event will be asserted at the beacon interval prior to + + /* This AP-only event will be asserted at the beacon interval prior to the DTIM interval */ if (events & HERMES_EV_DTIM) { events &= ~(HERMES_EV_DTIM); @@ -955,7 +682,6 @@ beginning: /* Occurs when the asynchronous transmission process is unsuccessfully completed */ if (events & HERMES_EV_TXEXC) { - /* What buffer generated the event? Represented by an fid */ fid = hermes_read_reg(hw, HERMES_TXCOMPLFID); if(fid == 0xFFFF) { @@ -963,20 +689,17 @@ beginning: printf("unexpected txexc_fid interrupted\n"); } + if (orp->or_tx.ret_busy) + orp->or_tx_busy--; orp->or_tx.ret_busy = FALSE; - if(orp->or_flags & OR_F_SEND_AVAIL) { - orp->or_send_int = TRUE; - if (!orp->or_got_int){ - orp->or_got_int = TRUE; - int_event_check = TRUE; - } - } + orp->or_send_int = TRUE; + orp->or_got_int = TRUE; /* To detect illegal fids */ hermes_write_reg(hw, HERMES_TXCOMPLFID, 0xFFFF); events &= ~(HERMES_EV_TXEXC); - /* We don't do anything else yet. + /* We don't do anything else yet. * Could be used for statistics */ } @@ -991,15 +714,13 @@ beginning: printf("unexpected tx_fid interrupted\n"); } + if (orp->or_tx.ret_busy) + orp->or_tx_busy--; orp->or_tx.ret_busy = FALSE; - if(orp->or_flags & OR_F_SEND_AVAIL) { - orp->or_send_int = TRUE; - if (!orp->or_got_int){ - orp->or_got_int = TRUE; - int_event_check = TRUE; - } - } + orp->or_send_int = TRUE; + orp->or_got_int = TRUE; + orp->or_tx_alive = TRUE; /* To detect illegal fids */ hermes_write_reg(hw, HERMES_TXCOMPLFID, 0xFFFF); @@ -1020,37 +741,35 @@ beginning: if (fid == 0xFFFF){ /* An illegal frame identifier is found. Ignore */ printf("Allocate event on unexpected fid\n"); - return ; + goto next; } /* To be able to detect illegal fids */ hermes_write_reg(hw, HERMES_ALLOCFID, 0xFFFF); - + events &= ~(HERMES_EV_ALLOC); } - - /* Occurs when a frame is received by the asynchronous reception - * process */ - + /* Occurs when a frame is received */ if (events & HERMES_EV_RX) { - orp->or_ev_rx = TRUE; events &= ~(HERMES_EV_RX); - /* If the last buffer is still filled with data, then we don't + /* If the last buffer is still filled with data, then we don't * have any buffers available to store the data */ if(orp->rx_length[orp->rx_last] != 0) { /* indeed, we are going to overwrite information - * in a buffer */ + * in a buffer + */ } /* Which buffer is storing the data (represented by a fid) */ orp->rxfid[orp->rx_last] = hermes_read_reg (hw, HERMES_RXFID); - /* Get the packet from the card and store it in - * orp->rx_buf[orp->rx_last]. The length is returned by this - * function */ + /* Get the packet from the card and store it in + * orp->rx_buf[orp->rx_last]. The length is returned by this + * function + */ length = or_get_recvd_packet(orp, orp->rxfid[orp->rx_last], (orp->rx_buf[orp->rx_last])); @@ -1066,17 +785,14 @@ beginning: orp->rx_last++; orp->rx_last %= NR_RX_BUFS; - if (!orp->or_got_int){ - orp->or_got_int = TRUE; - } - int_event_check = TRUE; + orp->or_got_int = TRUE; } next: - if (events) { + if (events) { printf("Unknown event: 0x%x\n", events); } - /* Acknowledge to the card that the events have been processed. After + /* Acknowledge to the card that the events have been processed. After * this the card will assume we have processed any buffer which were in * use for this event. */ hermes_write_reg (hw, HERMES_EVACK, evstat); @@ -1087,26 +803,22 @@ next: } } - /***************************************************************************** - * or_watchdog_f * + * or_alarm * * * * Will be called regularly to see whether the driver has crashed. If that * * condition is detected, reset the driver and card * *****************************************************************************/ -static void or_watchdog_f(minix_timer_t *tp) +static void or_alarm(clock_t __unused stamp) { t_or *orp; - + /* Use a synchronous alarm instead of a watchdog timer. */ - sys_setalarm(system_hz, 0); + sys_setalarm(sys_hz(), 0); orp = &or_state; - if (orp->or_mode != OR_M_ENABLED) - return; - - if (!(orp->or_flags & OR_F_SEND_AVAIL)) { + if (orp->or_tx_busy == 0) { /* Assume that an idle system is alive */ orp->or_tx_alive= TRUE; return; @@ -1120,39 +832,28 @@ static void or_watchdog_f(minix_timer_t *tp) orp->or_tx_alive= FALSE; return; } - - printf("or_watchdog_f: resetting instance %d\n", or_instance); - + + printf("or_alarm: resetting card\n"); + orp->or_need_reset= TRUE; orp->or_got_int= TRUE; - check_int_events(); + or_check_ints(orp); } /***************************************************************************** - * mess_reply * - *****************************************************************************/ -static void mess_reply (message * req, message * reply_mess) -{ - if (ipc_send(req->m_source, reply_mess) != 0) - panic("orinoco: unable to mess_reply"); - -} - -/***************************************************************************** - * or_writev_s * + * or_send * * * - * Write data which is denoted by the message to the card and send it. * + * Send a packet, if possible * *****************************************************************************/ -static void or_writev_s (message * mp, int from_int) { - int count, size, err, data_len, data_off; - int o, j, n, i, s, p, cps ; +static int or_send(struct netdriver_data *data, size_t size) +{ + size_t p, data_len, data_off; + int err; struct ethhdr *eh; t_or *orp; hermes_t *hw; struct hermes_tx_descriptor desc; - int iov_offset = 0; struct header_struct hdr; - iovec_s_t *iovp; u16_t txfid; /* We need space for the max packet size itself, plus an ethernet @@ -1161,120 +862,72 @@ static void or_writev_s (message * mp, int from_int) { * packets from the card, which has an IO granularity of 16 * bits */ static u8_t databuf[IEEE802_11_DATA_LEN + ETH_HLEN + 2 + 1]; - memset (databuf, 0, IEEE802_11_DATA_LEN + ETH_HLEN + 3); orp = &or_state; - - count = mp->m_net_netdrv_dl_writev_s.count; - - orp->or_client = mp->m_source; hw = &(orp->hw); /* Switch off interrupts. The card is accessable via 2 BAPs, one for - * reading and one for writing. In theory these BAPs should be + * reading and one for writing. In theory these BAPs should be * independent, but in practice, the are not. By switching off the * interrupts of the card, the chances of one interfering with the - * other should be less */ - if (from_int){ - /* We were called with from_int, meaning that the last time we - * were called, no tx buffers were available, and we had to - * suspend. Now, we'll try again to find an empty buffer in the - * card */ - assert (orp->or_flags & OR_F_SEND_AVAIL); - orp->or_flags &= ~OR_F_SEND_AVAIL; - orp->or_send_int = FALSE; - orp->or_tx_alive = TRUE; - } + * other should be less + */ + /* ..except that this is not happening at all here. */ txfid = orp->or_tx.or_txfid; if (orp->or_tx.ret_busy || orp->connected == 0) { /* there is no buffer in the card available */ - assert(!(orp->or_flags & OR_F_SEND_AVAIL)); - /* Remember that there is a packet to be sent available */ - orp->or_flags |= OR_F_SEND_AVAIL; - goto suspend_write_s; + return SUSPEND; } - assert (orp->or_mode == OR_M_ENABLED); - assert (orp->or_flags & OR_F_ENABLED); + /* Copy the data to be sent from the vector to the databuf */ + netdriver_copyin(data, 0, databuf, size); + /* Zero out the rest of the buffer */ + memset(&databuf[size], 0, sizeof(databuf) - size); - /* Copy the data to be send from the vector to the databuf */ - size = 0; - o = 0; - for (i = 0; i < count; i += IOVEC_NR, - iov_offset += IOVEC_NR * sizeof (orp->or_iovec_s[0])) { - - n = IOVEC_NR; - if (i + n > count) - n = count - i; - - cps = sys_safecopyfrom(mp->m_source, - mp->m_net_netdrv_dl_writev_s.grant, iov_offset, - (vir_bytes) orp->or_iovec_s, - n * sizeof(orp->or_iovec_s[0])); - if (cps != OK) - printf("orinoco: sys_safecopyfrom failed: %d\n", cps); - - for (j = 0, iovp = orp->or_iovec_s; j < n; j++, iovp++) { - s = iovp->iov_size; - if (size + s > ETH_MAX_PACK_SIZE_TAGGED) { - printf("Orinoco: invalid pkt size\n"); - } - - cps = sys_safecopyfrom(mp->m_source, iovp->iov_grant, - 0, (vir_bytes) databuf + o, s); - if (cps != OK) - printf("orinoco: sys_safecopyfrom failed:%d\n", - cps); - - size += s; - o += s; - } - } - - assert(size >= ETH_MIN_PACK_SIZE); - - memset (&desc, 0, sizeof (desc)); - /* Reclaim the tx buffer once the data is sent (OK), or it is clear - * that transmission failed (EX). Reclaiming means that we can reuse - * the buffer again for transmission */ + memset(&desc, 0, sizeof(desc)); + /* Reclaim the tx buffer once the data is sent (OK), or it is clear + * that transmission failed (EX). Reclaiming means that we can reuse + * the buffer again for transmission + */ desc.tx_control = HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX; - /* Actually, this reclaim bit is the only thing which needs to be set - * in the descriptor */ - err = hermes_bap_pwrite (hw, USER_BAP, &desc, sizeof (desc), txfid, - 0); + /* Actually, this reclaim bit is the only thing which needs to be set + * in the descriptor + */ + err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc), txfid, 0); if (err) { printf("hermes_bap_pwrite() descriptor error:resetting card\n"); - /* When this happens, the card is quite confused: it will not - * recover. Reset it */ + /* When this happens, the card is quite confused: it will not + * recover. Reset it + */ or_reset(); - goto fail; + return OK; /* pretend the packet was sent anyway.. */ } eh = (struct ethhdr *) databuf; /* Encapsulate Ethernet-II frames */ - if (ntohs (eh->h_proto) > 1500) { + if (ntohs(eh->h_proto) > 1500) { /* Ethernet-II frame */ data_len = size - ETH_HLEN; data_off = HERMES_802_3_OFFSET + sizeof (hdr); /* 802.3 header */ - memcpy (hdr.dest, eh->h_dest, ETH_ALEN); - memcpy (hdr.src, eh->h_src, ETH_ALEN); - hdr.len = htons (data_len + ENCAPS_OVERHEAD); + memcpy(hdr.dest, eh->h_dest, ETH_ALEN); + memcpy(hdr.src, eh->h_src, ETH_ALEN); + hdr.len = htons(data_len + ENCAPS_OVERHEAD); /* 802.2 header */ - memcpy (&hdr.dsap, &encaps_hdr, sizeof (encaps_hdr)); + memcpy(&hdr.dsap, &encaps_hdr, sizeof (encaps_hdr)); hdr.ethertype = eh->h_proto; - err = hermes_bap_pwrite (hw, USER_BAP, &hdr, sizeof (hdr), + err = hermes_bap_pwrite(hw, USER_BAP, &hdr, sizeof(hdr), txfid, HERMES_802_3_OFFSET); if (err) { - printf ("%s: Error %d writing packet header to BAP\n", + printf("%s: Error %d writing packet header to BAP\n", orp->or_name, err); - goto fail; + return OK; /* pretend the packet was sent anyway.. */ } p = ETH_HLEN; @@ -1286,86 +939,44 @@ static void or_writev_s (message * mp, int from_int) { } /* Round up for odd length packets */ - err = hermes_bap_pwrite (hw, USER_BAP, - (void *) &(databuf[p]), RUP_EVEN (data_len), - txfid, data_off); + err = hermes_bap_pwrite(hw, USER_BAP, (void *) &(databuf[p]), + RUP_EVEN(data_len), txfid, data_off); if (err) { - printf ("hermes_bap_pwrite(data): error %d\n", err); - goto fail; + printf("hermes_bap_pwrite(data): error %d\n", err); + return OK; /* pretend the packet was sent anyway.. */ } - /* this should be before the docmd_wait. Cause otherwise the bit can - be cleared in the handler (if irq's not off) before it is set - and then 1 reset (ret_busy=false) is lost */ + /* this should be before the docmd_wait. Cause otherwise the bit can + * be cleared in the handler (if irq's not off) before it is set + * and then 1 reset (ret_busy=false) is lost + */ orp->or_tx.ret_busy = TRUE; + orp->or_tx_busy++; /* Send the packet which was constructed in txfid */ err = hermes_docmd_wait (hw, HERMES_CMD_TX | HERMES_CMD_RECL, txfid, NULL); if (err) { - printf ("hermes_docmd_wait(TX|RECL): error %d\n", err); + printf("hermes_docmd_wait(TX|RECL): error %d\n", err); /* Mark the buffer as available again */ orp->or_tx.ret_busy = FALSE; - goto fail; - } - -fail: - /* If the interrupt handler called, don't send a reply. The reply - * will be sent after all interrupts are handled. - */ - orp->or_flags |= OR_F_PACK_SENT; - - if (from_int) { - return; + orp->or_tx_busy--; + return OK; /* pretend the packet was sent anyway.. */ } - reply (orp); - return; - -suspend_write_s: - orp->or_tx_mess = *mp; - - reply (orp); - return; + return OK; } - -/***************************************************************************** - * reply * - * * - * Send a message back to the caller, informing it about the data received * - * or sent * - *****************************************************************************/ -static void reply (t_or * orp) { - message reply; - int flags = DL_NOFLAGS, r; - - if (orp->or_flags & OR_F_PACK_SENT) - flags |= DL_PACK_SEND; - if (orp->or_flags & OR_F_PACK_RECV) - flags |= DL_PACK_RECV; - - reply.m_type = DL_TASK_REPLY; - reply.m_netdrv_net_dl_task.flags = flags; - reply.m_netdrv_net_dl_task.count = orp->or_read_s; - - r = ipc_send(orp->or_client, &reply); - - if (r < 0) - panic("orinoco: send failed: %d", r); - - orp->or_read_s = 0; - orp->or_flags &= ~(OR_F_PACK_SENT | OR_F_PACK_RECV); -} - - /***************************************************************************** * or_ev_info * * * * Process information which comes in from the card * *****************************************************************************/ -static void or_ev_info (t_or * orp) +static void or_ev_info(t_or * orp) { + struct hermes_tallies_frame tallies; + struct hermes_linkstatus linkstatus; + u16_t newstatus; u16_t infofid; int err, len, type; hermes_t *hw = &orp->hw; @@ -1389,67 +1000,48 @@ static void or_ev_info (t_or * orp) switch (type) { case HERMES_INQ_TALLIES: - { - struct hermes_tallies_frame tallies; - - if (len > sizeof (tallies)) { - printf ("%s: Tallies frame too long ", - orp->or_name); - printf ("(%d bytes)\n", len); - len = sizeof (tallies); - } - hermes_read_words (hw, HERMES_DATA1, - (void *) &tallies, len / 2); - /* TODO: do something with the tallies structure */ + if (len > sizeof(tallies)) { + printf("%s: Tallies frame too long ", orp->or_name); + printf("(%d bytes)\n", len); + len = sizeof (tallies); } + hermes_read_words(hw, HERMES_DATA1, (void *)&tallies, len / 2); + /* TODO: do something with the tallies structure */ break; - case HERMES_INQ_LINKSTATUS: { - u16_t newstatus; - struct hermes_linkstatus linkstatus; + case HERMES_INQ_LINKSTATUS: + if (len != sizeof(linkstatus)) { + printf("%s: Unexpected size for linkstatus ", + orp->or_name); + printf("frame (%d bytes)\n", len); + } - if (len != sizeof (linkstatus)) { - printf ("%s: Unexpected size for linkstatus ", - orp->or_name); - printf ("frame (%d bytes)\n", len); - } + hermes_read_words(hw, HERMES_DATA1, (void *)&linkstatus, + len / 2); + newstatus = linkstatus.linkstatus; - hermes_read_words (hw, HERMES_DATA1, - (void *) &linkstatus, len / 2); - newstatus = linkstatus.linkstatus; - - if ((newstatus == HERMES_LINKSTATUS_CONNECTED) - || (newstatus == HERMES_LINKSTATUS_AP_CHANGE) - || (newstatus == HERMES_LINKSTATUS_AP_IN_RANGE)) { - orp->connected = 1; - - if(orp->or_flags & OR_F_SEND_AVAIL) { - orp->or_send_int = TRUE; + if ((newstatus == HERMES_LINKSTATUS_CONNECTED) + || (newstatus == HERMES_LINKSTATUS_AP_CHANGE) + || (newstatus == HERMES_LINKSTATUS_AP_IN_RANGE)) { + orp->connected = 1; + orp->or_send_int = TRUE; orp->or_got_int = TRUE; - int_event_check = TRUE; + } + else if ((newstatus == HERMES_LINKSTATUS_NOT_CONNECTED) + || (newstatus == HERMES_LINKSTATUS_DISCONNECTED) + || (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE) + || (newstatus == HERMES_LINKSTATUS_ASSOC_FAILED)) { + orp->connected = 0; } + if (newstatus != orp->last_linkstatus) + print_linkstatus(orp, newstatus); - } - else if ((newstatus == - HERMES_LINKSTATUS_NOT_CONNECTED) - || (newstatus == - HERMES_LINKSTATUS_DISCONNECTED) - || (newstatus == - HERMES_LINKSTATUS_AP_OUT_OF_RANGE) - || (newstatus == - HERMES_LINKSTATUS_ASSOC_FAILED)) { - orp->connected = 0; - } + orp->last_linkstatus = newstatus; - if (newstatus != orp->last_linkstatus) - print_linkstatus(orp, newstatus); - - orp->last_linkstatus = newstatus; - } break; default: - printf ("%s:Unknown information frame received(type %04x).\n", + printf("%s:Unknown information frame received (type %04x).\n", orp->or_name, type); break; } @@ -1460,7 +1052,8 @@ static void or_ev_info (t_or * orp) * * * Process information which comes in from the card * *****************************************************************************/ -static void print_linkstatus (t_or * orp, u16_t status) { +static void print_linkstatus(t_or * orp, u16_t status) +{ int err; u16_t d; char *s; @@ -1492,52 +1085,45 @@ static void print_linkstatus (t_or * orp, u16_t status) { s = "UNKNOWN"; } - printf ("%s: link status: %s, ", orp->or_name, s); + printf("%s: link status: %s, ", orp->or_name, s); - err = hermes_read_wordrec (hw, USER_BAP, - HERMES_RID_CURRENTCHANNEL, &d); + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENTCHANNEL, &d); if (err) { - printf ("%s: Error %d \n", orp->or_name, err); + printf("error %d\n", err); return; } - printf("channel: %d, freq: %ld MHz ", - d, (channel_frequency[d-1])); - + printf("channel: %d, freq: %ld MHz\n", d, (channel_frequency[d-1])); } - /***************************************************************************** * or_check_ints * * * * Process events which have been postponed in the interrupt handler * *****************************************************************************/ -static void or_check_ints (t_or * orp) +static void or_check_ints(t_or * orp) { + if (!orp->or_got_int) + return; + orp->or_got_int = FALSE; + if (orp->or_need_reset) or_reset(); - if ((orp->rx_first!=orp->rx_last) && (orp->or_flags & OR_F_READING)) { - orp->or_ev_rx = 0; - or_readv_s (&orp->or_rx_mess, TRUE); - } - if (orp->or_send_int) { - or_writev_s (&orp->or_tx_mess, TRUE); - } + if (orp->rx_first != orp->rx_last) + netdriver_recv(); - if (orp->or_flags & (OR_F_PACK_SENT | OR_F_PACK_RECV)) { - reply (orp); - } + if (orp->or_send_int) + netdriver_send(); } - /***************************************************************************** * is_ethersnap * * * * is there an LLC and SNAP header in the ethernet packet? The inet task * * isn't very interested in it... * *****************************************************************************/ -static int is_ethersnap(struct header_struct *hdr) { - +static int is_ethersnap(struct header_struct *hdr) +{ /* We de-encapsulate all packets which, a) have SNAP headers * (i.e. SSAP=DSAP=0xaa and CTRL=0x3 in the 802.2 LLC header * and where b) the OUI of the SNAP header is 00:00:00 or @@ -1546,42 +1132,24 @@ static int is_ethersnap(struct header_struct *hdr) { return (memcmp(&hdr->dsap, &encaps_hdr, 5) == 0) && ( (hdr->oui[2] == 0x00) || (hdr->oui[2] == 0xf8) ); } - + /***************************************************************************** - * or_readv_s * + * or_recv * * * - * Copy the data which is stored in orp->rx_buf[orp->rx_first] in the vector * - * which was given with the message *mp * + * Receive a packet, if one is available * *****************************************************************************/ -static void or_readv_s (message * mp, int from_int) +static ssize_t or_recv(struct netdriver_data *data, size_t max) { - int i, j, n, o, s, count, size, cps; - int iov_offset = 0, length; t_or *orp; - iovec_s_t *iovp; u8_t *databuf; + size_t length; orp = &or_state; - orp->or_client = mp->m_source; - count = mp->m_net_netdrv_dl_readv_s.count; + if (orp->rx_first == orp->rx_last) + return SUSPEND; - assert (orp->or_mode == OR_M_ENABLED); - assert (orp->or_flags & OR_F_ENABLED); - - if (!from_int && (orp->rx_first==orp->rx_last)) - - { - /* if we are not called from a hard int (data is not yet available) and - * there are no buffers (or->rx_buf[x]) which contain any data, we cant - * copy any data to the inet server. Goto suspend, and wait for data - * to arrive */ - goto suspend_readv_s; - } - - - - /* and store the pointer to this data in databuf */ + /* store the pointer to this data in databuf */ databuf = &(orp->rx_buf[orp->rx_first][0]); length = orp->rx_length[orp->rx_first]; @@ -1592,94 +1160,36 @@ static void or_readv_s (message * mp, int from_int) orp->rx_first++; orp->rx_first %= NR_RX_BUFS; - o = 0; - /* The data which we want to be copied to the vector starts at - * *databuf and will be copied to the vecor below */ - size = 0; - for (i = 0; i < count; i += IOVEC_NR, - iov_offset += IOVEC_NR * sizeof(orp->or_iovec_s[0])) { - n = IOVEC_NR; - if (i + n > count) - n = count - i; + if (length > max) + length = max; - cps = sys_safecopyfrom(mp->m_source, - mp->m_net_netdrv_dl_readv_s.grant, iov_offset, - (vir_bytes)orp->or_iovec_s, - n * sizeof(orp->or_iovec_s[0])); - if (cps != OK) - panic("orinoco: warning: sys_safecopytp failed: %d", cps); - - for (j = 0, iovp = orp->or_iovec_s; j < n; j++, iovp++) { - s = iovp->iov_size; - if (size + s > length) { - assert (length > size); - s = length - size; - } - cps = sys_safecopyto(mp->m_source, iovp->iov_grant, 0, - (vir_bytes) databuf + o, s); - if (cps != OK) - panic("orinoco: warning: sys_safecopy failed: %d", cps); - - size += s; - if (size == length) - break; - o += s; - } - if (size == length) - break; - } - - assert(size >= length); + netdriver_copyout(data, 0, databuf, length); orp->or_stat.ets_packetR++; - orp->or_read_s = length; - orp->or_flags &= ~OR_F_READING; - orp->or_flags |= OR_F_PACK_RECV; - - if (!from_int) { - /* There was data in the orp->rx_buf[x] which is now copied to - * the inet sever. Tell the inet server */ - reply (orp); - } - - return; -suspend_readv_s: - if (from_int) { - assert (orp->or_flags & OR_F_READING); - /* No need to store any state */ - return; - } - - /* We want to store the message, so that next time when we are called - * by hard int, we know where to copy the received data */ - orp->or_rx_mess = *mp; - assert (!(orp->or_flags & OR_F_READING)); - orp->or_flags |= OR_F_READING; - - reply (orp); + return length; } - /***************************************************************************** * or_get_recvd_packet * * * * The card has received data. Retrieve the data from the card and put it * * in a buffer in the driver (in the orp structure) * *****************************************************************************/ -static int or_get_recvd_packet(t_or *orp, u16_t rxfid, u8_t *databuf) { +static int or_get_recvd_packet(t_or *orp, u16_t rxfid, u8_t *databuf) +{ struct hermes_rx_descriptor desc; hermes_t *hw; struct header_struct hdr; int err, length, offset; u16_t status; - + memset(databuf, 0, IEEE802_11_FRAME_LEN); hw = &(orp->hw); - /* Read the data from the buffer in the card which holds the data. - * First get the descriptor which will tell us whether the packet is + /* Read the data from the buffer in the card which holds the data. + * First get the descriptor which will tell us whether the packet is * healthy*/ err = hermes_bap_pread (hw, IRQ_BAP, &desc, sizeof (desc), rxfid, 0); if (err) { @@ -1716,7 +1226,7 @@ static int or_get_recvd_packet(t_or *orp, u16_t rxfid, u8_t *databuf) { } length = ntohs (hdr.len); - + /* Sanity checks */ if (length < 3) { /* No for even an 802.2 LLC header */ @@ -1748,50 +1258,29 @@ static int or_get_recvd_packet(t_or *orp, u16_t rxfid, u8_t *databuf) { return -1; } - /* Some types of firmware give us the SNAP and OUI headers. Remove these. + /* Some types of firmware give us the SNAP and OUI headers. Remove + * these. */ if (is_ethersnap(&hdr)) { length -= 8; - - memcpy (databuf + ETH_ALEN * 2, - databuf + sizeof(struct header_struct) - 2, + memcpy(databuf + ETH_ALEN * 2, + databuf + sizeof(struct header_struct) - 2, length - ETH_ALEN * 2); } if(length<60) length=60; - + return length; } /***************************************************************************** - * or_getstat_s * + * or_stat * * * * Return the statistics structure. The statistics aren't updated until now, * * so this won't return much interesting yet. * *****************************************************************************/ -static void or_getstat_s (message * mp) { - int r; - eth_stat_t stats; - t_or *orp; - - orp = &or_state; - - assert (orp->or_mode == OR_M_ENABLED); - assert (orp->or_flags & OR_F_ENABLED); - - stats = orp->or_stat; - - r = sys_safecopyto(mp->m_source, mp->m_net_netdrv_dl_getstat_s.grant, - 0, (vir_bytes) &stats, sizeof(stats)); - if(r != OK) { - panic("or_getstat_s: sys_safecopyto failed: %d", r); - } - - mp->m_type = DL_STAT_REPLY; - - r = ipc_send(mp->m_source, mp); - if(r != OK) - panic("orinoco: getstat_s failed: %d", r); +static void or_stat(eth_stat_t *stat) +{ + memcpy(stat, &or_state.or_stat, sizeof(*stat)); } - diff --git a/minix/drivers/net/orinoco/orinoco.h b/minix/drivers/net/orinoco/orinoco.h index 6adb838b5..97c38eb1c 100644 --- a/minix/drivers/net/orinoco/orinoco.h +++ b/minix/drivers/net/orinoco/orinoco.h @@ -26,74 +26,39 @@ typedef struct s_or { int or_irq; int or_hook_id; - int or_mode; - int or_flags; - char *or_model; - int or_client; int or_link_up; int or_got_int; int or_tx_alive; int or_send_int; - int or_clear_rx; - u32_t or_base_port; int or_need_reset; int or_report_link; /* Events */ - int or_ev_rx; - int or_ev_tx; - int or_ev_info; - int or_ev_txexc; - int or_ev_alloc; int connected; - u16_t channel_mask; - u16_t channel; - u16_t ap_density; - u16_t rts_thresh; - int bitratemode; int last_linkstatus; - int max_data_len; - int port_type; /* Rx */ phys_bytes or_rx_buf; - vir_bytes or_read_s; u16_t rxfid[NR_RX_BUFS]; int rx_length[NR_RX_BUFS]; u8_t rx_buf[NR_RX_BUFS][IEEE802_11_FRAME_LEN]; - u8_t rx_offset[NR_RX_BUFS]; int rx_first; int rx_last; int rx_current; /* Tx */ u16_t or_nicbuf_size; - vir_bytes or_transm_s; int or_tx_head; int or_tx_tail; + int or_tx_busy; struct { int ret_busy; u16_t or_txfid; } or_tx; - u32_t or_ertxth; - /* PCI related */ - int or_seen; - int devind; - - /* 'large' items */ - irq_hook_t or_hook; eth_stat_t or_stat; - message or_rx_mess; - message or_tx_mess; - ether_addr_t or_address; - iovec_t or_iovec[IOVEC_NR]; - iovec_s_t or_iovec_s[IOVEC_NR]; - char or_name[sizeof (OR_NAME)]; + char or_name[sizeof(OR_NAME)]; hermes_t hw; - char nick[IW_ESSID_MAX_SIZE + 1]; - - } t_or; diff --git a/minix/drivers/net/rtl8139/Makefile b/minix/drivers/net/rtl8139/Makefile index 0cb21b28a..9b114f366 100644 --- a/minix/drivers/net/rtl8139/Makefile +++ b/minix/drivers/net/rtl8139/Makefile @@ -1,13 +1,13 @@ # Makefile for the Realtek RTL8139 ethernet driver (RTL8139) PROG= rtl8139 -SRCS= rtl8139.c liveupdate.c +SRCS= rtl8139.c FILES=$(PROG).conf FILESNAME=$(PROG) FILESDIR= /etc/system.conf.d -DPADD+= ${LIBNETDRIVER} ${LIBSYS} ${LIBTIMERS} -LDADD+= -lnetdriver -lsys -ltimers +DPADD+= ${LIBNETDRIVER} ${LIBSYS} +LDADD+= -lnetdriver -lsys CPPFLAGS+= -I${NETBSDSRCDIR}/minix diff --git a/minix/drivers/net/rtl8139/liveupdate.c b/minix/drivers/net/rtl8139/liveupdate.c index 9baaab8c0..d824b094b 100644 --- a/minix/drivers/net/rtl8139/liveupdate.c +++ b/minix/drivers/net/rtl8139/liveupdate.c @@ -1,3 +1,5 @@ +/* Code left here for historical purposes only. TODO: move into libnetdriver */ + #include "rtl8139.h" /* State management variables. */ diff --git a/minix/drivers/net/rtl8139/rtl8139.c b/minix/drivers/net/rtl8139/rtl8139.c index 6318d2fd9..2a259e42a 100644 --- a/minix/drivers/net/rtl8139/rtl8139.c +++ b/minix/drivers/net/rtl8139/rtl8139.c @@ -16,7 +16,7 @@ #include "rtl8139.h" -re_t re_state; +static re_t re_state; static int re_instance; @@ -64,225 +64,114 @@ static void my_outl(u16_t port, u32_t value) { #define rl_outw(port, offset, value) (my_outw((port) + (offset), (value))) #define rl_outl(port, offset, value) (my_outl((port) + (offset), (value))) -static void rl_init(message *mp); -static void rl_pci_conf(void); -static int rl_probe(re_t *rep, int skip); -static void rl_conf_hw(re_t *rep); +static int rl_init(unsigned int instance, ether_addr_t *addr); +static int rl_probe(re_t *rep, unsigned int skip); static void rl_init_buf(re_t *rep); -static void rl_init_hw(re_t *rep); +static void rl_init_hw(re_t *rep, ether_addr_t *addr); static void rl_reset_hw(re_t *rep); -static void rl_confaddr(re_t *rep); +static void rl_confaddr(re_t *rep, ether_addr_t *addr); +static void rl_stop(void); static void rl_rec_mode(re_t *rep); -static void rl_readv_s(const message *mp, int from_int); -static void rl_writev_s(const message *mp, int from_int); +static void rl_mode(unsigned int mode); +static ssize_t rl_recv(struct netdriver_data *data, size_t max); +static int rl_send(struct netdriver_data *data, size_t size); +static void rl_intr(unsigned int mask); static void rl_check_ints(re_t *rep); static void rl_report_link(re_t *rep); +#if VERBOSE static void mii_print_techab(u16_t techab); static void mii_print_stat_speed(u16_t stat, u16_t extstat); +#endif static void rl_clear_rx(re_t *rep); static void rl_do_reset(re_t *rep); -static void rl_getstat_s(message *mp); -static void reply(re_t *rep); -static void mess_reply(message *req, message *reply); -static void check_int_events(void); -static void do_hard_int(void); -static void rtl8139_dump(message *m); +static void rl_stat(eth_stat_t *stat); +static void rl_other(const message *m_ptr, int ipc_status); +static void rl_dump(void); #if 0 static void dump_phy(re_t *rep); #endif static int rl_handler(re_t *rep); -static void rl_watchdog_f(minix_timer_t *tp); -static void tell_dev(vir_bytes start, size_t size, int pci_bus, int +static void rl_alarm(clock_t stamp); +static void tell_iommu(vir_bytes start, size_t size, int pci_bus, int pci_dev, int pci_func); -/* The message used in the main loop is made global, so that rl_watchdog_f() - * can change its message type to fake an interrupt message. - */ -static message m; -static int int_event_check; /* set to TRUE if events arrived */ - -static u32_t system_hz; - -/* SEF functions and variables. */ -static void sef_local_startup(void); -static int sef_cb_init_fresh(int type, sef_init_info_t *info); -static void sef_cb_signal_handler(int signo); -EXTERN int sef_cb_lu_prepare(int state); -EXTERN int sef_cb_lu_state_isvalid(int state); -EXTERN void sef_cb_lu_state_dump(int state); +static const struct netdriver rl_table = { + .ndr_init = rl_init, + .ndr_stop = rl_stop, + .ndr_mode = rl_mode, + .ndr_recv = rl_recv, + .ndr_send = rl_send, + .ndr_stat = rl_stat, + .ndr_intr = rl_intr, + .ndr_alarm = rl_alarm, + .ndr_other = rl_other, +}; /*===========================================================================* * main * *===========================================================================*/ int main(int argc, char *argv[]) { - int r; - int ipc_status; - /* SEF local startup. */ env_setargs(argc, argv); - sef_local_startup(); - while (TRUE) - { - if ((r= netdriver_receive(ANY, &m, &ipc_status)) != OK) - panic("netdriver_receive failed: %d", r); + netdriver_task(&rl_table); - if (is_ipc_notify(ipc_status)) { - switch (_ENDPOINT_P(m.m_source)) { - case CLOCK: - /* - * Under MINIX, synchronous alarms are - * used instead of watchdog functions. - * The approach is very different: MINIX - * VMD timeouts are handled within the - * kernel (the watchdog is executed by - * CLOCK), and notify() the driver in - * some cases. MINIX timeouts result in - * a SYN_ALARM message to the driver and - * thus are handled where they should be - * handled. Locally, watchdog functions - * are used again. - */ - rl_watchdog_f(NULL); - break; - case HARDWARE: - do_hard_int(); - if (int_event_check) - check_int_events(); - break ; - case TTY_PROC_NR: - rtl8139_dump(&m); - break; - default: - panic("illegal notify from: %d", - m.m_source); - } - - /* done, get nwe message */ - continue; - } - - switch (m.m_type) - { - case DL_WRITEV_S: rl_writev_s(&m, FALSE); break; - case DL_READV_S: rl_readv_s(&m, FALSE); break; - case DL_CONF: rl_init(&m); break; - case DL_GETSTAT_S: rl_getstat_s(&m); break; - default: - panic("illegal message: %d", m.m_type); - } - } + return 0; } /*===========================================================================* - * sef_local_startup * + * rl_intr * *===========================================================================*/ -static void sef_local_startup() -{ - /* Register init callbacks. */ - sef_setcb_init_fresh(sef_cb_init_fresh); - sef_setcb_init_lu(sef_cb_init_fresh); - sef_setcb_init_restart(sef_cb_init_fresh); - - /* Register live update callbacks. */ - sef_setcb_lu_prepare(sef_cb_lu_prepare); - sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid); - sef_setcb_lu_state_dump(sef_cb_lu_state_dump); - - /* Register signal callbacks. */ - sef_setcb_signal_handler(sef_cb_signal_handler); - - /* Let SEF perform startup. */ - sef_startup(); -} - -/*===========================================================================* - * sef_cb_init_fresh * - *===========================================================================*/ -static int sef_cb_init_fresh(int type, sef_init_info_t *UNUSED(info)) -{ -/* Initialize the rtl8139 driver. */ - long v; -#if RTL8139_FKEY - int r, fkeys, sfkeys; -#endif - - system_hz = sys_hz(); - - v = 0; - (void) env_parse("instance", "d", 0, &v, 0, 255); - re_instance = (int) v; - -#if RTL8139_FKEY - /* Observe some function key for debug dumps. */ - fkeys = sfkeys = 0; bit_set(sfkeys, 9); - if ((r=fkey_map(&fkeys, &sfkeys)) != OK) - printf("Warning: RTL8139 couldn't observe Shift+F9 key: %d\n",r); -#endif - - /* Claim buffer memory now. */ - rl_init_buf(&re_state); - - /* Announce we are up! */ - netdriver_announce(); - - return(OK); -} - -/*===========================================================================* - * sef_cb_signal_handler * - *===========================================================================*/ -static void sef_cb_signal_handler(int signo) +static void rl_intr(unsigned int __unused mask) { re_t *rep; - - /* Only check for termination signal, ignore anything else. */ - if (signo != SIGTERM) return; + int s; rep = &re_state; - if (rep->re_mode == REM_ENABLED) - rl_outb(rep->re_base_port, RL_CR, 0); - exit(0); -} + /* Run interrupt handler at driver level. */ + rl_handler(rep); -/*===========================================================================* - * check_int_events * - *===========================================================================*/ -static void check_int_events(void) -{ - re_t *rep; + /* Reenable interrupts for this hook. */ + if ((s = sys_irqenable(&rep->re_hook_id)) != OK) + printf("RTL8139: error, couldn't enable interrupts: %d\n", s); - rep= &re_state; - - if (rep->re_mode != REM_ENABLED) - return; - if (!rep->re_got_int) - return; - rep->re_got_int= 0; - assert(rep->re_flags & REF_ENABLED); + /* Perform tasks based on the flagged conditions. */ rl_check_ints(rep); } /*===========================================================================* - * rtl8139_dump * + * rl_other * *===========================================================================*/ -static void rtl8139_dump(m) -message *m; /* pointer to request message */ +static void rl_other(const message *m_ptr, int ipc_status) +{ + if (is_ipc_notify(ipc_status) && m_ptr->m_source == TTY_PROC_NR) + rl_dump(); +} + +/*===========================================================================* + * rl_stop * + *===========================================================================*/ +static void rl_stop(void) +{ + re_t *rep; + + rep = &re_state; + + rl_outb(rep->re_base_port, RL_CR, 0); +} + +/*===========================================================================* + * rl_dump * + *===========================================================================*/ +static void rl_dump(void) { re_t *rep; rep= &re_state; printf("\n"); - if (rep->re_mode == REM_DISABLED) - printf("Realtek RTL 8139 instance %d is disabled\n", - re_instance); - - if (rep->re_mode != REM_ENABLED) - return; - printf("Realtek RTL 8139 statistics of instance %d:\n", re_instance); printf("recvErr :%8ld\t", rep->re_stat.ets_recvErr); @@ -307,8 +196,6 @@ message *m; /* pointer to request message */ printf("OWC :%8ld\t", rep->re_stat.ets_OWC); - printf("re_flags = 0x%x\n", rep->re_flags); - 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), @@ -322,93 +209,73 @@ message *m; /* pointer to request message */ } /*===========================================================================* - * rl_init * + * rl_mode * *===========================================================================*/ -static void rl_init(mp) -message *mp; +static void rl_mode(unsigned int mode) { - static int first_time= 1; - re_t *rep; - message reply_mess; - - if (first_time) - { - first_time= 0; - rl_pci_conf(); /* Configure PCI devices. */ - - /* Use a synchronous alarm instead of a watchdog timer. */ - sys_setalarm(system_hz, 0); - } rep= &re_state; - if (rep->re_mode == REM_DISABLED) - { - /* This is the default, try to (re)locate the device. */ - rl_conf_hw(rep); - if (rep->re_mode == REM_DISABLED) - { - /* Probe failed, or the device is configured off. */ - reply_mess.m_type= DL_CONF_REPLY; - reply_mess.m_netdrv_net_dl_conf.stat= ENXIO; - mess_reply(mp, &reply_mess); - return; - } - if (rep->re_mode == REM_ENABLED) - rl_init_hw(rep); -#if VERBOSE /* load silently ... can always check status later */ - rl_report_link(rep); -#endif - } - assert(rep->re_mode == REM_ENABLED); - assert(rep->re_flags & REF_ENABLED); - - rep->re_flags &= ~(REF_PROMISC | REF_MULTI | REF_BROAD); - - if (mp->m_net_netdrv_dl_conf.mode & DL_PROMISC_REQ) - rep->re_flags |= REF_PROMISC; - if (mp->m_net_netdrv_dl_conf.mode & DL_MULTI_REQ) - rep->re_flags |= REF_MULTI; - if (mp->m_net_netdrv_dl_conf.mode & DL_BROAD_REQ) - rep->re_flags |= REF_BROAD; + rep->re_mode = mode; rl_rec_mode(rep); - - reply_mess.m_type = DL_CONF_REPLY; - reply_mess.m_netdrv_net_dl_conf.stat = OK; - memcpy(reply_mess.m_netdrv_net_dl_conf.hw_addr, - rep->re_address.ea_addr, - sizeof(reply_mess.m_netdrv_net_dl_conf.hw_addr)); - - mess_reply(mp, &reply_mess); } /*===========================================================================* - * rl_pci_conf * + * rl_init * *===========================================================================*/ -static void rl_pci_conf() +static int rl_init(unsigned int instance, ether_addr_t *addr) { +/* Initialize the rtl8139 driver. */ re_t *rep; +#if RTL8139_FKEY + int r, fkeys, sfkeys; +#endif + /* Initialize driver state. */ rep= &re_state; + memset(rep, 0, sizeof(*rep)); + rep->re_link_up= -1; /* Unknown */ + rep->re_ertxth= RL_TSD_ERTXTH_8; strlcpy(rep->re_name, "rtl8139#0", sizeof(rep->re_name)); - rep->re_name[8] += re_instance; - rep->re_seen= FALSE; + rep->re_name[8] += instance; - pci_init(); + re_instance = instance; - if (rl_probe(rep, re_instance)) - rep->re_seen= TRUE; + /* Try to find a matching device. */ + if (!rl_probe(rep, instance)) + return ENXIO; + + /* Claim buffer memory. */ + rl_init_buf(rep); + + /* Initialize the device we found. */ + rl_init_hw(rep, addr); + +#if VERBOSE + /* Report initial link status. */ + rl_report_link(rep); +#endif + + /* Use a synchronous alarm instead of a watchdog timer. */ + sys_setalarm(sys_hz(), 0); + +#if RTL8139_FKEY + /* Observe some function key for debug dumps. */ + fkeys = sfkeys = 0; bit_set(sfkeys, 9); + if ((r = fkey_map(&fkeys, &sfkeys)) != OK) + printf("Warning: RTL8139 couldn't observe Shift+F9 key: %d\n",r); +#endif + + return OK; } /*===========================================================================* * rl_probe * *===========================================================================*/ -static int rl_probe(rep, skip) -re_t *rep; -int skip; +static int rl_probe(re_t *rep, unsigned int skip) { int r, devind; u16_t cr, vid, did; @@ -418,6 +285,8 @@ int skip; char *dname; #endif + pci_init(); + r= pci_first_dev(&devind, &vid, &did); if (r == 0) return 0; @@ -452,53 +321,18 @@ int skip; 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); - } +#if VERBOSE + printf("%s: using I/O address 0x%lx, IRQ %d\n", + rep->re_name, (unsigned long)bar, ilr); +#endif 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; +static void rl_init_buf(re_t *rep) { size_t rx_bufsize, tx_bufsize, tot_bufsize; phys_bytes buf; @@ -517,9 +351,8 @@ re_t *rep; #define BUF_ALIGNMENT (64*1024) - if(!(mallocbuf = alloc_contig(BUF_ALIGNMENT + tot_bufsize, 0, &buf))) { - panic("Couldn't allocate kernel buffer"); - } + if (!(mallocbuf = alloc_contig(BUF_ALIGNMENT + tot_bufsize, 0, &buf))) + panic("Couldn't allocate kernel buffer"); /* click-align mallocced buffer. this is what we used to get * from kmalloc() too. @@ -529,7 +362,7 @@ re_t *rep; buf += BUF_ALIGNMENT - off; } - tell_dev((vir_bytes)mallocbuf, tot_bufsize, 0, 0, 0); + tell_iommu((vir_bytes)mallocbuf, tot_bufsize, 0, 0, 0); for (i= 0; ire_flags = REF_EMPTY; - rep->re_flags |= REF_ENABLED; - - /* Set the interrupt handler. The policy is to only send HARD_INT + /* 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; + 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); @@ -578,23 +410,19 @@ re_t *rep; } #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_confaddr(rep, addr); + +#if VERBOSE + printf("%s: Ethernet address ", rep->re_name); + for (i= 0; i < 6; i++) + printf("%x%c", addr->ea_addr[i], i < 5 ? ':' : '\n'); +#endif } /*===========================================================================* * rl_reset_hw * *===========================================================================*/ -static void rl_reset_hw(rep) -re_t *rep; +static void rl_reset_hw(re_t *rep) { port_t port; u32_t t; @@ -660,7 +488,7 @@ re_t *rep; bus_buf= vm_1phys2bus(rep->re_rx_buf); rl_outl(port, RL_RBSTART, bus_buf); - /* Initialize Tx */ + /* Initialize Tx */ for (i= 0; ire_tx[i].ret_busy= FALSE; @@ -670,6 +498,8 @@ re_t *rep; assert(t & RL_TSD_OWN); } + rep->re_tx_busy = 0; + #if 0 dump_phy(rep); #endif @@ -700,8 +530,7 @@ re_t *rep; /*===========================================================================* * rl_confaddr * *===========================================================================*/ -static void rl_confaddr(rep) -re_t *rep; +static void rl_confaddr(re_t *rep, ether_addr_t *addr) { static char eakey[]= RL_ENVVAR "#_EA"; static char eafmt[]= "x:x:x:x:x:x"; @@ -720,7 +549,7 @@ re_t *rep; { if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET) break; - rep->re_address.ea_addr[i]= v; + addr->ea_addr[i]= v; } if (i != 0 && i != 6) env_panic(eakey); /* It's all or nothing */ @@ -732,25 +561,24 @@ re_t *rep; 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)); + w |= (addr->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)); + w |= (addr->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); + addr->ea_addr[i]= rl_inb(port, RL_IDR+i); } /*===========================================================================* * rl_rec_mode * *===========================================================================*/ -static void rl_rec_mode(rep) -re_t *rep; +static void rl_rec_mode(re_t *rep) { port_t port; u32_t rcr; @@ -758,11 +586,11 @@ re_t *rep; 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) + if (rep->re_mode & NDEV_PROMISC) rcr |= RL_RCR_AB | RL_RCR_AM | RL_RCR_AAP; - if (rep->re_flags & REF_BROAD) + if (rep->re_mode & NDEV_BROAD) rcr |= RL_RCR_AB; - if (rep->re_flags & REF_MULTI) + if (rep->re_mode & NDEV_MULTI) rcr |= RL_RCR_AM; rcr |= RL_RCR_APM; @@ -770,39 +598,28 @@ re_t *rep; } /*===========================================================================* - * rl_readv_s * + * rl_recv * *===========================================================================*/ -static void rl_readv_s(const message *mp, int from_int) +static ssize_t rl_recv(struct netdriver_data *data, size_t max) { - int i, j, n, o, s, s1, count, size; + int o, s; port_t port; unsigned amount, totlen, packlen; u16_t d_start, d_end; - u32_t l, rxstat = 0x12345678; + u32_t l, rxstat; re_t *rep; - iovec_s_t *iovp; - int cps; - int iov_offset = 0; rep= &re_state; - rep->re_client= mp->m_source; - count = mp->m_net_netdrv_dl_readv_s.count; - if (rep->re_clear_rx) - goto suspend; /* Buffer overflow */ - - assert(rep->re_mode == REM_ENABLED); - assert(rep->re_flags & REF_ENABLED); + return SUSPEND; /* Buffer overflow */ 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)) + if (rl_inb(port, RL_CR) & RL_CR_BUFE) { /* Receive buffer is empty, suspend */ - goto suspend; + return SUSPEND; } d_start= rl_inw(port, RL_CAPR) + RL_CAPR_DATA_OFF; @@ -811,7 +628,7 @@ static void rl_readv_s(const message *mp, int from_int) #if RX_BUFSIZE <= USHRT_MAX if (d_start >= RX_BUFSIZE) { - printf("rl_readv: strange value in RL_CAPR: 0x%x\n", + printf("rl_recv: strange value in RL_CAPR: 0x%x\n", rl_inw(port, RL_CAPR)); d_start %= RX_BUFSIZE; } @@ -824,14 +641,6 @@ static void rl_readv_s(const message *mp, int from_int) rxstat = *(u32_t *) (rep->v_re_rx_buf + d_start); - if (rep->re_clear_rx) - { -#if 0 - printf("rl_readv: late buffer overflow\n"); -#endif - goto suspend; /* Buffer overflow */ - } - /* Should convert from little endian to host byte order */ if (!(rxstat & RL_RXS_ROK)) @@ -846,7 +655,7 @@ static void rl_readv_s(const message *mp, int from_int) { /* Someting went wrong */ printf( - "rl_readv: bad length (%u) in status 0x%08x at offset 0x%x\n", + "rl_recv: bad length (%u) in status 0x%08x at offset 0x%x\n", totlen, rxstat, d_start); printf( "d_start: 0x%x, d_end: 0x%x, totlen: %d, rxstat: 0x%x\n", @@ -861,106 +670,22 @@ static void rl_readv_s(const message *mp, int from_int) if (totlen+4 > amount) { - printf("rl_readv: packet not yet ready\n"); - goto suspend; + printf("rl_recv: packet not yet ready\n"); + return SUSPEND; } /* Should subtract the CRC */ - packlen= totlen - ETH_CRC_SIZE; + packlen = MIN(totlen - ETH_CRC_SIZE, max); - size= 0; - o= d_start+4; - for (i= 0; ire_iovec_s[0])) - { - n= IOVEC_NR; - if (i+n > count) - n= count-i; + /* Copy out the data. The packet may wrap in the receive buffer. */ + o = (d_start+4) % RX_BUFSIZE; + s = MIN(RX_BUFSIZE - o, packlen); - cps = sys_safecopyfrom(mp->m_source, - mp->m_net_netdrv_dl_readv_s.grant, iov_offset, - (vir_bytes) rep->re_iovec_s, - n * sizeof(rep->re_iovec_s[0])); - if (cps != OK) { - panic("rl_readv_s: sys_safecopyfrom failed: %d", - cps); - } - - for (j= 0, iovp= rep->re_iovec_s; jiov_size; - if (size + s > packlen) - { - assert(packlen > size); - s= packlen-size; - } - -#if 0 - if (sys_umap(mp->m_source, D, iovp->iov_addr, s, &dst_phys) != OK) - panic("umap_local failed"); -#endif - - if (o >= RX_BUFSIZE) - { - o -= RX_BUFSIZE; - assert(o < RX_BUFSIZE); - } - - if (o+s > RX_BUFSIZE) - { - assert(om_source, - iovp->iov_grant, 0, - (vir_bytes) rep->v_re_rx_buf+o, s1); - if (cps != OK) { - panic("rl_readv_s: sys_safecopyto failed: %d", - cps); - } - cps = sys_safecopyto(mp->m_source, - iovp->iov_grant, s1, - (vir_bytes) rep->v_re_rx_buf, s-s1); - if (cps != OK) { - panic("rl_readv_s: sys_safecopyto failed: %d", cps); - } - } - else - { - cps = sys_safecopyto(mp->m_source, - iovp->iov_grant, 0, - (vir_bytes) rep->v_re_rx_buf+o, s); - if (cps != OK) - panic("rl_readv_s: sys_safecopyto failed: %d", cps); - } - - size += s; - if (size == packlen) - break; - o += s; - } - if (size == packlen) - break; - } - if (size < packlen) - { - assert(0); - } - - if (rep->re_clear_rx) - { - /* For some reason the receiver FIFO is not stopped when - * the buffer is full. - */ -#if 0 - printf("rl_readv: later buffer overflow\n"); -#endif - goto suspend; /* Buffer overflow */ - } + netdriver_copyout(data, 0, rep->v_re_rx_buf + o, s); + if (s < packlen) + netdriver_copyout(data, s, rep->v_re_rx_buf, packlen - s); rep->re_stat.ets_packetR++; - rep->re_read_s= packlen; - rep->re_flags= (rep->re_flags & ~REF_READING) | REF_PACK_RECV; /* Avoid overflow in 16-bit computations */ l= d_start; @@ -973,145 +698,41 @@ static void rl_readv_s(const message *mp, int from_int) } rl_outw(port, RL_CAPR, l-RL_CAPR_DATA_OFF); - if (!from_int) - reply(rep); - - return; - -suspend: - if (from_int) - { - assert(rep->re_flags & REF_READING); - - /* No need to store any state */ - return; - } - - rep->re_rx_mess= *mp; - assert(!(rep->re_flags & REF_READING)); - rep->re_flags |= REF_READING; - - reply(rep); + return packlen; } /*===========================================================================* - * rl_writev_s * + * rl_send * *===========================================================================*/ -static void rl_writev_s(const message *mp, int from_int) +static int rl_send(struct netdriver_data *data, size_t size) { - int i, j, n, s, count, size; int tx_head; re_t *rep; - iovec_s_t *iovp; - char *ret; - int cps; - int iov_offset = 0; rep= &re_state; - rep->re_client= mp->m_source; - count = mp->m_net_netdrv_dl_writev_s.count; - - assert(rep->re_mode == REM_ENABLED); - assert(rep->re_flags & REF_ENABLED); - - if (from_int) - { - assert(rep->re_flags & REF_SEND_AVAIL); - rep->re_flags &= ~REF_SEND_AVAIL; - rep->re_send_int= FALSE; - rep->re_tx_alive= TRUE; - } - tx_head= rep->re_tx_head; if (rep->re_tx[tx_head].ret_busy) - { - assert(!(rep->re_flags & REF_SEND_AVAIL)); - rep->re_flags |= REF_SEND_AVAIL; - goto suspend; - } + return SUSPEND; - assert(!(rep->re_flags & REF_SEND_AVAIL)); - assert(!(rep->re_flags & REF_PACK_SENT)); + netdriver_copyin(data, 0, rep->re_tx[tx_head].v_ret_buf, size); - size= 0; - ret = rep->re_tx[tx_head].v_ret_buf; - for (i= 0; ire_iovec_s[0])) - { - n= IOVEC_NR; - if (i+n > count) - n= count-i; - cps = sys_safecopyfrom(mp->m_source, - mp->m_net_netdrv_dl_writev_s.grant, iov_offset, - (vir_bytes) rep->re_iovec_s, - n * sizeof(rep->re_iovec_s[0])); - if (cps != OK) { - panic("rl_writev_s: sys_safecopyfrom failed: %d", cps); - } - - for (j= 0, iovp= rep->re_iovec_s; jiov_size; - if (size + s > ETH_MAX_PACK_SIZE_TAGGED) { - panic("invalid packet size"); - } - cps = sys_safecopyfrom(mp->m_source, iovp->iov_grant, - 0, (vir_bytes) ret, s); - if (cps != OK) { - panic("rl_writev_s: sys_safecopyfrom failed: %d", cps); - } - size += s; - ret += s; - } - } - if (size < ETH_MIN_PACK_SIZE) - panic("invalid packet size: %d", size); - - rl_outl(rep->re_base_port, RL_TSD0+tx_head*4, - rep->re_ertxth | size); + rl_outl(rep->re_base_port, RL_TSD0+tx_head*4, rep->re_ertxth | size); rep->re_tx[tx_head].ret_busy= TRUE; + rep->re_tx_busy++; if (++tx_head == N_TX_BUF) tx_head= 0; assert(tx_head < RL_N_TX); rep->re_tx_head= tx_head; - rep->re_flags |= REF_PACK_SENT; - - /* If the interrupt handler called, don't send a reply. The reply - * will be sent after all interrupts are handled. - */ - if (from_int) - return; - reply(rep); - return; - -suspend: -#if 0 - printf("rl_writev: head %d, tail %d, busy: %d %d %d %d\n", - 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_writev: TSD: 0x%x, 0x%x, 0x%x, 0x%x\n", - 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)); -#endif - - if (from_int) - panic("should not be sending"); - - rep->re_tx_mess= *mp; - reply(rep); + return OK; } /*===========================================================================* * rl_check_ints * *===========================================================================*/ -static void rl_check_ints(rep) -re_t *rep; +static void rl_check_ints(re_t *rep) { #if 0 10-1f R/W TSD[0-3] Transmit Status of Descriptor [0-3] @@ -1152,45 +773,41 @@ re_t *rep; 15-0 R RXERCNT Received packet counter #endif - int re_flags; + if (!rep->re_got_int) + return; + rep->re_got_int = FALSE; - re_flags= rep->re_flags; + netdriver_recv(); - if ((re_flags & REF_READING) && - !(rl_inb(rep->re_base_port, RL_CR) & RL_CR_BUFE)) - { - rl_readv_s(&rep->re_rx_mess, TRUE /* from int */); - } if (rep->re_clear_rx) rl_clear_rx(rep); if (rep->re_need_reset) rl_do_reset(rep); - if (rep->re_send_int) - { - rl_writev_s(&rep->re_tx_mess, TRUE /* from int */); + if (rep->re_send_int) { + rep->re_send_int = FALSE; + + netdriver_send(); } - if (rep->re_report_link) - rl_report_link(rep); + if (rep->re_report_link) { + rep->re_report_link = FALSE; - if (rep->re_flags & (REF_PACK_SENT | REF_PACK_RECV)) - reply(rep); + rl_report_link(rep); + } } /*===========================================================================* * rl_report_link * *===========================================================================*/ -static void rl_report_link(rep) -re_t *rep; +static void rl_report_link(re_t *rep) { port_t port; u16_t mii_ctrl, mii_status, mii_ana, mii_anlpa, mii_ane, mii_extstat; u8_t msr; int f, link_up; - rep->re_report_link= FALSE; port= rep->re_base_port; msr= rl_inb(port, RL_MSR); link_up= !(msr & RL_MSR_LINKB); @@ -1250,8 +867,7 @@ re_t *rep; return; } - if (!debug) goto resspeed; - +#if VERBOSE printf("%s: ", rep->re_name); mii_print_stat_speed(mii_status, mii_extstat); printf("\n"); @@ -1293,14 +909,16 @@ re_t *rep; printf("%s: remote cap.: ", rep->re_name); mii_print_techab(mii_anlpa); printf("\n"); - resspeed: +#endif + printf("%s: ", rep->re_name); printf("link up at %d Mbps, ", (msr & RL_MSR_SPEED_10) ? 10 : 100); printf("%s duplex\n", ((mii_ctrl & MII_CTRL_DM) ? "full" : "half")); } +#if VERBOSE static void mii_print_techab(u16_t techab) { int fs, ft; @@ -1469,6 +1087,7 @@ static void mii_print_stat_speed(u16_t stat, u16_t extstat) } } } +#endif /* VERBOSE */ /*===========================================================================* * rl_clear_rx * @@ -1508,98 +1127,32 @@ static void rl_clear_rx(re_t *rep) /*===========================================================================* * rl_do_reset * *===========================================================================*/ -static void rl_do_reset(rep) -re_t *rep; +static void rl_do_reset(re_t *rep) { rep->re_need_reset= FALSE; rl_reset_hw(rep); rl_rec_mode(rep); rep->re_tx_head= 0; - if (rep->re_flags & REF_SEND_AVAIL) - { - rep->re_tx[rep->re_tx_head].ret_busy= FALSE; - rep->re_send_int= TRUE; - } + if (rep->re_tx[rep->re_tx_head].ret_busy) + rep->re_tx_busy--; + rep->re_tx[rep->re_tx_head].ret_busy= FALSE; + rep->re_send_int= TRUE; } /*===========================================================================* - * rl_getstat_s * + * rl_stat * *===========================================================================*/ -static void rl_getstat_s(mp) -message *mp; +static void rl_stat(eth_stat_t *stat) { - int r; - eth_stat_t stats; - re_t *rep; - - rep= &re_state; - - assert(rep->re_mode == REM_ENABLED); - assert(rep->re_flags & REF_ENABLED); - - stats= rep->re_stat; - - r = sys_safecopyto(mp->m_source, mp->m_net_netdrv_dl_getstat_s.grant, - 0, (vir_bytes) &stats, sizeof(stats)); - if (r != OK) - panic("rl_getstat_s: sys_safecopyto failed: %d", r); - - mp->m_type= DL_STAT_REPLY; - r= ipc_send(mp->m_source, mp); - if (r != OK) - panic("rl_getstat_s: ipc_send failed: %d", r); -} - -/*===========================================================================* - * reply * - *===========================================================================*/ -static void reply(rep) -re_t *rep; -{ - message reply; - int flags; - int r; - - flags = DL_NOFLAGS; - if (rep->re_flags & REF_PACK_SENT) - flags |= DL_PACK_SEND; - if (rep->re_flags & REF_PACK_RECV) - flags |= DL_PACK_RECV; - - reply.m_type = DL_TASK_REPLY; - reply.m_netdrv_net_dl_task.flags = flags; - reply.m_netdrv_net_dl_task.count = rep->re_read_s; - - r= ipc_send(rep->re_client, &reply); - - if (r < 0) { - printf("RTL8139 tried sending to %d, type %d\n", - rep->re_client, reply.m_type); - panic("ipc_send failed: %d", r); - } - - rep->re_read_s = 0; - rep->re_flags &= ~(REF_PACK_SENT | REF_PACK_RECV); -} - -/*===========================================================================* - * mess_reply * - *===========================================================================*/ -static void mess_reply(req, reply_mess) -message *req; -message *reply_mess; -{ - if (ipc_send(req->m_source, reply_mess) != OK) - panic("unable to mess_reply"); + memcpy(stat, &re_state.re_stat, sizeof(*stat)); } #if 0 /*===========================================================================* * dump_phy * *===========================================================================*/ -static void dump_phy(rep) -re_t *rep; +static void dump_phy(re_t *rep) { port_t port; u32_t t; @@ -1693,21 +1246,6 @@ re_t *rep; } #endif -/*===========================================================================* - * do_hard_int * - *===========================================================================*/ -static void do_hard_int(void) -{ - int s; - - /* Run interrupt handler at driver level. */ - rl_handler(&re_state); - - /* Reenable interrupts for this hook. */ - if ((s=sys_irqenable(&re_state.re_hook_id)) != OK) - printf("RTL8139: error, couldn't enable interrupts: %d\n", s); -} - /*===========================================================================* * rl_handler * *===========================================================================*/ @@ -1716,10 +1254,6 @@ static int rl_handler(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 - int_event_check = FALSE; /* disable check by default */ port= rep->re_base_port; @@ -1746,7 +1280,6 @@ static int rl_handler(re_t *rep) { rep->re_report_link= TRUE; rep->re_got_int= TRUE; - int_event_check = TRUE; } } if (isr & RL_IMR_RXOVW) @@ -1756,40 +1289,14 @@ static int rl_handler(re_t *rep) /* 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; - } + rep->re_got_int= 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); @@ -1798,41 +1305,6 @@ static int rl_handler(re_t *rep) 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); - SPIN_UNTIL(!(rl_inb(port, RL_CR) & RL_CR_TE), 1000000); - if (rl_inb(port, RL_CR) & RL_CR_TE) { - panic("cannot disable transmitter"); - } - 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); @@ -1862,7 +1334,6 @@ static int rl_handler(re_t *rep) rep->re_stat.ets_transAb++; tcr= rl_inl(port, RL_TCR); rl_outl(port, RL_TCR, tcr | RL_TCR_CLRABT); -#endif } /* Transmit completed */ @@ -1923,7 +1394,8 @@ static int rl_handler(re_t *rep) /* Increase ERTXTH */ ertxth= tsd + (1 << RL_TSD_ERTXTH_S); ertxth &= RL_TSD_ERTXTH_M; - if (debug && ertxth > rep->re_ertxth) +#if VERBOSE + if (ertxth > rep->re_ertxth) { printf("%s: new ertxth: %d bytes\n", rep->re_name, @@ -1931,19 +1403,18 @@ static int rl_handler(re_t *rep) 32); rep->re_ertxth= ertxth; } +#endif } rep->re_tx[tx_tail].ret_busy= FALSE; + rep->re_tx_busy--; #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", + "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[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) @@ -1951,18 +1422,9 @@ static int rl_handler(re_t *rep) 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; - } - } + rep->re_send_int= TRUE; + rep->re_got_int= TRUE; + rep->re_tx_alive= TRUE; } assert(i < 2*N_TX_BUF); } @@ -1976,20 +1438,19 @@ static int rl_handler(re_t *rep) } /*===========================================================================* - * rl_watchdog_f * + * rl_alarm * *===========================================================================*/ -static void rl_watchdog_f(tp) -minix_timer_t *tp; +static void rl_alarm(clock_t __unused stamp) { re_t *rep; + /* Use a synchronous alarm instead of a watchdog timer. */ - sys_setalarm(system_hz, 0); + sys_setalarm(sys_hz(), 0); rep= &re_state; - if (rep->re_mode != REM_ENABLED) - return; - if (!(rep->re_flags & REF_SEND_AVAIL)) + assert(rep->re_tx_busy >= 0 && rep->re_tx_busy <= N_TX_BUF); + if (rep->re_tx_busy == 0) { /* Assume that an idle system is alive */ rep->re_tx_alive= TRUE; @@ -2000,7 +1461,7 @@ minix_timer_t *tp; rep->re_tx_alive= FALSE; return; } - printf("rl_watchdog_f: resetting instance %d\n", re_instance); + printf("rl_alarm: resetting instance %d\n", re_instance); 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), @@ -2013,242 +1474,13 @@ minix_timer_t *tp; 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(); + + rl_check_ints(rep); } -#if 0 - -static void rtl_init(struct dpeth *dep); -static u16_t get_ee_word(dpeth_t *dep, int a); -static void ee_wen(dpeth_t *dep); -static void set_ee_word(dpeth_t *dep, int a, u16_t w); -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(dpeth_t *dep, int a, u16_t w) -dpeth_t *dep; -int a; -u16_t w; -{ - int b, i, cmd; - - outb_reg3(dep, 1, 0x80 | 0x8); /* Set CS */ - - cmd= 0x140 | (a & 0x3f); /* 1 0 1 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); - } - for (i= 15; i >= 0; i--) - { - b= (w & (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 data */ - outb_reg3(dep, 1, 0x80); /* Drop CS */ - /* micro_delay(1); */ /* Is this required? */ - outb_reg3(dep, 1, 0x80 | 0x8); /* Set CS */ - SPIN_UNTIL(inb_reg3(dep, 1) & 1, 10000); - if (!(inb_reg3(dep, 1) & 1)) - panic("device remains busy"); -} - -static void ee_wds(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= 0x100; /* 1 0 0 0 0 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 */ - outb_reg3(dep, 1, 0x00); /* back to normal */ - outb_reg0(dep, DP_CR, CR_PS_P0); /* back to bank 0 */ -} -#endif - -static void tell_dev(buf, size, pci_bus, pci_dev, pci_func) -vir_bytes buf; -size_t size; -int pci_bus; -int pci_dev; -int pci_func; +/* TODO: obviously this needs a lot of work. */ +static void tell_iommu(vir_bytes buf, size_t size, int pci_bus, int pci_dev, + int pci_func) { int r; endpoint_t dev_e; @@ -2258,9 +1490,8 @@ int pci_func; if (r != OK) { #if 0 - printf( - "rtl8139`tell_dev: ds_retrieve_label_endpt failed for 'amddev': %d\n", - r); + printf("rtl8139`tell_dev: ds_retrieve_label_endpt failed " + "for 'amddev': %d\n", r); #endif return; } diff --git a/minix/drivers/net/rtl8139/rtl8139.h b/minix/drivers/net/rtl8139/rtl8139.h index 85d472ce2..19b995287 100644 --- a/minix/drivers/net/rtl8139/rtl8139.h +++ b/minix/drivers/net/rtl8139/rtl8139.h @@ -6,32 +6,9 @@ Created: Aug 2003 by Philip Homburg #include #include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include - -#include -#include +#include #include -#include -#include -#include "kernel/const.h" -#include "kernel/config.h" -#include "kernel/type.h" #define RL_IDR 0x00 /* Ethernet address * Note: RL_9346CR_EEM_CONFIG mode is @@ -453,18 +430,12 @@ d8 R/W Config5 Configuration register 5 d9-ff reserved #endif -#define Proc_number(p) proc_number(p) -#define debug 0 -#define printW() ((void)0) #define vm_1phys2bus(p) (p) #define RX_BUFSIZE RL_RCR_RBLEN_64K_SIZE #define RX_BUFBITS RL_RCR_RBLEN_64K #define N_TX_BUF RL_N_TX -/* I/O vectors are handled IOVEC_NR entries at a time. */ -#define IOVEC_NR 16 - /* Configuration */ #define RL_ENVVAR "RTLETH" @@ -473,8 +444,6 @@ typedef struct re port_t re_base_port; int re_irq; int re_mode; - int re_flags; - int re_client; int re_link_up; int re_got_int; int re_send_int; @@ -482,12 +451,12 @@ typedef struct re int re_clear_rx; int re_need_reset; int re_tx_alive; - char *re_model; + int re_tx_busy; + const char *re_model; /* Rx */ phys_bytes re_rx_buf; char *v_re_rx_buf; - vir_bytes re_read_s; /* Tx */ int re_tx_head; @@ -500,33 +469,10 @@ typedef struct re } re_tx[N_TX_BUF]; u32_t re_ertxth; /* Early Tx Threshold */ - /* PCI related */ - int re_seen; /* TRUE iff device available */ - - /* 'large' items */ int re_hook_id; /* IRQ hook id at kernel */ eth_stat_t re_stat; - ether_addr_t re_address; - message re_rx_mess; - message re_tx_mess; char re_name[sizeof("rtl8139#n")]; - iovec_t re_iovec[IOVEC_NR]; - iovec_s_t re_iovec_s[IOVEC_NR]; -} -re_t; - -#define REM_DISABLED 0x0 -#define REM_ENABLED 0x1 - -#define REF_PACK_SENT 0x001 -#define REF_PACK_RECV 0x002 -#define REF_SEND_AVAIL 0x004 -#define REF_READING 0x010 -#define REF_EMPTY 0x000 -#define REF_PROMISC 0x040 -#define REF_MULTI 0x080 -#define REF_BROAD 0x100 -#define REF_ENABLED 0x200 +} re_t; /* * $PchId: rtl8139.h,v 1.1 2003/09/05 10:58:50 philip Exp $ diff --git a/minix/drivers/net/rtl8169/Makefile b/minix/drivers/net/rtl8169/Makefile index e45e7843f..f68d31910 100644 --- a/minix/drivers/net/rtl8169/Makefile +++ b/minix/drivers/net/rtl8169/Makefile @@ -6,8 +6,8 @@ FILES=$(PROG).conf FILESNAME=$(PROG) FILESDIR= /etc/system.conf.d -DPADD+= ${LIBNETDRIVER} ${LIBSYS} ${LIBTIMERS} -LDADD+= -lnetdriver -lsys -ltimers +DPADD+= ${LIBNETDRIVER} ${LIBSYS} +LDADD+= -lnetdriver -lsys CPPFLAGS+= -I${NETBSDSRCDIR}/minix diff --git a/minix/drivers/net/rtl8169/rtl8169.c b/minix/drivers/net/rtl8169/rtl8169.c index 420736e30..47c7bcab9 100644 --- a/minix/drivers/net/rtl8169/rtl8169.c +++ b/minix/drivers/net/rtl8169/rtl8169.c @@ -9,39 +9,19 @@ #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include - -#include #include -#include -#include "kernel/const.h" -#include "kernel/config.h" -#include "kernel/type.h" - -#define VERBOSE 0 /* display message during init */ #include "rtl8169.h" -#define IOVEC_NR 16 /* I/O vectors are handled IOVEC_NR entries at a time. */ +#define VERBOSE 0 /* display message during init */ -#define RE_DTCC_VALUE 600 /* DTCC Update after every 10 minutes */ +#define RE_DTCC_VALUE 600 /* DTCC Update once every 10 minutes */ #define RX_CONFIG_MASK 0xff7e1880 /* Clears the bits supported by chip */ -#define RE_INTR_MASK (RL_IMR_TDU | RL_IMR_FOVW | RL_IMR_PUN | RL_IMR_RDU | RL_IMR_TER | RL_IMR_TOK | RL_IMR_RER | RL_IMR_ROK) +#define RE_INTR_MASK (RL_IMR_TDU | RL_IMR_FOVW | RL_IMR_PUN | RL_IMR_RDU | \ + RL_IMR_TER | RL_IMR_TOK | RL_IMR_RER | RL_IMR_ROK) #define RL_ENVVAR "RTLETH" /* Configuration */ @@ -63,14 +43,14 @@ typedef struct re_dtcc u32_t TxEr_high; /* high 32-bits of Tx errors */ u32_t RxEr; /* Rx errors */ u16_t MissPkt; /* Missed packets */ - u16_t FAE; /* Frame Aignment Error packets (MII mode only) */ - u32_t Tx1Col; /* Tx Ok packets with only 1 collision happened before Tx Ok */ - u32_t TxMCol; /* Tx Ok packets with > 1 and < 16 collisions happened before Tx Ok */ - u32_t RxOkPhy_low; /* low 32-bits of Rx Ok packets with physical addr destination ID */ - u32_t RxOkPhy_high; /* high 32-bits of Rx Ok packets with physical addr destination ID */ - u32_t RxOkBrd_low; /* low 32-bits of Rx Ok packets with broadcast destination ID */ - u32_t RxOkBrd_high; /* high 32-bits of Rx Ok packets with broadcast destination ID */ - u32_t RxOkMul; /* Rx Ok Packets with multicast destination ID */ + u16_t FAE; /* Frame Alignment Error packets (MII only) */ + u32_t Tx1Col; /* Tx Ok packets with 1 collision before Tx */ + u32_t TxMCol; /* Tx Ok packets with 2..15 collisions */ + u32_t RxOkPhy_low; /* low 32-bits of Rx Ok packets for us */ + u32_t RxOkPhy_high; /* high 32-bits of Rx Ok packets for us */ + u32_t RxOkBrd_low; /* low 32-bits of Rx Ok broadcast packets */ + u32_t RxOkBrd_high; /* high 32-bits of Rx Ok broadcast packets */ + u32_t RxOkMul; /* Rx Ok multicast packets */ u16_t TxAbt; /* Tx abort packets */ u16_t TxUndrn; /* Tx underrun packets */ } re_dtcc; @@ -79,27 +59,22 @@ typedef struct re { port_t re_base_port; int re_irq; int re_mode; - int re_flags; - endpoint_t re_client; int re_link_up; int re_got_int; int re_send_int; int re_report_link; int re_need_reset; int re_tx_alive; - int setup; u32_t re_mac; - char *re_model; + const char *re_model; /* Rx */ int re_rx_head; struct { - int ret_busy; phys_bytes ret_buf; char *v_ret_buf; } re_rx[N_RX_DESC]; - vir_bytes re_read_s; re_desc *re_rx_desc; /* Rx descriptor buffer */ phys_bytes p_rx_desc; /* Rx descriptor buffer physical */ @@ -112,38 +87,16 @@ typedef struct re { } re_tx[N_TX_DESC]; re_desc *re_tx_desc; /* Tx descriptor buffer */ phys_bytes p_tx_desc; /* Tx descriptor buffer physical */ + int re_tx_busy; /* how many Tx descriptors are busy? */ - /* PCI related */ - int re_seen; /* TRUE iff device available */ - - /* 'large' items */ int re_hook_id; /* IRQ hook id at kernel */ eth_stat_t re_stat; phys_bytes dtcc_buf; /* Dump Tally Counter buffer physical */ re_dtcc *v_dtcc_buf; /* Dump Tally Counter buffer */ u32_t dtcc_counter; /* DTCC update counter */ - ether_addr_t re_address; - message re_rx_mess; - message re_tx_mess; char re_name[sizeof("rtl8169#n")]; - iovec_t re_iovec[IOVEC_NR]; - iovec_s_t re_iovec_s[IOVEC_NR]; u32_t interrupts; -} -re_t; - -#define REM_DISABLED 0x0 -#define REM_ENABLED 0x1 - -#define REF_PACK_SENT 0x001 -#define REF_PACK_RECV 0x002 -#define REF_SEND_AVAIL 0x004 -#define REF_READING 0x010 -#define REF_EMPTY 0x000 -#define REF_PROMISC 0x040 -#define REF_MULTI 0x080 -#define REF_BROAD 0x100 -#define REF_ENABLED 0x200 +} re_t; static re_t re_state; @@ -202,167 +155,102 @@ static void my_outl(u16_t port, u32_t value) #define rl_outw(port, offset, value) (my_outw((port) + (offset), (value))) #define rl_outl(port, offset, value) (my_outl((port) + (offset), (value))) -static void rl_init(message *mp); -static void rl_pci_conf(void); -static int rl_probe(re_t *rep, int skip); -static void rl_conf_hw(re_t *rep); +static int rl_init(unsigned int instance, ether_addr_t *addr); +static int rl_probe(re_t *rep, unsigned int skip); static void rl_init_buf(re_t *rep); -static void rl_init_hw(re_t *rep); +static void rl_init_hw(re_t *rep, ether_addr_t *addr); static void rl_reset_hw(re_t *rep); -static void rl_confaddr(re_t *rep); +static void rl_confaddr(re_t *rep, ether_addr_t *addr); +static void rl_stop(void); static void rl_rec_mode(re_t *rep); -static void rl_readv_s(const message *mp, int from_int); -static void rl_writev_s(const message *mp, int from_int); +static void rl_mode(unsigned int mode); +static ssize_t rl_recv(struct netdriver_data *data, size_t max); +static int rl_send(struct netdriver_data *data, size_t size); +static void rl_intr(unsigned int mask); static void rl_check_ints(re_t *rep); -static void rl_report_link(re_t *rep); static void rl_do_reset(re_t *rep); -static void rl_getstat_s(message *mp); -static void reply(re_t *rep); -static void mess_reply(message *req, message *reply); -static void check_int_events(void); -static void do_hard_int(void); +static void rl_stat(eth_stat_t *stat); +#if VERBOSE +static void rl_report_link(re_t *rep); static void dump_phy(const re_t *rep); +#endif static void rl_handler(re_t *rep); -static void rl_watchdog_f(minix_timer_t *tp); +static void rl_alarm(clock_t stamp); -/* - * The message used in the main loop is made global, so that rl_watchdog_f() - * can change its message type to fake an interrupt message. - */ -static message m; -static int int_event_check; /* set to TRUE if events arrived */ - -u32_t system_hz; - -/* SEF functions and variables. */ -static void sef_local_startup(void); -static int sef_cb_init_fresh(int type, sef_init_info_t *info); -static void sef_cb_signal_handler(int signo); +static const struct netdriver rl_table = { + .ndr_init = rl_init, + .ndr_stop = rl_stop, + .ndr_mode = rl_mode, + .ndr_recv = rl_recv, + .ndr_send = rl_send, + .ndr_stat = rl_stat, + .ndr_intr = rl_intr, + .ndr_alarm = rl_alarm +}; /*===========================================================================* * main * *===========================================================================*/ int main(int argc, char *argv[]) { - int r; - int ipc_status; - - /* SEF local startup. */ env_setargs(argc, argv); - sef_local_startup(); - while (TRUE) { - if ((r = netdriver_receive(ANY, &m, &ipc_status)) != OK) - panic("netdriver_receive failed: %d", r); + netdriver_task(&rl_table); - if (is_ipc_notify(ipc_status)) { - switch (_ENDPOINT_P(m.m_source)) { - case CLOCK: - /* - * Under MINIX, synchronous alarms are used - * instead of watchdog functions. - * The approach is very different: MINIX VMD - * timeouts are handled within the kernel - * (the watchdog is executed by CLOCK), and - * notify() the driver in some cases. MINIX - * timeouts result in a SYN_ALARM message to - * the driver and thus are handled where they - * should be handled. Locally, watchdog - * functions are used again. - */ - rl_watchdog_f(NULL); - break; - case HARDWARE: - do_hard_int(); - if (int_event_check) { - check_int_events(); - } - break ; - default: - panic("illegal notify from: %d", m.m_type); - } - - /* done, get nwe message */ - continue; - } - - switch (m.m_type) { - case DL_WRITEV_S: rl_writev_s(&m, FALSE); break; - case DL_READV_S: rl_readv_s(&m, FALSE); break; - case DL_CONF: rl_init(&m); break; - case DL_GETSTAT_S: rl_getstat_s(&m); break; - default: - panic("illegal message: %d", m.m_type); - } - } + return 0; } /*===========================================================================* - * sef_local_startup * + * rl_init * *===========================================================================*/ -static void sef_local_startup() -{ - /* Register init callbacks. */ - sef_setcb_init_fresh(sef_cb_init_fresh); - sef_setcb_init_lu(sef_cb_init_fresh); - sef_setcb_init_restart(sef_cb_init_fresh); - - /* Register live update callbacks. */ - sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready); - sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_workfree); - - /* Register signal callbacks. */ - sef_setcb_signal_handler(sef_cb_signal_handler); - - /* Let SEF perform startup. */ - sef_startup(); -} - -/*===========================================================================* - * sef_cb_init_fresh * - *===========================================================================*/ -static int sef_cb_init_fresh(int type, sef_init_info_t *UNUSED(info)) +static int rl_init(unsigned int instance, ether_addr_t *addr) { /* Initialize the rtl8169 driver. */ - long v; + re_t *rep; - system_hz = sys_hz(); + /* Initialize driver state. */ + rep = &re_state; + memset(rep, 0, sizeof(*rep)); - v = 0; - (void) env_parse("instance", "d", 0, &v, 0, 255); - re_instance = (int) v; + strlcpy(rep->re_name, "rtl8169#0", sizeof(rep->re_name)); + rep->re_name[8] += re_instance; + + re_instance = instance; + + /* Try to find a matching device. */ + if (!rl_probe(rep, instance)) + return ENXIO; /* Claim buffer memory now. */ rl_init_buf(&re_state); - /* Announce we are up! */ - netdriver_announce(); + /* Initialize the device we found. */ + rl_init_hw(rep, addr); - return(OK); + /* Use a synchronous alarm instead of a watchdog timer. */ + sys_setalarm(sys_hz(), 0); + + return OK; } /*===========================================================================* - * sef_cb_signal_handler * + * rl_stop * *===========================================================================*/ -static void sef_cb_signal_handler(int signo) +static void rl_stop(void) { re_t *rep; - /* Only check for termination signal, ignore anything else. */ - if (signo != SIGTERM) return; - rep = &re_state; - if (rep->re_mode == REM_ENABLED) - rl_outb(rep->re_base_port, RL_CR, RL_CR_RST); - exit(0); + rl_outb(rep->re_base_port, RL_CR, RL_CR_RST); } static void mdio_write(u16_t port, int regaddr, int value) { int i; - rl_outl(port, RL_PHYAR, 0x80000000 | (regaddr & 0x1F) << 16 | (value & 0xFFFF)); + rl_outl(port, RL_PHYAR, + 0x80000000 | (regaddr & 0x1F) << 16 | (value & 0xFFFF)); for (i = 20; i > 0; i--) { /* @@ -396,24 +284,6 @@ static int mdio_read(u16_t port, int regaddr) return value; } -/*===========================================================================* - * check_int_events * - *===========================================================================*/ -static void check_int_events(void) -{ - re_t *rep; - - rep = &re_state; - - if (rep->re_mode != REM_ENABLED) - return; - if (!rep->re_got_int) - return; - rep->re_got_int = 0; - assert(rep->re_flags & REF_ENABLED); - rl_check_ints(rep); -} - static void rtl8169_update_stat(re_t *rep) { port_t port; @@ -454,12 +324,6 @@ static void rtl8169_dump(void) rep = &re_state; printf("\n"); - if (rep->re_mode == REM_DISABLED) - printf("Realtek RTL 8169 instance %d is disabled\n", - re_instance); - - if (rep->re_mode != REM_ENABLED) - return; rtl8169_update_stat(rep); @@ -484,135 +348,75 @@ static void rtl8169_dump(void) printf("fifoUnder :%8ld\t", rep->re_stat.ets_fifoUnder); printf("fifoOver :%8ld\t", rep->re_stat.ets_fifoOver); printf("OWC :%8ld\n", rep->re_stat.ets_OWC); - printf("interrupts :%8lu\n", rep->interrupts); + printf("interrupts :%8u\n", rep->interrupts); printf("\nRealtek RTL 8169 Tally Counters:\n"); dtcc = rep->v_dtcc_buf; if (dtcc->TxOk_high) - printf("TxOk :%8ld%08ld\t", dtcc->TxOk_high, dtcc->TxOk_low); + printf("TxOk :%8u%08u\t", + dtcc->TxOk_high, dtcc->TxOk_low); else - printf("TxOk :%16lu\t", dtcc->TxOk_low); + printf("TxOk :%16u\t", dtcc->TxOk_low); if (dtcc->RxOk_high) - printf("RxOk :%8ld%08ld\n", dtcc->RxOk_high, dtcc->RxOk_low); + printf("RxOk :%8u%08u\n", + dtcc->RxOk_high, dtcc->RxOk_low); else - printf("RxOk :%16lu\n", dtcc->RxOk_low); + printf("RxOk :%16u\n", dtcc->RxOk_low); if (dtcc->TxEr_high) - printf("TxEr :%8ld%08ld\t", dtcc->TxEr_high, dtcc->TxEr_low); + printf("TxEr :%8u%08u\t", + dtcc->TxEr_high, dtcc->TxEr_low); else - printf("TxEr :%16ld\t", dtcc->TxEr_low); + printf("TxEr :%16u\t", dtcc->TxEr_low); - printf("RxEr :%16ld\n", dtcc->RxEr); + printf("RxEr :%16u\n", dtcc->RxEr); - printf("Tx1Col :%16ld\t", dtcc->Tx1Col); - printf("TxMCol :%16ld\n", dtcc->TxMCol); + printf("Tx1Col :%16u\t", dtcc->Tx1Col); + printf("TxMCol :%16u\n", dtcc->TxMCol); if (dtcc->RxOkPhy_high) - printf("RxOkPhy :%8ld%08ld\t", dtcc->RxOkPhy_high, dtcc->RxOkPhy_low); + printf("RxOkPhy :%8u%08u\t", + dtcc->RxOkPhy_high, dtcc->RxOkPhy_low); else - printf("RxOkPhy :%16ld\t", dtcc->RxOkPhy_low); + printf("RxOkPhy :%16u\t", dtcc->RxOkPhy_low); if (dtcc->RxOkBrd_high) - printf("RxOkBrd :%8ld%08ld\n", dtcc->RxOkBrd_high, dtcc->RxOkBrd_low); + printf("RxOkBrd :%8u%08u\n", + dtcc->RxOkBrd_high, dtcc->RxOkBrd_low); else - printf("RxOkBrd :%16ld\n", dtcc->RxOkBrd_low); + printf("RxOkBrd :%16u\n", dtcc->RxOkBrd_low); - printf("RxOkMul :%16ld\t", dtcc->RxOkMul); + printf("RxOkMul :%16u\t", dtcc->RxOkMul); printf("MissPkt :%16d\n", dtcc->MissPkt); printf("\nRealtek RTL 8169 Miscellaneous Info:\n"); - printf("re_flags : 0x%08x\n", rep->re_flags); printf("tx_head :%8d busy %d\t", rep->re_tx_head, rep->re_tx[rep->re_tx_head].ret_busy); } #endif /*===========================================================================* - * do_init * + * rl_mode * *===========================================================================*/ -static void rl_init(mp) -message *mp; +static void rl_mode(unsigned int mode) { - static int first_time = 1; - re_t *rep; - message reply_mess; - - if (first_time) { - first_time = 0; - rl_pci_conf(); /* Configure PCI devices. */ - - /* Use a synchronous alarm instead of a watchdog timer. */ - sys_setalarm(system_hz, 0); - } rep = &re_state; - if (rep->re_mode == REM_DISABLED) { - /* This is the default, try to (re)locate the device. */ - rl_conf_hw(rep); - if (rep->re_mode == REM_DISABLED) { - /* Probe failed, or the device is configured off. */ - reply_mess.m_type = DL_CONF_REPLY; - reply_mess.m_netdrv_net_dl_conf.stat = ENXIO; - mess_reply(mp, &reply_mess); - return; - } - if (rep->re_mode == REM_ENABLED) - rl_init_hw(rep); - } - assert(rep->re_mode == REM_ENABLED); - assert(rep->re_flags & REF_ENABLED); - - rep->re_flags &= ~(REF_PROMISC | REF_MULTI | REF_BROAD); - - if (mp->m_net_netdrv_dl_conf.mode & DL_PROMISC_REQ) - rep->re_flags |= REF_PROMISC; - if (mp->m_net_netdrv_dl_conf.mode & DL_MULTI_REQ) - rep->re_flags |= REF_MULTI; - if (mp->m_net_netdrv_dl_conf.mode & DL_BROAD_REQ) - rep->re_flags |= REF_BROAD; + rep->re_mode = mode; rl_rec_mode(rep); - - reply_mess.m_type = DL_CONF_REPLY; - reply_mess.m_netdrv_net_dl_conf.stat = OK; - memcpy(reply_mess.m_netdrv_net_dl_conf.hw_addr, - rep->re_address.ea_addr, - sizeof(reply_mess.m_netdrv_net_dl_conf.hw_addr)); - - mess_reply(mp, &reply_mess); -} - -/*===========================================================================* - * rl_pci_conf * - *===========================================================================*/ -static void rl_pci_conf() -{ - re_t *rep; - - rep = &re_state; - - strlcpy(rep->re_name, "rtl8169#0", sizeof(rep->re_name)); - rep->re_name[8] += re_instance; - rep->re_seen = FALSE; - - pci_init(); - - if (rl_probe(rep, re_instance)) - rep->re_seen = TRUE; } /*===========================================================================* * rl_probe * *===========================================================================*/ -static int rl_probe(rep, skip) -re_t *rep; -int skip; +static int rl_probe(re_t *rep, unsigned int skip) { int r, devind; u16_t vid, did; @@ -622,6 +426,8 @@ int skip; char *dname; #endif + pci_init(); + r = pci_first_dev(&devind, &vid, &did); if (r == 0) return 0; @@ -657,40 +463,10 @@ int skip; 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) - rep->re_mode = REM_ENABLED; /* PCI device is present */ - if (rep->re_mode != REM_ENABLED) - return; - - rep->re_flags = REF_EMPTY; - rep->re_link_up = 0; - rep->re_got_int = 0; - rep->re_send_int = 0; - rep->re_report_link = 0; - rep->re_need_reset = 0; - rep->re_tx_alive = 0; - rep->re_rx_head = 0; - rep->re_read_s = 0; - rep->re_tx_head = 0; - rep->re_stat = empty_stat; - rep->dtcc_counter = 0; -} - /*===========================================================================* * rl_init_buf * *===========================================================================*/ -static void rl_init_buf(rep) -re_t *rep; +static void rl_init_buf(re_t *rep) { size_t rx_bufsize, tx_bufsize, rx_descsize, tx_descsize, tot_bufsize; struct re_desc *desc; @@ -698,8 +474,6 @@ re_t *rep; char *mallocbuf; int d; - assert(!rep->setup); - /* Allocate receive and transmit descriptors */ rx_descsize = (N_RX_DESC * sizeof(struct re_desc)); tx_descsize = (N_TX_DESC * sizeof(struct re_desc)); @@ -742,10 +516,12 @@ re_t *rep; mallocbuf += rx_bufsize; /* Setting Rx descriptor */ - if (d == (N_RX_DESC - 1)) /* Last descriptor? if so, set the EOR bit */ - desc->status = DESC_EOR | DESC_OWN | (RX_BUFSIZE & DESC_RX_LENMASK); + if (d == (N_RX_DESC - 1)) /* Last descriptor: set EOR bit */ + desc->status = DESC_EOR | DESC_OWN | + (RX_BUFSIZE & DESC_RX_LENMASK); else - desc->status = DESC_OWN | (RX_BUFSIZE & DESC_RX_LENMASK); + desc->status = DESC_OWN | + (RX_BUFSIZE & DESC_RX_LENMASK); desc->addr_low = rep->re_rx[d].ret_buf; desc++; @@ -762,28 +538,23 @@ re_t *rep; desc->addr_low = rep->re_tx[d].ret_buf; desc++; } + rep->re_tx_busy = 0; /* Dump Tally Counter buffer */ rep->dtcc_buf = buf; rep->v_dtcc_buf = (re_dtcc *)mallocbuf; - - rep->setup = 1; } /*===========================================================================* * rl_init_hw * *===========================================================================*/ -static void rl_init_hw(rep) -re_t *rep; +static void rl_init_hw(re_t *rep, ether_addr_t *addr) { int s; #if VERBOSE int i; #endif - 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 @@ -803,11 +574,12 @@ re_t *rep; rep->re_name, rep->re_model, rep->re_mac); #endif - rl_confaddr(rep); + rl_confaddr(rep, addr); + #if VERBOSE printf("%s: Ethernet address ", rep->re_name); for (i = 0; i < 6; i++) { - printf("%x%c", rep->re_address.ea_addr[i], + printf("%x%c", addr->ea_addr[i], i < 5 ? ':' : '\n'); } #endif @@ -920,8 +692,7 @@ static void rtl8169scd_phy_config(port_t port) /*===========================================================================* * rl_reset_hw * *===========================================================================*/ -static void rl_reset_hw(rep) -re_t *rep; +static void rl_reset_hw(re_t *rep) { port_t port; u32_t t; @@ -996,7 +767,8 @@ re_t *rep; micro_delay(100); } - t = mdio_read(port, MII_CTRL) | MII_CTRL_ANE | MII_CTRL_DM | MII_CTRL_SP_1000; + t = mdio_read(port, MII_CTRL); + t |= MII_CTRL_ANE | MII_CTRL_DM | MII_CTRL_SP_1000; mdio_write(port, MII_CTRL, t); t = mdio_read(port, MII_ANA); @@ -1056,12 +828,10 @@ re_t *rep; /*===========================================================================* * rl_confaddr * *===========================================================================*/ -static void rl_confaddr(rep) -re_t *rep; +static void rl_confaddr(re_t *rep, ether_addr_t *addr) { static char eakey[] = RL_ENVVAR "#_EA"; static char eafmt[] = "x:x:x:x:x:x"; - int i; port_t port; u32_t w; @@ -1075,7 +845,7 @@ re_t *rep; 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; + addr->ea_addr[i] = v; } if (i != 0 && i != 6) @@ -1087,25 +857,24 @@ re_t *rep; 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)); + w |= (addr->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)); + w |= (addr->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); + addr->ea_addr[i] = rl_inb(port, RL_IDR+i); } /*===========================================================================* * rl_rec_mode * *===========================================================================*/ -static void rl_rec_mode(rep) -re_t *rep; +static void rl_rec_mode(re_t *rep) { port_t port; u32_t rcr; @@ -1119,279 +888,127 @@ re_t *rep; 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) + if (rep->re_mode & NDEV_PROMISC) rcr |= RL_RCR_AB | RL_RCR_AM | RL_RCR_AAP; - if (rep->re_flags & REF_BROAD) + if (rep->re_mode & NDEV_BROAD) rcr |= RL_RCR_AB; - if (rep->re_flags & REF_MULTI) + if (rep->re_mode & NDEV_MULTI) rcr |= RL_RCR_AM; rcr |= RL_RCR_APM; rl_outl(port, RL_RCR, RL_RCR_RXFTH_UNLIM | RL_RCR_MXDMA_1024 | rcr); } -void transmittest(re_t *rep) -{ - int tx_head; - int ipc_status; - - tx_head = rep->re_tx_head; - - if(rep->re_tx[tx_head].ret_busy) { - do { - message m; - int r; - if ((r = netdriver_receive(ANY, &m, &ipc_status)) != OK) - panic("netdriver_receive failed: %d", r); - } while(m.m_source != HARDWARE); - assert(!(rep->re_flags & REF_SEND_AVAIL)); - rep->re_flags |= REF_SEND_AVAIL; - } - - return; -} - /*===========================================================================* - * rl_readv_s * + * rl_recv * *===========================================================================*/ -static void rl_readv_s(const message *mp, int from_int) +static ssize_t rl_recv(struct netdriver_data *data, size_t max) { - int i, j, n, s, count, size, index; + int index; port_t port; unsigned totlen, packlen; re_desc *desc; - u32_t rxstat = 0x12345678; + u32_t rxstat; re_t *rep; - iovec_s_t *iovp; - int cps; - int iov_offset = 0; rep = &re_state; - rep->re_client = mp->m_source; - count = mp->m_net_netdrv_dl_readv_s.count; - - 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)) - goto suspend; /* Receive buffer is empty, suspend */ + if (rl_inb(port, RL_CR) & RL_CR_BUFE) + return SUSPEND; /* Receive buffer is empty, suspend */ index = rep->re_rx_head; desc = rep->re_rx_desc; desc += index; -readvs_loop: - rxstat = desc->status; - if (rxstat & DESC_OWN) - goto suspend; + for (;;) { + rxstat = desc->status; - if (rxstat & DESC_RX_CRC) - rep->re_stat.ets_CRCerr++; + if (rxstat & DESC_OWN) + return SUSPEND; + + if (rxstat & DESC_RX_CRC) + rep->re_stat.ets_CRCerr++; + + if ((rxstat & (DESC_FS | DESC_LS)) == (DESC_FS | DESC_LS)) + break; - if ((rxstat & (DESC_FS | DESC_LS)) != (DESC_FS | DESC_LS)) { #if VERBOSE - printf("rl_readv_s: packet is fragmented\n"); + printf("rl_recv: packet is fragmented\n"); #endif /* Fix the fragmented packet */ if (index == N_RX_DESC - 1) { - desc->status = DESC_EOR | DESC_OWN | (RX_BUFSIZE & DESC_RX_LENMASK); + desc->status = DESC_EOR | DESC_OWN | + (RX_BUFSIZE & DESC_RX_LENMASK); index = 0; desc = rep->re_rx_desc; } else { - desc->status = DESC_OWN | (RX_BUFSIZE & DESC_RX_LENMASK); + desc->status = DESC_OWN | + (RX_BUFSIZE & DESC_RX_LENMASK); index++; desc++; } - goto readvs_loop; /* Loop until we get correct packet */ + /* Loop until we get correct packet */ } totlen = rxstat & DESC_RX_LENMASK; if (totlen < 8 || totlen > 2 * ETH_MAX_PACK_SIZE) { /* Someting went wrong */ - printf("rl_readv_s: bad length (%u) in status 0x%08x\n", + printf("rl_recv: bad length (%u) in status 0x%08x\n", totlen, rxstat); panic(NULL); } /* Should subtract the CRC */ packlen = totlen - ETH_CRC_SIZE; + if (packlen > max) + packlen = max; - size = 0; - for (i = 0; i < count; i += IOVEC_NR, - iov_offset += IOVEC_NR * sizeof(rep->re_iovec_s[0])) - { - n = IOVEC_NR; - if (i + n > count) - n = count-i; - cps = sys_safecopyfrom(mp->m_source, - mp->m_net_netdrv_dl_readv_s.grant, iov_offset, - (vir_bytes) rep->re_iovec_s, - n * sizeof(rep->re_iovec_s[0])); - if (cps != OK) { - panic("rl_readv_s: sys_safecopyfrom failed: %d", cps); - } - - for (j = 0, iovp = rep->re_iovec_s; j < n; j++, iovp++) { - s = iovp->iov_size; - if (size + s > packlen) { - assert(packlen > size); - s = packlen-size; - } - - cps = sys_safecopyto(mp->m_source, iovp->iov_grant, 0, - (vir_bytes) rep->re_rx[index].v_ret_buf + size, s); - if (cps != OK) - panic("rl_readv_s: sys_safecopyto failed: %d", cps); - - size += s; - if (size == packlen) - break; - } - if (size == packlen) - break; - } - if (size < packlen) - assert(0); + netdriver_copyout(data, 0, rep->re_rx[index].v_ret_buf, packlen); rep->re_stat.ets_packetR++; - rep->re_read_s = packlen; + if (index == N_RX_DESC - 1) { - desc->status = DESC_EOR | DESC_OWN | (RX_BUFSIZE & DESC_RX_LENMASK); + desc->status = DESC_EOR | DESC_OWN | + (RX_BUFSIZE & DESC_RX_LENMASK); index = 0; } else { - desc->status = DESC_OWN | (RX_BUFSIZE & DESC_RX_LENMASK); + desc->status = DESC_OWN | (RX_BUFSIZE & DESC_RX_LENMASK); index++; } rep->re_rx_head = index; assert(rep->re_rx_head < N_RX_DESC); - rep->re_flags = (rep->re_flags & ~REF_READING) | REF_PACK_RECV; - if (!from_int) - reply(rep); - - return; - -suspend: - if (from_int) { - assert(rep->re_flags & REF_READING); - - /* No need to store any state */ - return; - } - - rep->re_rx_mess = *mp; - assert(!(rep->re_flags & REF_READING)); - rep->re_flags |= REF_READING; - - reply(rep); + return packlen; } /*===========================================================================* - * rl_writev_s * + * rl_send * *===========================================================================*/ -static void rl_writev_s(const message *mp, int from_int) +static int rl_send(struct netdriver_data *data, size_t size) { - int i, j, n, s, count, size; int tx_head; re_t *rep; - iovec_s_t *iovp; re_desc *desc; - char *ret; - int cps; - int iov_offset = 0; rep = &re_state; - rep->re_client = mp->m_source; - count = mp->m_net_netdrv_dl_writev_s.count; - assert(rep->setup); - - assert(rep->re_mode == REM_ENABLED); - assert(rep->re_flags & REF_ENABLED); - - if (from_int) { - assert(rep->re_flags & REF_SEND_AVAIL); - rep->re_flags &= ~REF_SEND_AVAIL; - rep->re_send_int = FALSE; - rep->re_tx_alive = TRUE; - } - tx_head = rep->re_tx_head; desc = rep->re_tx_desc; desc += tx_head; - if(!desc || !rep->re_tx_desc) { - printf("desc %p, re_tx_desc %p, tx_head %d, setup %d\n", - desc, rep->re_tx_desc, tx_head, rep->setup); - } - + assert(desc); assert(rep->re_tx_desc); assert(rep->re_tx_head >= 0 && rep->re_tx_head < N_TX_DESC); - assert(desc); + if (rep->re_tx[tx_head].ret_busy) + return SUSPEND; - if (rep->re_tx[tx_head].ret_busy) { - assert(!(rep->re_flags & REF_SEND_AVAIL)); - rep->re_flags |= REF_SEND_AVAIL; - if (rep->re_tx[tx_head].ret_busy) - goto suspend; - - /* - * Race condition, the interrupt handler may clear re_busy - * before we got a chance to set REF_SEND_AVAIL. Checking - * ret_busy twice should be sufficient. - */ -#if VERBOSE - printf("rl_writev_s: race detected\n"); -#endif - rep->re_flags &= ~REF_SEND_AVAIL; - rep->re_send_int = FALSE; - } - - assert(!(rep->re_flags & REF_SEND_AVAIL)); - assert(!(rep->re_flags & REF_PACK_SENT)); - - size = 0; - ret = rep->re_tx[tx_head].v_ret_buf; - for (i = 0; i < count; i += IOVEC_NR, - iov_offset += IOVEC_NR * sizeof(rep->re_iovec_s[0])) - { - n = IOVEC_NR; - if (i + n > count) - n = count - i; - cps = sys_safecopyfrom(mp->m_source, - mp->m_net_netdrv_dl_writev_s.grant, iov_offset, - (vir_bytes) rep->re_iovec_s, - n * sizeof(rep->re_iovec_s[0])); - if (cps != OK) { - panic("rl_writev_s: sys_safecopyfrom failed: %d", cps); - } - - for (j = 0, iovp = rep->re_iovec_s; j < n; j++, iovp++) { - s = iovp->iov_size; - if (size + s > ETH_MAX_PACK_SIZE_TAGGED) - panic("invalid packet size"); - - cps = sys_safecopyfrom(mp->m_source, iovp->iov_grant, - 0, (vir_bytes) ret, s); - if (cps != OK) { - panic("rl_writev_s: sys_safecopyfrom failed: %d", cps); - } - size += s; - ret += s; - } - } - assert(desc); - if (size < ETH_MIN_PACK_SIZE) - panic("invalid packet size: %d", size); + netdriver_copyin(data, 0, rep->re_tx[tx_head].v_ret_buf, size); rep->re_tx[tx_head].ret_busy = TRUE; + rep->re_tx_busy++; if (tx_head == N_TX_DESC - 1) { desc->status = DESC_EOR | DESC_OWN | DESC_FS | DESC_LS | size; @@ -1405,67 +1022,45 @@ static void rl_writev_s(const message *mp, int from_int) rep->re_tx_head = tx_head; rl_outl(rep->re_base_port, RL_TPPOLL, RL_TPPOLL_NPQ); - rep->re_flags |= REF_PACK_SENT; - /* - * If the interrupt handler called, don't send a reply. The reply - * will be sent after all interrupts are handled. - */ - if (from_int) - return; - reply(rep); - return; - -suspend: - if (from_int) - panic("should not be sending"); - - rep->re_tx_mess = *mp; - reply(rep); + return OK; } /*===========================================================================* * rl_check_ints * *===========================================================================*/ -static void rl_check_ints(rep) -re_t *rep; +static void rl_check_ints(re_t *rep) { - int re_flags; + if (!rep->re_got_int) + return; + rep->re_got_int = FALSE; - re_flags = rep->re_flags; - - if ((re_flags & REF_READING) && - !(rl_inb(rep->re_base_port, RL_CR) & RL_CR_BUFE)) - { - assert(rep->re_rx_mess.m_type == DL_READV_S); - rl_readv_s(&rep->re_rx_mess, TRUE /* from int */); - } + netdriver_recv(); if (rep->re_need_reset) rl_do_reset(rep); if (rep->re_send_int) { - assert(rep->re_tx_mess.m_type == DL_WRITEV_S); - rl_writev_s(&rep->re_tx_mess, TRUE /* from int */); + rep->re_send_int = FALSE; + + netdriver_send(); } if (rep->re_report_link) { rep->re_report_link = FALSE; +#if VERBOSE rl_report_link(rep); +#endif } - - if (rep->re_flags & (REF_PACK_SENT | REF_PACK_RECV)) - reply(rep); } /*===========================================================================* * rl_report_link * *===========================================================================*/ -static void rl_report_link(rep) -re_t *rep; -{ #if VERBOSE +static void rl_report_link(re_t *rep) +{ port_t port; u8_t mii_status; @@ -1494,102 +1089,38 @@ re_t *rep; else printf(", half duplex"); printf("\n"); -#endif dump_phy(rep); } +#endif /*===========================================================================* * rl_do_reset * *===========================================================================*/ -static void rl_do_reset(rep) -re_t *rep; +static void rl_do_reset(re_t *rep) { rep->re_need_reset = FALSE; rl_reset_hw(rep); rl_rec_mode(rep); rep->re_tx_head = 0; - if (rep->re_flags & REF_SEND_AVAIL) { - rep->re_tx[rep->re_tx_head].ret_busy = FALSE; - rep->re_send_int = TRUE; - } + if (rep->re_tx[rep->re_tx_head].ret_busy) + rep->re_tx_busy--; + rep->re_tx[rep->re_tx_head].ret_busy = FALSE; + rep->re_send_int = TRUE; } /*===========================================================================* - * rl_getstat_s * + * rl_stat * *===========================================================================*/ -static void rl_getstat_s(mp) -message *mp; +static void rl_stat(eth_stat_t *stat) { - int r; - eth_stat_t stats; - re_t *rep; - - rep = &re_state; - - assert(rep->re_mode == REM_ENABLED); - assert(rep->re_flags & REF_ENABLED); - - stats = rep->re_stat; - - r = sys_safecopyto(mp->m_source, mp->m_net_netdrv_dl_getstat_s.grant, - 0, (vir_bytes) &stats, sizeof(stats)); - if (r != OK) - panic("rl_getstat_s: sys_safecopyto failed: %d", r); - - mp->m_type = DL_STAT_REPLY; - r = ipc_send(mp->m_source, mp); - if (r != OK) - panic("rl_getstat_s: ipc_send failed: %d", r); -} - -/*===========================================================================* - * reply * - *===========================================================================*/ -static void reply(rep) -re_t *rep; -{ - message reply; - int flags; - int r; - - flags = DL_NOFLAGS; - if (rep->re_flags & REF_PACK_SENT) - flags |= DL_PACK_SEND; - if (rep->re_flags & REF_PACK_RECV) - flags |= DL_PACK_RECV; - - reply.m_type = DL_TASK_REPLY; - reply.m_netdrv_net_dl_task.flags = flags; - reply.m_netdrv_net_dl_task.count = rep->re_read_s; - - r = ipc_send(rep->re_client, &reply); - - if (r < 0) { - printf("RTL8169 tried sending to %d, type %d\n", - rep->re_client, reply.m_type); - panic("ipc_send failed: %d", r); - } - - rep->re_read_s = 0; - rep->re_flags &= ~(REF_PACK_SENT | REF_PACK_RECV); -} - -/*===========================================================================* - * mess_reply * - *===========================================================================*/ -static void mess_reply(req, reply_mess) -message *req; -message *reply_mess; -{ - if (ipc_send(req->m_source, reply_mess) != OK) - panic("unable to mess_reply"); + memcpy(stat, &re_state.re_stat, sizeof(*stat)); } +#if VERBOSE static void dump_phy(const re_t *rep) { -#if VERBOSE port_t port; u32_t t; @@ -1765,19 +1296,28 @@ static void dump_phy(const re_t *rep) printf(" 1000BaseT-HD"); printf("\n"); } -#endif } +#endif -static void do_hard_int(void) +/*===========================================================================* + * rl_intr * + *===========================================================================*/ +static void rl_intr(unsigned int __unused mask) { + re_t *rep; int s; + rep = &re_state; + /* Run interrupt handler at driver level. */ - rl_handler(&re_state); + rl_handler(rep); /* Reenable interrupts for this hook. */ - if ((s = sys_irqenable(&re_state.re_hook_id)) != OK) + if ((s = sys_irqenable(&rep->re_hook_id)) != OK) printf("RTL8169: error, couldn't enable interrupts: %d\n", s); + + /* Perform tasks based on the flagged conditions. */ + rl_check_ints(rep); } /*===========================================================================* @@ -1788,7 +1328,6 @@ static void rl_handler(re_t *rep) int i, port, tx_head, tx_tail, link_up; u16_t isr; re_desc *desc; - int_event_check = FALSE; /* disable check by default */ port = rep->re_base_port; @@ -1816,7 +1355,6 @@ static void rl_handler(re_t *rep) if (link_up != rep->re_link_up) { rep->re_report_link = TRUE; rep->re_got_int = TRUE; - int_event_check = TRUE; } } @@ -1825,10 +1363,7 @@ static void rl_handler(re_t *rep) rep->re_stat.ets_recvErr++; isr &= ~(RL_ISR_RDU | 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; - } + rep->re_got_int = TRUE; } if ((isr & (RL_ISR_TDU | RL_ISR_TER | RL_ISR_TOK)) || 1) { @@ -1864,18 +1399,15 @@ static void rl_handler(re_t *rep) rep->re_stat.ets_packetT++; rep->re_tx[tx_tail].ret_busy = FALSE; + rep->re_tx_busy--; if (++tx_tail >= N_TX_DESC) tx_tail = 0; assert(tx_tail < N_TX_DESC); - if (rep->re_flags & REF_SEND_AVAIL) { - rep->re_send_int = TRUE; - if (!rep->re_got_int) { - rep->re_got_int = TRUE; - int_event_check = TRUE; - } - } + rep->re_send_int = TRUE; + rep->re_got_int = TRUE; + rep->re_tx_alive = TRUE; } assert(i < 2 * N_TX_DESC); } @@ -1889,40 +1421,36 @@ static void rl_handler(re_t *rep) } /*===========================================================================* - * rl_watchdog_f * + * rl_alarm * *===========================================================================*/ -static void rl_watchdog_f(tp) -minix_timer_t *tp; +static void rl_alarm(clock_t __unused stamp) { re_t *rep; + /* Use a synchronous alarm instead of a watchdog timer. */ - sys_setalarm(system_hz, 0); + sys_setalarm(sys_hz(), 0); rep = &re_state; - if (rep->re_mode != REM_ENABLED) - return; - /* Should collect statistics */ if (!(++rep->dtcc_counter % RE_DTCC_VALUE)) rtl8169_update_stat(rep); - if (!(rep->re_flags & REF_SEND_AVAIL)) { - /* Assume that an idle system is alive */ - rep->re_tx_alive = TRUE; + assert(rep->re_tx_busy >= 0 && rep->re_tx_busy <= N_TX_DESC); + if (rep->re_tx_busy == 0) { + /* Assume that an idle system is alive */ + rep->re_tx_alive = TRUE; return; } if (rep->re_tx_alive) { rep->re_tx_alive = FALSE; return; } - printf("rl_watchdog_f: resetting instance %d mode 0x%x flags 0x%x\n", - re_instance, rep->re_mode, rep->re_flags); + printf("rl_alarm: resetting instance %d\n", re_instance); printf("tx_head :%8d busy %d\t", rep->re_tx_head, rep->re_tx[rep->re_tx_head].ret_busy); rep->re_need_reset = TRUE; rep->re_got_int = TRUE; - check_int_events(); + rl_check_ints(rep); } - diff --git a/minix/drivers/net/virtio_net/virtio_net.c b/minix/drivers/net/virtio_net/virtio_net.c index e7daa1a6e..9ba7313a4 100644 --- a/minix/drivers/net/virtio_net/virtio_net.c +++ b/minix/drivers/net/virtio_net/virtio_net.c @@ -22,11 +22,18 @@ #include "virtio_net.h" +#define VERBOSE 0 + +#if VERBOSE #define dput(s) do { dprintf(s); printf("\n"); } while (0) #define dprintf(s) do { \ printf("%s: ", name); \ printf s; \ } while (0) +#else +#define dput(s) +#define dprintf(s) +#endif static struct virtio_device *net_dev; @@ -50,6 +57,7 @@ struct packet { phys_bytes phdr; char *vdata; phys_bytes pdata; + size_t len; STAILQ_ENTRY(packet) next; }; @@ -60,7 +68,6 @@ static struct virtio_net_hdr *hdrs_vir; static phys_bytes hdrs_phys; static struct packet *packets; static int in_rx; -static int started; /* Packets on this list can be given to the host */ static STAILQ_HEAD(free_list, packet) free_list; @@ -68,21 +75,13 @@ static STAILQ_HEAD(free_list, packet) free_list; /* Packets on this list are to be given to inet */ static STAILQ_HEAD(recv_list, packet) recv_list; -/* State about pending inet messages */ -static int rx_pending; -static message pending_rx_msg; -static int tx_pending; -static message pending_tx_msg; - /* Various state data */ -static u8_t virtio_net_mac[6]; static eth_stat_t virtio_net_stats; static int spurious_interrupt; - /* Prototypes */ -static int virtio_net_probe(int skip); -static int virtio_net_config(void); +static int virtio_net_probe(unsigned int skip); +static void virtio_net_config(ether_addr_t *addr); static int virtio_net_alloc_bufs(void); static void virtio_net_init_queues(void); @@ -90,28 +89,24 @@ static void virtio_net_refill_rx_queue(void); static void virtio_net_check_queues(void); static void virtio_net_check_pending(void); -static void virtio_net_fetch_iovec(iovec_s_t *iov, message *m, - cp_grant_id_t grant, size_t count); -static int virtio_net_cpy_to_user(message *m); -static int virtio_net_cpy_from_user(message *m); - -static void virtio_net_intr(message *m); -static void virtio_net_write(message *m); -static void virtio_net_read(message *m); -static void virtio_net_conf(message *m); -static void virtio_net_getstat(message *m); - -static void virtio_net_notify(message *m); -static void virtio_net_msg(message *m); -static void virtio_net_main_loop(void); - -static void sef_local_startup(void); -static int sef_cb_init_fresh(int type, sef_init_info_t *info); -static void sef_cb_signal_handler(int signo); +static int virtio_net_init(unsigned int instance, ether_addr_t *addr); +static void virtio_net_stop(void); +static int virtio_net_send(struct netdriver_data *data, size_t len); +static ssize_t virtio_net_recv(struct netdriver_data *data, size_t max); +static void virtio_net_stat(eth_stat_t *stat); +static void virtio_net_intr(unsigned int mask); +static const struct netdriver virtio_net_table = { + .ndr_init = virtio_net_init, + .ndr_stop = virtio_net_stop, + .ndr_recv = virtio_net_recv, + .ndr_send = virtio_net_send, + .ndr_stat = virtio_net_stat, + .ndr_intr = virtio_net_intr, +}; /* TODO: Features are pretty much ignored */ -struct virtio_feature netf[] = { +static struct virtio_feature netf[] = { { "partial csum", VIRTIO_NET_F_CSUM, 0, 0 }, { "given mac", VIRTIO_NET_F_MAC, 0, 1 }, { "status ", VIRTIO_NET_F_STATUS, 0, 0 }, @@ -120,7 +115,7 @@ struct virtio_feature netf[] = { }; static int -virtio_net_probe(int skip) +virtio_net_probe(unsigned int skip) { /* virtio-net has at least 2 queues */ int queues = 2; @@ -142,8 +137,8 @@ virtio_net_probe(int skip) return OK; } -static int -virtio_net_config(void) +static void +virtio_net_config(ether_addr_t * addr) { u32_t mac14; u32_t mac56; @@ -153,12 +148,12 @@ virtio_net_config(void) dprintf(("Mac set by host: ")); mac14 = virtio_sread32(net_dev, 0); mac56 = virtio_sread32(net_dev, 4); - *(u32_t*)virtio_net_mac = mac14; - *(u16_t*)(virtio_net_mac + 4) = mac56; + memcpy(&addr->ea_addr[0], &mac14, 4); + memcpy(&addr->ea_addr[4], &mac56, 2); for (i = 0; i < 6; i++) - printf("%02x%s", virtio_net_mac[i], - i == 5 ? "\n" : ":"); + dprintf(("%02x%s", addr->ea_addr[i], + i == 5 ? "\n" : ":")); } else { dput(("No mac")); } @@ -174,8 +169,6 @@ virtio_net_config(void) if (virtio_host_supports(net_dev, VIRTIO_NET_F_CTRL_RX)) dput(("Host supports control channel for RX")); - - return OK; } static int @@ -233,7 +226,6 @@ virtio_net_refill_rx_queue(void) struct packet *p; while ((in_rx < BUF_PACKETS / 2) && !STAILQ_EMPTY(&free_list)) { - /* peek */ p = STAILQ_FIRST(&free_list); /* remove */ @@ -253,7 +245,6 @@ virtio_net_refill_rx_queue(void) virtio_to_queue(net_dev, RX_Q, phys, 2, p); in_rx++; - } if (in_rx == 0 && STAILQ_EMPTY(&free_list)) { @@ -266,18 +257,21 @@ static void virtio_net_check_queues(void) { struct packet *p; + size_t len; /* Put the received packets into the recv list */ - while (virtio_from_queue(net_dev, RX_Q, (void **)&p) == 0) { + while (virtio_from_queue(net_dev, RX_Q, (void **)&p, &len) == 0) { + p->len = len; STAILQ_INSERT_TAIL(&recv_list, p, next); in_rx--; virtio_net_stats.ets_packetR++; } - /* Packets from the TX queue just indicated they are free to + /* + * Packets from the TX queue just indicated they are free to * be reused now. inet already knows about them as being sent. */ - while (virtio_from_queue(net_dev, TX_Q, (void **)&p) == 0) { + while (virtio_from_queue(net_dev, TX_Q, (void **)&p, NULL) == 0) { memset(p->vhdr, 0, sizeof(*p->vhdr)); memset(p->vdata, 0, MAX_PACK_SIZE); STAILQ_INSERT_HEAD(&free_list, p, next); @@ -288,173 +282,19 @@ virtio_net_check_queues(void) static void virtio_net_check_pending(void) { - int dst = 0xDEAD; - int r; - - message reply; - reply.m_type = DL_TASK_REPLY; - reply.m_netdrv_net_dl_task.flags = DL_NOFLAGS; - reply.m_netdrv_net_dl_task.count = 0; /* Pending read and something in recv_list? */ - if (!STAILQ_EMPTY(&recv_list) && rx_pending) { - dst = pending_rx_msg.m_source; - reply.m_netdrv_net_dl_task.count = - virtio_net_cpy_to_user(&pending_rx_msg); - reply.m_netdrv_net_dl_task.flags |= DL_PACK_RECV; - rx_pending = 0; - } + if (!STAILQ_EMPTY(&recv_list)) + netdriver_recv(); - if (!STAILQ_EMPTY(&free_list) && tx_pending) { - dst = pending_tx_msg.m_source; - virtio_net_cpy_from_user(&pending_tx_msg); - reply.m_netdrv_net_dl_task.flags |= DL_PACK_SEND; - tx_pending = 0; - } - - /* Only reply if a pending request was handled */ - if (reply.m_netdrv_net_dl_task.flags != DL_NOFLAGS) - if ((r = ipc_send(dst, &reply)) != OK) - panic("%s: ipc_send to %d failed (%d)", name, dst, r); + if (!STAILQ_EMPTY(&free_list)) + netdriver_send(); } static void -virtio_net_fetch_iovec(iovec_s_t *iov, message *m, cp_grant_id_t grant, size_t count) +virtio_net_intr(unsigned int __unused mask) { - int r; - r = sys_safecopyfrom(m->m_source, grant, 0, (vir_bytes)iov, - count * sizeof(iov[0])); - if (r != OK) - panic("%s: iovec fail for %d (%d)", name, m->m_source, r); -} - -static int -virtio_net_cpy_to_user(message *m) -{ - /* Hmm, this looks so similar to cpy_from_user... TODO */ - int i, r, size, ivsz; - int left = MAX_PACK_SIZE; /* Try copying the whole packet */ - int bytes = 0; - iovec_s_t iovec[NR_IOREQS]; - struct packet *p; - - /* This should only be called if recv_list has some entries */ - assert(!STAILQ_EMPTY(&recv_list)); - - p = STAILQ_FIRST(&recv_list); - STAILQ_REMOVE_HEAD(&recv_list, next); - - virtio_net_fetch_iovec(iovec, m, m->m_net_netdrv_dl_readv_s.grant, - m->m_net_netdrv_dl_readv_s.count); - - for (i = 0; i < m->m_net_netdrv_dl_readv_s.count && left > 0; i++) { - ivsz = iovec[i].iov_size; - size = left > ivsz ? ivsz : left; - r = sys_safecopyto(m->m_source, iovec[i].iov_grant, 0, - (vir_bytes) p->vdata + bytes, size); - - if (r != OK) - panic("%s: copy to %d failed (%d)", name, - m->m_source, - r); - - left -= size; - bytes += size; - } - - if (left != 0) - dput(("Uhm... left=%d", left)); - - /* Clean the packet */ - memset(p->vhdr, 0, sizeof(*p->vhdr)); - memset(p->vdata, 0, MAX_PACK_SIZE); - STAILQ_INSERT_HEAD(&free_list, p, next); - - return bytes; -} - -static int -sys_easy_vsafecopy_from(endpoint_t src_proc, iovec_s_t *iov, int count, - vir_bytes dst, size_t max, size_t *copied) -{ - int i, r; - size_t left = max; - vir_bytes cur_off = 0; - struct vscp_vec vv[NR_IOREQS]; - - for (i = 0; i < count && left > 0; i++) { - vv[i].v_from = src_proc; - vv[i].v_to = SELF; - vv[i].v_gid = iov[i].iov_grant; - vv[i].v_offset = 0; - vv[i].v_addr = dst + cur_off; - vv[i].v_bytes = iov[i].iov_size; - - /* More data in iov than the buffer can hold, this should be - * manageable by the caller. - */ - if (left - vv[i].v_bytes > left) { - printf("sys_easy_vsafecopy_from: buf too small!\n"); - return ENOMEM; - } - - left -= iov[i].iov_size; - cur_off += iov[i].iov_size; - } - - /* Now that we prepared the vscp_vec, we can call vsafecopy() */ - if ((r = sys_vsafecopy(vv, count)) != OK) - printf("sys_vsafecopy: failed: (%d)\n", r); - - if (copied) - *copied = cur_off; - - return OK; -} - -static int -virtio_net_cpy_from_user(message *m) -{ - /* Put user bytes into a a free packet buffer and - * then forward this packet to the TX queue. - */ - int r; - iovec_s_t iovec[NR_IOREQS]; - struct vumap_phys phys[2]; - struct packet *p; - size_t bytes; - - /* This should only be called if free_list has some entries */ - assert(!STAILQ_EMPTY(&free_list)); - - p = STAILQ_FIRST(&free_list); - STAILQ_REMOVE_HEAD(&free_list, next); - - virtio_net_fetch_iovec(iovec, m, m->m_net_netdrv_dl_writev_s.grant, - m->m_net_netdrv_dl_writev_s.count); - - r = sys_easy_vsafecopy_from(m->m_source, iovec, - m->m_net_netdrv_dl_writev_s.count, (vir_bytes)p->vdata, - MAX_PACK_SIZE, &bytes); - - if (r != OK) - panic("%s: copy from %d failed", name, m->m_source); - - - phys[0].vp_addr = p->phdr; - assert(!(phys[0].vp_addr & 1)); - phys[0].vp_size = sizeof(struct virtio_net_hdr); - phys[1].vp_addr = p->pdata; - assert(!(phys[1].vp_addr & 1)); - phys[1].vp_size = bytes; - virtio_to_queue(net_dev, TX_Q, phys, 2, p); - return bytes; -} - -static void -virtio_net_intr(message *m) -{ /* Check and clear interrupt flag */ if (virtio_had_irq(net_dev)) { virtio_net_check_queues(); @@ -468,202 +308,131 @@ virtio_net_intr(message *m) virtio_net_check_pending(); virtio_irq_enable(net_dev); + + /* Readd packets to the receive queue as necessary. */ + virtio_net_refill_rx_queue(); } -static void -virtio_net_write(message *m) -{ - int r; - message reply; - - reply.m_type = DL_TASK_REPLY; - reply.m_netdrv_net_dl_task.flags = DL_NOFLAGS; - reply.m_netdrv_net_dl_task.count = 0; - - - if (!STAILQ_EMPTY(&free_list)) { - /* free_list contains at least one packet, use it */ - reply.m_netdrv_net_dl_task.count = virtio_net_cpy_from_user(m); - reply.m_netdrv_net_dl_task.flags = DL_PACK_SEND; - } else { - pending_tx_msg = *m; - tx_pending = 1; - } - - if ((r = ipc_send(m->m_source, &reply)) != OK) - panic("%s: ipc_send to %d failed (%d)", name, m->m_source, r); -} - -static void -virtio_net_read(message *m) -{ - int r; - message reply; - - reply.m_type = DL_TASK_REPLY; - reply.m_netdrv_net_dl_task.flags = DL_NOFLAGS; - reply.m_netdrv_net_dl_task.count = 0; - - if (!STAILQ_EMPTY(&recv_list)) { - /* recv_list contains at least one packet, copy it */ - reply.m_netdrv_net_dl_task.count = virtio_net_cpy_to_user(m); - reply.m_netdrv_net_dl_task.flags = DL_PACK_RECV; - } else { - rx_pending = 1; - pending_rx_msg = *m; - } - - if ((r = ipc_send(m->m_source, &reply)) != OK) - panic("%s: ipc_send to %d failed (%d)", name, m->m_source, r); -} - -static void -virtio_net_conf(message *m) -{ - /* TODO: Add the multicast, broadcast filtering etc. */ - int i, r; - - message reply; - - /* If this is the first CONF message we see, fully initialize - * the device now. - */ - if (!started) { - started = 1; - virtio_device_ready(net_dev); - virtio_irq_enable(net_dev); - } - - /* Prepare reply */ - memcpy(reply.m_netdrv_net_dl_conf.hw_addr, virtio_net_mac, - sizeof(reply.m_netdrv_net_dl_conf.hw_addr)); - - reply.m_type = DL_CONF_REPLY; - reply.m_netdrv_net_dl_conf.stat = OK; - - if ((r = ipc_send(m->m_source, &reply)) != OK) - panic("%s: ipc_send to %d failed (%d)", name, m->m_source, r); -} - -static void -virtio_net_getstat(message *m) -{ - int r; - message reply; - - reply.m_type = DL_STAT_REPLY; - - r = sys_safecopyto(m->m_source, m->m_net_netdrv_dl_getstat_s.grant, 0, - (vir_bytes)&virtio_net_stats, - sizeof(virtio_net_stats)); - - if (r != OK) - panic("%s: copy to %d failed (%d)", name, m->m_source, r); - - if ((r = ipc_send(m->m_source, &reply)) != OK) - panic("%s: ipc_send to %d failed (%d)", name, m->m_source, r); -} - -static void -virtio_net_notify(message *m) -{ - if (_ENDPOINT_P(m->m_source) == HARDWARE) - virtio_net_intr(m); -} - -static void -virtio_net_msg(message *m) -{ - switch (m->m_type) { - case DL_WRITEV_S: - virtio_net_write(m); - break; - case DL_READV_S: - virtio_net_read(m); - break; - case DL_CONF: - virtio_net_conf(m); - break; - case DL_GETSTAT_S: - virtio_net_getstat(m); - break; - default: - panic("%s: illegal message: %d", name, m->m_type); - } -} - -static void -virtio_net_main_loop(void) -{ - message m; - int ipc_status; - int r; - - while (TRUE) { - - virtio_net_refill_rx_queue(); - - if ((r = netdriver_receive(ANY, &m, &ipc_status)) != OK) - panic("%s: netdriver_receive failed: %d", name, r); - - if (is_ipc_notify(ipc_status)) - virtio_net_notify(&m); - else - virtio_net_msg(&m); - } -} - -int -main(int argc, char *argv[]) -{ - env_setargs(argc, argv); - sef_local_startup(); - - virtio_net_main_loop(); -} - -static void -sef_local_startup() -{ - sef_setcb_init_fresh(sef_cb_init_fresh); - sef_setcb_init_lu(sef_cb_init_fresh); - sef_setcb_init_restart(sef_cb_init_fresh); - - sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready); - sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_workfree); - - sef_setcb_signal_handler(sef_cb_signal_handler); - - sef_startup(); -} - +/* + * Put user bytes into a free packet buffer, forward this packet to the TX + * queue, and return OK. If there are no free packet buffers, return SUSPEND. + */ static int -sef_cb_init_fresh(int type, sef_init_info_t *info) +virtio_net_send(struct netdriver_data * data, size_t len) { - long instance = 0; - env_parse("instance", "d", 0, &instance, 0, 255); + struct vumap_phys phys[2]; + struct packet *p; - if (virtio_net_probe((int)instance) != OK) - panic("%s: No device found", name); + if (STAILQ_EMPTY(&free_list)) + return SUSPEND; - if (virtio_net_config() != OK) - panic("%s: No device found", name); + p = STAILQ_FIRST(&free_list); + STAILQ_REMOVE_HEAD(&free_list, next); + + if (len > MAX_PACK_SIZE) + panic("%s: packet too large to send: %zu", name, len); + + netdriver_copyin(data, 0, p->vdata, len); + + phys[0].vp_addr = p->phdr; + assert(!(phys[0].vp_addr & 1)); + phys[0].vp_size = sizeof(struct virtio_net_hdr); + phys[1].vp_addr = p->pdata; + assert(!(phys[1].vp_addr & 1)); + phys[1].vp_size = len; + virtio_to_queue(net_dev, TX_Q, phys, 2, p); + + return OK; +} + +/* + * Put a packet receive from the RX queue into a user buffer, and return the + * packet length. If there are no received packets, return SUSPEND. + */ +static ssize_t +virtio_net_recv(struct netdriver_data * data, size_t max) +{ + struct packet *p; + ssize_t len; + + /* Get the first received packet, if any. */ + if (STAILQ_EMPTY(&recv_list)) + return SUSPEND; + + p = STAILQ_FIRST(&recv_list); + STAILQ_REMOVE_HEAD(&recv_list, next); + + /* Copy out the packet contents. */ + len = p->len - sizeof(struct virtio_net_hdr); + if (len > max) + len = max; + + /* + * HACK: due to lack of padding, received packets may in fact be + * smaller than the minimum ethernet packet size. Inet will accept the + * packets just fine if we increase the length to its minimum. We + * already zeroed out the rest of the packet data, so this is safe. + */ + if (len < ETH_MIN_PACK_SIZE) + len = ETH_MIN_PACK_SIZE; + + netdriver_copyout(data, 0, p->vdata, len); + + /* Clean the packet. */ + memset(p->vhdr, 0, sizeof(*p->vhdr)); + memset(p->vdata, 0, MAX_PACK_SIZE); + STAILQ_INSERT_HEAD(&free_list, p, next); + + /* Readd packets to the receive queue as necessary. */ + virtio_net_refill_rx_queue(); + + return len; +} + +/* + * Return statistics. + */ +static void +virtio_net_stat(eth_stat_t *stat) +{ + + memcpy(stat, &virtio_net_stats, sizeof(*stat)); +} + +/* + * Initialize the driver and the virtual hardware. + */ +static int +virtio_net_init(unsigned int instance, ether_addr_t *addr) +{ + int r; + + if ((r = virtio_net_probe(instance)) != OK) + return r; + + virtio_net_config(addr); if (virtio_net_alloc_bufs() != OK) panic("%s: Buffer allocation failed", name); virtio_net_init_queues(); - netdriver_announce(); + /* Add packets to the receive queue. */ + virtio_net_refill_rx_queue(); + + virtio_device_ready(net_dev); + + virtio_irq_enable(net_dev); return(OK); } +/* + * The driver is terminating. Clean up. + */ static void -sef_cb_signal_handler(int signo) +virtio_net_stop(void) { - if (signo != SIGTERM) - return; dput(("Terminating")); @@ -675,6 +444,18 @@ sef_cb_signal_handler(int signo) virtio_free_queues(net_dev); virtio_free_device(net_dev); net_dev = NULL; - - exit(1); +} + +/* + * The virtio-net device driver. + */ +int +main(int argc, char *argv[]) +{ + + env_setargs(argc, argv); + + netdriver_task(&virtio_net_table); + + return 0; } diff --git a/minix/drivers/storage/virtio_blk/virtio_blk.c b/minix/drivers/storage/virtio_blk/virtio_blk.c index 4583101c7..d7a3c7338 100644 --- a/minix/drivers/storage/virtio_blk/virtio_blk.c +++ b/minix/drivers/storage/virtio_blk/virtio_blk.c @@ -439,7 +439,7 @@ virtio_blk_device_intr(void) thread_id_t *tid; /* Multiple requests might have finished */ - while (!virtio_from_queue(blk_dev, 0, (void**)&tid)) + while (!virtio_from_queue(blk_dev, 0, (void**)&tid, NULL)) blockdriver_mt_wakeup(*tid); } diff --git a/minix/include/minix/netdriver.h b/minix/include/minix/netdriver.h index 58ce47564..693855838 100644 --- a/minix/include/minix/netdriver.h +++ b/minix/include/minix/netdriver.h @@ -5,9 +5,63 @@ #include #include +#include -/* Functions defined by netdriver.c: */ -void netdriver_announce(void); -int netdriver_receive(endpoint_t src, message *m_ptr, int *status_ptr); +/* The flags that make up the requested receive mode. */ +#define NDEV_NOMODE DL_NOMODE /* targeted packets only */ +#define NDEV_PROMISC DL_PROMISC_REQ /* promiscuous mode */ +#define NDEV_MULTI DL_MULTI_REQ /* receive multicast packets */ +#define NDEV_BROAD DL_BROAD_REQ /* receive broadcast packets */ + +/* + * For now, only ethernet-type network drivers are supported, and thus, we use + * some ethernet-specific data structures. + */ +#include +#include + +/* Opaque data structure for copying in and out actual packet data. */ +struct netdriver_data; + +/* Function call table for network drivers. */ +struct netdriver { + int (*ndr_init)(unsigned int instance, ether_addr_t *addr); + void (*ndr_stop)(void); + void (*ndr_mode)(unsigned int mode); + ssize_t (*ndr_recv)(struct netdriver_data *data, size_t max); + int (*ndr_send)(struct netdriver_data *data, size_t size); + void (*ndr_stat)(eth_stat_t *stat); + void (*ndr_intr)(unsigned int mask); + void (*ndr_alarm)(clock_t stamp); + void (*ndr_other)(const message *m_ptr, int ipc_status); +}; + +/* Functions defined by libnetdriver. */ +void netdriver_task(const struct netdriver *ndp); + +void netdriver_announce(void); /* legacy; deprecated */ +int netdriver_init(const struct netdriver *ndp); +void netdriver_process(const struct netdriver * __restrict ndp, + const message * __restrict m_ptr, int ipc_status); +void netdriver_terminate(void); + +void netdriver_recv(void); +void netdriver_send(void); + +void netdriver_copyin(struct netdriver_data * __restrict data, size_t off, + void * __restrict ptr, size_t size); +void netdriver_copyout(struct netdriver_data * __restrict data, size_t off, + const void * __restrict ptr, size_t size); + +void netdriver_portinb(struct netdriver_data *data, size_t off, long port, + size_t size); +void netdriver_portoutb(struct netdriver_data *data, size_t off, long port, + size_t size); +void netdriver_portinw(struct netdriver_data *data, size_t off, long port, + size_t size); +void netdriver_portoutw(struct netdriver_data *data, size_t off, long port, + size_t size); + +#define netdriver_receive sef_receive_status /* legacy; deprecated */ #endif /* _MINIX_NETDRIVER_H */ diff --git a/minix/include/minix/virtio.h b/minix/include/minix/virtio.h index aec6d4b89..aee338e1c 100644 --- a/minix/include/minix/virtio.h +++ b/minix/include/minix/virtio.h @@ -98,11 +98,12 @@ int virtio_to_queue(struct virtio_device *dev, int qidx, struct vumap_phys *bufs, size_t num, void *data); /* - * If the host used a chain of descriptors, return 0 and set data - * as was given to virtio_to_queue(). If the host has not processed - * any element returns -1. + * If the host used a chain of descriptors, return 0, set data as was given to + * virtio_to_queue(), and if len is not NULL, set it to the resulting length. + * If the host has not processed any element, return -1. */ -int virtio_from_queue(struct virtio_device *dev, int qidx, void **data); +int virtio_from_queue(struct virtio_device *dev, int qidx, void **data, + size_t *len); /* IRQ related functions */ void virtio_irq_enable(struct virtio_device *dev); diff --git a/minix/lib/libnetdriver/Makefile b/minix/lib/libnetdriver/Makefile index 2c670a4ca..a0abb86fd 100644 --- a/minix/lib/libnetdriver/Makefile +++ b/minix/lib/libnetdriver/Makefile @@ -6,6 +6,6 @@ CPPFLAGS+= -D_MINIX_SYSTEM LIB= netdriver -SRCS= netdriver.c +SRCS= netdriver.c portio.c .include diff --git a/minix/lib/libnetdriver/netdriver.c b/minix/lib/libnetdriver/netdriver.c index 51adcf2a5..bdea11df6 100644 --- a/minix/lib/libnetdriver/netdriver.c +++ b/minix/lib/libnetdriver/netdriver.c @@ -1,82 +1,620 @@ -/* This file contains device independent network device driver interface. - * - * Changes: - * Apr 01, 2010 Created (Cristiano Giuffrida) - * - * The file contains the following entry points: - * - * netdriver_announce: called by a network driver to announce it is up - * netdriver_receive: receive() interface for network drivers - */ +/* The device-independent network driver framework. */ #include #include #include #include +#include -static int conf_expected = TRUE; +#include "netdriver.h" -/*===========================================================================* - * netdriver_announce * - *===========================================================================*/ -void netdriver_announce() +static const struct netdriver *netdriver_table = NULL; + +static int running; + +static int conf_expected; + +static endpoint_t pending_endpt; +static struct netdriver_data pending_recv, pending_send; + +static int defer_reply; +static unsigned int pending_flags; +static size_t pending_size; + +static ether_addr_t hw_addr; + +/* + * Announce we are up after a fresh start or restart. + */ +void +netdriver_announce(void) { -/* Announce we are up after a fresh start or restart. */ - int r; - char key[DS_MAX_KEYLEN]; - char label[DS_MAX_KEYLEN]; - const char *driver_prefix = "drv.net."; + const char *driver_prefix = "drv.net."; + char label[DS_MAX_KEYLEN]; + char key[DS_MAX_KEYLEN]; + int r; - /* Publish a driver up event. */ - r = ds_retrieve_label_name(label, sef_self()); - if (r != OK) { - panic("driver_announce: unable to get own label: %d\n", r); - } - snprintf(key, DS_MAX_KEYLEN, "%s%s", driver_prefix, label); - r = ds_publish_u32(key, DS_DRIVER_UP, DSF_OVERWRITE); - if (r != OK) { - panic("driver_announce: unable to publish driver up event: %d\n", r); - } + /* Publish a driver up event. */ + if ((r = ds_retrieve_label_name(label, sef_self())) != OK) + panic("netdriver: unable to get own label: %d", r); - conf_expected = TRUE; + snprintf(key, sizeof(key), "%s%s", driver_prefix, label); + if ((r = ds_publish_u32(key, DS_DRIVER_UP, DSF_OVERWRITE)) != OK) + panic("netdriver: unable to publish driver up event: %d", r); } -/*===========================================================================* - * netdriver_receive * - *===========================================================================*/ -int netdriver_receive(src, m_ptr, status_ptr) -endpoint_t src; -message *m_ptr; -int *status_ptr; +/* + * Prepare for copying. Given a flat offset, return the vector element index + * and an offset into that element. Panic if the request does not fall + * entirely within the vector. + */ +size_t +netdriver_prepare_copy(struct netdriver_data * data, size_t off, size_t size, + unsigned int * indexp) { -/* receive() interface for drivers. */ - int r; + unsigned int i; - while (TRUE) { - /* Wait for a request. */ - r = sef_receive_status(src, m_ptr, status_ptr); - if (r != OK) { - return r; + assert(data->size > 0); + + /* + * In theory we could truncate when copying out, but this creates a + * problem for port-based I/O, where the size of the transfer is + * typically specified in advance. We could do extra port-based I/O + * to discard the extra bytes, but the driver is better off doing such + * truncation itself. Thus, we disallow copying (in and out) beyond + * the given data vector altogether. + */ + if (off + size > data->size) + panic("netdriver: request to copy beyond data size"); + + /* + * Find the starting offset in the vector. If this turns out to be + * expensive, this can be adapted to store the last + * pair in the "data" structure (this is the reason it is not 'const'). + */ + for (i = 0; i < data->count; i++) { + assert(data->iovec[i].iov_size > 0); + + if (off >= data->iovec[i].iov_size) + off -= data->iovec[i].iov_size; + else + break; } - /* Let non-datalink requests through regardless. */ - if (!IS_DL_RQ(m_ptr->m_type)) { - return r; - } + assert(i < data->count); - /* See if only DL_CONF is to be expected. */ - if(conf_expected) { - if(m_ptr->m_type == DL_CONF) { - conf_expected = FALSE; - } - else { - continue; - } - } - - break; - } - - return OK; + *indexp = i; + return off; } +/* + * Copy in or out packet data from/to a vector of grants. + */ +static void +netdriver_copy(struct netdriver_data * data, size_t off, vir_bytes addr, + size_t size, int copyin) +{ + struct vscp_vec vec[SCPVEC_NR]; + size_t chunk; + unsigned int i, v; + int r; + + off = netdriver_prepare_copy(data, off, size, &i); + + /* Generate a new vector with all the individual copies to make. */ + for (v = 0; size > 0; v++) { + chunk = data->iovec[i].iov_size - off; + if (chunk > size) + chunk = size; + assert(chunk > 0); + + /* + * We should be able to fit the entire I/O request in a single + * copy vector. If not, MINIX3 has been misconfigured. + */ + if (v >= SCPVEC_NR) + panic("netdriver: invalid vector size constant"); + + if (copyin) { + vec[v].v_from = data->endpt; + vec[v].v_to = SELF; + } else { + vec[v].v_from = SELF; + vec[v].v_to = data->endpt; + } + vec[v].v_gid = data->iovec[i].iov_grant; + vec[v].v_offset = off; + vec[v].v_addr = addr; + vec[v].v_bytes = chunk; + + i++; + off = 0; + addr += chunk; + size -= chunk; + } + + assert(v > 0 && v <= SCPVEC_NR); + + /* + * If only one vector element was generated, use a direct copy. This + * saves the kernel from having to copy in the vector. + */ + if (v == 1) { + if (copyin) + r = sys_safecopyfrom(vec->v_from, vec->v_gid, + vec->v_offset, vec->v_addr, vec->v_bytes); + else + r = sys_safecopyto(vec->v_to, vec->v_gid, + vec->v_offset, vec->v_addr, vec->v_bytes); + } else + r = sys_vsafecopy(vec, v); + + if (r != OK) + panic("netdriver: unable to copy data: %d", r); +} + +/* + * Copy in packet data. + */ +void +netdriver_copyin(struct netdriver_data * __restrict data, size_t off, + void * __restrict ptr, size_t size) +{ + + netdriver_copy(data, off, (vir_bytes)ptr, size, TRUE /*copyin*/); +} + +/* + * Copy out packet data. + */ +void +netdriver_copyout(struct netdriver_data * __restrict data, size_t off, + const void * __restrict ptr, size_t size) +{ + + netdriver_copy(data, off, (vir_bytes)ptr, size, FALSE /*copyin*/); +} + +/* + * Send a reply to a request. + */ +static void +send_reply(endpoint_t endpt, message * m_ptr) +{ + int r; + + if ((r = ipc_send(endpt, m_ptr)) != OK) + panic("netdriver: unable to send to %d: %d", endpt, r); +} + +/* + * Defer sending any replies to task requests until the next call to + * check_replies(). The purpose of this is aggregation of task replies to both + * send and receive requests into a single reply message, which saves on + * messages, in particular when processing interrupts. + */ +static void +defer_replies(void) +{ + + assert(netdriver_table != NULL); + assert(defer_reply == FALSE); + + defer_reply = TRUE; +} + +/* + * Check if we have to reply to earlier task (I/O) requests, and if so, send + * the reply. If deferred is FALSE and the call to this function was preceded + * by a call to defer_replies(), do not send a reply yet. If always_send is + * TRUE, send a reply even if no tasks have completed yet. + */ +static void +check_replies(int deferred, int always_send) +{ + message m_reply; + + if (defer_reply && !deferred) + return; + + defer_reply = FALSE; + + if (pending_flags == 0 && !always_send) + return; + + assert(pending_endpt != NONE); + + memset(&m_reply, 0, sizeof(m_reply)); + m_reply.m_type = DL_TASK_REPLY; + m_reply.m_netdrv_net_dl_task.flags = pending_flags; + m_reply.m_netdrv_net_dl_task.count = pending_size; + + send_reply(pending_endpt, &m_reply); + + pending_flags = 0; + pending_size = 0; +} + +/* + * Resume receiving packets. In particular, if a receive request was pending, + * call the driver's receive function. If the call is successful, schedule + * sending a reply to the requesting party. + */ +void +netdriver_recv(void) +{ + ssize_t r; + + if (pending_recv.size == 0) + return; + + assert(netdriver_table != NULL); + + /* + * For convenience of driver writers: if the receive function returns + * zero, simply call it again, to simplify discarding invalid packets. + */ + do { + r = netdriver_table->ndr_recv(&pending_recv, + pending_recv.size); + + /* + * The default policy is: drop undersized packets, panic on + * oversized packets. The driver may implement any other + * policy (e.g., pad small packets, drop or truncate large + * packets), but it should at least test against the given + * 'max' value. The reason that truncation should be + * implemented in the driver rather than here, is explained in + * an earlier comment about truncating copy operations. + */ + if (r >= 0 && r < ETH_MIN_PACK_SIZE) + r = 0; + else if (r > (ssize_t)pending_recv.size) + panic("netdriver: oversized packet returned: %zd", r); + } while (r == 0); + + if (r == SUSPEND) + return; + if (r < 0) + panic("netdriver: driver reported receive failure: %d", r); + + assert(r >= ETH_MIN_PACK_SIZE && (size_t)r <= pending_recv.size); + + pending_flags |= DL_PACK_RECV; + pending_size = r; + + pending_recv.size = 0; + + check_replies(FALSE /*deferred*/, FALSE /*always_send*/); +} + +/* + * Resume sending packets. In particular, if a send request was pending, call + * the driver's send function. If the call is successful, schedule sending a + * reply to the requesting party. This function relies on being called + * between init_pending() and check_pending(). + */ +void +netdriver_send(void) +{ + int r; + + if (pending_send.size == 0) + return; + + assert(netdriver_table != NULL); + + r = netdriver_table->ndr_send(&pending_send, pending_send.size); + + if (r == SUSPEND) + return; + if (r < 0) + panic("netdriver: driver reported send failure: %d", r); + + pending_flags |= DL_PACK_SEND; + + pending_send.size = 0; + + check_replies(FALSE /*deferred*/, FALSE /*always_send*/); +} + +/* + * Process a request to receive or send a packet. + */ +static void +do_readwrite(const struct netdriver * __restrict ndp, endpoint_t endpt, + cp_grant_id_t grant, unsigned int count, int write) +{ + struct netdriver_data *data; + unsigned int i; + int r; + + /* Copy in the I/O vector. */ + data = (write) ? &pending_send : &pending_recv; + + if (data->size != 0) + panic("netdriver: multiple concurrent requests"); + + if (count == 0 || count > NR_IOREQS) + panic("netdriver: bad I/O vector count: %u", count); + + data->endpt = endpt; + data->count = count; + + if ((r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes)data->iovec, + sizeof(data->iovec[0]) * count)) != OK) + panic("netdriver: unable to copy in I/O vector: %d", r); + + for (i = 0; i < count; i++) + data->size += data->iovec[i].iov_size; + + if (data->size < ETH_MIN_PACK_SIZE || + (!write && data->size < ETH_MAX_PACK_SIZE_TAGGED)) + panic("netdriver: invalid I/O vector size: %zu\n", data->size); + + /* Save the endpoint to which we should reply. */ + if (pending_endpt != NONE && pending_endpt != endpt) + panic("netdriver: multiple request sources"); + pending_endpt = endpt; + + /* Resume sending or receiving. */ + defer_replies(); + + if (write) + netdriver_send(); + else + netdriver_recv(); + + /* Always send a reply in this case, even if no flags are set. */ + check_replies(TRUE /*deferred*/, TRUE /*always_send*/); +} + +/* + * Process a request to configure the driver, by setting its mode and obtaining + * its ethernet hardware address. We already have the latter as a result of + * calling the ndr_init callback function. + */ +static void +do_conf(const struct netdriver * __restrict ndp, + const message * __restrict m_ptr) +{ + message m_reply; + + if (ndp->ndr_mode != NULL) + ndp->ndr_mode(m_ptr->m_net_netdrv_dl_conf.mode); + + memset(&m_reply, 0, sizeof(m_reply)); + m_reply.m_type = DL_CONF_REPLY; + m_reply.m_netdrv_net_dl_conf.stat = OK; /* legacy */ + memcpy(&m_reply.m_netdrv_net_dl_conf.hw_addr, &hw_addr, + sizeof(m_reply.m_netdrv_net_dl_conf.hw_addr)); + + send_reply(m_ptr->m_source, &m_reply); +} + +/* + * Process a request to obtain statistics from the driver. + */ +static void +do_getstat(const struct netdriver * __restrict ndp, + const message * __restrict m_ptr) +{ + message m_reply; + eth_stat_t stat; + int r; + + memset(&stat, 0, sizeof(stat)); + + if (ndp->ndr_stat != NULL) + ndp->ndr_stat(&stat); + + if ((r = sys_safecopyto(m_ptr->m_source, + m_ptr->m_net_netdrv_dl_getstat_s.grant, 0, (vir_bytes)&stat, + sizeof(stat))) != OK) + panic("netdriver: unable to copy out statistics: %d", r); + + memset(&m_reply, 0, sizeof(m_reply)); + m_reply.m_type = DL_STAT_REPLY; + + send_reply(m_ptr->m_source, &m_reply); +} + +/* + * Process an incoming message, and send a reply. + */ +void +netdriver_process(const struct netdriver * __restrict ndp, + const message * __restrict m_ptr, int ipc_status) +{ + + netdriver_table = ndp; + + /* Check for notifications first. */ + if (is_ipc_notify(ipc_status)) { + defer_replies(); + + switch (_ENDPOINT_P(m_ptr->m_source)) { + case HARDWARE: + if (ndp->ndr_intr != NULL) + ndp->ndr_intr(m_ptr->m_notify.interrupts); + break; + + case CLOCK: + if (ndp->ndr_alarm != NULL) + ndp->ndr_alarm(m_ptr->m_notify.timestamp); + break; + + default: + if (ndp->ndr_other != NULL) + ndp->ndr_other(m_ptr, ipc_status); + } + + /* + * Any of the above calls may end up invoking netdriver_send() + * and/or netdriver_recv(), which may in turn have deferred + * sending a reply to an earlier request. See if we have to + * send the reply now. + */ + check_replies(TRUE /*deferred*/, FALSE /*always_send*/); + } + + /* + * Discard datalink requests preceding a first DL_CONF request, so that + * after a driver restart, any in-flight request is discarded. This is + * a rather blunt approach and must be revised if the protocol is ever + * made less inefficient (i.e. not strictly serialized). Note that for + * correct driver operation it is important that non-datalink requests, + * interrupts in particular, do not go through this check. + */ + if (IS_DL_RQ(m_ptr->m_type) && conf_expected) { + if (m_ptr->m_type != DL_CONF) + return; /* do not send a reply */ + + conf_expected = FALSE; + } + + switch (m_ptr->m_type) { + case DL_CONF: + do_conf(ndp, m_ptr); + break; + + case DL_GETSTAT_S: + do_getstat(ndp, m_ptr); + break; + + case DL_READV_S: + do_readwrite(ndp, m_ptr->m_source, + m_ptr->m_net_netdrv_dl_readv_s.grant, + m_ptr->m_net_netdrv_dl_readv_s.count, FALSE /*write*/); + break; + + case DL_WRITEV_S: + do_readwrite(ndp, m_ptr->m_source, + m_ptr->m_net_netdrv_dl_writev_s.grant, + m_ptr->m_net_netdrv_dl_writev_s.count, TRUE /*write*/); + break; + + default: + defer_replies(); + + if (ndp->ndr_other != NULL) + ndp->ndr_other(m_ptr, ipc_status); + + /* As above: see if we have to send a reply now. */ + check_replies(TRUE /*deferred*/, FALSE /*always_send*/); + } +} + +/* + * Perform initialization. Return OK or an error code. + */ +int +netdriver_init(const struct netdriver * ndp) +{ + unsigned int instance; + long v; + int r; + + /* Initialize global variables. */ + pending_recv.size = 0; + pending_send.size = 0; + pending_endpt = NONE; + defer_reply = FALSE; + pending_flags = 0; + pending_size = 0; + conf_expected = TRUE; + + /* Get the card instance number. */ + v = 0; + (void)env_parse("instance", "d", 0, &v, 0, 255); + instance = (unsigned int)v; + + /* Call the initialization routine. */ + memset(&hw_addr, 0, sizeof(hw_addr)); + + if (ndp->ndr_init != NULL && + (r = ndp->ndr_init(instance, &hw_addr)) != OK) + return r; + + /* Announce we are up! */ + netdriver_announce(); + + return OK; +} + +/* + * SEF initialization function. + */ +static int +do_init(int __unused type, sef_init_info_t * __unused info) +{ + const struct netdriver *ndp; + + ndp = netdriver_table; + assert(ndp != NULL); + + return netdriver_init(ndp); +} + +/* + * Break out of the main loop after finishing the current request. + */ +void +netdriver_terminate(void) +{ + + if (netdriver_table != NULL && netdriver_table->ndr_stop != NULL) + netdriver_table->ndr_stop(); + + running = FALSE; + + sef_cancel(); +} + +/* + * The process has received a signal. See if we have to terminate. + */ +static void +got_signal(int sig) +{ + + if (sig != SIGTERM) + return; + + netdriver_terminate(); +} + +/* + * Main program of any network driver. + */ +void +netdriver_task(const struct netdriver * ndp) +{ + message mess; + int r, ipc_status; + + /* Perform SEF initialization. */ + sef_setcb_init_fresh(do_init); + sef_setcb_init_restart(do_init); /* TODO: revisit this */ + sef_setcb_signal_handler(got_signal); + + netdriver_table = ndp; + + sef_startup(); + + netdriver_table = NULL; + + /* The main message loop. */ + running = TRUE; + + while (running) { + if ((r = sef_receive_status(ANY, &mess, &ipc_status)) != OK) { + if (r == EINTR) + continue; /* sef_cancel() was called */ + + panic("netdriver: sef_receive_status failed: %d", r); + } + + netdriver_process(ndp, &mess, ipc_status); + } +} diff --git a/minix/lib/libnetdriver/netdriver.h b/minix/lib/libnetdriver/netdriver.h new file mode 100644 index 000000000..24b9c5cc0 --- /dev/null +++ b/minix/lib/libnetdriver/netdriver.h @@ -0,0 +1,15 @@ +#ifndef _MINIX_LIB_NETDRIVER_NETDRIVER_H +#define _MINIX_LIB_NETDRIVER_NETDRIVER_H + +/* Data (I/O) structure. */ +struct netdriver_data { + endpoint_t endpt; + size_t size; + unsigned int count; + iovec_s_t iovec[NR_IOREQS]; +}; + +size_t netdriver_prepare_copy(struct netdriver_data *data, size_t offp, + size_t size, unsigned int * indexp); + +#endif /* !_MINIX_LIB_NETDRIVER_NETDRIVER_H */ diff --git a/minix/lib/libnetdriver/portio.c b/minix/lib/libnetdriver/portio.c new file mode 100644 index 000000000..432166f29 --- /dev/null +++ b/minix/lib/libnetdriver/portio.c @@ -0,0 +1,193 @@ +/* + * Port-based I/O routines. These are in a separate module because most + * drivers will not use them, and system services are statically linked. + */ +#include +#include +#include + +#include "netdriver.h" + +/* + * Port-based I/O byte sequence copy routine. + */ +static void +netdriver_portb(struct netdriver_data * data, size_t off, long port, + size_t size, int portin) +{ + size_t chunk; + unsigned int i; + int r, req; + + off = netdriver_prepare_copy(data, off, size, &i); + + req = portin ? DIO_SAFE_INPUT_BYTE : DIO_SAFE_OUTPUT_BYTE; + + while (size > 0) { + chunk = data->iovec[i].iov_size - off; + if (chunk > size) + chunk = size; + assert(chunk > 0); + + if ((r = sys_sdevio(req, port, data->endpt, + (void *)data->iovec[i].iov_grant, chunk, off)) != OK) + panic("netdriver: port I/O failed: %d", r); + + i++; + off = 0; + size -= chunk; + } +} + +/* + * Transfer bytes from hardware to a destination buffer using port-based I/O. + */ +void +netdriver_portinb(struct netdriver_data * data, size_t off, long port, + size_t size) +{ + + return netdriver_portb(data, off, port, size, TRUE /*portin*/); +} + +/* + * Transfer bytes from a source buffer to hardware using port-based I/O. + */ +void +netdriver_portoutb(struct netdriver_data * data, size_t off, long port, + size_t size) +{ + + return netdriver_portb(data, off, port, size, FALSE /*portin*/); +} + +/* + * Transfer words from hardware to a destination buffer using port-based I/O. + */ +void +netdriver_portinw(struct netdriver_data * data, size_t off, long port, + size_t size) +{ + uint8_t buf[2]; + uint32_t value; + size_t chunk; + unsigned int i; + int r, odd_byte; + + off = netdriver_prepare_copy(data, off, size, &i); + + odd_byte = 0; + while (size > 0) { + chunk = data->iovec[i].iov_size - off; + if (chunk > size) + chunk = size; + assert(chunk > 0); + + if (odd_byte) { + if ((r = sys_safecopyto(data->endpt, + data->iovec[i].iov_grant, off, (vir_bytes)&buf[1], + 1)) != OK) + panic("netdriver: unable to copy data: %d", r); + + off++; + size--; + chunk--; + } + + odd_byte = chunk & 1; + chunk -= odd_byte; + + if (chunk > 0) { + if ((r = sys_safe_insw(port, data->endpt, + data->iovec[i].iov_grant, off, chunk)) != OK) + panic("netdriver: port input failed: %d", r); + + off += chunk; + size -= chunk; + } + + if (odd_byte) { + if ((r = sys_inw(port, &value)) != OK) + panic("netdriver: port input failed: %d", r); + *(uint16_t *)buf = (uint16_t)value; + + if ((r = sys_safecopyto(data->endpt, + data->iovec[i].iov_grant, off, (vir_bytes)&buf[0], + 1)) != OK) + panic("netdriver: unable to copy data: %d", r); + + size--; + } + + i++; + off = 0; + } +} + +/* + * Transfer words from a source buffer to hardware using port-based I/O. + */ +void +netdriver_portoutw(struct netdriver_data * data, size_t off, long port, + size_t size) +{ + uint8_t buf[2]; + size_t chunk; + unsigned int i; + int r, odd_byte; + + off = netdriver_prepare_copy(data, off, size, &i); + + odd_byte = 0; + while (size > 0) { + chunk = data->iovec[i].iov_size - off; + if (chunk > size) + chunk = size; + assert(chunk > 0); + + if (odd_byte) { + if ((r = sys_safecopyfrom(data->endpt, + data->iovec[i].iov_grant, off, (vir_bytes)&buf[1], + 1)) != OK) + panic("netdriver: unable to copy data: %d", r); + + if ((r = sys_outw(port, *(uint16_t *)buf)) != OK) + panic("netdriver: port output failed: %d", r); + + off++; + size--; + chunk--; + } + + odd_byte = chunk & 1; + chunk -= odd_byte; + + if (chunk > 0) { + if ((r = sys_safe_outsw(port, data->endpt, + data->iovec[i].iov_grant, off, chunk)) != OK) + panic("netdriver: port output failed: %d", r); + + off += chunk; + size -= chunk; + } + + if (odd_byte) { + if ((r = sys_safecopyfrom(data->endpt, + data->iovec[i].iov_grant, off, (vir_bytes)&buf[0], + 1)) != OK) + panic("netdriver: unable to copy data: %d", r); + + size--; + } + + i++; + off = 0; + } + + if (odd_byte) { + buf[1] = 0; + + if ((r = sys_outw(port, *(uint16_t *)buf)) != OK) + panic("netdriver: port output failed: %d", r); + } +} diff --git a/minix/lib/libvirtio/virtio.c b/minix/lib/libvirtio/virtio.c index 1ff715a04..95c64cbe0 100644 --- a/minix/lib/libvirtio/virtio.c +++ b/minix/lib/libvirtio/virtio.c @@ -639,7 +639,8 @@ virtio_to_queue(struct virtio_device *dev, int qidx, struct vumap_phys *bufs, } int -virtio_from_queue(struct virtio_device *dev, int qidx, void **data) +virtio_from_queue(struct virtio_device *dev, int qidx, void **data, + size_t *len) { struct virtio_queue *q; struct vring *vring; @@ -718,6 +719,9 @@ virtio_from_queue(struct virtio_device *dev, int qidx, void **data) *data = q->data[uel->id]; q->data[uel->id] = NULL; + if (len != NULL) + *len = uel->len; + return 0; } diff --git a/minix/net/Makefile b/minix/net/Makefile index 3a589825b..223f74188 100644 --- a/minix/net/Makefile +++ b/minix/net/Makefile @@ -6,6 +6,8 @@ SUBDIR+= inet . if ${MKLWIP} == "yes" SUBDIR+= lwip . endif # ${MKLWIP} == "yes" + +SUBDIR+= uds .endif # ${MKIMAGEONLY} == "no" .include diff --git a/minix/drivers/net/uds/Makefile b/minix/net/uds/Makefile similarity index 100% rename from minix/drivers/net/uds/Makefile rename to minix/net/uds/Makefile diff --git a/minix/drivers/net/uds/ioc_uds.c b/minix/net/uds/ioc_uds.c similarity index 100% rename from minix/drivers/net/uds/ioc_uds.c rename to minix/net/uds/ioc_uds.c diff --git a/minix/drivers/net/uds/uds.c b/minix/net/uds/uds.c similarity index 100% rename from minix/drivers/net/uds/uds.c rename to minix/net/uds/uds.c diff --git a/minix/drivers/net/uds/uds.h b/minix/net/uds/uds.h similarity index 100% rename from minix/drivers/net/uds/uds.h rename to minix/net/uds/uds.h