eth_v10.c
来自「linux 内核源代码」· C语言 代码 · 共 1,954 行 · 第 1/4 页
C
1,954 行
if (cris_request_io_interface(if_eth, cardname)) { printk(KERN_CRIT "etrax_ethernet_init failed to get IO interface\n"); return -EBUSY; } dev = alloc_etherdev(sizeof(struct net_local)); if (!dev) return -ENOMEM; np = netdev_priv(dev); /* we do our own locking */ dev->features |= NETIF_F_LLTX; dev->base_addr = (unsigned int)R_NETWORK_SA_0; /* just to have something to show */ /* now setup our etrax specific stuff */ dev->irq = NETWORK_DMA_RX_IRQ_NBR; /* we really use DMATX as well... */ dev->dma = NETWORK_RX_DMA_NBR; /* fill in our handlers so the network layer can talk to us in the future */ dev->open = e100_open; dev->hard_start_xmit = e100_send_packet; dev->stop = e100_close; dev->get_stats = e100_get_stats; dev->set_multicast_list = set_multicast_list; dev->set_mac_address = e100_set_mac_address; dev->ethtool_ops = &e100_ethtool_ops; dev->do_ioctl = e100_ioctl; dev->set_config = e100_set_config; dev->tx_timeout = e100_tx_timeout;#ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = e100_netpoll;#endif spin_lock_init(&np->lock); spin_lock_init(&np->led_lock); spin_lock_init(&np->transceiver_lock); /* Initialise the list of Etrax DMA-descriptors */ /* Initialise receive descriptors */ for (i = 0; i < NBR_OF_RX_DESC; i++) { /* Allocate two extra cachelines to make sure that buffer used * by DMA does not share cacheline with any other data (to * avoid cache bug) */ RxDescList[i].skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE + 2 * L1_CACHE_BYTES); if (!RxDescList[i].skb) return -ENOMEM; RxDescList[i].descr.ctrl = 0; RxDescList[i].descr.sw_len = MAX_MEDIA_DATA_SIZE; RxDescList[i].descr.next = virt_to_phys(&RxDescList[i + 1]); RxDescList[i].descr.buf = L1_CACHE_ALIGN(virt_to_phys(RxDescList[i].skb->data)); RxDescList[i].descr.status = 0; RxDescList[i].descr.hw_len = 0; prepare_rx_descriptor(&RxDescList[i].descr); } RxDescList[NBR_OF_RX_DESC - 1].descr.ctrl = d_eol; RxDescList[NBR_OF_RX_DESC - 1].descr.next = virt_to_phys(&RxDescList[0]); rx_queue_len = 0; /* Initialize transmit descriptors */ for (i = 0; i < NBR_OF_TX_DESC; i++) { TxDescList[i].descr.ctrl = 0; TxDescList[i].descr.sw_len = 0; TxDescList[i].descr.next = virt_to_phys(&TxDescList[i + 1].descr); TxDescList[i].descr.buf = 0; TxDescList[i].descr.status = 0; TxDescList[i].descr.hw_len = 0; TxDescList[i].skb = 0; } TxDescList[NBR_OF_TX_DESC - 1].descr.ctrl = d_eol; TxDescList[NBR_OF_TX_DESC - 1].descr.next = virt_to_phys(&TxDescList[0].descr); /* Initialise initial pointers */ myNextRxDesc = &RxDescList[0]; myLastRxDesc = &RxDescList[NBR_OF_RX_DESC - 1]; myFirstTxDesc = &TxDescList[0]; myNextTxDesc = &TxDescList[0]; myLastTxDesc = &TxDescList[NBR_OF_TX_DESC - 1]; /* Register device */ err = register_netdev(dev); if (err) { free_netdev(dev); return err; } /* set the default MAC address */ e100_set_mac_address(dev, &default_mac); /* Initialize speed indicator stuff. */ current_speed = 10; current_speed_selection = 0; /* Auto */ speed_timer.expires = jiffies + NET_LINK_UP_CHECK_INTERVAL; speed_timer.data = (unsigned long)dev; speed_timer.function = e100_check_speed; clear_led_timer.function = e100_clear_network_leds; clear_led_timer.data = (unsigned long)dev; full_duplex = 0; current_duplex = autoneg; duplex_timer.expires = jiffies + NET_DUPLEX_CHECK_INTERVAL; duplex_timer.data = (unsigned long)dev; duplex_timer.function = e100_check_duplex; /* Initialize mii interface */ np->mii_if.phy_id_mask = 0x1f; np->mii_if.reg_num_mask = 0x1f; np->mii_if.dev = dev; np->mii_if.mdio_read = e100_get_mdio_reg; np->mii_if.mdio_write = e100_set_mdio_reg; /* Initialize group address registers to make sure that no */ /* unwanted addresses are matched */ *R_NETWORK_GA_0 = 0x00000000; *R_NETWORK_GA_1 = 0x00000000; /* Initialize next time the led can flash */ led_next_time = jiffies; return 0;}/* set MAC address of the interface. called from the core after a * SIOCSIFADDR ioctl, and from the bootup above. */static inte100_set_mac_address(struct net_device *dev, void *p){ struct net_local *np = netdev_priv(dev); struct sockaddr *addr = p; DECLARE_MAC_BUF(mac); spin_lock(&np->lock); /* preemption protection */ /* remember it */ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); /* Write it to the hardware. * Note the way the address is wrapped: * *R_NETWORK_SA_0 = a0_0 | (a0_1 << 8) | (a0_2 << 16) | (a0_3 << 24); * *R_NETWORK_SA_1 = a0_4 | (a0_5 << 8); */ *R_NETWORK_SA_0 = dev->dev_addr[0] | (dev->dev_addr[1] << 8) | (dev->dev_addr[2] << 16) | (dev->dev_addr[3] << 24); *R_NETWORK_SA_1 = dev->dev_addr[4] | (dev->dev_addr[5] << 8); *R_NETWORK_SA_2 = 0; /* show it in the log as well */ printk(KERN_INFO "%s: changed MAC to %s\n", dev->name, print_mac(mac, dev->dev_addr)); spin_unlock(&np->lock); return 0;}/* * Open/initialize the board. This is called (in the current kernel) * sometime after booting when the 'ifconfig' program is run. * * This routine should set everything up anew at each open, even * registers that "should" only need to be set once at boot, so that * there is non-reboot way to recover if something goes wrong. */static inte100_open(struct net_device *dev){ unsigned long flags; /* enable the MDIO output pin */ *R_NETWORK_MGM_CTRL = IO_STATE(R_NETWORK_MGM_CTRL, mdoe, enable); *R_IRQ_MASK0_CLR = IO_STATE(R_IRQ_MASK0_CLR, overrun, clr) | IO_STATE(R_IRQ_MASK0_CLR, underrun, clr) | IO_STATE(R_IRQ_MASK0_CLR, excessive_col, clr); /* clear dma0 and 1 eop and descr irq masks */ *R_IRQ_MASK2_CLR = IO_STATE(R_IRQ_MASK2_CLR, dma0_descr, clr) | IO_STATE(R_IRQ_MASK2_CLR, dma0_eop, clr) | IO_STATE(R_IRQ_MASK2_CLR, dma1_descr, clr) | IO_STATE(R_IRQ_MASK2_CLR, dma1_eop, clr); /* Reset and wait for the DMA channels */ RESET_DMA(NETWORK_TX_DMA_NBR); RESET_DMA(NETWORK_RX_DMA_NBR); WAIT_DMA(NETWORK_TX_DMA_NBR); WAIT_DMA(NETWORK_RX_DMA_NBR); /* Initialise the etrax network controller */ /* allocate the irq corresponding to the receiving DMA */ if (request_irq(NETWORK_DMA_RX_IRQ_NBR, e100rxtx_interrupt, IRQF_SAMPLE_RANDOM, cardname, (void *)dev)) { goto grace_exit0; } /* allocate the irq corresponding to the transmitting DMA */ if (request_irq(NETWORK_DMA_TX_IRQ_NBR, e100rxtx_interrupt, 0, cardname, (void *)dev)) { goto grace_exit1; } /* allocate the irq corresponding to the network errors etc */ if (request_irq(NETWORK_STATUS_IRQ_NBR, e100nw_interrupt, 0, cardname, (void *)dev)) { goto grace_exit2; } /* * Always allocate the DMA channels after the IRQ, * and clean up on failure. */ if (cris_request_dma(NETWORK_TX_DMA_NBR, cardname, DMA_VERBOSE_ON_ERROR, dma_eth)) { goto grace_exit3; } if (cris_request_dma(NETWORK_RX_DMA_NBR, cardname, DMA_VERBOSE_ON_ERROR, dma_eth)) { goto grace_exit4; } /* give the HW an idea of what MAC address we want */ *R_NETWORK_SA_0 = dev->dev_addr[0] | (dev->dev_addr[1] << 8) | (dev->dev_addr[2] << 16) | (dev->dev_addr[3] << 24); *R_NETWORK_SA_1 = dev->dev_addr[4] | (dev->dev_addr[5] << 8); *R_NETWORK_SA_2 = 0;#if 0 /* use promiscuous mode for testing */ *R_NETWORK_GA_0 = 0xffffffff; *R_NETWORK_GA_1 = 0xffffffff; *R_NETWORK_REC_CONFIG = 0xd; /* broadcast rec, individ. rec, ma0 enabled */#else SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, max_size, size1522); SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, broadcast, receive); SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, ma0, enable); SETF(network_rec_config_shadow, R_NETWORK_REC_CONFIG, duplex, full_duplex); *R_NETWORK_REC_CONFIG = network_rec_config_shadow;#endif *R_NETWORK_GEN_CONFIG = IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk) | IO_STATE(R_NETWORK_GEN_CONFIG, enable, on); SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, clr); SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, delay, none); SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, cancel, dont); SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, cd, enable); SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, retry, enable); SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, pad, enable); SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, crc, enable); *R_NETWORK_TR_CTRL = network_tr_ctrl_shadow; local_irq_save(flags); /* enable the irq's for ethernet DMA */ *R_IRQ_MASK2_SET = IO_STATE(R_IRQ_MASK2_SET, dma0_eop, set) | IO_STATE(R_IRQ_MASK2_SET, dma1_eop, set); *R_IRQ_MASK0_SET = IO_STATE(R_IRQ_MASK0_SET, overrun, set) | IO_STATE(R_IRQ_MASK0_SET, underrun, set) | IO_STATE(R_IRQ_MASK0_SET, excessive_col, set); /* make sure the irqs are cleared */ *R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do); *R_DMA_CH1_CLR_INTR = IO_STATE(R_DMA_CH1_CLR_INTR, clr_eop, do); /* make sure the rec and transmit error counters are cleared */ (void)*R_REC_COUNTERS; /* dummy read */ (void)*R_TR_COUNTERS; /* dummy read */ /* start the receiving DMA channel so we can receive packets from now on */ *R_DMA_CH1_FIRST = virt_to_phys(myNextRxDesc); *R_DMA_CH1_CMD = IO_STATE(R_DMA_CH1_CMD, cmd, start); /* Set up transmit DMA channel so it can be restarted later */ *R_DMA_CH0_FIRST = 0; *R_DMA_CH0_DESCR = virt_to_phys(myLastTxDesc); netif_start_queue(dev); local_irq_restore(flags); /* Probe for transceiver */ if (e100_probe_transceiver(dev)) goto grace_exit5; /* Start duplex/speed timers */ add_timer(&speed_timer); add_timer(&duplex_timer); /* We are now ready to accept transmit requeusts from * the queueing layer of the networking. */ netif_carrier_on(dev); return 0;grace_exit5: cris_free_dma(NETWORK_RX_DMA_NBR, cardname);grace_exit4: cris_free_dma(NETWORK_TX_DMA_NBR, cardname);grace_exit3: free_irq(NETWORK_STATUS_IRQ_NBR, (void *)dev);grace_exit2: free_irq(NETWORK_DMA_TX_IRQ_NBR, (void *)dev);grace_exit1: free_irq(NETWORK_DMA_RX_IRQ_NBR, (void *)dev);grace_exit0: return -EAGAIN;}#if defined(CONFIG_ETRAX_NO_PHY)static voiddummy_check_speed(struct net_device* dev){ current_speed = 100;}#elsestatic voidgeneric_check_speed(struct net_device* dev){ unsigned long data; struct net_local *np = netdev_priv(dev); data = e100_get_mdio_reg(dev, np->mii_if.phy_id, MII_ADVERTISE); if ((data & ADVERTISE_100FULL) || (data & ADVERTISE_100HALF)) current_speed = 100; else current_speed = 10;}static voidtdk_check_speed(struct net_device* dev){ unsigned long data; struct net_local *np = netdev_priv(dev); data = e100_get_mdio_reg(dev, np->mii_if.phy_id, MDIO_TDK_DIAGNOSTIC_REG); current_speed = (data & MDIO_TDK_DIAGNOSTIC_RATE ? 100 : 10);}static voidbroadcom_check_speed(struct net_device* dev){ unsigned long data; struct net_local *np = netdev_priv(dev); data = e100_get_mdio_reg(dev, np->mii_if.phy_id, MDIO_AUX_CTRL_STATUS_REG); current_speed = (data & MDIO_BC_SPEED ? 100 : 10);}static voidintel_check_speed(struct net_device* dev){ unsigned long data; struct net_local *np = netdev_priv(dev); data = e100_get_mdio_reg(dev, np->mii_if.phy_id, MDIO_INT_STATUS_REG_2); current_speed = (data & MDIO_INT_SPEED ? 100 : 10);}#endifstatic voide100_check_speed(unsigned long priv){ struct net_device* dev = (struct net_device*)priv; struct net_local *np = netdev_priv(dev); static int led_initiated = 0; unsigned long data; int old_speed = current_speed; spin_lock(&np->transceiver_lock); data = e100_get_mdio_reg(dev, np->mii_if.phy_id, MII_BMSR); if (!(data & BMSR_LSTATUS)) { current_speed = 0; } else { transceiver->check_speed(dev); } spin_lock(&np->led_lock); if ((old_speed != current_speed) || !led_initiated) { led_initiated = 1; e100_set_network_leds(NO_NETWORK_ACTIVITY); if (current_speed) netif_carrier_on(dev); else netif_carrier_off(dev); } spin_unlock(&np->led_lock); /* Reinitialize the timer. */ speed_timer.expires = jiffies + NET_LINK_UP_CHECK_INTERVAL; add_timer(&speed_timer); spin_unlock(&np->transceiver_lock);}static voide100_negotiate(struct net_device* dev){ struct net_local *np = netdev_priv(dev); unsigned short data = e100_get_mdio_reg(dev, np->mii_if.phy_id, MII_ADVERTISE); /* Discard old speed and duplex settings */ data &= ~(ADVERTISE_100HALF | ADVERTISE_100FULL | ADVERTISE_10HALF | ADVERTISE_10FULL); switch (current_speed_selection) { case 10: if (current_duplex == full) data |= ADVERTISE_10FULL; else if (current_duplex == half) data |= ADVERTISE_10HALF; else data |= ADVERTISE_10HALF | ADVERTISE_10FULL; break; case 100: if (current_duplex == full) data |= ADVERTISE_100FULL; else if (current_duplex == half) data |= ADVERTISE_100HALF; else data |= ADVERTISE_100HALF | ADVERTISE_100FULL; break; case 0: /* Auto */ if (current_duplex == full) data |= ADVERTISE_100FULL | ADVERTISE_10FULL; else if (current_duplex == half) data |= ADVERTISE_100HALF | ADVERTISE_10HALF; else data |= ADVERTISE_10HALF | ADVERTISE_10FULL | ADVERTISE_100HALF | ADVERTISE_100FULL; break; default: /* assume autoneg speed and duplex */ data |= ADVERTISE_10HALF | ADVERTISE_10FULL | ADVERTISE_100HALF | ADVERTISE_100FULL; break; } e100_set_mdio_reg(dev, np->mii_if.phy_id, MII_ADVERTISE, data); /* Renegotiate with link partner */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?