|  | /* | 
|  | * 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 <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 __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; | 
|  | } |