cregit-Linux how code gets into the kernel

Release 4.11 drivers/net/ethernet/netx-eth.c

/*
 * drivers/net/ethernet/netx-eth.c
 *
 * Copyright (c) 2005 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
 */

#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>

#include <linux/netdevice.h>
#include <linux/platform_device.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/mii.h>

#include <asm/io.h>
#include <mach/hardware.h>
#include <mach/netx-regs.h>
#include <mach/pfifo.h>
#include <mach/xc.h>
#include <linux/platform_data/eth-netx.h>

/* XC Fifo Offsets */

#define EMPTY_PTR_FIFO(xcno)    (0 + ((xcno) << 3))	
/* Index of the empty pointer FIFO */

#define IND_FIFO_PORT_HI(xcno)  (1 + ((xcno) << 3))	
/* Index of the FIFO where received */
							/* Data packages are indicated by XC */

#define IND_FIFO_PORT_LO(xcno)  (2 + ((xcno) << 3))	
/* Index of the FIFO where received */
							/* Data packages are indicated by XC */

#define REQ_FIFO_PORT_HI(xcno)  (3 + ((xcno) << 3))	
/* Index of the FIFO where Data packages */
							/* have to be indicated by ARM which */
							/* shall be sent */

#define REQ_FIFO_PORT_LO(xcno)  (4 + ((xcno) << 3))	
/* Index of the FIFO where Data packages */
							/* have to be indicated by ARM which shall */
							/* be sent */

#define CON_FIFO_PORT_HI(xcno)  (5 + ((xcno) << 3))	
/* Index of the FIFO where sent Data packages */
							/* are confirmed */

#define CON_FIFO_PORT_LO(xcno)  (6 + ((xcno) << 3))	
/* Index of the FIFO where sent Data */
							/* packages are confirmed */

#define PFIFO_MASK(xcno)        (0x7f << (xcno*8))


#define FIFO_PTR_FRAMELEN_SHIFT 0

#define FIFO_PTR_FRAMELEN_MASK  (0x7ff << 0)

#define FIFO_PTR_FRAMELEN(len)  (((len) << 0) & FIFO_PTR_FRAMELEN_MASK)

#define FIFO_PTR_TIMETRIG       (1<<11)

#define FIFO_PTR_MULTI_REQ

#define FIFO_PTR_ORIGIN         (1<<14)

#define FIFO_PTR_VLAN           (1<<15)

#define FIFO_PTR_FRAMENO_SHIFT  16

#define FIFO_PTR_FRAMENO_MASK   (0x3f << 16)

#define FIFO_PTR_FRAMENO(no)    (((no) << 16) & FIFO_PTR_FRAMENO_MASK)

#define FIFO_PTR_SEGMENT_SHIFT  22

#define FIFO_PTR_SEGMENT_MASK   (0xf << 22)

#define FIFO_PTR_SEGMENT(seg)   (((seg) & 0xf) << 22)

#define FIFO_PTR_ERROR_SHIFT    28

#define FIFO_PTR_ERROR_MASK     (0xf << 28)


#define ISR_LINK_STATUS_CHANGE (1<<4)

#define ISR_IND_LO             (1<<3)

#define ISR_CON_LO             (1<<2)

#define ISR_IND_HI             (1<<1)

#define ISR_CON_HI             (1<<0)


#define ETH_MAC_LOCAL_CONFIG 0x1560

#define ETH_MAC_4321         0x1564

#define ETH_MAC_65           0x1568


#define MAC_TRAFFIC_CLASS_ARRANGEMENT_SHIFT 16

#define MAC_TRAFFIC_CLASS_ARRANGEMENT_MASK (0xf<<MAC_TRAFFIC_CLASS_ARRANGEMENT_SHIFT)

#define MAC_TRAFFIC_CLASS_ARRANGEMENT(x) (((x)<<MAC_TRAFFIC_CLASS_ARRANGEMENT_SHIFT) & MAC_TRAFFIC_CLASS_ARRANGEMENT_MASK)

#define LOCAL_CONFIG_LINK_STATUS_IRQ_EN (1<<24)

#define LOCAL_CONFIG_CON_LO_IRQ_EN (1<<23)

#define LOCAL_CONFIG_CON_HI_IRQ_EN (1<<22)

#define LOCAL_CONFIG_IND_LO_IRQ_EN (1<<21)

#define LOCAL_CONFIG_IND_HI_IRQ_EN (1<<20)


#define CARDNAME "netx-eth"

/* LSB must be zero */

#define INTERNAL_PHY_ADR 0x1c


struct netx_eth_priv {
	


void                    __iomem *sram_base, *xpec_base, *xmac_base;
	
int                     id;
	
struct mii_if_info      mii;
	
u32                     msg_enable;
	
struct xc               *xc;
	
spinlock_t              lock;
};


static void netx_eth_set_multicast_list(struct net_device *ndev) { /* implement me */ }

Contributors

PersonTokensPropCommitsCommitProp
Sascha Hauer12100.00%1100.00%
Total12100.00%1100.00%


static int netx_eth_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) { struct netx_eth_priv *priv = netdev_priv(ndev); unsigned char *buf = skb->data; unsigned int len = skb->len; spin_lock_irq(&priv->lock); memcpy_toio(priv->sram_base + 1560, (void *)buf, len); if (len < 60) { memset_io(priv->sram_base + 1560 + len, 0, 60 - len); len = 60; } pfifo_push(REQ_FIFO_PORT_LO(priv->id), FIFO_PTR_SEGMENT(priv->id) | FIFO_PTR_FRAMENO(1) | FIFO_PTR_FRAMELEN(len)); ndev->stats.tx_packets++; ndev->stats.tx_bytes += skb->len; netif_stop_queue(ndev); spin_unlock_irq(&priv->lock); dev_kfree_skb(skb); return NETDEV_TX_OK; }

Contributors

PersonTokensPropCommitsCommitProp
Sascha Hauer16098.77%133.33%
Patrick McHardy10.62%133.33%
David S. Miller10.62%133.33%
Total162100.00%3100.00%


static void netx_eth_receive(struct net_device *ndev) { struct netx_eth_priv *priv = netdev_priv(ndev); unsigned int val, frameno, seg, len; unsigned char *data; struct sk_buff *skb; val = pfifo_pop(IND_FIFO_PORT_LO(priv->id)); frameno = (val & FIFO_PTR_FRAMENO_MASK) >> FIFO_PTR_FRAMENO_SHIFT; seg = (val & FIFO_PTR_SEGMENT_MASK) >> FIFO_PTR_SEGMENT_SHIFT; len = (val & FIFO_PTR_FRAMELEN_MASK) >> FIFO_PTR_FRAMELEN_SHIFT; skb = netdev_alloc_skb(ndev, len); if (unlikely(skb == NULL)) { ndev->stats.rx_dropped++; return; } data = skb_put(skb, len); memcpy_fromio(data, priv->sram_base + frameno * 1560, len); pfifo_push(EMPTY_PTR_FIFO(priv->id), FIFO_PTR_SEGMENT(seg) | FIFO_PTR_FRAMENO(frameno)); skb->protocol = eth_type_trans(skb, ndev); netif_rx(skb); ndev->stats.rx_packets++; ndev->stats.rx_bytes += len; }

Contributors

PersonTokensPropCommitsCommitProp
Sascha Hauer18096.77%125.00%
Pradeep A. Dalvi31.61%125.00%
Adrian Bunk21.08%125.00%
David S. Miller10.54%125.00%
Total186100.00%4100.00%


static irqreturn_t netx_eth_interrupt(int irq, void *dev_id) { struct net_device *ndev = dev_id; struct netx_eth_priv *priv = netdev_priv(ndev); int status; unsigned long flags; spin_lock_irqsave(&priv->lock, flags); status = readl(NETX_PFIFO_XPEC_ISR(priv->id)); while (status) { int fill_level; writel(status, NETX_PFIFO_XPEC_ISR(priv->id)); if ((status & ISR_CON_HI) || (status & ISR_IND_HI)) printk("%s: unexpected status: 0x%08x\n", __func__, status); fill_level = readl(NETX_PFIFO_FILL_LEVEL(IND_FIFO_PORT_LO(priv->id))); while (fill_level--) netx_eth_receive(ndev); if (status & ISR_CON_LO) netif_wake_queue(ndev); if (status & ISR_LINK_STATUS_CHANGE) mii_check_media(&priv->mii, netif_msg_link(priv), 1); status = readl(NETX_PFIFO_XPEC_ISR(priv->id)); } spin_unlock_irqrestore(&priv->lock, flags); return IRQ_HANDLED; }

Contributors

PersonTokensPropCommitsCommitProp
Sascha Hauer18499.46%150.00%
Harvey Harrison10.54%150.00%
Total185100.00%2100.00%


static int netx_eth_open(struct net_device *ndev) { struct netx_eth_priv *priv = netdev_priv(ndev); if (request_irq (ndev->irq, netx_eth_interrupt, IRQF_SHARED, ndev->name, ndev)) return -EAGAIN; writel(ndev->dev_addr[0] | ndev->dev_addr[1]<<8 | ndev->dev_addr[2]<<16 | ndev->dev_addr[3]<<24, priv->xpec_base + NETX_XPEC_RAM_START_OFS + ETH_MAC_4321); writel(ndev->dev_addr[4] | ndev->dev_addr[5]<<8, priv->xpec_base + NETX_XPEC_RAM_START_OFS + ETH_MAC_65); writel(LOCAL_CONFIG_LINK_STATUS_IRQ_EN | LOCAL_CONFIG_CON_LO_IRQ_EN | LOCAL_CONFIG_CON_HI_IRQ_EN | LOCAL_CONFIG_IND_LO_IRQ_EN | LOCAL_CONFIG_IND_HI_IRQ_EN, priv->xpec_base + NETX_XPEC_RAM_START_OFS + ETH_MAC_LOCAL_CONFIG); mii_check_media(&priv->mii, netif_msg_link(priv), 1); netif_start_queue(ndev); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Sascha Hauer15999.38%150.00%
Thomas Gleixner10.62%150.00%
Total160100.00%2100.00%


static int netx_eth_close(struct net_device *ndev) { struct netx_eth_priv *priv = netdev_priv(ndev); netif_stop_queue(ndev); writel(0, priv->xpec_base + NETX_XPEC_RAM_START_OFS + ETH_MAC_LOCAL_CONFIG); free_irq(ndev->irq, ndev); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Sascha Hauer51100.00%1100.00%
Total51100.00%1100.00%


static void netx_eth_timeout(struct net_device *ndev) { struct netx_eth_priv *priv = netdev_priv(ndev); int i; printk(KERN_ERR "%s: transmit timed out, resetting\n", ndev->name); spin_lock_irq(&priv->lock); xc_reset(priv->xc); xc_start(priv->xc); for (i=2; i<=18; i++) pfifo_push(EMPTY_PTR_FIFO(priv->id), FIFO_PTR_FRAMENO(i) | FIFO_PTR_SEGMENT(priv->id)); spin_unlock_irq(&priv->lock); netif_wake_queue(ndev); }

Contributors

PersonTokensPropCommitsCommitProp
Sascha Hauer104100.00%1100.00%
Total104100.00%1100.00%


static int netx_eth_phy_read(struct net_device *ndev, int phy_id, int reg) { unsigned int val; val = MIIMU_SNRDY | MIIMU_PREAMBLE | MIIMU_PHYADDR(phy_id) | MIIMU_REGADDR(reg) | MIIMU_PHY_NRES; writel(val, NETX_MIIMU); while (readl(NETX_MIIMU) & MIIMU_SNRDY); return readl(NETX_MIIMU) >> 16; }

Contributors

PersonTokensPropCommitsCommitProp
Sascha Hauer64100.00%1100.00%
Total64100.00%1100.00%


static void netx_eth_phy_write(struct net_device *ndev, int phy_id, int reg, int value) { unsigned int val; val = MIIMU_SNRDY | MIIMU_PREAMBLE | MIIMU_PHYADDR(phy_id) | MIIMU_REGADDR(reg) | MIIMU_PHY_NRES | MIIMU_OPMODE_WRITE | MIIMU_DATA(value); writel(val, NETX_MIIMU); while (readl(NETX_MIIMU) & MIIMU_SNRDY); }

Contributors

PersonTokensPropCommitsCommitProp
Sascha Hauer66100.00%1100.00%
Total66100.00%1100.00%

static const struct net_device_ops netx_eth_netdev_ops = { .ndo_open = netx_eth_open, .ndo_stop = netx_eth_close, .ndo_start_xmit = netx_eth_hard_start_xmit, .ndo_tx_timeout = netx_eth_timeout, .ndo_set_rx_mode = netx_eth_set_multicast_list, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = eth_mac_addr, };
static int netx_eth_enable(struct net_device *ndev) { struct netx_eth_priv *priv = netdev_priv(ndev); unsigned int mac4321, mac65; int running, i, ret; bool inv_mac_addr = false; ndev->netdev_ops = &netx_eth_netdev_ops; ndev->watchdog_timeo = msecs_to_jiffies(5000); priv->msg_enable = NETIF_MSG_LINK; priv->mii.phy_id_mask = 0x1f; priv->mii.reg_num_mask = 0x1f; priv->mii.force_media = 0; priv->mii.full_duplex = 0; priv->mii.dev = ndev; priv->mii.mdio_read = netx_eth_phy_read; priv->mii.mdio_write = netx_eth_phy_write; priv->mii.phy_id = INTERNAL_PHY_ADR + priv->id; running = xc_running(priv->xc); xc_stop(priv->xc); /* if the xc engine is already running, assume the bootloader has * loaded the firmware for us */ if (running) { /* get Node Address from hardware */ mac4321 = readl(priv->xpec_base + NETX_XPEC_RAM_START_OFS + ETH_MAC_4321); mac65 = readl(priv->xpec_base + NETX_XPEC_RAM_START_OFS + ETH_MAC_65); ndev->dev_addr[0] = mac4321 & 0xff; ndev->dev_addr[1] = (mac4321 >> 8) & 0xff; ndev->dev_addr[2] = (mac4321 >> 16) & 0xff; ndev->dev_addr[3] = (mac4321 >> 24) & 0xff; ndev->dev_addr[4] = mac65 & 0xff; ndev->dev_addr[5] = (mac65 >> 8) & 0xff; } else { if (xc_request_firmware(priv->xc)) { printk(CARDNAME ": requesting firmware failed\n"); return -ENODEV; } } xc_reset(priv->xc); xc_start(priv->xc); if (!is_valid_ether_addr(ndev->dev_addr)) inv_mac_addr = true; for (i=2; i<=18; i++) pfifo_push(EMPTY_PTR_FIFO(priv->id), FIFO_PTR_FRAMENO(i) | FIFO_PTR_SEGMENT(priv->id)); ret = register_netdev(ndev); if (inv_mac_addr) printk("%s: Invalid ethernet MAC address. Please set using ip\n", ndev->name); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Sascha Hauer34091.64%133.33%
Harvey Hunt287.55%133.33%
Alexander Beregalov30.81%133.33%
Total371100.00%3100.00%


static int netx_eth_drv_probe(struct platform_device *pdev) { struct netx_eth_priv *priv; struct net_device *ndev; struct netxeth_platform_data *pdata; int ret; ndev = alloc_etherdev(sizeof (struct netx_eth_priv)); if (!ndev) { ret = -ENOMEM; goto exit; } SET_NETDEV_DEV(ndev, &pdev->dev); platform_set_drvdata(pdev, ndev); priv = netdev_priv(ndev); pdata = dev_get_platdata(&pdev->dev); priv->xc = request_xc(pdata->xcno, &pdev->dev); if (!priv->xc) { dev_err(&pdev->dev, "unable to request xc engine\n"); ret = -ENODEV; goto exit_free_netdev; } ndev->irq = priv->xc->irq; priv->id = pdev->id; priv->xpec_base = priv->xc->xpec_base; priv->xmac_base = priv->xc->xmac_base; priv->sram_base = priv->xc->sram_base; spin_lock_init(&priv->lock); ret = pfifo_request(PFIFO_MASK(priv->id)); if (ret) { printk("unable to request PFIFO\n"); goto exit_free_xc; } ret = netx_eth_enable(ndev); if (ret) goto exit_free_pfifo; return 0; exit_free_pfifo: pfifo_free(PFIFO_MASK(priv->id)); exit_free_xc: free_xc(priv->xc); exit_free_netdev: free_netdev(ndev); exit: return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Sascha Hauer25295.45%133.33%
Uwe Kleine-König83.03%133.33%
Jingoo Han41.52%133.33%
Total264100.00%3100.00%


static int netx_eth_drv_remove(struct platform_device *pdev) { struct net_device *ndev = platform_get_drvdata(pdev); struct netx_eth_priv *priv = netdev_priv(ndev); unregister_netdev(ndev); xc_stop(priv->xc); free_xc(priv->xc); free_netdev(ndev); pfifo_free(PFIFO_MASK(priv->id)); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Sascha Hauer6798.53%150.00%
Jingoo Han11.47%150.00%
Total68100.00%2100.00%


static int netx_eth_drv_suspend(struct platform_device *pdev, pm_message_t state) { dev_err(&pdev->dev, "suspend not implemented\n"); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Sascha Hauer27100.00%1100.00%
Total27100.00%1100.00%


static int netx_eth_drv_resume(struct platform_device *pdev) { dev_err(&pdev->dev, "resume not implemented\n"); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Sascha Hauer24100.00%1100.00%
Total24100.00%1100.00%

static struct platform_driver netx_eth_driver = { .probe = netx_eth_drv_probe, .remove = netx_eth_drv_remove, .suspend = netx_eth_drv_suspend, .resume = netx_eth_drv_resume, .driver = { .name = CARDNAME, }, };
static int __init netx_eth_init(void) { unsigned int phy_control, val; printk("NetX Ethernet driver\n"); phy_control = PHY_CONTROL_PHY_ADDRESS(INTERNAL_PHY_ADR>>1) | PHY_CONTROL_PHY1_MODE(PHY_MODE_ALL) | PHY_CONTROL_PHY1_AUTOMDIX | PHY_CONTROL_PHY1_EN | PHY_CONTROL_PHY0_MODE(PHY_MODE_ALL) | PHY_CONTROL_PHY0_AUTOMDIX | PHY_CONTROL_PHY0_EN | PHY_CONTROL_CLK_XLATIN; val = readl(NETX_SYSTEM_IOC_ACCESS_KEY); writel(val, NETX_SYSTEM_IOC_ACCESS_KEY); writel(phy_control | PHY_CONTROL_RESET, NETX_SYSTEM_PHY_CONTROL); udelay(100); val = readl(NETX_SYSTEM_IOC_ACCESS_KEY); writel(val, NETX_SYSTEM_IOC_ACCESS_KEY); writel(phy_control, NETX_SYSTEM_PHY_CONTROL); return platform_driver_register(&netx_eth_driver); }

Contributors

PersonTokensPropCommitsCommitProp
Sascha Hauer105100.00%1100.00%
Total105100.00%1100.00%


static void __exit netx_eth_cleanup(void) { platform_driver_unregister(&netx_eth_driver); }

Contributors

PersonTokensPropCommitsCommitProp
Sascha Hauer15100.00%1100.00%
Total15100.00%1100.00%

module_init(netx_eth_init); module_exit(netx_eth_cleanup); MODULE_AUTHOR("Sascha Hauer, Pengutronix"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:" CARDNAME); MODULE_FIRMWARE("xc0.bin"); MODULE_FIRMWARE("xc1.bin"); MODULE_FIRMWARE("xc2.bin");

Overall Contributors

PersonTokensPropCommitsCommitProp
Sascha Hauer215794.44%15.26%
Alexander Beregalov451.97%15.26%
Harvey Hunt281.23%15.26%
Ben Hutchings150.66%15.26%
Uwe Kleine-König80.35%15.26%
Kay Sievers60.26%15.26%
Jingoo Han50.22%210.53%
Russell King40.18%15.26%
Alexey Dobriyan30.13%15.26%
Pradeep A. Dalvi30.13%15.26%
Adrian Bunk20.09%15.26%
David S. Miller20.09%15.26%
Arnd Bergmann10.04%15.26%
Harvey Harrison10.04%15.26%
Patrick McHardy10.04%15.26%
Jeff Kirsher10.04%15.26%
Jiri Pirko10.04%15.26%
Thomas Gleixner10.04%15.26%
Total2284100.00%19100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.