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

📄 ibm_emac_zmii.c

📁 linux-2.6.15.6
💻 C
字号:
/* * drivers/net/ibm_emac/ibm_emac_zmii.c * * Driver for PowerPC 4xx on-chip ethernet controller, ZMII bridge support. * * Copyright (c) 2004, 2005 Zultys Technologies. * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net> * * Based on original work by *      Armin Kuster <akuster@mvista.com> * 	Copyright 2001 MontaVista Softare Inc. * * 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. * */#include <linux/config.h>#include <linux/kernel.h>#include <linux/ethtool.h>#include <asm/io.h>#include "ibm_emac_core.h"#include "ibm_emac_debug.h"/* ZMIIx_FER */#define ZMII_FER_MDI(idx)	(0x80000000 >> ((idx) * 4))#define ZMII_FER_MDI_ALL	(ZMII_FER_MDI(0) | ZMII_FER_MDI(1) | \				 ZMII_FER_MDI(2) | ZMII_FER_MDI(3))#define ZMII_FER_SMII(idx)	(0x40000000 >> ((idx) * 4))#define ZMII_FER_RMII(idx)	(0x20000000 >> ((idx) * 4))#define ZMII_FER_MII(idx)	(0x10000000 >> ((idx) * 4))/* ZMIIx_SSR */#define ZMII_SSR_SCI(idx)	(0x40000000 >> ((idx) * 4))#define ZMII_SSR_FSS(idx)	(0x20000000 >> ((idx) * 4))#define ZMII_SSR_SP(idx)	(0x10000000 >> ((idx) * 4))/* ZMII only supports MII, RMII and SMII  * we also support autodetection for backward compatibility */static inline int zmii_valid_mode(int mode){	return  mode == PHY_MODE_MII ||		mode == PHY_MODE_RMII ||		mode == PHY_MODE_SMII ||		mode == PHY_MODE_NA;}static inline const char *zmii_mode_name(int mode){	switch (mode) {	case PHY_MODE_MII:		return "MII";	case PHY_MODE_RMII:		return "RMII";	case PHY_MODE_SMII:		return "SMII";	default:		BUG();	}}static inline u32 zmii_mode_mask(int mode, int input){	switch (mode) {	case PHY_MODE_MII:		return ZMII_FER_MII(input);	case PHY_MODE_RMII:		return ZMII_FER_RMII(input);	case PHY_MODE_SMII:		return ZMII_FER_SMII(input);	default:		return 0;	}}static int __init zmii_init(struct ocp_device *ocpdev, int input, int *mode){	struct ibm_ocp_zmii *dev = ocp_get_drvdata(ocpdev);	struct zmii_regs *p;	ZMII_DBG("%d: init(%d, %d)" NL, ocpdev->def->index, input, *mode);	if (!dev) {		dev = kzalloc(sizeof(struct ibm_ocp_zmii), GFP_KERNEL);		if (!dev) {			printk(KERN_ERR			       "zmii%d: couldn't allocate device structure!\n",			       ocpdev->def->index);			return -ENOMEM;		}		dev->mode = PHY_MODE_NA;		p = (struct zmii_regs *)ioremap(ocpdev->def->paddr,						sizeof(struct zmii_regs));		if (!p) {			printk(KERN_ERR			       "zmii%d: could not ioremap device registers!\n",			       ocpdev->def->index);			kfree(dev);			return -ENOMEM;		}		dev->base = p;		ocp_set_drvdata(ocpdev, dev);				/* We may need FER value for autodetection later */		dev->fer_save = in_be32(&p->fer);		/* Disable all inputs by default */		out_be32(&p->fer, 0);	} else		p = dev->base;	if (!zmii_valid_mode(*mode)) {		/* Probably an EMAC connected to RGMII, 		 * but it still may need ZMII for MDIO 		 */		goto out;	}	/* Autodetect ZMII mode if not specified.	 * This is only for backward compatibility with the old driver.	 * Please, always specify PHY mode in your board port to avoid	 * any surprises.	 */	if (dev->mode == PHY_MODE_NA) {		if (*mode == PHY_MODE_NA) {			u32 r = dev->fer_save;			ZMII_DBG("%d: autodetecting mode, FER = 0x%08x" NL,				 ocpdev->def->index, r);						if (r & (ZMII_FER_MII(0) | ZMII_FER_MII(1)))				dev->mode = PHY_MODE_MII;			else if (r & (ZMII_FER_RMII(0) | ZMII_FER_RMII(1)))				dev->mode = PHY_MODE_RMII;			else				dev->mode = PHY_MODE_SMII;		} else			dev->mode = *mode;		printk(KERN_NOTICE "zmii%d: bridge in %s mode\n",		       ocpdev->def->index, zmii_mode_name(dev->mode));	} else {		/* All inputs must use the same mode */		if (*mode != PHY_MODE_NA && *mode != dev->mode) {			printk(KERN_ERR			       "zmii%d: invalid mode %d specified for input %d\n",			       ocpdev->def->index, *mode, input);			return -EINVAL;		}	}	/* Report back correct PHY mode, 	 * it may be used during PHY initialization.	 */	*mode = dev->mode;	/* Enable this input */	out_be32(&p->fer, in_be32(&p->fer) | zmii_mode_mask(dev->mode, input));      out:	++dev->users;	return 0;}int __init zmii_attach(void *emac){	struct ocp_enet_private *dev = emac;	struct ocp_func_emac_data *emacdata = dev->def->additions;	if (emacdata->zmii_idx >= 0) {		dev->zmii_input = emacdata->zmii_mux;		dev->zmii_dev =		    ocp_find_device(OCP_VENDOR_IBM, OCP_FUNC_ZMII,				    emacdata->zmii_idx);		if (!dev->zmii_dev) {			printk(KERN_ERR "emac%d: unknown zmii%d!\n",			       dev->def->index, emacdata->zmii_idx);			return -ENODEV;		}		if (zmii_init		    (dev->zmii_dev, dev->zmii_input, &emacdata->phy_mode)) {			printk(KERN_ERR			       "emac%d: zmii%d initialization failed!\n",			       dev->def->index, emacdata->zmii_idx);			return -ENODEV;		}	}	return 0;}void __zmii_enable_mdio(struct ocp_device *ocpdev, int input){	struct ibm_ocp_zmii *dev = ocp_get_drvdata(ocpdev);	u32 fer = in_be32(&dev->base->fer) & ~ZMII_FER_MDI_ALL;	ZMII_DBG2("%d: mdio(%d)" NL, ocpdev->def->index, input);	out_be32(&dev->base->fer, fer | ZMII_FER_MDI(input));}void __zmii_set_speed(struct ocp_device *ocpdev, int input, int speed){	struct ibm_ocp_zmii *dev = ocp_get_drvdata(ocpdev);	u32 ssr = in_be32(&dev->base->ssr);	ZMII_DBG("%d: speed(%d, %d)" NL, ocpdev->def->index, input, speed);	if (speed == SPEED_100)		ssr |= ZMII_SSR_SP(input);	else		ssr &= ~ZMII_SSR_SP(input);	out_be32(&dev->base->ssr, ssr);}void __exit __zmii_fini(struct ocp_device *ocpdev, int input){	struct ibm_ocp_zmii *dev = ocp_get_drvdata(ocpdev);	BUG_ON(!dev || dev->users == 0);	ZMII_DBG("%d: fini(%d)" NL, ocpdev->def->index, input);	/* Disable this input */	out_be32(&dev->base->fer,		 in_be32(&dev->base->fer) & ~zmii_mode_mask(dev->mode, input));	if (!--dev->users) {		/* Free everything if this is the last user */		ocp_set_drvdata(ocpdev, NULL);		iounmap((void *)dev->base);		kfree(dev);	}}int __zmii_get_regs_len(struct ocp_device *ocpdev){	return sizeof(struct emac_ethtool_regs_subhdr) +	    sizeof(struct zmii_regs);}void *zmii_dump_regs(struct ocp_device *ocpdev, void *buf){	struct ibm_ocp_zmii *dev = ocp_get_drvdata(ocpdev);	struct emac_ethtool_regs_subhdr *hdr = buf;	struct zmii_regs *regs = (struct zmii_regs *)(hdr + 1);	hdr->version = 0;	hdr->index = ocpdev->def->index;	memcpy_fromio(regs, dev->base, sizeof(struct zmii_regs));	return regs + 1;}

⌨️ 快捷键说明

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