⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ibm_emac_core.c

📁 h内核
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * ibm_emac_core.c * * Ethernet driver for the built in ethernet on the IBM 4xx PowerPC * processors. *  * (c) 2003 Benjamin Herrenschmidt <benh@kernel.crashing.org> * * Based on original work by * *      Armin Kuster <akuster@mvista.com> * 	Johnnie Peters <jpeters@mvista.com> * * This program is free software; you can redistribute  it and/or modify it * under  the terms of  the GNU General  Public License as published by the * Free Software Foundation;  either version 2 of the  License, or (at your * option) any later version. * TODO *       - Check for races in the "remove" code path *       - Add some Power Management to the MAC and the PHY *       - Audit remaining of non-rewritten code (--BenH) *       - Cleanup message display using msglevel mecanism *       - Address all errata *       - Audit all register update paths to ensure they *         are being written post soft reset if required. */#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/string.h>#include <linux/timer.h>#include <linux/ptrace.h>#include <linux/errno.h>#include <linux/ioport.h>#include <linux/slab.h>#include <linux/interrupt.h>#include <linux/delay.h>#include <linux/init.h>#include <linux/types.h>#include <linux/dma-mapping.h>#include <linux/ethtool.h>#include <linux/mii.h>#include <linux/bitops.h>#include <asm/processor.h>#include <asm/io.h>#include <asm/dma.h>#include <asm/irq.h>#include <asm/uaccess.h>#include <asm/ocp.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <linux/crc32.h>#include "ibm_emac_core.h"//#define MDIO_DEBUG(fmt) printk fmt#define MDIO_DEBUG(fmt)//#define LINK_DEBUG(fmt) printk fmt#define LINK_DEBUG(fmt)//#define PKT_DEBUG(fmt) printk fmt#define PKT_DEBUG(fmt)#define DRV_NAME        "emac"#define DRV_VERSION     "2.0"#define DRV_AUTHOR      "Benjamin Herrenschmidt <benh@kernel.crashing.org>"#define DRV_DESC        "IBM EMAC Ethernet driver"/* * When mdio_idx >= 0, contains a list of emac ocp_devs * that have had their initialization deferred until the * common MDIO controller has been initialized. */LIST_HEAD(emac_init_list);MODULE_AUTHOR(DRV_AUTHOR);MODULE_DESCRIPTION(DRV_DESC);MODULE_LICENSE("GPL");static int skb_res = SKB_RES;module_param(skb_res, int, 0444);MODULE_PARM_DESC(skb_res, "Amount of data to reserve on skb buffs\n"		 "The 405 handles a misaligned IP header fine but\n"		 "this can help if you are routing to a tunnel or a\n"		 "device that needs aligned data. 0..2");#define RGMII_PRIV(ocpdev) ((struct ibm_ocp_rgmii*)ocp_get_drvdata(ocpdev))static unsigned int rgmii_enable[] = {	RGMII_RTBI,	RGMII_RGMII,	RGMII_TBI,	RGMII_GMII};static unsigned int rgmii_speed_mask[] = {	RGMII_MII2_SPDMASK,	RGMII_MII3_SPDMASK};static unsigned int rgmii_speed100[] = {	RGMII_MII2_100MB,	RGMII_MII3_100MB};static unsigned int rgmii_speed1000[] = {	RGMII_MII2_1000MB,	RGMII_MII3_1000MB};#define ZMII_PRIV(ocpdev) ((struct ibm_ocp_zmii*)ocp_get_drvdata(ocpdev))static unsigned int zmii_enable[][4] = {	{ZMII_SMII0, ZMII_RMII0, ZMII_MII0,	 ~(ZMII_MDI1 | ZMII_MDI2 | ZMII_MDI3)},	{ZMII_SMII1, ZMII_RMII1, ZMII_MII1,	 ~(ZMII_MDI0 | ZMII_MDI2 | ZMII_MDI3)},	{ZMII_SMII2, ZMII_RMII2, ZMII_MII2,	 ~(ZMII_MDI0 | ZMII_MDI1 | ZMII_MDI3)},	{ZMII_SMII3, ZMII_RMII3, ZMII_MII3, ~(ZMII_MDI0 | ZMII_MDI1 | ZMII_MDI2)}};static unsigned int mdi_enable[] = {	ZMII_MDI0,	ZMII_MDI1,	ZMII_MDI2,	ZMII_MDI3};static unsigned int zmii_speed = 0x0;static unsigned int zmii_speed100[] = {	ZMII_MII0_100MB,	ZMII_MII1_100MB,	ZMII_MII2_100MB,	ZMII_MII3_100MB};/* Since multiple EMACs share MDIO lines in various ways, we need * to avoid re-using the same PHY ID in cases where the arch didn't * setup precise phy_map entries */static u32 busy_phy_map = 0;/* If EMACs share a common MDIO device, this points to it */static struct net_device *mdio_ndev = NULL;struct emac_def_dev {	struct list_head link;	struct ocp_device *ocpdev;	struct ibm_ocp_mal *mal;};static struct net_device_stats *emac_stats(struct net_device *dev){	struct ocp_enet_private *fep = dev->priv;	return &fep->stats;};static intemac_init_rgmii(struct ocp_device *rgmii_dev, int input, int phy_mode){	struct ibm_ocp_rgmii *rgmii = RGMII_PRIV(rgmii_dev);	const char *mode_name[] = { "RTBI", "RGMII", "TBI", "GMII" };	int mode = -1;	if (!rgmii) {		rgmii = kmalloc(sizeof(struct ibm_ocp_rgmii), GFP_KERNEL);		if (rgmii == NULL) {			printk(KERN_ERR			       "rgmii%d: Out of memory allocating RGMII structure!\n",			       rgmii_dev->def->index);			return -ENOMEM;		}		memset(rgmii, 0, sizeof(*rgmii));		rgmii->base =		    (struct rgmii_regs *)ioremap(rgmii_dev->def->paddr,						 sizeof(*rgmii->base));		if (rgmii->base == NULL) {			printk(KERN_ERR			       "rgmii%d: Cannot ioremap bridge registers!\n",			       rgmii_dev->def->index);			kfree(rgmii);			return -ENOMEM;		}		ocp_set_drvdata(rgmii_dev, rgmii);	}	if (phy_mode) {		switch (phy_mode) {		case PHY_MODE_GMII:			mode = GMII;			break;		case PHY_MODE_TBI:			mode = TBI;			break;		case PHY_MODE_RTBI:			mode = RTBI;			break;		case PHY_MODE_RGMII:		default:			mode = RGMII;		}		rgmii->base->fer &= ~RGMII_FER_MASK(input);		rgmii->base->fer |= rgmii_enable[mode] << (4 * input);	} else {		switch ((rgmii->base->fer & RGMII_FER_MASK(input)) >> (4 *								       input)) {		case RGMII_RTBI:			mode = RTBI;			break;		case RGMII_RGMII:			mode = RGMII;			break;		case RGMII_TBI:			mode = TBI;			break;		case RGMII_GMII:			mode = GMII;		}	}	/* Set mode to RGMII if nothing valid is detected */	if (mode < 0)		mode = RGMII;	printk(KERN_NOTICE "rgmii%d: input %d in %s mode\n",	       rgmii_dev->def->index, input, mode_name[mode]);	rgmii->mode[input] = mode;	rgmii->users++;	return 0;}static voidemac_rgmii_port_speed(struct ocp_device *ocpdev, int input, int speed){	struct ibm_ocp_rgmii *rgmii = RGMII_PRIV(ocpdev);	unsigned int rgmii_speed;	rgmii_speed = in_be32(&rgmii->base->ssr);	rgmii_speed &= ~rgmii_speed_mask[input];	if (speed == 1000)		rgmii_speed |= rgmii_speed1000[input];	else if (speed == 100)		rgmii_speed |= rgmii_speed100[input];	out_be32(&rgmii->base->ssr, rgmii_speed);}static void emac_close_rgmii(struct ocp_device *ocpdev){	struct ibm_ocp_rgmii *rgmii = RGMII_PRIV(ocpdev);	BUG_ON(!rgmii || rgmii->users == 0);	if (!--rgmii->users) {		ocp_set_drvdata(ocpdev, NULL);		iounmap((void *)rgmii->base);		kfree(rgmii);	}}static int emac_init_zmii(struct ocp_device *zmii_dev, int input, int phy_mode){	struct ibm_ocp_zmii *zmii = ZMII_PRIV(zmii_dev);	const char *mode_name[] = { "SMII", "RMII", "MII" };	int mode = -1;	if (!zmii) {		zmii = kmalloc(sizeof(struct ibm_ocp_zmii), GFP_KERNEL);		if (zmii == NULL) {			printk(KERN_ERR			       "zmii%d: Out of memory allocating ZMII structure!\n",			       zmii_dev->def->index);			return -ENOMEM;		}		memset(zmii, 0, sizeof(*zmii));		zmii->base =		    (struct zmii_regs *)ioremap(zmii_dev->def->paddr,						sizeof(*zmii->base));		if (zmii->base == NULL) {			printk(KERN_ERR			       "zmii%d: Cannot ioremap bridge registers!\n",			       zmii_dev->def->index);			kfree(zmii);			return -ENOMEM;		}		ocp_set_drvdata(zmii_dev, zmii);	}	if (phy_mode) {		switch (phy_mode) {		case PHY_MODE_MII:			mode = MII;			break;		case PHY_MODE_RMII:			mode = RMII;			break;		case PHY_MODE_SMII:		default:			mode = SMII;		}		zmii->base->fer &= ~ZMII_FER_MASK(input);		zmii->base->fer |= zmii_enable[input][mode];	} else {		switch ((zmii->base->fer & ZMII_FER_MASK(input)) << (4 * input)) {		case ZMII_MII0:			mode = MII;			break;		case ZMII_RMII0:			mode = RMII;			break;		case ZMII_SMII0:			mode = SMII;		}	}	/* Set mode to SMII if nothing valid is detected */	if (mode < 0)		mode = SMII;	printk(KERN_NOTICE "zmii%d: input %d in %s mode\n",	       zmii_dev->def->index, input, mode_name[mode]);	zmii->mode[input] = mode;	zmii->users++;	return 0;}static void emac_enable_zmii_port(struct ocp_device *ocpdev, int input){	u32 mask;	struct ibm_ocp_zmii *zmii = ZMII_PRIV(ocpdev);	mask = in_be32(&zmii->base->fer);	mask &= zmii_enable[input][MDI];	/* turn all non enabled MDI's off */	mask |= zmii_enable[input][zmii->mode[input]] | mdi_enable[input];	out_be32(&zmii->base->fer, mask);}static voidemac_zmii_port_speed(struct ocp_device *ocpdev, int input, int speed){	struct ibm_ocp_zmii *zmii = ZMII_PRIV(ocpdev);	if (speed == 100)		zmii_speed |= zmii_speed100[input];	else		zmii_speed &= ~zmii_speed100[input];	out_be32(&zmii->base->ssr, zmii_speed);}static void emac_close_zmii(struct ocp_device *ocpdev){	struct ibm_ocp_zmii *zmii = ZMII_PRIV(ocpdev);	BUG_ON(!zmii || zmii->users == 0);	if (!--zmii->users) {		ocp_set_drvdata(ocpdev, NULL);		iounmap((void *)zmii->base);		kfree(zmii);	}}int emac_phy_read(struct net_device *dev, int mii_id, int reg){	int count;	uint32_t stacr;	struct ocp_enet_private *fep = dev->priv;	emac_t *emacp = fep->emacp;	MDIO_DEBUG(("%s: phy_read, id: 0x%x, reg: 0x%x\n", dev->name, mii_id,		    reg));	/* Enable proper ZMII port */	if (fep->zmii_dev)		emac_enable_zmii_port(fep->zmii_dev, fep->zmii_input);	/* Use the EMAC that has the MDIO port */	if (fep->mdio_dev) {		dev = fep->mdio_dev;		fep = dev->priv;		emacp = fep->emacp;	}	count = 0;	while ((((stacr = in_be32(&emacp->em0stacr)) & EMAC_STACR_OC) == 0)					&& (count++ < MDIO_DELAY))		udelay(1);	MDIO_DEBUG((" (count was %d)\n", count));	if ((stacr & EMAC_STACR_OC) == 0) {		printk(KERN_WARNING "%s: PHY read timeout #1!\n", dev->name);		return -1;	}	/* Clear the speed bits and make a read request to the PHY */	stacr = ((EMAC_STACR_READ | (reg & 0x1f)) & ~EMAC_STACR_CLK_100MHZ);	stacr |= ((mii_id & 0x1F) << 5);	out_be32(&emacp->em0stacr, stacr);	count = 0;	while ((((stacr = in_be32(&emacp->em0stacr)) & EMAC_STACR_OC) == 0)					&& (count++ < MDIO_DELAY))		udelay(1);	MDIO_DEBUG((" (count was %d)\n", count));	if ((stacr & EMAC_STACR_OC) == 0) {		printk(KERN_WARNING "%s: PHY read timeout #2!\n", dev->name);		return -1;	}	/* Check for a read error */	if (stacr & EMAC_STACR_PHYE) {		MDIO_DEBUG(("EMAC MDIO PHY error !\n"));		return -1;	}	MDIO_DEBUG((" -> 0x%x\n", stacr >> 16));	return (stacr >> 16);}void emac_phy_write(struct net_device *dev, int mii_id, int reg, int data){	int count;	uint32_t stacr;	struct ocp_enet_private *fep = dev->priv;	emac_t *emacp = fep->emacp;	MDIO_DEBUG(("%s phy_write, id: 0x%x, reg: 0x%x, data: 0x%x\n",		    dev->name, mii_id, reg, data));	/* Enable proper ZMII port */	if (fep->zmii_dev)		emac_enable_zmii_port(fep->zmii_dev, fep->zmii_input);	/* Use the EMAC that has the MDIO port */	if (fep->mdio_dev) {		dev = fep->mdio_dev;		fep = dev->priv;		emacp = fep->emacp;	}	count = 0;	while ((((stacr = in_be32(&emacp->em0stacr)) & EMAC_STACR_OC) == 0)					&& (count++ < MDIO_DELAY))		udelay(1);	MDIO_DEBUG((" (count was %d)\n", count));	if ((stacr & EMAC_STACR_OC) == 0) {		printk(KERN_WARNING "%s: PHY write timeout #2!\n", dev->name);		return;	}	/* Clear the speed bits and make a read request to the PHY */	stacr = ((EMAC_STACR_WRITE | (reg & 0x1f)) & ~EMAC_STACR_CLK_100MHZ);	stacr |= ((mii_id & 0x1f) << 5) | ((data & 0xffff) << 16);	out_be32(&emacp->em0stacr, stacr);	count = 0;	while ((((stacr = in_be32(&emacp->em0stacr)) & EMAC_STACR_OC) == 0)					&& (count++ < MDIO_DELAY))		udelay(1);	MDIO_DEBUG((" (count was %d)\n", count));	if ((stacr & EMAC_STACR_OC) == 0)		printk(KERN_WARNING "%s: PHY write timeout #2!\n", dev->name);	/* Check for a write error */	if ((stacr & EMAC_STACR_PHYE) != 0) {		MDIO_DEBUG(("EMAC MDIO PHY error !\n"));	}}static void emac_txeob_dev(void *param, u32 chanmask){	struct net_device *dev = param;	struct ocp_enet_private *fep = dev->priv;	unsigned long flags;	spin_lock_irqsave(&fep->lock, flags);	PKT_DEBUG(("emac_txeob_dev() entry, tx_cnt: %d\n", fep->tx_cnt));

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -