linux/drivers/net/ibm_emac/ibm_emac_tah.c
Eugene Surovegin 37448f7d39 [PATCH] New PowerPC 4xx on-chip ethernet controller driver
This patch replaces current PowerPC 4xx EMAC driver with
new, re-written from the scratch version. This patch is quite big
(~234K) because there is virtualy 0% of common code between old and
new version.

New driver uses NAPI, it solves stability problems under heavy packet
load and low memory, corrects chip register access and fixes numerous
small bugs I don't even remember now.

This patch has been tested on all supported in 2.6 PPC 4xx boards.
It's been used in production for almost a year now on custom
4xx hardware. PPC32 specific parts are already upstream.

Patch was acked by the current EMAC driver maintainer (Matt Porter). I
will be maintaining this new version.

Signed-off-by: Eugene Surovegin <ebs@ebshome.net>
--

 Kconfig                   |   72
 ibm_emac/Makefile         |   13
 ibm_emac/ibm_emac.h       |  418 +++--
 ibm_emac/ibm_emac_core.c  | 3414 ++++++++++++++++++++++++----------------------
 ibm_emac/ibm_emac_core.h  |  313 ++--
 ibm_emac/ibm_emac_debug.c |  377 ++---
 ibm_emac/ibm_emac_debug.h |   63
 ibm_emac/ibm_emac_mal.c   |  674 +++++----
 ibm_emac/ibm_emac_mal.h   |  336 +++-
 ibm_emac/ibm_emac_phy.c   |  335 ++--
 ibm_emac/ibm_emac_phy.h   |  105 -
 ibm_emac/ibm_emac_rgmii.c |  201 ++
 ibm_emac/ibm_emac_rgmii.h |   68
 ibm_emac/ibm_emac_tah.c   |  111 +
 ibm_emac/ibm_emac_tah.h   |   96 -
 ibm_emac/ibm_emac_zmii.c  |  255 +++
 ibm_emac/ibm_emac_zmii.h  |  114 -
 17 files changed, 4114 insertions(+), 2851 deletions(-)
Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
2005-10-28 16:42:01 -04:00

111 lines
2.8 KiB
C

/*
* drivers/net/ibm_emac/ibm_emac_tah.c
*
* Driver for PowerPC 4xx on-chip ethernet controller, TAH support.
*
* Copyright 2004 MontaVista Software, Inc.
* Matt Porter <mporter@kernel.crashing.org>
*
* Copyright (c) 2005 Eugene Surovegin <ebs@ebshome.net>
*
* 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 <asm/io.h>
#include "ibm_emac_core.h"
static int __init tah_init(struct ocp_device *ocpdev)
{
struct tah_regs *p;
if (ocp_get_drvdata(ocpdev)) {
printk(KERN_ERR "tah%d: already in use!\n", ocpdev->def->index);
return -EBUSY;
}
/* Initialize TAH and enable IPv4 checksum verification, no TSO yet */
p = (struct tah_regs *)ioremap(ocpdev->def->paddr, sizeof(*p));
if (!p) {
printk(KERN_ERR "tah%d: could not ioremap device registers!\n",
ocpdev->def->index);
return -ENOMEM;
}
ocp_set_drvdata(ocpdev, p);
__tah_reset(ocpdev);
return 0;
}
int __init tah_attach(void *emac)
{
struct ocp_enet_private *dev = emac;
struct ocp_func_emac_data *emacdata = dev->def->additions;
/* Check if we need to attach to a TAH */
if (emacdata->tah_idx >= 0) {
dev->tah_dev = ocp_find_device(OCP_ANY_ID, OCP_FUNC_TAH,
emacdata->tah_idx);
if (!dev->tah_dev) {
printk(KERN_ERR "emac%d: unknown tah%d!\n",
dev->def->index, emacdata->tah_idx);
return -ENODEV;
}
if (tah_init(dev->tah_dev)) {
printk(KERN_ERR
"emac%d: tah%d initialization failed!\n",
dev->def->index, emacdata->tah_idx);
return -ENODEV;
}
}
return 0;
}
void __exit __tah_fini(struct ocp_device *ocpdev)
{
struct tah_regs *p = ocp_get_drvdata(ocpdev);
BUG_ON(!p);
ocp_set_drvdata(ocpdev, NULL);
iounmap((void *)p);
}
void __tah_reset(struct ocp_device *ocpdev)
{
struct tah_regs *p = ocp_get_drvdata(ocpdev);
int n;
/* Reset TAH */
out_be32(&p->mr, TAH_MR_SR);
n = 100;
while ((in_be32(&p->mr) & TAH_MR_SR) && n)
--n;
if (unlikely(!n))
printk(KERN_ERR "tah%d: reset timeout\n", ocpdev->def->index);
/* 10KB TAH TX FIFO accomodates the max MTU of 9000 */
out_be32(&p->mr,
TAH_MR_CVR | TAH_MR_ST_768 | TAH_MR_TFS_10KB | TAH_MR_DTFP |
TAH_MR_DIG);
}
int __tah_get_regs_len(struct ocp_device *ocpdev)
{
return sizeof(struct emac_ethtool_regs_subhdr) +
sizeof(struct tah_regs);
}
void *tah_dump_regs(struct ocp_device *ocpdev, void *buf)
{
struct tah_regs *dev = ocp_get_drvdata(ocpdev);
struct emac_ethtool_regs_subhdr *hdr = buf;
struct tah_regs *regs = (struct tah_regs *)(hdr + 1);
hdr->version = 0;
hdr->index = ocpdev->def->index;
memcpy_fromio(regs, dev, sizeof(struct tah_regs));
return regs + 1;
}