X-Git-Url: http://bbs.cooldavid.org/git/?p=jme.git;a=blobdiff_plain;f=jme.c;h=ac6fc1ced2a60ea8aed02a15804aad5f0a35eea5;hp=b35706a98fb86e81a4b3324cee8b912222fc2af1;hb=refs%2Ftags%2Fjme-0.9b;hpb=b3821cc585b81f316d02684eb74ef3b9259681c8 diff --git a/jme.c b/jme.c index b35706a..ac6fc1c 100644 --- a/jme.c +++ b/jme.c @@ -23,12 +23,7 @@ /* * TODO: - * - Implement MSI-X. - * Along with multiple RX queue, for CPU load balancing. * - Decode register dump for ethtool. - * - Implement NAPI? - * PCC Support Both Packet Counter and Timeout Interrupt for - * receive and transmit complete, does NAPI really needed? */ #include @@ -70,15 +65,15 @@ jme_mdio_read(struct net_device *netdev, int phy, int reg) smi_reg_addr(reg)); wmb(); - for (i = JME_PHY_TIMEOUT ; i > 0 ; --i) { - udelay(1); + for (i = JME_PHY_TIMEOUT * 50 ; i > 0 ; --i) { + udelay(20); val = jread32(jme, JME_SMI); if ((val & SMI_OP_REQ) == 0) break; } if (i == 0) { - jeprintk(netdev->name, "phy read timeout : %d\n", reg); + jeprintk("jme", "phy(%d) read timeout : %d\n", phy, reg); return 0; } @@ -97,15 +92,15 @@ jme_mdio_write(struct net_device *netdev, smi_phy_addr(phy) | smi_reg_addr(reg)); wmb(); - for (i = JME_PHY_TIMEOUT ; i > 0 ; --i) { - udelay(1); + for (i = JME_PHY_TIMEOUT * 50 ; i > 0 ; --i) { + udelay(20); val = jread32(jme, JME_SMI); if ((val & SMI_OP_REQ) == 0) break; } if (i == 0) - jeprintk(netdev->name, "phy write timeout : %d\n", reg); + jeprintk("jme", "phy(%d) write timeout : %d\n", phy, reg); return; } @@ -168,6 +163,7 @@ jme_reset_mac_processor(struct jme_adapter *jme) { __u32 mask[WAKEUP_FRAME_MASK_DWNR] = {0,0,0,0}; __u32 crc = 0xCDCDCDCD; + __u32 gpreg0; int i; jwrite32(jme, JME_GHC, jme->reg_ghc | GHC_SWRST); @@ -177,7 +173,11 @@ jme_reset_mac_processor(struct jme_adapter *jme) jwrite32(jme, JME_RXMCHT_HI, 0x00000000); for(i = 0 ; i < WAKEUP_FRAME_NR ; ++i) jme_setup_wakeup_frame(jme, mask, crc, i); - jwrite32(jme, JME_GPREG0, GPREG0_DEFAULT); + if(jme->fpgaver) + gpreg0 = GPREG0_DEFAULT | GPREG0_LNKINTPOLL; + else + gpreg0 = GPREG0_DEFAULT; + jwrite32(jme, JME_GPREG0, gpreg0); jwrite32(jme, JME_GPREG1, 0); } @@ -247,6 +247,11 @@ __always_inline static void jme_set_rx_pcc(struct jme_adapter *jme, int p) { switch(p) { + case PCC_OFF: + jwrite32(jme, JME_PCCRX0, + ((PCC_OFF_TO << PCCRXTO_SHIFT) & PCCRXTO_MASK) | + ((PCC_OFF_CNT << PCCRX_SHIFT) & PCCRX_MASK)); + break; case PCC_P1: jwrite32(jme, JME_PCCRX0, ((PCC_P1_TO << PCCRXTO_SHIFT) & PCCRXTO_MASK) | @@ -265,8 +270,10 @@ jme_set_rx_pcc(struct jme_adapter *jme, int p) default: break; } + wmb(); - dprintk(jme->dev->name, "Switched to PCC_P%d\n", p); + if(!(jme->flags & JME_FLAG_POLL)) + dprintk(jme->dev->name, "Switched to PCC_P%d\n", p); } static void @@ -315,6 +322,19 @@ jme_disable_shadow(struct jme_adapter *jme) jwrite32(jme, JME_SHBA_LO, 0x0); } +static __u32 +jme_linkstat_from_phy(struct jme_adapter *jme) +{ + __u32 phylink, bmsr; + + phylink = jme_mdio_read(jme->dev, jme->mii_if.phy_id, 17); + bmsr = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_BMSR); + if(bmsr & BMCR_ANCOMP) + phylink |= PHY_LINK_AUTONEG_COMPLETE; + + return phylink; +} + static int jme_check_link(struct net_device *netdev, int testonly) { @@ -324,7 +344,11 @@ jme_check_link(struct net_device *netdev, int testonly) int rc = 0; linkmsg[0] = '\0'; - phylink = jread32(jme, JME_PHY_LINK); + + if(jme->fpgaver) + phylink = jme_linkstat_from_phy(jme); + else + phylink = jread32(jme, JME_PHY_LINK); if (phylink & PHY_LINK_UP) { if(!(phylink & PHY_LINK_AUTONEG_COMPLETE)) { @@ -359,8 +383,11 @@ jme_check_link(struct net_device *netdev, int testonly) --cnt) { udelay(1); - phylink = jread32(jme, JME_PHY_LINK); + if(jme->fpgaver) + phylink = jme_linkstat_from_phy(jme); + else + phylink = jread32(jme, JME_PHY_LINK); } if(!cnt) @@ -379,21 +406,24 @@ jme_check_link(struct net_device *netdev, int testonly) jme->phylink = phylink; + ghc = jme->reg_ghc & ~(GHC_SPEED_10M | + GHC_SPEED_100M | + GHC_SPEED_1000M | + GHC_DPX); switch(phylink & PHY_LINK_SPEED_MASK) { case PHY_LINK_SPEED_10M: - ghc = GHC_SPEED_10M; + ghc |= GHC_SPEED_10M; strcat(linkmsg, "10 Mbps, "); break; case PHY_LINK_SPEED_100M: - ghc = GHC_SPEED_100M; + ghc |= GHC_SPEED_100M; strcat(linkmsg, "100 Mbps, "); break; case PHY_LINK_SPEED_1000M: - ghc = GHC_SPEED_1000M; + ghc |= GHC_SPEED_1000M; strcat(linkmsg, "1000 Mbps, "); break; default: - ghc = 0; break; } ghc |= (phylink & PHY_LINK_DUPLEX) ? GHC_DPX : 0; @@ -463,7 +493,7 @@ jme_setup_tx_resources(struct jme_adapter *jme) RING_DESC_ALIGN); txring->dma = ALIGN(txring->dmaalloc, RING_DESC_ALIGN); txring->next_to_use = 0; - txring->next_to_clean = 0; + atomic_set(&txring->next_to_clean, 0); atomic_set(&txring->nr_free, jme->tx_ring_size); /* @@ -506,7 +536,7 @@ jme_free_tx_resources(struct jme_adapter *jme) txring->dma = 0; } txring->next_to_use = 0; - txring->next_to_clean = 0; + atomic_set(&txring->next_to_clean, 0); atomic_set(&txring->nr_free, 0); } @@ -667,7 +697,7 @@ jme_free_rx_resources(struct jme_adapter *jme) rxring->dma = 0; } rxring->next_to_use = 0; - rxring->next_to_clean = 0; + atomic_set(&rxring->next_to_clean, 0); } static int @@ -694,7 +724,7 @@ jme_setup_rx_resources(struct jme_adapter *jme) RING_DESC_ALIGN); rxring->dma = ALIGN(rxring->dmaalloc, RING_DESC_ALIGN); rxring->next_to_use = 0; - rxring->next_to_clean = 0; + atomic_set(&rxring->next_to_clean, 0); /* * Initiallize Receive Descriptors @@ -777,6 +807,41 @@ jme_disable_rx_engine(struct jme_adapter *jme) } +static int +jme_rxsum_ok(struct jme_adapter *jme, __u16 flags) +{ + if(!(flags & (RXWBFLAG_TCPON | RXWBFLAG_UDPON | RXWBFLAG_IPV4))) + return false; + + if(unlikely((flags & RXWBFLAG_TCPON) && + !(flags & RXWBFLAG_TCPCS))) { + csum_dbg(jme->dev->name, "TCP Checksum error.\n"); + goto out_sumerr; + } + + if(unlikely((flags & RXWBFLAG_UDPON) && + !(flags & RXWBFLAG_UDPCS))) { + csum_dbg(jme->dev->name, "UDP Checksum error.\n"); + goto out_sumerr; + } + + if(unlikely((flags & RXWBFLAG_IPV4) && + !(flags & RXWBFLAG_IPCS))) { + csum_dbg(jme->dev->name, "IPv4 Checksum error.\n"); + goto out_sumerr; + } + + return true; + +out_sumerr: + csum_dbg(jme->dev->name, "%s%s%s%s\n", + (flags & RXWBFLAG_IPV4)?"IPv4 ":"", + (flags & RXWBFLAG_IPV6)?"IPv6 ":"", + (flags & RXWBFLAG_UDPON)?"UDP ":"", + (flags & RXWBFLAG_TCPON)?"TCP":""); + return false; +} + static void jme_alloc_and_feed_skb(struct jme_adapter *jme, int idx) { @@ -811,10 +876,7 @@ jme_alloc_and_feed_skb(struct jme_adapter *jme, int idx) skb_put(skb, framesize); skb->protocol = eth_type_trans(skb, jme->dev); - if((rxdesc->descwb.flags & - (RXWBFLAG_TCPON | - RXWBFLAG_UDPON | - RXWBFLAG_IPV4))) + if(jme_rxsum_ok(jme, rxdesc->descwb.flags)) skb->ip_summed = CHECKSUM_UNNECESSARY; else skb->ip_summed = CHECKSUM_NONE; @@ -826,13 +888,13 @@ jme_alloc_and_feed_skb(struct jme_adapter *jme, int idx) if(jme->vlgrp) { vlan_dbg(jme->dev->name, "VLAN Passed to kernel.\n"); - vlan_hwaccel_rx(skb, jme->vlgrp, + jme->jme_vlan_rx(skb, jme->vlgrp, le32_to_cpu(rxdesc->descwb.vlan)); NET_STAT(jme).rx_bytes += 4; } } else { - netif_rx(skb); + jme->jme_rx(skb); } if((le16_to_cpu(rxdesc->descwb.flags) & RXWBFLAG_DEST) == @@ -848,28 +910,7 @@ jme_alloc_and_feed_skb(struct jme_adapter *jme, int idx) } -static int -jme_rxsum_bad(struct jme_adapter *jme, __u16 flags) -{ - if(unlikely((flags & RXWBFLAG_TCPON) && - !(flags & RXWBFLAG_TCPCS))) { - csum_dbg(jme->dev->name, "TCP Checksum error.\n"); - return 1; - } - else if(unlikely((flags & RXWBFLAG_UDPON) && - !(flags & RXWBFLAG_UDPCS))) { - csum_dbg(jme->dev->name, "UDP Checksum error.\n"); - return 1; - } - else if(unlikely((flags & RXWBFLAG_IPV4) && - !(flags & RXWBFLAG_IPCS))) { - csum_dbg(jme->dev->name, "IPv4 Checksum error.\n"); - return 1; - } - else { - return 0; - } -} + static int jme_process_receive(struct jme_adapter *jme, int limit) @@ -878,7 +919,16 @@ jme_process_receive(struct jme_adapter *jme, int limit) volatile struct rxdesc *rxdesc = rxring->desc; int i, j, ccnt, desccnt, mask = jme->rx_ring_mask; - i = rxring->next_to_clean; + if(unlikely(!atomic_dec_and_test(&jme->rx_cleaning))) + goto out_inc; + + if(unlikely(atomic_read(&jme->link_changing) != 1)) + goto out_inc; + + if(unlikely(!netif_carrier_ok(jme->dev))) + goto out_inc; + + i = atomic_read(&rxring->next_to_clean); while( limit-- > 0 ) { rxdesc = rxring->desc; @@ -893,8 +943,7 @@ jme_process_receive(struct jme_adapter *jme, int limit) rx_dbg(jme->dev->name, "RX: Cleaning %d\n", i); if(unlikely(desccnt > 1 || - rxdesc->descwb.errstat & RXWBERR_ALLERR || - jme_rxsum_bad(jme, rxdesc->descwb.flags))) { + rxdesc->descwb.errstat & RXWBERR_ALLERR)) { if(rxdesc->descwb.errstat & RXWBERR_CRCERR) ++(NET_STAT(jme).rx_crc_errors); @@ -913,7 +962,6 @@ jme_process_receive(struct jme_adapter *jme, int limit) for(j = i, ccnt = desccnt ; ccnt-- ; ) { jme_set_clean_rxdesc(jme, j); - j = (j + 1) & (mask); } @@ -925,13 +973,17 @@ jme_process_receive(struct jme_adapter *jme, int limit) i = (i + desccnt) & (mask); } + out: rx_dbg(jme->dev->name, "RX: Stop at %d\n", i); rx_dbg(jme->dev->name, "RX: RXNDA offset %d\n", (jread32(jme, JME_RXNDA) - jread32(jme, JME_RXDBA_LO)) >> 4); - rxring->next_to_clean = i; + atomic_set(&rxring->next_to_clean, i); + +out_inc: + atomic_inc(&jme->rx_cleaning); return limit > 0 ? limit : 0; @@ -940,8 +992,10 @@ out: static void jme_attempt_pcc(struct dynpcc_info *dpi, int atmp) { - if(likely(atmp == dpi->cur)) + if(likely(atmp == dpi->cur)) { + dpi->cnt = 0; return; + } if(dpi->attempt == atmp) { ++(dpi->cnt); @@ -960,13 +1014,13 @@ jme_dynamic_pcc(struct jme_adapter *jme) if((NET_STAT(jme).rx_bytes - dpi->last_bytes) > PCC_P3_THRESHOLD) jme_attempt_pcc(dpi, PCC_P3); - else if((NET_STAT(jme).rx_bytes - dpi->last_bytes) > PCC_P2_THRESHOLD + else if((NET_STAT(jme).rx_packets - dpi->last_pkts) > PCC_P2_THRESHOLD || dpi->intr_cnt > PCC_INTR_THRESHOLD) jme_attempt_pcc(dpi, PCC_P2); else jme_attempt_pcc(dpi, PCC_P1); - if(unlikely(dpi->attempt != dpi->cur && dpi->cnt > 20)) { + if(unlikely(dpi->attempt != dpi->cur && dpi->cnt > 5)) { jme_set_rx_pcc(jme, dpi->attempt); dpi->cur = dpi->attempt; dpi->cnt = 0; @@ -984,7 +1038,7 @@ jme_start_pcc_timer(struct jme_adapter *jme) TMCSR_EN | ((0xFFFFFF - PCC_INTERVAL_US) & TMCSR_CNT)); } -static void +__always_inline static void jme_stop_pcc_timer(struct jme_adapter *jme) { jwrite32(jme, JME_TMCSR, 0); @@ -1004,10 +1058,24 @@ jme_pcc_tasklet(unsigned long arg) return; } - jme_dynamic_pcc(jme); + if(!(jme->flags & JME_FLAG_POLL)) + jme_dynamic_pcc(jme); + jme_start_pcc_timer(jme); } +__always_inline static void +jme_polling_mode(struct jme_adapter *jme) +{ + jme_set_rx_pcc(jme, PCC_OFF); +} + +__always_inline static void +jme_interrupt_mode(struct jme_adapter *jme) +{ + jme_set_rx_pcc(jme, PCC_P1); +} + static void jme_link_change_tasklet(unsigned long arg) { @@ -1039,6 +1107,9 @@ jme_link_change_tasklet(unsigned long arg) jme_reset_mac_processor(jme); jme_free_rx_resources(jme); jme_free_tx_resources(jme); + + if(jme->flags & JME_FLAG_POLL) + jme_polling_mode(jme); } jme_check_link(netdev, 0); @@ -1064,6 +1135,10 @@ jme_link_change_tasklet(unsigned long arg) jme_enable_tx_engine(jme); netif_start_queue(netdev); + + if(jme->flags & JME_FLAG_POLL) + jme_interrupt_mode(jme); + jme_start_pcc_timer(jme); } @@ -1081,20 +1156,34 @@ jme_rx_clean_tasklet(unsigned long arg) struct jme_adapter *jme = (struct jme_adapter*)arg; struct dynpcc_info *dpi = &(jme->dpi); - if(unlikely(!atomic_dec_and_test(&jme->rx_cleaning))) - goto out; + jme_process_receive(jme, jme->rx_ring_size); + ++(dpi->intr_cnt); - if(unlikely(atomic_read(&jme->link_changing) != 1)) - goto out; +} - if(unlikely(!netif_carrier_ok(jme->dev))) - goto out; +static int +jme_poll(JME_NAPI_HOLDER(holder), JME_NAPI_WEIGHT(budget)) +{ + struct jme_adapter *jme = jme_napi_priv(holder); + struct net_device *netdev = jme->dev; + int rest; - jme_process_receive(jme, jme->rx_ring_size); - ++(dpi->intr_cnt); + rest = jme_process_receive(jme, JME_NAPI_WEIGHT_VAL(budget)); -out: - atomic_inc(&jme->rx_cleaning); + while(atomic_read(&jme->rx_empty) > 0) { + atomic_dec(&jme->rx_empty); + ++(NET_STAT(jme).rx_dropped); + jme_restart_rx_engine(jme); + } + atomic_inc(&jme->rx_empty); + + if(rest) { + JME_RX_COMPLETE(netdev, holder); + jme_interrupt_mode(jme); + } + + JME_NAPI_WEIGHT_SET(budget, rest); + return JME_NAPI_WEIGHT_VAL(budget) - rest; } static void @@ -1111,7 +1200,13 @@ jme_rx_empty_tasklet(unsigned long arg) queue_dbg(jme->dev->name, "RX Queue Full!\n"); jme_rx_clean_tasklet(arg); - jme_restart_rx_engine(jme); + + while(atomic_read(&jme->rx_empty) > 0) { + atomic_dec(&jme->rx_empty); + ++(NET_STAT(jme).rx_dropped); + jme_restart_rx_engine(jme); + } + atomic_inc(&jme->rx_empty); } static void @@ -1153,7 +1248,7 @@ jme_tx_clean_tasklet(unsigned long arg) tx_dbg(jme->dev->name, "Tx Tasklet: In\n"); - for(i = txring->next_to_clean ; cnt < max ; ) { + for(i = atomic_read(&txring->next_to_clean) ; cnt < max ; ) { ctxbi = txbi + i; @@ -1192,6 +1287,7 @@ jme_tx_clean_tasklet(unsigned long arg) ctxbi->skb = NULL; ctxbi->len = 0; + ctxbi->start_xmit = 0; } else { if(!ctxbi->skb) @@ -1213,8 +1309,8 @@ jme_tx_clean_tasklet(unsigned long arg) tx_dbg(jme->dev->name, "Tx Tasklet: Stop %d Jiffies %lu\n", i, jiffies); - txring->next_to_clean = i; + atomic_set(&txring->next_to_clean, i); atomic_add(cnt, &txring->nr_free); jme_wake_queue_if_stopped(jme); @@ -1226,8 +1322,6 @@ out: static void jme_intr_msi(struct jme_adapter *jme, __u32 intrstat) { - __u32 handled; - /* * Disable interrupt */ @@ -1246,24 +1340,28 @@ jme_intr_msi(struct jme_adapter *jme, __u32 intrstat) if(intrstat & INTR_TMINTR) tasklet_schedule(&jme->pcc_task); - if(intrstat & INTR_RX0EMP) - tasklet_schedule(&jme->rxempty_task); - - if(intrstat & (INTR_PCCRX0TO | INTR_PCCRX0)) - tasklet_schedule(&jme->rxclean_task); - if(intrstat & (INTR_PCCTXTO | INTR_PCCTX)) tasklet_schedule(&jme->txclean_task); - handled = INTR_ENABLE | INTR_RX0 | INTR_TX0 | INTR_PAUSERCV; - if((intrstat & ~(handled)) != 0) { - /* - * Some interrupt not handled - * but not enabled also (for debug) - */ - dprintk(jme->dev->name, - "UN-handled interrupt.(%08x)\n", - intrstat & ~(handled)); + if(jme->flags & JME_FLAG_POLL) { + if(intrstat & INTR_RX0EMP) + atomic_inc(&jme->rx_empty); + + if((intrstat & (INTR_PCCRX0TO | INTR_PCCRX0 | INTR_RX0EMP))) { + if(likely(JME_RX_SCHEDULE_PREP(jme))) { + jme_polling_mode(jme); + JME_RX_SCHEDULE(jme); + } + } + } + else { + if(intrstat & INTR_RX0EMP) { + atomic_inc(&jme->rx_empty); + tasklet_schedule(&jme->rxempty_task); + } + + if(intrstat & (INTR_PCCRX0TO | INTR_PCCRX0)) + tasklet_schedule(&jme->rxclean_task); } out_reenable: @@ -1388,7 +1486,7 @@ static int jme_open(struct net_device *netdev) { struct jme_adapter *jme = netdev_priv(netdev); - int rc, timeout = 100; + int rc, timeout = 10; while( --timeout > 0 && @@ -1398,7 +1496,7 @@ jme_open(struct net_device *netdev) atomic_read(&jme->tx_cleaning) != 1 ) ) - msleep(10); + msleep(1); if(!timeout) { rc = -EBUSY; @@ -1407,6 +1505,7 @@ jme_open(struct net_device *netdev) jme_clear_pm(jme); jme_reset_mac_processor(jme); + JME_NAPI_ENABLE(jme); rc = jme_request_irq(jme); if(rc) @@ -1443,7 +1542,10 @@ jme_set_100m_half(struct jme_adapter *jme) if (bmcr != tmp) jme_mdio_write(jme->dev, jme->mii_if.phy_id, MII_BMCR, tmp); - jwrite32(jme, JME_GHC, GHC_SPEED_100M); + if(jme->fpgaver) + jwrite32(jme, JME_GHC, GHC_SPEED_100M | GHC_LINK_POLL); + else + jwrite32(jme, JME_GHC, GHC_SPEED_100M); } static void @@ -1465,6 +1567,8 @@ jme_close(struct net_device *netdev) jme_disable_shadow(jme); jme_free_irq(jme); + JME_NAPI_DISABLE(jme); + tasklet_kill(&jme->linkch_task); tasklet_kill(&jme->txclean_task); tasklet_kill(&jme->rxclean_task); @@ -1687,6 +1791,8 @@ jme_fill_first_tx_desc(struct jme_adapter *jme, struct sk_buff *skb, int idx) txbi->nr_desc = skb_shinfo(skb)->nr_frags + 2; txbi->skb = skb; txbi->len = skb->len; + if(!(txbi->start_xmit = jiffies)) + txbi->start_xmit = 1; return 0; } @@ -1695,6 +1801,9 @@ static void jme_stop_queue_if_full(struct jme_adapter *jme) { struct jme_ring *txring = jme->txring; + struct jme_buffer_info *txbi = txring->bufinf; + + txbi += atomic_read(&txring->next_to_clean); smp_wmb(); if(unlikely(atomic_read(&txring->nr_free) < (MAX_SKB_FRAGS+2))) { @@ -1707,6 +1816,11 @@ jme_stop_queue_if_full(struct jme_adapter *jme) } } + if(unlikely( txbi->start_xmit && + (jiffies - txbi->start_xmit) >= TX_TIMEOUT && + txbi->skb)) { + netif_stop_queue(jme->dev); + } } /* @@ -1871,11 +1985,14 @@ jme_tx_timeout(struct net_device *netdev) { struct jme_adapter *jme = netdev_priv(netdev); + jme->phylink = 0; + jme_reset_phy_processor(jme); + if(jme->flags & JME_FLAG_SSET) + jme_set_settings(netdev, &jme->old_ecmd); + /* - * Reset the link - * And the link change will reinitialize all RX/TX resources + * Force to Reset the link again */ - jme->phylink = 0; jme_reset_link(jme); } @@ -1941,10 +2058,18 @@ jme_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *ecmd) { struct jme_adapter *jme = netdev_priv(netdev); - ecmd->use_adaptive_rx_coalesce = true; ecmd->tx_coalesce_usecs = PCC_TX_TO; ecmd->tx_max_coalesced_frames = PCC_TX_CNT; + if(jme->flags & JME_FLAG_POLL) { + ecmd->use_adaptive_rx_coalesce = false; + ecmd->rx_coalesce_usecs = 0; + ecmd->rx_max_coalesced_frames = 0; + return 0; + } + + ecmd->use_adaptive_rx_coalesce = true; + switch(jme->dpi.cur) { case PCC_P1: ecmd->rx_coalesce_usecs = PCC_P1_TO; @@ -1965,6 +2090,37 @@ jme_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *ecmd) return 0; } +static int +jme_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *ecmd) +{ + struct jme_adapter *jme = netdev_priv(netdev); + struct dynpcc_info *dpi = &(jme->dpi); + + if(netif_running(netdev)) + return -EBUSY; + + if(ecmd->use_adaptive_rx_coalesce + && (jme->flags & JME_FLAG_POLL)) { + jme->flags &= ~JME_FLAG_POLL; + jme->jme_rx = netif_rx; + jme->jme_vlan_rx = vlan_hwaccel_rx; + dpi->cur = PCC_P1; + dpi->attempt = PCC_P1; + dpi->cnt = 0; + jme_set_rx_pcc(jme, PCC_P1); + jme_interrupt_mode(jme); + } + else if(!(ecmd->use_adaptive_rx_coalesce) + && !(jme->flags & JME_FLAG_POLL)) { + jme->flags |= JME_FLAG_POLL; + jme->jme_rx = netif_receive_skb; + jme->jme_vlan_rx = vlan_hwaccel_receive_skb; + jme_interrupt_mode(jme); + } + + return 0; +} + static void jme_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd) @@ -2203,6 +2359,7 @@ static const struct ethtool_ops jme_ethtool_ops = { .get_regs_len = jme_get_regs_len, .get_regs = jme_get_regs, .get_coalesce = jme_get_coalesce, + .set_coalesce = jme_set_coalesce, .get_pauseparam = jme_get_pauseparam, .set_pauseparam = jme_set_pauseparam, .get_wol = jme_get_wol, @@ -2243,18 +2400,39 @@ jme_pci_dma64(struct pci_dev *pdev) } __always_inline static void -jme_set_phy_ps(struct jme_adapter *jme) +jme_phy_init(struct jme_adapter *jme) +{ + __u16 reg26; + + reg26 = jme_mdio_read(jme->dev, jme->mii_if.phy_id, 26); + jme_mdio_write(jme->dev, jme->mii_if.phy_id, 26, reg26 | 0x1000); +} + +__always_inline static void +jme_set_gmii(struct jme_adapter *jme) +{ + jme_mdio_write(jme->dev, jme->mii_if.phy_id, 27, 0x0004); +} + +static void +jme_check_hw_ver(struct jme_adapter *jme) { - jme_mdio_write(jme->dev, jme->mii_if.phy_id, 26, 0x00001000); + __u32 chipmode; + + chipmode = jread32(jme, JME_CHIPMODE); + + jme->fpgaver = (chipmode & CM_FPGAVER_MASK) >> CM_FPGAVER_SHIFT; + jme->chipver = (chipmode & CM_CHIPVER_MASK) >> CM_CHIPVER_SHIFT; } static int __devinit jme_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { - int rc = 0, using_dac; + int rc = 0, using_dac, i; struct net_device *netdev; struct jme_adapter *jme; + __u16 bmcr, bmsr; /* * set up PCI device basics @@ -2324,6 +2502,8 @@ jme_init_one(struct pci_dev *pdev, jme = netdev_priv(netdev); jme->pdev = pdev; jme->dev = netdev; + jme->jme_rx = netif_rx; + jme->jme_vlan_rx = vlan_hwaccel_rx; jme->old_mtu = netdev->mtu = 1500; jme->phylink = 0; jme->tx_ring_size = 1 << 10; @@ -2347,6 +2527,8 @@ jme_init_one(struct pci_dev *pdev, goto err_out_unmap; } + NETIF_NAPI_SET(netdev, &jme->napi, jme_poll, jme->rx_ring_size >> 2) + spin_lock_init(&jme->phy_lock); spin_lock_init(&jme->macaddr_lock); spin_lock_init(&jme->rxmcs_lock); @@ -2354,6 +2536,7 @@ jme_init_one(struct pci_dev *pdev, atomic_set(&jme->link_changing, 1); atomic_set(&jme->rx_cleaning, 1); atomic_set(&jme->tx_cleaning, 1); + atomic_set(&jme->rx_empty, 1); tasklet_init(&jme->pcc_task, &jme_pcc_tasklet, @@ -2370,12 +2553,6 @@ jme_init_one(struct pci_dev *pdev, tasklet_init(&jme->rxempty_task, &jme_rx_empty_tasklet, (unsigned long) jme); - jme->mii_if.dev = netdev; - jme->mii_if.phy_id = 1; - jme->mii_if.supports_gmii = 1; - jme->mii_if.mdio_read = jme_mdio_read; - jme->mii_if.mdio_write = jme_mdio_write; - jme->dpi.cur = PCC_P1; jme->reg_ghc = GHC_DPX | GHC_SPEED_1000M; @@ -2384,6 +2561,7 @@ jme_init_one(struct pci_dev *pdev, jme->reg_txpfc = 0; jme->reg_pmcs = PMCS_LFEN | PMCS_LREN | PMCS_MFEN; jme->flags = JME_FLAG_TXCSUM | JME_FLAG_TSO; + /* * Get Max Read Req Size from PCI Config Space */ @@ -2402,11 +2580,46 @@ jme_init_one(struct pci_dev *pdev, /* - * Reset MAC processor and reload EEPROM for MAC Address + * Must check before reset_mac_processor */ + jme_check_hw_ver(jme); + jme->mii_if.dev = netdev; + if(jme->fpgaver) { + jme->mii_if.phy_id = 0; + for(i = 1 ; i < 32 ; ++i) { + bmcr = jme_mdio_read(netdev, i, MII_BMCR); + bmsr = jme_mdio_read(netdev, i, MII_BMSR); + if(bmcr != 0xFFFFU && (bmcr != 0 || bmsr != 0)) { + jme->mii_if.phy_id = i; + break; + } + } + + if(!jme->mii_if.phy_id) { + rc = -EIO; + printk(KERN_ERR PFX "Can not find phy_id.\n"); + goto err_out_free_shadow; + } + + jme->reg_ghc |= GHC_LINK_POLL; + } + else { + jme->mii_if.phy_id = 1; + } + jme->mii_if.supports_gmii = 1; + jme->mii_if.mdio_read = jme_mdio_read; + jme->mii_if.mdio_write = jme_mdio_write; + jme_clear_pm(jme); - jme_set_phy_ps(jme); + if(jme->fpgaver) + jme_set_gmii(jme); + else + jme_phy_init(jme); jme_phy_off(jme); + + /* + * Reset MAC processor and reload EEPROM for MAC Address + */ jme_reset_mac_processor(jme); rc = jme_reload_eeprom(jme); if(rc) { @@ -2433,7 +2646,9 @@ jme_init_one(struct pci_dev *pdev, } jprintk(netdev->name, - "JMC250 gigabit eth %02x:%02x:%02x:%02x:%02x:%02x\n", + "JMC250 gigabit%s ver:%u eth %02x:%02x:%02x:%02x:%02x:%02x\n", + (jme->fpgaver != 0)?" (FPGA)":"", + (jme->fpgaver != 0)?jme->fpgaver:jme->chipver, netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2], @@ -2514,6 +2729,9 @@ jme_suspend(struct pci_dev *pdev, pm_message_t state) jme_free_tx_resources(jme); netif_carrier_off(netdev); jme->phylink = 0; + + if(jme->flags & JME_FLAG_POLL) + jme_polling_mode(jme); }