Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 976de6a8 authored by Scott Wood's avatar Scott Wood Committed by David S. Miller
Browse files

fs_enet: Be an of_platform device when CONFIG_PPC_CPM_NEW_BINDING is set.



The existing OF glue code was crufty and broken.  Rather than fix it, it
will be removed, and the ethernet driver now talks to the device tree
directly.

The old, non-CONFIG_PPC_CPM_NEW_BINDING code can go away once CPM
platforms are dropped from arch/ppc (which will hopefully be soon), and
existing arch/powerpc boards that I wasn't able to test on for this
patchset get converted (which should be even sooner).

Signed-off-by: default avatarScott Wood <scottwood@freescale.com>
Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
parent 0d0d9c15
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@ config FS_ENET_HAS_SCC
config FS_ENET_HAS_FCC
	bool "Chip has an FCC usable for ethernet"
	depends on FS_ENET && CPM2
	select MDIO_BITBANG
	default y

config FS_ENET_HAS_FEC
+241 −17
Original line number Diff line number Diff line
@@ -42,12 +42,18 @@
#include <asm/irq.h>
#include <asm/uaccess.h>

#ifdef CONFIG_PPC_CPM_NEW_BINDING
#include <asm/of_platform.h>
#endif

#include "fs_enet.h"

/*************************************************/

#ifndef CONFIG_PPC_CPM_NEW_BINDING
static char version[] __devinitdata =
    DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")" "\n";
#endif

MODULE_AUTHOR("Pantelis Antoniou <panto@intracom.gr>");
MODULE_DESCRIPTION("Freescale Ethernet Driver");
@@ -948,6 +954,7 @@ static int fs_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
extern int fs_mii_connect(struct net_device *dev);
extern void fs_mii_disconnect(struct net_device *dev);

#ifndef CONFIG_PPC_CPM_NEW_BINDING
static struct net_device *fs_init_instance(struct device *dev,
		struct fs_platform_info *fpi)
{
@@ -1129,6 +1136,7 @@ static int fs_cleanup_instance(struct net_device *ndev)

	return 0;
}
#endif

/**************************************************************************************/

@@ -1137,35 +1145,250 @@ void *fs_enet_immap = NULL;

static int setup_immap(void)
{
	phys_addr_t paddr = 0;
	unsigned long size = 0;

#ifdef CONFIG_CPM1
	paddr = IMAP_ADDR;
	size = 0x10000;	/* map 64K */
#endif

#ifdef CONFIG_CPM2
	paddr = CPM_MAP_ADDR;
	size = 0x40000;	/* map 256 K */
	fs_enet_immap = ioremap(IMAP_ADDR, 0x4000);
	WARN_ON(!fs_enet_immap);
#elif defined(CONFIG_CPM2)
	fs_enet_immap = cpm2_immr;
#endif
	fs_enet_immap = ioremap(paddr, size);
	if (fs_enet_immap == NULL)
		return -EBADF;	/* XXX ahem; maybe just BUG_ON? */

	return 0;
}

static void cleanup_immap(void)
{
	if (fs_enet_immap != NULL) {
#if defined(CONFIG_CPM1)
	iounmap(fs_enet_immap);
		fs_enet_immap = NULL;
	}
#endif
}

/**************************************************************************************/

#ifdef CONFIG_PPC_CPM_NEW_BINDING
static int __devinit find_phy(struct device_node *np,
                              struct fs_platform_info *fpi)
{
	struct device_node *phynode, *mdionode;
	struct resource res;
	int ret = 0, len;

	const u32 *data = of_get_property(np, "phy-handle", &len);
	if (!data || len != 4)
		return -EINVAL;

	phynode = of_find_node_by_phandle(*data);
	if (!phynode)
		return -EINVAL;

	mdionode = of_get_parent(phynode);
	if (!mdionode)
		goto out_put_phy;

	ret = of_address_to_resource(mdionode, 0, &res);
	if (ret)
		goto out_put_mdio;

	data = of_get_property(phynode, "reg", &len);
	if (!data || len != 4)
		goto out_put_mdio;

	snprintf(fpi->bus_id, 16, PHY_ID_FMT, res.start, *data);

out_put_mdio:
	of_node_put(mdionode);
out_put_phy:
	of_node_put(phynode);
	return ret;
}

#ifdef CONFIG_FS_ENET_HAS_FEC
#define IS_FEC(match) ((match)->data == &fs_fec_ops)
#else
#define IS_FEC(match) 0
#endif

static int __devinit fs_enet_probe(struct of_device *ofdev,
                                   const struct of_device_id *match)
{
	struct net_device *ndev;
	struct fs_enet_private *fep;
	struct fs_platform_info *fpi;
	const u32 *data;
	const u8 *mac_addr;
	int privsize, len, ret = -ENODEV;

	fpi = kzalloc(sizeof(*fpi), GFP_KERNEL);
	if (!fpi)
		return -ENOMEM;

	if (!IS_FEC(match)) {
		data = of_get_property(ofdev->node, "fsl,cpm-command", &len);
		if (!data || len != 4)
			goto out_free_fpi;

		fpi->cp_command = *data;
	}

	fpi->rx_ring = 32;
	fpi->tx_ring = 32;
	fpi->rx_copybreak = 240;
	fpi->use_napi = 0;
	fpi->napi_weight = 17;

	ret = find_phy(ofdev->node, fpi);
	if (ret)
		goto out_free_fpi;

	privsize = sizeof(*fep) +
	           sizeof(struct sk_buff **) *
	           (fpi->rx_ring + fpi->tx_ring);

	ndev = alloc_etherdev(privsize);
	if (!ndev) {
		ret = -ENOMEM;
		goto out_free_fpi;
	}

	SET_MODULE_OWNER(ndev);
	dev_set_drvdata(&ofdev->dev, ndev);

	fep = netdev_priv(ndev);
	fep->dev = &ofdev->dev;
	fep->fpi = fpi;
	fep->ops = match->data;

	ret = fep->ops->setup_data(ndev);
	if (ret)
		goto out_free_dev;

	fep->rx_skbuff = (struct sk_buff **)&fep[1];
	fep->tx_skbuff = fep->rx_skbuff + fpi->rx_ring;

	spin_lock_init(&fep->lock);
	spin_lock_init(&fep->tx_lock);

	mac_addr = of_get_mac_address(ofdev->node);
	if (mac_addr)
		memcpy(ndev->dev_addr, mac_addr, 6);

	ret = fep->ops->allocate_bd(ndev);
	if (ret)
		goto out_cleanup_data;

	fep->rx_bd_base = fep->ring_base;
	fep->tx_bd_base = fep->rx_bd_base + fpi->rx_ring;

	fep->tx_ring = fpi->tx_ring;
	fep->rx_ring = fpi->rx_ring;

	ndev->open = fs_enet_open;
	ndev->hard_start_xmit = fs_enet_start_xmit;
	ndev->tx_timeout = fs_timeout;
	ndev->watchdog_timeo = 2 * HZ;
	ndev->stop = fs_enet_close;
	ndev->get_stats = fs_enet_get_stats;
	ndev->set_multicast_list = fs_set_multicast_list;
	if (fpi->use_napi) {
		ndev->poll = fs_enet_rx_napi;
		ndev->weight = fpi->napi_weight;
	}
	ndev->ethtool_ops = &fs_ethtool_ops;
	ndev->do_ioctl = fs_ioctl;

	init_timer(&fep->phy_timer_list);

	netif_carrier_off(ndev);

	ret = register_netdev(ndev);
	if (ret)
		goto out_free_bd;

	printk(KERN_INFO "%s: fs_enet: %02x:%02x:%02x:%02x:%02x:%02x\n",
	       ndev->name,
	       ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2],
	       ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]);

	return 0;

out_free_bd:
	fep->ops->free_bd(ndev);
out_cleanup_data:
	fep->ops->cleanup_data(ndev);
out_free_dev:
	free_netdev(ndev);
	dev_set_drvdata(&ofdev->dev, NULL);
out_free_fpi:
	kfree(fpi);
	return ret;
}

static int fs_enet_remove(struct of_device *ofdev)
{
	struct net_device *ndev = dev_get_drvdata(&ofdev->dev);
	struct fs_enet_private *fep = netdev_priv(ndev);

	unregister_netdev(ndev);

	fep->ops->free_bd(ndev);
	fep->ops->cleanup_data(ndev);
	dev_set_drvdata(fep->dev, NULL);

	free_netdev(ndev);
	return 0;
}

static struct of_device_id fs_enet_match[] = {
#ifdef CONFIG_FS_ENET_HAS_SCC
	{
		.compatible = "fsl,cpm1-scc-enet",
		.data = (void *)&fs_scc_ops,
	},
#endif
#ifdef CONFIG_FS_ENET_HAS_FCC
	{
		.compatible = "fsl,cpm2-fcc-enet",
		.data = (void *)&fs_fcc_ops,
	},
#endif
#ifdef CONFIG_FS_ENET_HAS_FEC
	{
		.compatible = "fsl,pq1-fec-enet",
		.data = (void *)&fs_fec_ops,
	},
#endif
	{}
};

static struct of_platform_driver fs_enet_driver = {
	.name	= "fs_enet",
	.match_table = fs_enet_match,
	.probe = fs_enet_probe,
	.remove = fs_enet_remove,
};

static int __init fs_init(void)
{
	int r = setup_immap();
	if (r != 0)
		return r;

	r = of_register_platform_driver(&fs_enet_driver);
	if (r != 0)
		goto out;

	return 0;

out:
	cleanup_immap();
	return r;
}

static void __exit fs_cleanup(void)
{
	of_unregister_platform_driver(&fs_enet_driver);
	cleanup_immap();
}
#else
static int __devinit fs_enet_probe(struct device *dev)
{
	struct net_device *ndev;
@@ -1279,6 +1502,7 @@ static void __exit fs_cleanup(void)
	driver_unregister(&fs_enet_scc_driver);
	cleanup_immap();
}
#endif

#ifdef CONFIG_NET_POLL_CONTROLLER
static void fs_enet_netpoll(struct net_device *dev)
+3 −52
Original line number Diff line number Diff line
@@ -24,19 +24,6 @@ struct fec_info {
#include <asm/cpm2.h>
#endif

/* This is used to operate with pins.
  Note that the actual port size may
    be different; cpm(s) handle it OK  */
struct bb_info {
	u8 mdio_dat_msk;
	u8 mdio_dir_msk;
	u8 *mdio_dir;
	u8 *mdio_dat;
	u8 mdc_msk;
	u8 *mdc_dat;
	int delay;
};

/* hw driver ops */
struct fs_ops {
	int (*setup_data)(struct net_device *dev);
@@ -85,48 +72,12 @@ struct phy_info {
#define ENET_RX_ALIGN  16
#define ENET_RX_FRSIZE L1_CACHE_ALIGN(PKT_MAXBUF_SIZE + ENET_RX_ALIGN - 1)

struct fs_enet_mii_bus {
	struct list_head list;
	spinlock_t mii_lock;
	const struct fs_mii_bus_info *bus_info;
	int refs;
	u32 usage_map;

	int (*mii_read)(struct fs_enet_mii_bus *bus,
			int phy_id, int location);

	void (*mii_write)(struct fs_enet_mii_bus *bus,
			int phy_id, int location, int value);

	union {
		struct {
			unsigned int mii_speed;
			void *fecp;
		} fec;

		struct {
			/* note that the actual port size may */
			/* be different; cpm(s) handle it OK  */
			u8 mdio_msk;
			u8 *mdio_dir;
			u8 *mdio_dat;
			u8 mdc_msk;
			u8 *mdc_dir;
			u8 *mdc_dat;
		} bitbang;

		struct {
			u16 lpa;
		} fixed;
	};
};

struct fs_enet_private {
	struct napi_struct napi;
	struct device *dev;	/* pointer back to the device (must be initialized first) */
	spinlock_t lock;	/* during all ops except TX pckt processing */
	spinlock_t tx_lock;	/* during fs_start_xmit and fs_tx         */
	const struct fs_platform_info *fpi;
	struct fs_platform_info *fpi;
	const struct fs_ops *ops;
	int rx_ring, tx_ring;
	dma_addr_t ring_mem_addr;
@@ -145,7 +96,6 @@ struct fs_enet_private {
	u32 msg_enable;
	struct mii_if_info mii_if;
	unsigned int last_mii_status;
	struct fs_enet_mii_bus *mii_bus;
	int interrupt;

	struct phy_device *phydev;
@@ -187,9 +137,10 @@ struct fs_enet_private {
};

/***************************************************************************/
#ifndef CONFIG_PPC_CPM_NEW_BINDING
int fs_enet_mdio_bb_init(void);
int fs_mii_fixed_init(struct fs_enet_mii_bus *bus);
int fs_enet_mdio_fec_init(void);
#endif

void fs_init_bds(struct net_device *dev);
void fs_cleanup_bds(struct net_device *dev);
+65 −24
Original line number Diff line number Diff line
@@ -42,6 +42,10 @@
#include <asm/irq.h>
#include <asm/uaccess.h>

#ifdef CONFIG_PPC_CPM_NEW_BINDING
#include <asm/of_device.h>
#endif

#include "fs_enet.h"

/*************************************************/
@@ -74,33 +78,64 @@

#define MAX_CR_CMD_LOOPS	10000

static inline int fcc_cr_cmd(struct fs_enet_private *fep, u32 mcn, u32 op)
static inline int fcc_cr_cmd(struct fs_enet_private *fep, u32 op)
{
	const struct fs_platform_info *fpi = fep->fpi;
	cpm2_map_t *immap = fs_enet_immap;
	cpm_cpm2_t *cpmp = &immap->im_cpm;
	u32 v;
	int i;

	/* Currently I don't know what feature call will look like. But
	   I guess there'd be something like do_cpm_cmd() which will require page & sblock */
	v = mk_cr_cmd(fpi->cp_page, fpi->cp_block, mcn, op);
	W32(cpmp, cp_cpcr, v | CPM_CR_FLG);
	W32(cpmp, cp_cpcr, fpi->cp_command | op | CPM_CR_FLG);
	for (i = 0; i < MAX_CR_CMD_LOOPS; i++)
		if ((R32(cpmp, cp_cpcr) & CPM_CR_FLG) == 0)
			break;
			return 0;

	if (i >= MAX_CR_CMD_LOOPS) {
	printk(KERN_ERR "%s(): Not able to issue CPM command\n",
	       __FUNCTION__);
	return 1;
}

	return 0;
}

static int do_pd_setup(struct fs_enet_private *fep)
{
#ifdef CONFIG_PPC_CPM_NEW_BINDING
	struct of_device *ofdev = to_of_device(fep->dev);
	struct fs_platform_info *fpi = fep->fpi;
	int ret = -EINVAL;

	fep->interrupt = of_irq_to_resource(ofdev->node, 0, NULL);
	if (fep->interrupt == NO_IRQ)
		goto out;

	fep->fcc.fccp = of_iomap(ofdev->node, 0);
	if (!fep->fcc.fccp)
		goto out;

	fep->fcc.ep = of_iomap(ofdev->node, 1);
	if (!fep->fcc.ep)
		goto out_fccp;

	fep->fcc.fcccp = of_iomap(ofdev->node, 2);
	if (!fep->fcc.fcccp)
		goto out_ep;

	fep->fcc.mem = (void *)cpm_dpalloc(128, 8);
	fpi->dpram_offset = (u32)cpm2_immr;
	if (IS_ERR_VALUE(fpi->dpram_offset)) {
		ret = fpi->dpram_offset;
		goto out_fcccp;
	}

	return 0;

out_fcccp:
	iounmap(fep->fcc.fcccp);
out_ep:
	iounmap(fep->fcc.ep);
out_fccp:
	iounmap(fep->fcc.fccp);
out:
	return ret;
#else
	struct platform_device *pdev = to_platform_device(fep->dev);
	struct resource *r;

@@ -138,6 +173,7 @@ static int do_pd_setup(struct fs_enet_private *fep)
		return -EINVAL;

	return 0;
#endif
}

#define FCC_NAPI_RX_EVENT_MSK	(FCC_ENET_RXF | FCC_ENET_RXB)
@@ -148,11 +184,17 @@ static int do_pd_setup(struct fs_enet_private *fep)
static int setup_data(struct net_device *dev)
{
	struct fs_enet_private *fep = netdev_priv(dev);
	const struct fs_platform_info *fpi = fep->fpi;
#ifndef CONFIG_PPC_CPM_NEW_BINDING
	struct fs_platform_info *fpi = fep->fpi;

	fpi->cp_command = (fpi->cp_page << 26) |
	                  (fpi->cp_block << 21) |
	                  (12 << 6);

	fep->fcc.idx = fs_get_fcc_index(fpi->fs_no);
	if ((unsigned int)fep->fcc.idx >= 3)	/* max 3 FCCs */
		return -EINVAL;
#endif

	if (do_pd_setup(fep) != 0)
		return -EINVAL;
@@ -226,7 +268,7 @@ static void set_multicast_one(struct net_device *dev, const u8 *mac)
	W16(ep, fen_taddrh, taddrh);
	W16(ep, fen_taddrm, taddrm);
	W16(ep, fen_taddrl, taddrl);
	fcc_cr_cmd(fep, 0x0C, CPM_CR_SET_GADDR);
	fcc_cr_cmd(fep, CPM_CR_SET_GADDR);
}

static void set_multicast_finish(struct net_device *dev)
@@ -281,7 +323,7 @@ static void restart(struct net_device *dev)

	/* clear everything (slow & steady does it) */
	for (i = 0; i < sizeof(*ep); i++)
		out_8((char *)ep + i, 0);
		out_8((u8 __iomem *)ep + i, 0);

	/* get physical address */
	rx_bd_base_phys = fep->ring_mem_addr;
@@ -397,7 +439,7 @@ static void restart(struct net_device *dev)
			S8(fcccp, fcc_gfemr, 0x20);
	}

	fcc_cr_cmd(fep, 0x0c, CPM_CR_INIT_TRX);
	fcc_cr_cmd(fep, CPM_CR_INIT_TRX);

	/* clear events */
	W16(fccp, fcc_fcce, 0xffff);
@@ -515,23 +557,22 @@ int get_regs(struct net_device *dev, void *p, int *sizep)
{
	struct fs_enet_private *fep = netdev_priv(dev);

	if (*sizep < sizeof(fcc_t) + sizeof(fcc_c_t) + sizeof(fcc_enet_t))
	if (*sizep < sizeof(fcc_t) + sizeof(fcc_enet_t) + 1)
		return -EINVAL;

	memcpy_fromio(p, fep->fcc.fccp, sizeof(fcc_t));
	p = (char *)p + sizeof(fcc_t);

	memcpy_fromio(p, fep->fcc.fcccp, sizeof(fcc_c_t));
	p = (char *)p + sizeof(fcc_c_t);

	memcpy_fromio(p, fep->fcc.ep, sizeof(fcc_enet_t));
	p = (char *)p + sizeof(fcc_enet_t);

	memcpy_fromio(p, fep->fcc.fcccp, 1);
	return 0;
}

int get_regs_len(struct net_device *dev)
{
	return sizeof(fcc_t) + sizeof(fcc_c_t) + sizeof(fcc_enet_t);
	return sizeof(fcc_t) + sizeof(fcc_enet_t) + 1;
}

/* Some transmit errors cause the transmitter to shut
@@ -551,7 +592,7 @@ void tx_restart(struct net_device *dev)
	udelay(10);
	S32(fccp, fcc_gfmr, FCC_GFMR_ENT);

	fcc_cr_cmd(fep, 0x0C, CPM_CR_RESTART_TX);
	fcc_cr_cmd(fep, CPM_CR_RESTART_TX);
}

/*************************************************************************/
+18 −1
Original line number Diff line number Diff line
@@ -43,6 +43,10 @@
#include <asm/commproc.h>
#endif

#ifdef CONFIG_PPC_CPM_NEW_BINDING
#include <asm/of_device.h>
#endif

#include "fs_enet.h"
#include "fec.h"

@@ -95,6 +99,19 @@ static int whack_reset(fec_t * fecp)

static int do_pd_setup(struct fs_enet_private *fep)
{
#ifdef CONFIG_PPC_CPM_NEW_BINDING
	struct of_device *ofdev = to_of_device(fep->dev);

	fep->interrupt = of_irq_to_resource(ofdev->node, 0, NULL);
	if (fep->interrupt == NO_IRQ)
		return -EINVAL;

	fep->fec.fecp = of_iomap(ofdev->node, 0);
	if (!fep->fcc.fccp)
		return -EINVAL;

	return 0;
#else
	struct platform_device *pdev = to_platform_device(fep->dev);
	struct resource	*r;

@@ -110,7 +127,7 @@ static int do_pd_setup(struct fs_enet_private *fep)
		return -EINVAL;

	return 0;

#endif
}

#define FEC_NAPI_RX_EVENT_MSK	(FEC_ENET_RXF | FEC_ENET_RXB)
Loading