+static inline void
+ramips_fe_int_disable(u32 mask)
+{
+ ramips_fe_wr(ramips_fe_rr(RAMIPS_FE_INT_ENABLE) & ~mask,
+ RAMIPS_FE_INT_ENABLE);
+ /* flush write */
+ ramips_fe_rr(RAMIPS_FE_INT_ENABLE);
+}
+
+static inline void
+ramips_fe_int_enable(u32 mask)
+{
+ ramips_fe_wr(ramips_fe_rr(RAMIPS_FE_INT_ENABLE) | mask,
+ RAMIPS_FE_INT_ENABLE);
+ /* flush write */
+ ramips_fe_rr(RAMIPS_FE_INT_ENABLE);
+}
+
+static inline void
+ramips_hw_set_macaddr(unsigned char *mac)
+{
+ ramips_fe_wr((mac[0] << 8) | mac[1], RAMIPS_GDMA1_MAC_ADRH);
+ ramips_fe_wr((mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) | mac[5],
+ RAMIPS_GDMA1_MAC_ADRL);
+}
+
+static struct sk_buff *
+ramips_alloc_skb(struct raeth_priv *re)
+{
+ struct sk_buff *skb;
+
+ skb = netdev_alloc_skb(re->netdev, MAX_RX_LENGTH + NET_IP_ALIGN);
+ if (!skb)
+ return NULL;
+
+ skb_reserve(skb, NET_IP_ALIGN);
+
+ return skb;
+}
+
+static void
+ramips_ring_setup(struct raeth_priv *re)
+{
+ int len;
+ int i;
+
+ len = NUM_TX_DESC * sizeof(struct ramips_tx_dma);
+ memset(re->tx, 0, len);
+
+ for (i = 0; i < NUM_TX_DESC; i++) {
+ struct ramips_tx_dma *txd;
+
+ txd = &re->tx[i];
+ txd->txd4 = TX_DMA_QN(3) | TX_DMA_PN(1);
+ txd->txd2 = TX_DMA_LSO | TX_DMA_DONE;
+
+ if (re->tx_skb[i] != NULL) {
+ netdev_warn(re->netdev,
+ "dirty skb for TX desc %d\n", i);
+ re->tx_skb[i] = NULL;
+ }
+ }
+
+ len = NUM_RX_DESC * sizeof(struct ramips_rx_dma);
+ memset(re->rx, 0, len);
+
+ for (i = 0; i < NUM_RX_DESC; i++) {
+ dma_addr_t dma_addr;
+
+ BUG_ON(re->rx_skb[i] == NULL);
+ dma_addr = dma_map_single(&re->netdev->dev, re->rx_skb[i]->data,
+ MAX_RX_LENGTH, DMA_FROM_DEVICE);
+ re->rx_dma[i] = dma_addr;
+ re->rx[i].rxd1 = (unsigned int) dma_addr;
+ re->rx[i].rxd2 = RX_DMA_LSO;
+ }
+
+ /* flush descriptors */
+ wmb();
+}
+
+static void
+ramips_ring_cleanup(struct raeth_priv *re)
+{
+ int i;
+
+ for (i = 0; i < NUM_RX_DESC; i++)
+ if (re->rx_skb[i])
+ dma_unmap_single(&re->netdev->dev, re->rx_dma[i],
+ MAX_RX_LENGTH, DMA_FROM_DEVICE);
+
+ for (i = 0; i < NUM_TX_DESC; i++)
+ if (re->tx_skb[i]) {
+ dev_kfree_skb_any(re->tx_skb[i]);
+ re->tx_skb[i] = NULL;
+ }
+}
+
+#if defined(CONFIG_RALINK_RT288X) || defined(CONFIG_RALINK_RT3883)
+
+#define RAMIPS_MDIO_RETRY 1000
+
+static unsigned char *ramips_speed_str(struct raeth_priv *re)
+{
+ switch (re->speed) {
+ case SPEED_1000:
+ return "1000";
+ case SPEED_100:
+ return "100";
+ case SPEED_10:
+ return "10";
+ }
+
+ return "?";
+}
+
+static void ramips_link_adjust(struct raeth_priv *re)
+{
+ struct ramips_eth_platform_data *pdata;
+ u32 mdio_cfg;
+
+ pdata = re->parent->platform_data;
+ if (!re->link) {
+ netif_carrier_off(re->netdev);
+ netdev_info(re->netdev, "link down\n");
+ return;
+ }
+
+ mdio_cfg = RAMIPS_MDIO_CFG_TX_CLK_SKEW_200 |
+ RAMIPS_MDIO_CFG_TX_CLK_SKEW_200 |
+ RAMIPS_MDIO_CFG_GP1_FRC_EN;
+
+ if (re->duplex == DUPLEX_FULL)
+ mdio_cfg |= RAMIPS_MDIO_CFG_GP1_DUPLEX;
+
+ if (re->tx_fc)
+ mdio_cfg |= RAMIPS_MDIO_CFG_GP1_FC_TX;
+
+ if (re->rx_fc)
+ mdio_cfg |= RAMIPS_MDIO_CFG_GP1_FC_RX;
+
+ switch (re->speed) {
+ case SPEED_10:
+ mdio_cfg |= RAMIPS_MDIO_CFG_GP1_SPEED_10;
+ break;
+ case SPEED_100:
+ mdio_cfg |= RAMIPS_MDIO_CFG_GP1_SPEED_100;
+ break;
+ case SPEED_1000:
+ mdio_cfg |= RAMIPS_MDIO_CFG_GP1_SPEED_1000;
+ break;
+ default:
+ BUG();
+ }
+
+ ramips_fe_wr(mdio_cfg, RAMIPS_MDIO_CFG);
+
+ netif_carrier_on(re->netdev);
+ netdev_info(re->netdev, "link up (%sMbps/%s duplex)\n",
+ ramips_speed_str(re),
+ (DUPLEX_FULL == re->duplex) ? "Full" : "Half");
+}
+
+static int
+ramips_mdio_wait_ready(struct raeth_priv *re)
+{
+ int retries;
+
+ retries = RAMIPS_MDIO_RETRY;
+ while (1) {
+ u32 t;
+
+ t = ramips_fe_rr(RAMIPS_MDIO_ACCESS);
+ if ((t & (0x1 << 31)) == 0)
+ return 0;
+
+ if (retries-- == 0)
+ break;
+
+ udelay(1);
+ }
+
+ dev_err(re->parent, "MDIO operation timed out\n");
+ return -ETIMEDOUT;
+}
+