+static void
+jme_attempt_pcc(struct dynpcc_info *dpi, int atmp)
+{
+ if (likely(atmp == dpi->cur)) {
+ dpi->cnt = 0;
+ return;
+ }
+
+ if (dpi->attempt == atmp) {
+ ++(dpi->cnt);
+ } else {
+ dpi->attempt = atmp;
+ dpi->cnt = 0;
+ }
+
+}
+
+static void
+jme_dynamic_pcc(struct jme_adapter *jme)
+{
+ register struct dynpcc_info *dpi = &(jme->dpi);
+
+ if ((NET_STAT(jme).rx_bytes - dpi->last_bytes) > PCC_P3_THRESHOLD)
+ jme_attempt_pcc(dpi, PCC_P3);
+ 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 > 5)) {
+ if (dpi->attempt < dpi->cur)
+ tasklet_schedule(&jme->rxclean_task);
+ jme_set_rx_pcc(jme, dpi->attempt);
+ dpi->cur = dpi->attempt;
+ dpi->cnt = 0;
+ }
+}
+
+static void
+jme_start_pcc_timer(struct jme_adapter *jme)
+{
+ struct dynpcc_info *dpi = &(jme->dpi);
+ dpi->last_bytes = NET_STAT(jme).rx_bytes;
+ dpi->last_pkts = NET_STAT(jme).rx_packets;
+ dpi->intr_cnt = 0;
+ jwrite32(jme, JME_TMCSR,
+ TMCSR_EN | ((0xFFFFFF - PCC_INTERVAL_US) & TMCSR_CNT));
+}
+
+static inline void
+jme_stop_pcc_timer(struct jme_adapter *jme)
+{
+ jwrite32(jme, JME_TMCSR, 0);
+}
+
+static void
+jme_shutdown_nic(struct jme_adapter *jme)
+{
+ u32 phylink;
+
+ phylink = jme_linkstat_from_phy(jme);
+
+ if (!(phylink & PHY_LINK_UP)) {
+ /*
+ * Disable all interrupt before issue timer
+ */
+ jme_stop_irq(jme);
+ jwrite32(jme, JME_TIMER2, TMCSR_EN | 0xFFFFFE);
+ }
+}
+
+static void
+jme_pcc_tasklet(unsigned long arg)
+{
+ struct jme_adapter *jme = (struct jme_adapter *)arg;
+ struct net_device *netdev = jme->dev;
+
+ if (unlikely(test_bit(JME_FLAG_SHUTDOWN, &jme->flags))) {
+ jme_shutdown_nic(jme);
+ return;
+ }
+
+ if (unlikely(!netif_carrier_ok(netdev) ||
+ (atomic_read(&jme->link_changing) != 1)
+ )) {
+ jme_stop_pcc_timer(jme);
+ return;
+ }
+
+ if (!(test_bit(JME_FLAG_POLL, &jme->flags)))
+ jme_dynamic_pcc(jme);
+
+ jme_start_pcc_timer(jme);
+}
+
+static inline void
+jme_polling_mode(struct jme_adapter *jme)
+{
+ jme_set_rx_pcc(jme, PCC_OFF);
+}
+
+static inline void
+jme_interrupt_mode(struct jme_adapter *jme)
+{
+ jme_set_rx_pcc(jme, PCC_P1);
+}
+
+static inline int
+jme_pseudo_hotplug_enabled(struct jme_adapter *jme)
+{
+ u32 apmc;
+ apmc = jread32(jme, JME_APMC);
+ return apmc & JME_APMC_PSEUDO_HP_EN;
+}
+
+static void
+jme_start_shutdown_timer(struct jme_adapter *jme)
+{
+ u32 apmc;
+
+ apmc = jread32(jme, JME_APMC) | JME_APMC_PCIE_SD_EN;
+ apmc &= ~JME_APMC_EPIEN_CTRL;
+ if (!no_extplug) {
+ jwrite32f(jme, JME_APMC, apmc | JME_APMC_EPIEN_CTRL_EN);
+ wmb();
+ }
+ jwrite32f(jme, JME_APMC, apmc);
+
+ jwrite32f(jme, JME_TIMER2, 0);
+ set_bit(JME_FLAG_SHUTDOWN, &jme->flags);
+ jwrite32(jme, JME_TMCSR,
+ TMCSR_EN | ((0xFFFFFF - APMC_PHP_SHUTDOWN_DELAY) & TMCSR_CNT));
+}
+
+static void
+jme_stop_shutdown_timer(struct jme_adapter *jme)
+{
+ u32 apmc;
+
+ jwrite32f(jme, JME_TMCSR, 0);
+ jwrite32f(jme, JME_TIMER2, 0);
+ clear_bit(JME_FLAG_SHUTDOWN, &jme->flags);
+
+ apmc = jread32(jme, JME_APMC);
+ apmc &= ~(JME_APMC_PCIE_SD_EN | JME_APMC_EPIEN_CTRL);
+ jwrite32f(jme, JME_APMC, apmc | JME_APMC_EPIEN_CTRL_DIS);
+ wmb();
+ jwrite32f(jme, JME_APMC, apmc);
+}
+