#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "gsc3280mac.h" #define GSC3280MAC_RESOURCE_NAME "gsc3280maceth" #define PHY_RESOURCE_NAME "gsc3280macphy" /*#define WORKAROUND*/ #undef GSC3280MAC_DEBUG /*#define GSC3280MAC_DEBUG*/ #ifdef GSC3280MAC_DEBUG #define DBG(nlevel, klevel, fmt, args...) \ ((void)(netif_msg_##nlevel(priv) && \ printk(KERN_##klevel fmt, ## args))) #else #define DBG(nlevel, klevel, fmt, args...) do { } while (0) #endif #undef GSC3280MAC_RX_DEBUG /*#define GSC3280MAC_RX_DEBUG*/ #ifdef GSC3280MAC_RX_DEBUG #define RX_DBG(fmt, args...) printk(fmt, ## args) #else #define RX_DBG(fmt, args...) do { } while (0) #endif #undef GSC3280MAC_XMIT_DEBUG /*#define GSC3280MAC_XMIT_DEBUG*/ #ifdef GSC3280MAC_TX_DEBUG #define TX_DBG(fmt, args...) printk(fmt, ## args) #else #define TX_DBG(fmt, args...) do { } while (0) #endif #define GSC3280MAC_ALIGN(x) L1_CACHE_ALIGN(x) #define JUMBO_LEN 9000 /* Module parameters */ #define TX_TIMEO 5000 /* default 5 seconds */ static int watchdog = TX_TIMEO; module_param(watchdog, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(watchdog, "Transmit timeout in milliseconds"); static int debug = -1; /* -1: default, 0: no output, 16: all */ module_param(debug, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Message Level (0: no output, 16: all)"); static int phyaddr = -1; module_param(phyaddr, int, S_IRUGO); MODULE_PARM_DESC(phyaddr, "Physical device address"); #define DMA_TX_SIZE 256 static int dma_txsize = DMA_TX_SIZE; module_param(dma_txsize, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(dma_txsize, "Number of descriptors in the TX list"); #define DMA_RX_SIZE 256 static int dma_rxsize = DMA_RX_SIZE; module_param(dma_rxsize, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(dma_rxsize, "Number of descriptors in the RX list"); static int flow_ctrl = FLOW_OFF; module_param(flow_ctrl, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(flow_ctrl, "Flow control ability [on/off]"); static int pause = PAUSE_TIME; module_param(pause, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(pause, "Flow Control Pause Time"); #define TC_DEFAULT 64 static int tc = TC_DEFAULT; module_param(tc, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(tc, "DMA threshold control value"); /* Pay attention to tune this parameter; take care of both * hardware capability and network stabitily/performance impact. * Many tests showed that ~4ms latency seems to be good enough. */ #ifdef CONFIG_GSC3280MAC_TIMER #define DEFAULT_PERIODIC_RATE 256 static int tmrate = DEFAULT_PERIODIC_RATE; module_param(tmrate, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(tmrate, "External timer freq. (default: 256Hz)"); #endif #define DMA_BUFFER_SIZE BUF_SIZE_2KiB static int buf_sz = DMA_BUFFER_SIZE; module_param(buf_sz, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(buf_sz, "DMA buffer size"); static int buf_max; static const u32 default_msg_level = (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN | NETIF_MSG_TIMER); static irqreturn_t gsc3280mac_interrupt(int irq, void *dev_id); /** * gsc3280mac_verify_args - verify the driver parameters. * Description: it verifies if some wrong parameter is passed to the driver. * Note that wrong parameters are replaced with the default values. */ static void gsc3280mac_verify_args(void) { if (unlikely(watchdog < 0)) watchdog = TX_TIMEO; if (unlikely(dma_rxsize < 0)) dma_rxsize = DMA_RX_SIZE; if (unlikely(dma_txsize < 0)) dma_txsize = DMA_TX_SIZE; if (unlikely((buf_sz < DMA_BUFFER_SIZE) || (buf_sz > BUF_SIZE_16KiB))) buf_sz = DMA_BUFFER_SIZE; if (unlikely(flow_ctrl > 1)) flow_ctrl = FLOW_AUTO; else if (likely(flow_ctrl < 0)) flow_ctrl = FLOW_OFF; if (unlikely((pause < 0) || (pause > 0xffff))) pause = PAUSE_TIME; } #if defined(GSC3280MAC_XMIT_DEBUG) || defined(GSC3280MAC_RX_DEBUG) static void print_pkt(unsigned char *buf, int len) { int j; pr_info("len = %d byte, buf addr: 0x%p", len, buf); for (j = 0; j < len; j++) { if ((j % 16) == 0) pr_info("\n %03x:", j); pr_info(" %02x", buf[j]); } pr_info("\n"); } #endif /* minimum number of free TX descriptors required to wake up TX process */ #define GSC3280MAC_TX_THRESH(x) (x->dma_tx_size/4) static inline u32 gsc3280mac_tx_avail(struct gsc3280mac_priv *priv) { return priv->dirty_tx + priv->dma_tx_size - priv->cur_tx - 1; } /* some HW system configuraton registers have to be * set according to the link speed negotiated. */ static inline void gsc3280mac_hw_fix_mac_speed(struct gsc3280mac_priv *priv) { struct phy_device *phydev = priv->phydev; if (likely(priv->plat->fix_mac_speed)) priv->plat->fix_mac_speed(priv->plat->bsp_priv, phydev->speed); } /** * gsc3280mac_adjust_link * @dev: net device structure * Description: it adjusts the link parameters. */ static void gsc3280mac_adjust_link(struct net_device *dev) { struct gsc3280mac_priv *priv = netdev_priv(dev); struct phy_device *phydev = priv->phydev; unsigned long flags; int new_state = 0; unsigned int fc = priv->flow_ctrl, pause_time = priv->pause; if (phydev == NULL) return; DBG(probe, DEBUG, "gsc3280mac_adjust_link: called. address %d link %d\n", phydev->addr, phydev->link); spin_lock_irqsave(&priv->lock, flags); if (phydev->link) { u32 ctrl = readl(priv->ioaddr + MAC_CTRL_REG); /* Now we make sure that we can be in full duplex mode. * If not, we operate in half-duplex mode. */ if (phydev->duplex != priv->oldduplex) { new_state = 1; if (!(phydev->duplex)) ctrl &= ~priv->hw->link.duplex; else ctrl |= priv->hw->link.duplex; priv->oldduplex = phydev->duplex; } /* Flow Control operation */ if (phydev->pause) priv->hw->mac->flow_ctrl(priv->ioaddr, phydev->duplex, fc, pause_time); if (phydev->speed != priv->speed) { new_state = 1; switch (phydev->speed) { case 1000: ctrl &= ~priv->hw->link.port; gsc3280mac_hw_fix_mac_speed(priv); break; case 100: case 10: ctrl |= priv->hw->link.port; if (phydev->speed == SPEED_100) { ctrl |= priv->hw->link.speed; } else { ctrl &= ~(priv->hw->link.speed); } gsc3280mac_hw_fix_mac_speed(priv); break; default: if (netif_msg_link(priv)) pr_warning("%s: Speed (%d) is not 10" " or 100!\n", dev->name, phydev->speed); break; } priv->speed = phydev->speed; } writel(ctrl, priv->ioaddr + MAC_CTRL_REG); if (!priv->oldlink) { new_state = 1; priv->oldlink = 1; } } else if (priv->oldlink) { new_state = 1; priv->oldlink = 0; priv->speed = 0; priv->oldduplex = -1; } if (new_state && netif_msg_link(priv)) phy_print_status(phydev); spin_unlock_irqrestore(&priv->lock, flags); DBG(probe, DEBUG, "gsc3280mac_adjust_link: exiting\n"); } /** * gsc3280mac_init_phy - PHY initialization * @dev: net device structure * Description: it initializes the driver's PHY state, and attaches the PHY * to the mac driver. * Return value: * 0 on success */ static int gsc3280mac_init_phy(struct net_device *dev) { struct gsc3280mac_priv *priv = netdev_priv(dev); struct phy_device *phydev; char phy_id[MII_BUS_ID_SIZE + 3]; char bus_id[MII_BUS_ID_SIZE]; priv->oldlink = 0; priv->speed = 0; priv->oldduplex = -1; if (priv->phy_addr == -1) { /* We don't have a PHY, so do nothing */ return 0; } snprintf(bus_id, MII_BUS_ID_SIZE, "%x", priv->plat->bus_id); snprintf(phy_id, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id, priv->phy_addr); pr_debug("gsc3280mac_init_phy: trying to attach to %s\n", phy_id); phydev = phy_connect(dev, phy_id, &gsc3280mac_adjust_link, 0, priv->phy_interface); if (IS_ERR(phydev)) { pr_err("%s: Could not attach to PHY\n", dev->name); return PTR_ERR(phydev); } /* * Broken HW is sometimes missing the pull-up resistor on the * MDIO line, which results in reads to non-existent devices returning * 0 rather than 0xffff. Catch this here and treat 0 as a non-existent * device as well. * Note: phydev->phy_id is the result of reading the UID PHY registers. */ if (phydev->phy_id == 0) { phy_disconnect(phydev); return -ENODEV; } pr_debug("gsc3280mac_init_phy: %s: attached to PHY (UID 0x%x)" " Link = %d\n", dev->name, phydev->phy_id, phydev->link); priv->phydev = phydev; return 0; } static inline void gsc3280mac_enable_mac(void __iomem *ioaddr) { u32 value = readl(ioaddr + MAC_CTRL_REG); value |= MAC_RNABLE_RX | MAC_ENABLE_TX; writel(value, ioaddr + MAC_CTRL_REG); } static inline void gsc3280mac_disable_mac(void __iomem *ioaddr) { u32 value = readl(ioaddr + MAC_CTRL_REG); value &= ~(MAC_ENABLE_TX | MAC_RNABLE_RX); writel(value, ioaddr + MAC_CTRL_REG); } /** * display_ring * @p: pointer to the ring. * @size: size of the ring. * Description: display all the descriptors within the ring. */ static void display_ring(struct dma_desc *p, int size) { struct tmp_s { u64 a; unsigned int b; unsigned int c; }; int i; for (i = 0; i < size; i++) { struct tmp_s *x = (struct tmp_s *)(p + i); pr_info("\t%d [0x%x]: DES0=0x%x DES1=0x%x BUF1=0x%x BUF2=0x%x", i, (unsigned int)virt_to_phys(&p[i]), (unsigned int)(x->a), (unsigned int)((x->a) >> 32), x->b, x->c); pr_info("\n"); } } /** * init_dma_desc_rings - init the RX/TX descriptor rings * @dev: net device structure * Description: this function initializes the DMA RX/TX descriptors * and allocates the socket buffers. */ static void init_dma_desc_rings(struct net_device *dev) { int i; struct gsc3280mac_priv *priv = netdev_priv(dev); struct sk_buff *skb; unsigned int txsize = priv->dma_tx_size; unsigned int rxsize = priv->dma_rx_size; unsigned int bfsize = priv->dma_buf_sz; int buff2_needed = 0, dis_ic = 0; /* Set the Buffer size according to the MTU; * indeed, in case of jumbo we need to bump-up the buffer sizes. */ if (unlikely(dev->mtu >= BUF_SIZE_8KiB)) bfsize = BUF_SIZE_16KiB; else if (unlikely(dev->mtu >= BUF_SIZE_4KiB)) bfsize = BUF_SIZE_8KiB; else if (unlikely(dev->mtu >= BUF_SIZE_2KiB)) bfsize = BUF_SIZE_4KiB; else if (unlikely(dev->mtu >= DMA_BUFFER_SIZE)) bfsize = BUF_SIZE_2KiB; else bfsize = DMA_BUFFER_SIZE; #ifdef CONFIG_GSC3280MAC_TIMER /* Disable interrupts on completion for the reception if timer is on */ if (likely(priv->tm->enable)) dis_ic = 1; #endif /* If the MTU exceeds 8k so use the second buffer in the chain */ if (unlikely(priv->plat->enh_desc)) buf_max = BUF_SIZE_8KiB; else buf_max = BUF_SIZE_2KiB; if (unlikely(bfsize > buf_max)) buff2_needed = 1; DBG(probe, INFO, "gsc3280mac: txsize %d, rxsize %d, bfsize %d\n", txsize, rxsize, bfsize); priv->rx_skbuff_dma = kmalloc(rxsize * sizeof(dma_addr_t), GFP_KERNEL); priv->rx_skbuff = kmalloc(sizeof(struct sk_buff *) * rxsize, GFP_KERNEL); priv->dma_rx = (struct dma_desc *)dma_alloc_coherent(priv->device, rxsize * sizeof(struct dma_desc), &priv->dma_rx_phy, GFP_KERNEL); priv->tx_skbuff = kmalloc(sizeof(struct sk_buff *) * txsize, GFP_KERNEL); priv->dma_tx = (struct dma_desc *)dma_alloc_coherent(priv->device, txsize * sizeof(struct dma_desc), &priv->dma_tx_phy, GFP_KERNEL); if ((priv->dma_rx == NULL) || (priv->dma_tx == NULL)) { pr_err("%s:ERROR allocating the DMA Tx/Rx desc\n", __func__); return; } DBG(probe, INFO, "gsc3280mac (%s) DMA desc rings: virt addr (Rx %p, " "Tx %p)\n\tDMA phy addr (Rx 0x%08x, Tx 0x%08x)\n", dev->name, priv->dma_rx, priv->dma_tx, (unsigned int)priv->dma_rx_phy, (unsigned int)priv->dma_tx_phy); /* RX INITIALIZATION */ DBG(probe, INFO, "gsc3280mac: SKB addresses:\n" "skb\t\tskb data\tdma data\n"); for (i = 0; i < rxsize; i++) { struct dma_desc *p = priv->dma_rx + i; skb = netdev_alloc_skb_ip_align(dev, bfsize); if (unlikely(skb == NULL)) { pr_err("%s: Rx init fails; skb is NULL\n", __func__); break; } priv->rx_skbuff[i] = skb; priv->rx_skbuff_dma[i] = dma_map_single(priv->device, skb->data, bfsize, DMA_FROM_DEVICE); p->des2 = priv->rx_skbuff_dma[i]; if (unlikely(buff2_needed)) p->des3 = p->des2 + (buf_max & ~0x11); DBG(probe, INFO, "[%p]\t[%p]\t[%x]\n", priv->rx_skbuff[i], priv->rx_skbuff[i]->data, priv->rx_skbuff_dma[i]); } priv->cur_rx = 0; priv->dirty_rx = (unsigned int)(i - rxsize); priv->dma_buf_sz = bfsize; buf_sz = bfsize; /* TX INITIALIZATION */ for (i = 0; i < txsize; i++) { priv->tx_skbuff[i] = NULL; priv->dma_tx[i].des2 = 0; priv->dma_tx[i].des3 = 0; } priv->dirty_tx = 0; priv->cur_tx = 0; /* Clear the Rx/Tx descriptors */ priv->hw->desc->init_rx_desc(priv->dma_rx, rxsize, buff2_needed, dis_ic); priv->hw->desc->init_tx_desc(priv->dma_tx, txsize); if (netif_msg_hw(priv)) { pr_info("RX descriptor ring:\n"); display_ring(priv->dma_rx, rxsize); pr_info("TX descriptor ring:\n"); display_ring(priv->dma_tx, txsize); } } static void dma_free_rx_skbufs(struct gsc3280mac_priv *priv) { int i; for (i = 0; i < priv->dma_rx_size; i++) { if (priv->rx_skbuff[i]) { dma_unmap_single(priv->device, priv->rx_skbuff_dma[i], priv->dma_buf_sz, DMA_FROM_DEVICE); dev_kfree_skb_any(priv->rx_skbuff[i]); } priv->rx_skbuff[i] = NULL; } } static void dma_free_tx_skbufs(struct gsc3280mac_priv *priv) { int i; for (i = 0; i < priv->dma_tx_size; i++) { if (priv->tx_skbuff[i] != NULL) { struct dma_desc *p = priv->dma_tx + i; if (p->des2) dma_unmap_single(priv->device, p->des2, priv->hw->desc->get_tx_len(p), DMA_TO_DEVICE); dev_kfree_skb_any(priv->tx_skbuff[i]); priv->tx_skbuff[i] = NULL; } } } static void free_dma_desc_resources(struct gsc3280mac_priv *priv) { /* Release the DMA TX/RX socket buffers */ dma_free_rx_skbufs(priv); dma_free_tx_skbufs(priv); /* Free the region of consistent memory previously allocated for * the DMA */ dma_free_coherent(priv->device, priv->dma_tx_size * sizeof(struct dma_desc), priv->dma_tx, priv->dma_tx_phy); dma_free_coherent(priv->device, priv->dma_rx_size * sizeof(struct dma_desc), priv->dma_rx, priv->dma_rx_phy); kfree(priv->rx_skbuff_dma); kfree(priv->rx_skbuff); kfree(priv->tx_skbuff); } /** * gsc3280mac_dma_operation_mode - HW DMA operation mode * @priv : pointer to the private device structure. * Description: it sets the DMA operation mode: tx/rx DMA thresholds * or Store-And-Forward capability. */ static void gsc3280mac_dma_operation_mode(struct gsc3280mac_priv *priv) { if (likely((priv->plat->tx_coe) && (!priv->no_csum_insertion))) { /* In case of GSC3280MAC, SF mode has to be enabled * to perform the TX COE. This depends on: * 1) TX COE if actually supported * 2) There is no bugged Jumbo frame support * that needs to not insert csum in the TDES. */ priv->hw->dma->dma_mode(priv->ioaddr, SF_DMA_MODE, SF_DMA_MODE); tc = SF_DMA_MODE; } else #ifdef WORKAROUND priv->hw->dma->dma_mode(priv->ioaddr, SF_DMA_MODE, SF_DMA_MODE); #else priv->hw->dma->dma_mode(priv->ioaddr, tc, tc/*SF_DMA_MODE*/); #endif } /** * gsc3280mac_tx: * @priv: private driver structure * Description: it reclaims resources after transmission completes. */ static void gsc3280mac_tx(struct gsc3280mac_priv *priv) { unsigned int txsize = priv->dma_tx_size; while (priv->dirty_tx != priv->cur_tx) { int last; unsigned int entry = priv->dirty_tx % txsize; struct sk_buff *skb = priv->tx_skbuff[entry]; struct dma_desc *p = priv->dma_tx + entry; /* Check if the descriptor is owned by the DMA. */ if (priv->hw->desc->get_tx_owner(p)) break; /* Verify tx error by looking at the last segment */ last = priv->hw->desc->get_tx_ls(p); if (likely(last)) { int tx_error = priv->hw->desc->tx_status(&priv->dev->stats, &priv->xstats, p, priv->ioaddr); if (likely(tx_error == 0)) { priv->dev->stats.tx_packets++; priv->xstats.tx_pkt_n++; } else priv->dev->stats.tx_errors++; } TX_DBG("%s: curr %d, dirty %d\n", __func__, priv->cur_tx, priv->dirty_tx); if (likely(p->des2)) dma_unmap_single(priv->device, p->des2, priv->hw->desc->get_tx_len(p), DMA_TO_DEVICE); if (unlikely(p->des3)) p->des3 = 0; if (likely(skb != NULL)) { /* * If there's room in the queue (limit it to size) * we add this skb back into the pool, * if it's the right size. */ /* if ((skb_queue_len(&priv->rx_recycle) < priv->dma_rx_size) && skb_recycle_check(skb, priv->dma_buf_sz+NET_IP_ALIGN)) { skb_reserve(skb, NET_IP_ALIGN); __skb_queue_head(&priv->rx_recycle, skb); } else*/ dev_kfree_skb(skb); priv->tx_skbuff[entry] = NULL; } priv->hw->desc->release_tx_desc(p); entry = (++priv->dirty_tx) % txsize; } if (unlikely(netif_queue_stopped(priv->dev) && gsc3280mac_tx_avail(priv) > GSC3280MAC_TX_THRESH(priv))) { netif_tx_lock(priv->dev); if (netif_queue_stopped(priv->dev) && gsc3280mac_tx_avail(priv) > GSC3280MAC_TX_THRESH(priv)) { TX_DBG("%s: restart transmit\n", __func__); netif_wake_queue(priv->dev); } netif_tx_unlock(priv->dev); } } static inline void gsc3280mac_enable_irq(struct gsc3280mac_priv *priv) { #ifdef CONFIG_GSC3280MAC_TIMER if (likely(priv->tm->enable)) priv->tm->timer_start(tmrate); else #endif priv->hw->dma->enable_dma_irq(priv->ioaddr); } static inline void gsc3280mac_disable_irq(struct gsc3280mac_priv *priv) { #ifdef CONFIG_GSC3280MAC_TIMER if (likely(priv->tm->enable)) priv->tm->timer_stop(); else #endif priv->hw->dma->disable_dma_irq(priv->ioaddr); } static int gsc3280mac_has_work(struct gsc3280mac_priv *priv) { unsigned int has_work = 0; int rxret, tx_work = 0; rxret = priv->hw->desc->get_rx_owner(priv->dma_rx + (priv->cur_rx % priv->dma_rx_size)); if (priv->dirty_tx != priv->cur_tx) tx_work = 1; if (likely(!rxret || tx_work)) has_work = 1; return has_work; } static inline void _gsc3280mac_schedule(struct gsc3280mac_priv *priv) { if (likely(gsc3280mac_has_work(priv))) { gsc3280mac_disable_irq(priv); napi_schedule(&priv->napi); } } #ifdef CONFIG_GSC3280MAC_TIMER void gsc3280mac_schedule(struct net_device *dev) { struct gsc3280mac_priv *priv = netdev_priv(dev); priv->xstats.sched_timer_n++; _gsc3280mac_schedule(priv); } static void gsc3280mac_no_timer_started(unsigned int x) {; }; static void gsc3280mac_no_timer_stopped(void) {; }; #endif /** * gsc3280mac_tx_err: * @priv: pointer to the private device structure * Description: it cleans the descriptors and restarts the transmission * in case of errors. */ static void gsc3280mac_tx_err(struct gsc3280mac_priv *priv) { netif_stop_queue(priv->dev); priv->hw->dma->stop_tx(priv->ioaddr); dma_free_tx_skbufs(priv); priv->hw->desc->init_tx_desc(priv->dma_tx, priv->dma_tx_size); priv->dirty_tx = 0; priv->cur_tx = 0; priv->hw->dma->start_tx(priv->ioaddr); priv->dev->stats.tx_errors++; netif_wake_queue(priv->dev); } static void gsc3280mac_dma_interrupt(struct gsc3280mac_priv *priv) { int status; status = priv->hw->dma->dma_interrupt(priv->ioaddr, &priv->xstats); if (likely(status == handle_tx_rx)) _gsc3280mac_schedule(priv); else if (unlikely(status == tx_hard_error_bump_tc)) { /* Try to bump up the dma threshold on this failure */ if (unlikely(tc != SF_DMA_MODE) && (tc <= 256)) { tc += 64; #ifdef WORKAROUND priv->hw->dma->dma_mode(priv->ioaddr, SF_DMA_MODE, SF_DMA_MODE); #else priv->hw->dma->dma_mode(priv->ioaddr, tc, tc/*SF_DMA_MODE*/); #endif priv->xstats.threshold = tc; } } else if (unlikely(status == tx_hard_error)) gsc3280mac_tx_err(priv); } #if 0 #define BITMASK (0x80000000) static void gpio_init(void) { volatile unsigned long int *gpio_ls_sync = (unsigned long int *)0xbc110060; volatile unsigned long int *gpio_inttype_level = (unsigned long int *)0xbc110038; volatile unsigned long int *gpio_int_polarity = (unsigned long int *)0xbc11003c; volatile unsigned long int *gpio_inten = (unsigned long int *)0xbc110030; volatile unsigned long int *gpio_status = (unsigned long int *)0xbc110040; volatile unsigned long int *gpio_debounce = (unsigned long int *)0xbc110048; printk("gpio init start\n"); *gpio_ls_sync = BITMASK; *gpio_inttype_level = ~0;//0x4; *gpio_int_polarity = 0;//0x80000000; *gpio_debounce = BITMASK; *gpio_inten = ~0;//0x800000; printk("gpio init end, %lx\n", *gpio_status); } static irqreturn_t gpio_interrupt(int irq, void *dev_id) { volatile unsigned long int *gpio_status = (unsigned long int *)0xbc110040; volatile unsigned long int *gpio_porta_eoi = (unsigned long int *)0xbc11004c; int count = 1000; volatile unsigned long int status = *gpio_status; printk("gpio status(%lx)\n", status); *gpio_porta_eoi = status;//0x800000; while(count --); printk("GPIO status(%lx)\n", *gpio_status); return IRQ_HANDLED; } #include static int buserror_write(struct file *file, const char *buffer, unsigned long count, void *data) { static char strbuf[64]; unsigned int addr, d; long cnt; memset(strbuf, 0, sizeof(strbuf)); cnt = copy_from_user(strbuf, buffer, count); if (cnt != 0) { printk("copy_from_user not finished\n"); } printk("userland string: %s\n", strbuf); sscanf(strbuf, "%x %x", &addr, &d); printk("*%x = %x\n", addr, d); *(unsigned int *)addr = d; printk("*%x = %x\n", addr, *(unsigned int *)addr); return count; } static void buserror_init(void) { struct proc_dir_entry *entry = create_proc_entry("buserror", S_IFREG | 0700, NULL); if (entry == NULL) { printk("failed to create buserror\n"); return; } entry->write_proc = buserror_write; entry->data = 0; } #endif /** * gsc3280mac_open - open entry point of the driver * @dev : pointer to the device structure. * Description: * This function is the open entry point of the driver. * Return value: * 0 on success and an appropriate (-)ve integer as defined in errno.h * file on failure. */ static int gsc3280mac_open(struct net_device *dev) { struct gsc3280mac_priv *priv = netdev_priv(dev); int ret; /* Check that the MAC address is valid. If its not, refuse * to bring the device up. The user must specify an * address using the following linux command: * ifconfig eth0 hw ether xx:xx:xx:xx:xx:xx */ if (!is_valid_ether_addr(dev->dev_addr)) { random_ether_addr(dev->dev_addr); pr_warning("%s: generated random MAC address %pM\n", dev->name, dev->dev_addr); } gsc3280mac_verify_args(); #ifdef CONFIG_GSC3280MAC_TIMER priv->tm = kzalloc(sizeof(struct gsc3280mac_timer *), GFP_KERNEL); if (unlikely(priv->tm == NULL)) { pr_err("%s: ERROR: timer memory alloc failed\n", __func__); return -ENOMEM; } priv->tm->freq = tmrate; /* Test if the external timer can be actually used. * In case of failure continue without timer. */ if (unlikely((gsc3280mac_open_ext_timer(dev, priv->tm)) < 0)) { pr_warning("gsc3280maceth: cannot attach the external timer.\n"); priv->tm->freq = 0; priv->tm->timer_start = gsc3280mac_no_timer_started; priv->tm->timer_stop = gsc3280mac_no_timer_stopped; } else priv->tm->enable = 1; #endif ret = gsc3280mac_init_phy(dev); if (unlikely(ret)) { pr_err("%s: Cannot attach to PHY (error: %d)\n", __func__, ret); goto open_error; } /* Create and initialize the TX/RX descriptors chains. */ priv->dma_tx_size = GSC3280MAC_ALIGN(dma_txsize); priv->dma_rx_size = GSC3280MAC_ALIGN(dma_rxsize); priv->dma_buf_sz = GSC3280MAC_ALIGN(buf_sz); init_dma_desc_rings(dev); /* DMA initialization and SW reset */ ret = priv->hw->dma->init(priv->ioaddr, priv->plat->pbl, priv->dma_tx_phy, priv->dma_rx_phy); if (ret < 0) { pr_err("%s: DMA initialization failed\n", __func__); goto open_error; } /* Copy the MAC addr into the HW */ priv->hw->mac->set_umac_addr(priv->ioaddr, dev->dev_addr, 0); /* If required, perform hw setup of the bus. */ if (priv->plat->bus_setup) priv->plat->bus_setup(priv->ioaddr); /* Initialize the MAC Core */ priv->hw->mac->core_init(priv->ioaddr); priv->rx_coe = priv->hw->mac->rx_coe(priv->ioaddr); if (priv->rx_coe) pr_info("gsc3280mac: Rx Checksum Offload Engine supported\n"); if (priv->plat->tx_coe) pr_info("\tTX Checksum insertion supported\n"); netdev_update_features(dev); /* Initialise the MMC (if present) to disable all interrupts. */ writel(0xffffffff, priv->ioaddr + MMC_HIGH_INTR_MASK); writel(0xffffffff, priv->ioaddr + MMC_LOW_INTR_MASK); /* Request the IRQ lines */ ret = request_irq(dev->irq, gsc3280mac_interrupt, IRQF_DISABLED, dev->name, dev); if (unlikely(ret < 0)) { pr_err("%s: ERROR: allocating the IRQ %d (error: %d)\n", __func__, dev->irq, ret); goto open_error; } /* Enable the MAC Rx/Tx */ gsc3280mac_enable_mac(priv->ioaddr); /* Set the HW DMA mode and the COE */ gsc3280mac_dma_operation_mode(priv); /* Extra statistics */ memset(&priv->xstats, 0, sizeof(struct gsc3280mac_extra_stats)); priv->xstats.threshold = tc; /* Start the ball rolling... */ DBG(probe, DEBUG, "%s: DMA RX/TX processes started...\n", dev->name); priv->hw->dma->start_tx(priv->ioaddr); priv->hw->dma->start_rx(priv->ioaddr); #ifdef CONFIG_GSC3280MAC_TIMER priv->tm->timer_start(tmrate); #endif /* Dump DMA/MAC registers */ if (netif_msg_hw(priv)) { priv->hw->mac->dump_regs(priv->ioaddr); priv->hw->dma->dump_regs(priv->ioaddr); } if (priv->phydev) phy_start(priv->phydev); napi_enable(&priv->napi); skb_queue_head_init(&priv->rx_recycle); netif_start_queue(dev); return 0; open_error: #ifdef CONFIG_GSC3280MAC_TIMER kfree(priv->tm); #endif if (priv->phydev) phy_disconnect(priv->phydev); return ret; } /** * gsc3280mac_release - close entry point of the driver * @dev : device pointer. * Description: * This is the stop entry point of the driver. */ static int gsc3280mac_release(struct net_device *dev) { struct gsc3280mac_priv *priv = netdev_priv(dev); /* Stop and disconnect the PHY */ if (priv->phydev) { phy_stop(priv->phydev); phy_disconnect(priv->phydev); priv->phydev = NULL; } netif_stop_queue(dev); #ifdef CONFIG_GSC3280MAC_TIMER /* Stop and release the timer */ gsc3280mac_close_ext_timer(); if (priv->tm != NULL) kfree(priv->tm); #endif napi_disable(&priv->napi); skb_queue_purge(&priv->rx_recycle); /* Free the IRQ lines */ free_irq(dev->irq, dev); /* Stop TX/RX DMA and clear the descriptors */ priv->hw->dma->stop_tx(priv->ioaddr); priv->hw->dma->stop_rx(priv->ioaddr); /* Release and free the Rx/Tx resources */ free_dma_desc_resources(priv); /* Disable the MAC Rx/Tx */ gsc3280mac_disable_mac(priv->ioaddr); netif_carrier_off(dev); return 0; } static unsigned int gsc3280mac_handle_jumbo_frames(struct sk_buff *skb, struct net_device *dev, int csum_insertion) { struct gsc3280mac_priv *priv = netdev_priv(dev); unsigned int nopaged_len = skb_headlen(skb); unsigned int txsize = priv->dma_tx_size; unsigned int entry = priv->cur_tx % txsize; struct dma_desc *desc = priv->dma_tx + entry; unsigned int len,i; unsigned int bmax = buf_max; i = 0; len = nopaged_len; if (len > (bmax << 1)) { desc->des2 = dma_map_single(priv->device, skb->data, (bmax<<1), DMA_TO_DEVICE); desc->des3 = desc->des2 + bmax; priv->hw->desc->prepare_tx_desc(desc, 1, (bmax<<1), csum_insertion); len -= (bmax<<1); } else { desc->des2 = dma_map_single(priv->device, skb->data, len, DMA_TO_DEVICE); if (len > bmax) desc->des3 = desc->des2 + bmax; priv->hw->desc->prepare_tx_desc(desc, 1, len, csum_insertion); len = 0; } while (len > 0) { i++; entry = (++priv->cur_tx) % txsize; desc = priv->dma_tx + entry; if (len > (bmax << 1)) { desc->des2 = dma_map_single(priv->device, skb->data + (bmax<<1)*i, (bmax<<1), DMA_TO_DEVICE); desc->des3 = desc->des2 + bmax; priv->hw->desc->prepare_tx_desc(desc, 0, (bmax<<1), csum_insertion); len -= (bmax<<1); } else { desc->des2 = dma_map_single(priv->device, skb->data + (bmax<<1)*i, len, DMA_TO_DEVICE); desc->des3 = desc->des2 + bmax; priv->hw->desc->prepare_tx_desc(desc, 0, len, csum_insertion); len = 0; } priv->hw->desc->set_tx_owner(desc); priv->tx_skbuff[entry] = NULL; } return entry; } /** * gsc3280mac_xmit: * @skb : the socket buffer * @dev : device pointer * Description : Tx entry point of the driver. */ static netdev_tx_t gsc3280mac_xmit(struct sk_buff *skb, struct net_device *dev) { struct gsc3280mac_priv *priv = netdev_priv(dev); unsigned int txsize = priv->dma_tx_size; unsigned int entry; int i, csum_insertion = 0; int nfrags = skb_shinfo(skb)->nr_frags; struct dma_desc *desc, *first; unsigned int nopaged_len = skb_headlen(skb); if (unlikely(gsc3280mac_tx_avail(priv) < nfrags + 1)) { if (!netif_queue_stopped(dev)) { netif_stop_queue(dev); /* This is a hard error, log it. */ pr_err("%s: BUG! Tx Ring full when queue awake\n", __func__); } return NETDEV_TX_BUSY; } entry = priv->cur_tx % txsize; #ifdef GSC3280MAC_XMIT_DEBUG if ((skb->len > ETH_FRAME_LEN) || nfrags) pr_info("gsc3280mac xmit:\n" "\tskb addr %p - len: %d - nopaged_len: %d\n" "\tn_frags: %d - ip_summed: %d - %s gso\n", skb, skb->len, skb_headlen(skb), nfrags, skb->ip_summed, !skb_is_gso(skb) ? "isn't" : "is"); #endif csum_insertion = (skb->ip_summed == CHECKSUM_PARTIAL); desc = priv->dma_tx + entry; first = desc; #ifdef GSC3280MAC_XMIT_DEBUG if ((nfrags > 0) || (skb->len > ETH_FRAME_LEN)) pr_debug("gsc3280mac xmit: skb len: %d, nopaged_len: %d,\n" "\t\tn_frags: %d, ip_summed: %d\n", skb->len, skb_headlen(skb), nfrags, skb->ip_summed); #endif priv->tx_skbuff[entry] = skb; if (unlikely(nopaged_len > buf_max)) { printk("linear data > 8KB\n"); entry = gsc3280mac_handle_jumbo_frames(skb, dev, csum_insertion); desc = priv->dma_tx + entry; } else { desc->des2 = dma_map_single(priv->device, skb->data, nopaged_len, DMA_TO_DEVICE); priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len, csum_insertion); } for (i = 0; i < nfrags; i++) { skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; int len = frag->size; entry = (++priv->cur_tx) % txsize; desc = priv->dma_tx + entry; TX_DBG("\t[entry %d] segment len: %d\n", entry, len); desc->des2 = dma_map_page(priv->device, frag->page, frag->page_offset, len, DMA_TO_DEVICE); priv->tx_skbuff[entry] = NULL; priv->hw->desc->prepare_tx_desc(desc, 0, len, csum_insertion); priv->hw->desc->set_tx_owner(desc); } /* Interrupt on completition only for the latest segment */ priv->hw->desc->close_tx_desc(desc); #ifdef CONFIG_GSC3280MAC_TIMER /* Clean IC while using timer */ if (likely(priv->tm->enable)) priv->hw->desc->clear_tx_ic(desc); #endif /* To avoid raise condition */ priv->hw->desc->set_tx_owner(first); priv->cur_tx++; #ifdef GSC3280MAC_XMIT_DEBUG if (netif_msg_pktdata(priv)) { pr_info("gsc3280mac xmit: current=%d, dirty=%d, entry=%d, " "first=%p, nfrags=%d\n", (priv->cur_tx % txsize), (priv->dirty_tx % txsize), entry, first, nfrags); display_ring(priv->dma_tx, txsize); pr_info(">>> frame to be transmitted: "); print_pkt(skb->data, skb->len); } #endif if (unlikely(gsc3280mac_tx_avail(priv) <= (MAX_SKB_FRAGS + 1))) { TX_DBG("%s: stop transmitted packets\n", __func__); netif_stop_queue(dev); } dev->stats.tx_bytes += skb->len; priv->hw->dma->enable_dma_transmission(priv->ioaddr); return NETDEV_TX_OK; } static inline void gsc3280mac_rx_refill(struct gsc3280mac_priv *priv) { unsigned int rxsize = priv->dma_rx_size; int bfsize = priv->dma_buf_sz; struct dma_desc *p = priv->dma_rx; for (; priv->cur_rx - priv->dirty_rx > 0; priv->dirty_rx++) { unsigned int entry = priv->dirty_rx % rxsize; if (likely(priv->rx_skbuff[entry] == NULL)) { struct sk_buff *skb; skb = __skb_dequeue(&priv->rx_recycle); if (skb == NULL) skb = netdev_alloc_skb_ip_align(priv->dev, bfsize); if (unlikely(skb == NULL)) break; priv->rx_skbuff[entry] = skb; priv->rx_skbuff_dma[entry] = dma_map_single(priv->device, skb->data, bfsize, DMA_FROM_DEVICE); (p + entry)->des2 = priv->rx_skbuff_dma[entry]; if (unlikely(bfsize > buf_max)) (p + entry)->des3 = (p + entry)->des2 + (buf_max & ~0x11); RX_DBG(KERN_INFO "\trefill entry #%d\n", entry); } priv->hw->desc->set_rx_owner(p + entry); } } static int gsc3280mac_rx(struct gsc3280mac_priv *priv, int limit) { unsigned int rxsize = priv->dma_rx_size; unsigned int entry = priv->cur_rx % rxsize; unsigned int next_entry; unsigned int count = 0; struct dma_desc *p = priv->dma_rx + entry; struct dma_desc *p_next; #ifdef GSC3280MAC_RX_DEBUG if (netif_msg_hw(priv)) { pr_debug(">>> gsc3280mac_rx: descriptor ring:\n"); display_ring(priv->dma_rx, rxsize); } #endif count = 0; while (!priv->hw->desc->get_rx_owner(p)) { int status; if (count >= limit) break; count++; next_entry = (++priv->cur_rx) % rxsize; p_next = priv->dma_rx + next_entry; prefetch(p_next); /* read the status of the incoming frame */ status = (priv->hw->desc->rx_status(&priv->dev->stats, &priv->xstats, p)); if (unlikely(status == discard_frame)) priv->dev->stats.rx_errors++; else { struct sk_buff *skb; int frame_len; frame_len = priv->hw->desc->get_rx_frame_len(p); /* ACS is set; GSC3280MAC core strips PAD/FCS for IEEE 802.3 * Type frames (LLC/LLC-SNAP) */ if (unlikely(status != llc_snap)) frame_len -= ETH_FCS_LEN; #ifdef GSC3280MAC_RX_DEBUG if (frame_len > ETH_FRAME_LEN) pr_debug("\tRX frame size %d, COE status: %d\n", frame_len, status); if (netif_msg_hw(priv)) pr_debug("\tdesc: %p [entry %d] buff=0x%x\n", p, entry, p->des2); #endif skb = priv->rx_skbuff[entry]; if (unlikely(!skb)) { pr_err("%s: Inconsistent Rx descriptor chain\n", priv->dev->name); priv->dev->stats.rx_dropped++; break; } prefetch(skb->data - NET_IP_ALIGN); priv->rx_skbuff[entry] = NULL; skb_put(skb, frame_len); dma_unmap_single(priv->device, priv->rx_skbuff_dma[entry], priv->dma_buf_sz, DMA_FROM_DEVICE); #ifdef GSC3280MAC_RX_DEBUG if (netif_msg_pktdata(priv)) { pr_info(" frame received (%dbytes)", frame_len); print_pkt(skb->data, frame_len); } #endif skb->protocol = eth_type_trans(skb, priv->dev); if (likely(status == csum_none)) { /* always for the old mac 10/100 */ skb_checksum_none_assert(skb); netif_receive_skb(skb); } else { skb->ip_summed = CHECKSUM_UNNECESSARY; napi_gro_receive(&priv->napi, skb); } priv->dev->stats.rx_packets++; priv->dev->stats.rx_bytes += frame_len; } entry = next_entry; p = p_next; /* use prefetched values */ } gsc3280mac_rx_refill(priv); priv->xstats.rx_pkt_n += count; return count; } /** * gsc3280mac_poll - gsc3280mac poll method (NAPI) * @napi : pointer to the napi structure. * @budget : maximum number of packets that the current CPU can receive from * all interfaces. * Description : * This function implements the the reception process. * Also it runs the TX completion thread */ static int gsc3280mac_poll(struct napi_struct *napi, int budget) { struct gsc3280mac_priv *priv = container_of(napi, struct gsc3280mac_priv, napi); int work_done = 0; priv->xstats.poll_n++; gsc3280mac_tx(priv); work_done = gsc3280mac_rx(priv, budget); if (work_done < budget) { napi_complete(napi); gsc3280mac_enable_irq(priv); } return work_done; } /** * gsc3280mac_tx_timeout * @dev : Pointer to net device structure * Description: this function is called when a packet transmission fails to * complete within a reasonable tmrate. The driver will mark the error in the * netdev structure and arrange for the device to be reset to a sane state * in order to transmit a new packet. */ static void gsc3280mac_tx_timeout(struct net_device *dev) { struct gsc3280mac_priv *priv = netdev_priv(dev); /* Clear Tx resources and restart transmitting again */ gsc3280mac_tx_err(priv); } /* Configuration changes (passed on by ifconfig) */ static int gsc3280mac_config(struct net_device *dev, struct ifmap *map) { if (dev->flags & IFF_UP) /* can't act on a running interface */ return -EBUSY; /* Don't allow changing the I/O address */ if (map->base_addr != dev->base_addr) { pr_warning("%s: can't change I/O address\n", dev->name); return -EOPNOTSUPP; } /* Don't allow changing the IRQ */ if (map->irq != dev->irq) { pr_warning("%s: can't change IRQ number %d\n", dev->name, dev->irq); return -EOPNOTSUPP; } /* ignore other fields */ return 0; } /** * gsc3280mac_multicast_list - entry point for multicast addressing * @dev : pointer to the device structure * Description: * This function is a driver entry point which gets called by the kernel * whenever multicast addresses must be enabled/disabled. * Return value: * void. */ static void gsc3280mac_multicast_list(struct net_device *dev) { struct gsc3280mac_priv *priv = netdev_priv(dev); spin_lock(&priv->lock); priv->hw->mac->set_filter(dev); spin_unlock(&priv->lock); } /** * gsc3280mac_change_mtu - entry point to change MTU size for the device. * @dev : device pointer. * @new_mtu : the new MTU size for the device. * Description: the Maximum Transfer Unit (MTU) is used by the network layer * to drive packet transmission. Ethernet has an MTU of 1500 octets * (ETH_DATA_LEN). This value can be changed with ifconfig. * Return value: * 0 on success and an appropriate (-)ve integer as defined in errno.h * file on failure. */ static int gsc3280mac_change_mtu(struct net_device *dev, int new_mtu) { struct gsc3280mac_priv *priv = netdev_priv(dev); int max_mtu; if (netif_running(dev)) { pr_err("%s: must be stopped to change its MTU\n", dev->name); return -EBUSY; } max_mtu = JUMBO_LEN; if ((new_mtu < 46) || (new_mtu > max_mtu)) { pr_err("%s: invalid MTU, max MTU is: %d\n", dev->name, max_mtu); return -EINVAL; } dev->mtu = new_mtu; netdev_update_features(dev); return 0; } static u32 gsc3280mac_fix_features(struct net_device *dev, u32 features) { struct gsc3280mac_priv *priv = netdev_priv(dev); if (!priv->rx_coe) features &= ~NETIF_F_RXCSUM; if (!priv->plat->tx_coe) features &= ~NETIF_F_ALL_CSUM; /* Some GSC3280MAC devices have a bugged Jumbo frame support that * needs to have the Tx COE disabled for oversized frames * (due to limited buffer sizes). In this case we disable * the TX csum insertionin the TDES and not use SF. */ if (priv->plat->bugged_jumbo && (dev->mtu > ETH_DATA_LEN)) features &= ~NETIF_F_ALL_CSUM; return features; } static irqreturn_t gsc3280mac_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *)dev_id; struct gsc3280mac_priv *priv = netdev_priv(dev); if (unlikely(!dev)) { pr_err("%s: invalid dev pointer\n", __func__); return IRQ_NONE; } /* To handle GSC3280MAC own interrupts */ priv->hw->mac->host_irq_status((void __iomem *) dev->base_addr); gsc3280mac_dma_interrupt(priv); return IRQ_HANDLED; } #ifdef CONFIG_NET_POLL_CONTROLLER /* Polling receive - used by NETCONSOLE and other diagnostic tools * to allow network I/O with interrupts disabled. */ static void gsc3280mac_poll_controller(struct net_device *dev) { disable_irq(dev->irq); gsc3280mac_interrupt(dev->irq, dev); enable_irq(dev->irq); } #endif /** * gsc3280mac_ioctl - Entry point for the Ioctl * @dev: Device pointer. * @rq: An IOCTL specefic structure, that can contain a pointer to * a proprietary structure used to pass information to the driver. * @cmd: IOCTL command * Description: * Currently there are no special functionality supported in IOCTL, just the * phy_mii_ioctl(...) can be invoked. */ static int gsc3280mac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct gsc3280mac_priv *priv = netdev_priv(dev); int ret; if (!netif_running(dev)) return -EINVAL; if (!priv->phydev) return -EINVAL; spin_lock(&priv->lock); ret = phy_mii_ioctl(priv->phydev, rq, cmd); spin_unlock(&priv->lock); return ret; } #ifdef GSC3280MAC_VLAN_TAG_USED static void gsc3280mac_vlan_rx_register(struct net_device *dev, struct vlan_group *grp) { struct gsc3280mac_priv *priv = netdev_priv(dev); DBG(probe, INFO, "%s: Setting vlgrp to %p\n", dev->name, grp); spin_lock(&priv->lock); priv->vlgrp = grp; spin_unlock(&priv->lock); } #endif static const struct net_device_ops gsc3280mac_netdev_ops = { .ndo_open = gsc3280mac_open, .ndo_start_xmit = gsc3280mac_xmit, .ndo_stop = gsc3280mac_release, .ndo_change_mtu = gsc3280mac_change_mtu, .ndo_fix_features = gsc3280mac_fix_features, .ndo_set_multicast_list = gsc3280mac_multicast_list, .ndo_tx_timeout = gsc3280mac_tx_timeout, .ndo_do_ioctl = gsc3280mac_ioctl, .ndo_set_config = gsc3280mac_config, #ifdef GSC3280MAC_VLAN_TAG_USED .ndo_vlan_rx_register = gsc3280mac_vlan_rx_register, #endif #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = gsc3280mac_poll_controller, #endif .ndo_set_mac_address = eth_mac_addr, }; /** * gsc3280mac_probe - Initialization of the adapter . * @dev : device pointer * Description: The function initializes the network device structure for * the GSC3280MAC driver. It also calls the low level routines * in order to init the HW (i.e. the DMA engine) */ static int gsc3280mac_probe(struct net_device *dev) { int ret = 0; struct gsc3280mac_priv *priv = netdev_priv(dev); ether_setup(dev); dev->netdev_ops = &gsc3280mac_netdev_ops; gsc3280mac_set_ethtool_ops(dev); dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM #ifdef CONFIG_GSC3280MAC_HW | NETIF_F_RXCSUM | NETIF_F_ALL_CSUM #endif ; dev->features |= dev->hw_features | NETIF_F_HIGHDMA; dev->watchdog_timeo = msecs_to_jiffies(watchdog); #ifdef GSC3280MAC_VLAN_TAG_USED /* Both mac100 and gmac support receive VLAN tag detection */ dev->features |= NETIF_F_HW_VLAN_RX; #endif priv->msg_enable = netif_msg_init(debug, default_msg_level); if (flow_ctrl) priv->flow_ctrl = FLOW_AUTO; /* RX/TX pause on */ priv->pause = pause; netif_napi_add(dev, &priv->napi, gsc3280mac_poll, 64); /* Get the MAC address */ priv->hw->mac->get_umac_addr((void __iomem *) dev->base_addr, dev->dev_addr, 0); if (!is_valid_ether_addr(dev->dev_addr)) pr_warning("\tno valid MAC address;" "please, use ifconfig or nwhwconfig!\n"); spin_lock_init(&priv->lock); ret = register_netdev(dev); if (ret) { pr_err("%s: ERROR %i registering the device\n", __func__, ret); return -ENODEV; } DBG(probe, DEBUG, "%s: Scatter/Gather: %s - HW checksums: %s\n", dev->name, (dev->features & NETIF_F_SG) ? "on" : "off", (dev->features & NETIF_F_IP_CSUM) ? "on" : "off"); return ret; } /** * gsc3280mac_mac_device_setup * @dev : device pointer * Description: select and initialise the mac device (mac100 or Gmac). */ static int gsc3280mac_mac_device_setup(struct net_device *dev) { struct gsc3280mac_priv *priv = netdev_priv(dev); struct mac_device_info *device; device = gsc3280mac1000_setup(priv->ioaddr); if (!device) return -ENOMEM; if (unlikely(priv->plat->enh_desc)) { device->desc = &enh_desc_ops; pr_info("\tEnhanced descriptor structure\n"); } else device->desc = &ndesc_ops; priv->hw = device; if (device_can_wakeup(priv->device)) { priv->wolopts = WAKE_MAGIC; /* Magic Frame as default */ enable_irq_wake(dev->irq); } return 0; } static int gsc3280macphy_dvr_probe(struct platform_device *pdev) { struct plat_gsc3280macphy_data *plat_dat = pdev->dev.platform_data; pr_debug("gsc3280macphy_dvr_probe: added phy for bus %d\n", plat_dat->bus_id); return 0; } static int gsc3280macphy_dvr_remove(struct platform_device *pdev) { return 0; } static struct platform_driver gsc3280macphy_driver = { .driver = { .name = PHY_RESOURCE_NAME, }, .probe = gsc3280macphy_dvr_probe, .remove = gsc3280macphy_dvr_remove, }; /** * gsc3280mac_associate_phy * @dev: pointer to device structure * @data: points to the private structure. * Description: Scans through all the PHYs we have registered and checks if * any are associated with our MAC. If so, then just fill in * the blanks in our local context structure */ static int gsc3280mac_associate_phy(struct device *dev, void *data) { struct gsc3280mac_priv *priv = (struct gsc3280mac_priv *)data; struct plat_gsc3280macphy_data *plat_dat = dev->platform_data; DBG(probe, DEBUG, "%s: checking phy for bus %d\n", __func__, plat_dat->bus_id); /* Check that this phy is for the MAC being initialised */ if (priv->plat->bus_id != plat_dat->bus_id) return 0; /* OK, this PHY is connected to the MAC. Go ahead and get the parameters */ DBG(probe, DEBUG, "%s: OK. Found PHY config\n", __func__); priv->phy_irq = platform_get_irq_byname(to_platform_device(dev), "phyirq"); DBG(probe, DEBUG, "%s: PHY irq on bus %d is %d\n", __func__, plat_dat->bus_id, priv->phy_irq); /* Override with kernel parameters if supplied XXX CRS XXX * this needs to have multiple instances */ if ((phyaddr >= 0) && (phyaddr <= 31)) plat_dat->phy_addr = phyaddr; priv->phy_addr = plat_dat->phy_addr; priv->phy_mask = plat_dat->phy_mask; priv->phy_interface = plat_dat->interface; priv->phy_reset = plat_dat->phy_reset; DBG(probe, DEBUG, "%s: exiting\n", __func__); return 1; /* forces exit of driver_for_each_device() */ } /** * gsc3280mac_dvr_probe * @pdev: platform device pointer * Description: the driver is initialized through platform_device. */ static int gsc3280mac_dvr_probe(struct platform_device *pdev) { int ret = 0; struct resource *res; void __iomem *addr = NULL; struct net_device *ndev = NULL; struct gsc3280mac_priv *priv = NULL; struct plat_gsc3280macenet_data *plat_dat; pr_info("GSC3280MAC driver:\n\tplatform registration... "); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -ENODEV; pr_info("\tdone!\n"); if (!request_mem_region(res->start, resource_size(res), pdev->name)) { pr_err("%s: ERROR: memory allocation failed" "cannot get the I/O addr 0x%x\n", __func__, (unsigned int)res->start); return -EBUSY; } addr = ioremap(res->start, resource_size(res)); if (!addr) { pr_err("%s: ERROR: memory mapping failed\n", __func__); ret = -ENOMEM; goto out_release_region; } ndev = alloc_etherdev(sizeof(struct gsc3280mac_priv)); if (!ndev) { pr_err("%s: ERROR: allocating the device\n", __func__); ret = -ENOMEM; goto out_unmap; } SET_NETDEV_DEV(ndev, &pdev->dev); /* Get the MAC information */ ndev->irq = platform_get_irq_byname(pdev, "macirq"); if (ndev->irq == -ENXIO) { pr_err("%s: ERROR: MAC IRQ configuration " "information not found\n", __func__); ret = -ENXIO; goto out_free_ndev; } priv = netdev_priv(ndev); priv->device = &(pdev->dev); priv->dev = ndev; plat_dat = pdev->dev.platform_data; priv->plat = plat_dat; priv->ioaddr = addr; /* PMT module is not integrated in all the MAC devices. */ if (plat_dat->pmt) { pr_info("\tPMT module supported\n"); device_set_wakeup_capable(&pdev->dev, 1); } platform_set_drvdata(pdev, ndev); /* Set the I/O base addr */ ndev->base_addr = (unsigned long)addr; /* Custom initialisation */ if (priv->plat->init) { ret = priv->plat->init(pdev); if (unlikely(ret)) goto out_free_ndev; } /* MAC HW revice detection */ ret = gsc3280mac_mac_device_setup(ndev); if (ret < 0) goto out_plat_exit; /* Network Device Registration */ ret = gsc3280mac_probe(ndev); if (ret < 0) goto out_plat_exit; /* associate a PHY - it is provided by another platform bus */ if (!driver_for_each_device (&(gsc3280macphy_driver.driver), NULL, (void *)priv, gsc3280mac_associate_phy)) { pr_err("No PHY device is associated with this MAC!\n"); ret = -ENODEV; goto out_unregister; } pr_info("\t%s - (dev. name: %s - id: %d, IRQ #%d\n" "\tIO base addr: 0x%p)\n", ndev->name, pdev->name, pdev->id, ndev->irq, addr); /* MDIO bus Registration */ pr_debug("\tMDIO bus (id: %d)...", priv->plat->bus_id); ret = gsc3280mac_mdio_register(ndev); if (ret < 0) goto out_unregister; pr_debug("registered!\n"); return 0; out_unregister: unregister_netdev(ndev); out_plat_exit: if (priv->plat->exit) priv->plat->exit(pdev); out_free_ndev: free_netdev(ndev); platform_set_drvdata(pdev, NULL); out_unmap: iounmap(addr); out_release_region: release_mem_region(res->start, resource_size(res)); return ret; } /** * gsc3280mac_dvr_remove * @pdev: platform device pointer * Description: this function resets the TX/RX processes, disables the MAC RX/TX * changes the link status, releases the DMA descriptor rings, * unregisters the MDIO bus and unmaps the allocated memory. */ static int gsc3280mac_dvr_remove(struct platform_device *pdev) { struct net_device *ndev = platform_get_drvdata(pdev); struct gsc3280mac_priv *priv = netdev_priv(ndev); struct resource *res; pr_info("%s:\n\tremoving driver", __func__); priv->hw->dma->stop_rx(priv->ioaddr); priv->hw->dma->stop_tx(priv->ioaddr); gsc3280mac_disable_mac(priv->ioaddr); netif_carrier_off(ndev); gsc3280mac_mdio_unregister(ndev); if (priv->plat->exit) priv->plat->exit(pdev); platform_set_drvdata(pdev, NULL); unregister_netdev(ndev); iounmap((void *)priv->ioaddr); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(res->start, resource_size(res)); free_netdev(ndev); return 0; } #ifdef CONFIG_PM static int gsc3280mac_suspend(struct device *dev) { struct net_device *ndev = dev_get_drvdata(dev); struct gsc3280mac_priv *priv = netdev_priv(ndev); int dis_ic = 0; if (!ndev || !netif_running(ndev)) return 0; spin_lock(&priv->lock); netif_device_detach(ndev); netif_stop_queue(ndev); if (priv->phydev) phy_stop(priv->phydev); #ifdef CONFIG_GSC3280MAC_TIMER priv->tm->timer_stop(); if (likely(priv->tm->enable)) dis_ic = 1; #endif napi_disable(&priv->napi); /* Stop TX/RX DMA */ priv->hw->dma->stop_tx(priv->ioaddr); priv->hw->dma->stop_rx(priv->ioaddr); /* Clear the Rx/Tx descriptors */ priv->hw->desc->init_rx_desc(priv->dma_rx, priv->dma_rx_size, dis_ic); priv->hw->desc->init_tx_desc(priv->dma_tx, priv->dma_tx_size); /* Enable Power down mode by programming the PMT regs */ if (device_may_wakeup(priv->device)) priv->hw->mac->pmt(priv->ioaddr, priv->wolopts); else gsc3280mac_disable_mac(priv->ioaddr); spin_unlock(&priv->lock); return 0; } static int gsc3280mac_resume(struct device *dev) { struct net_device *ndev = dev_get_drvdata(dev); struct gsc3280mac_priv *priv = netdev_priv(ndev); if (!netif_running(ndev)) return 0; spin_lock(&priv->lock); /* Power Down bit, into the PM register, is cleared * automatically as soon as a magic packet or a Wake-up frame * is received. Anyway, it's better to manually clear * this bit because it can generate problems while resuming * from another devices (e.g. serial console). */ if (device_may_wakeup(priv->device)) priv->hw->mac->pmt(priv->ioaddr, 0); netif_device_attach(ndev); /* Enable the MAC and DMA */ gsc3280mac_enable_mac(priv->ioaddr); priv->hw->dma->start_tx(priv->ioaddr); priv->hw->dma->start_rx(priv->ioaddr); #ifdef CONFIG_GSC3280MAC_TIMER if (likely(priv->tm->enable)) priv->tm->timer_start(tmrate); #endif napi_enable(&priv->napi); if (priv->phydev) phy_start(priv->phydev); netif_start_queue(ndev); spin_unlock(&priv->lock); return 0; } static int gsc3280mac_freeze(struct device *dev) { struct net_device *ndev = dev_get_drvdata(dev); if (!ndev || !netif_running(ndev)) return 0; return gsc3280mac_release(ndev); } static int gsc3280mac_restore(struct device *dev) { struct net_device *ndev = dev_get_drvdata(dev); if (!ndev || !netif_running(ndev)) return 0; return gsc3280mac_open(ndev); } static const struct dev_pm_ops gsc3280mac_pm_ops = { .suspend = gsc3280mac_suspend, .resume = gsc3280mac_resume, .freeze = gsc3280mac_freeze, .thaw = gsc3280mac_restore, .restore = gsc3280mac_restore, }; #else static const struct dev_pm_ops gsc3280mac_pm_ops; #endif /* CONFIG_PM */ static struct platform_driver gsc3280mac_driver = { .probe = gsc3280mac_dvr_probe, .remove = gsc3280mac_dvr_remove, .driver = { .name = GSC3280MAC_RESOURCE_NAME, .owner = THIS_MODULE, .pm = &gsc3280mac_pm_ops, }, }; /** * gsc3280mac_init_module - Entry point for the driver * Description: This function is the entry point for the driver. */ static int __init gsc3280mac_init_module(void) { int ret; if (platform_driver_register(&gsc3280macphy_driver)) { pr_err("No PHY devices registered!\n"); return -ENODEV; } ret = platform_driver_register(&gsc3280mac_driver); return ret; } /** * gsc3280mac_cleanup_module - Cleanup routine for the driver * Description: This function is the cleanup routine for the driver. */ static void __exit gsc3280mac_cleanup_module(void) { platform_driver_unregister(&gsc3280macphy_driver); platform_driver_unregister(&gsc3280mac_driver); } #ifndef MODULE static int __init gsc3280mac_cmdline_opt(char *str) { char *opt; if (!str || !*str) return -EINVAL; while ((opt = strsep(&str, ",")) != NULL) { if (!strncmp(opt, "debug:", 6)) strict_strtoul(opt + 6, 0, (unsigned long *)&debug); else if (!strncmp(opt, "phyaddr:", 8)) strict_strtoul(opt + 8, 0, (unsigned long *)&phyaddr); else if (!strncmp(opt, "dma_txsize:", 11)) strict_strtoul(opt + 11, 0, (unsigned long *)&dma_txsize); else if (!strncmp(opt, "dma_rxsize:", 11)) strict_strtoul(opt + 11, 0, (unsigned long *)&dma_rxsize); else if (!strncmp(opt, "buf_sz:", 7)) strict_strtoul(opt + 7, 0, (unsigned long *)&buf_sz); else if (!strncmp(opt, "tc:", 3)) strict_strtoul(opt + 3, 0, (unsigned long *)&tc); else if (!strncmp(opt, "watchdog:", 9)) strict_strtoul(opt + 9, 0, (unsigned long *)&watchdog); else if (!strncmp(opt, "flow_ctrl:", 10)) strict_strtoul(opt + 10, 0, (unsigned long *)&flow_ctrl); else if (!strncmp(opt, "pause:", 6)) strict_strtoul(opt + 6, 0, (unsigned long *)&pause); #ifdef CONFIG_GSC3280MAC_TIMER else if (!strncmp(opt, "tmrate:", 7)) strict_strtoul(opt + 7, 0, (unsigned long *)&tmrate); #endif } return 0; } __setup("gsc3280maceth=", gsc3280mac_cmdline_opt); #endif module_init(gsc3280mac_init_module); module_exit(gsc3280mac_cleanup_module); MODULE_LICENSE("GPL");