cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

orinoco_nortel.c (8454B)


      1/* orinoco_nortel.c
      2 *
      3 * Driver for Prism II devices which would usually be driven by orinoco_cs,
      4 * but are connected to the PCI bus by a PCI-to-PCMCIA adapter used in
      5 * Nortel emobility, Symbol LA-4113 and Symbol LA-4123.
      6 *
      7 * Copyright (C) 2002 Tobias Hoffmann
      8 *           (C) 2003 Christoph Jungegger <disdos@traum404.de>
      9 *
     10 * Some of this code is borrowed from orinoco_plx.c
     11 *	Copyright (C) 2001 Daniel Barlow
     12 * Some of this code is borrowed from orinoco_pci.c
     13 *  Copyright (C) 2001 Jean Tourrilhes
     14 * Some of this code is "inspired" by linux-wlan-ng-0.1.10, but nothing
     15 * has been copied from it. linux-wlan-ng-0.1.10 is originally :
     16 *	Copyright (C) 1999 AbsoluteValue Systems, Inc.  All Rights Reserved.
     17 *
     18 * The contents of this file are subject to the Mozilla Public License
     19 * Version 1.1 (the "License"); you may not use this file except in
     20 * compliance with the License. You may obtain a copy of the License
     21 * at http://www.mozilla.org/MPL/
     22 *
     23 * Software distributed under the License is distributed on an "AS IS"
     24 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
     25 * the License for the specific language governing rights and
     26 * limitations under the License.
     27 *
     28 * Alternatively, the contents of this file may be used under the
     29 * terms of the GNU General Public License version 2 (the "GPL"), in
     30 * which case the provisions of the GPL are applicable instead of the
     31 * above.  If you wish to allow the use of your version of this file
     32 * only under the terms of the GPL and not to allow others to use your
     33 * version of this file under the MPL, indicate your decision by
     34 * deleting the provisions above and replace them with the notice and
     35 * other provisions required by the GPL.  If you do not delete the
     36 * provisions above, a recipient may use your version of this file
     37 * under either the MPL or the GPL.
     38 */
     39
     40#define DRIVER_NAME "orinoco_nortel"
     41#define PFX DRIVER_NAME ": "
     42
     43#include <linux/module.h>
     44#include <linux/kernel.h>
     45#include <linux/init.h>
     46#include <linux/delay.h>
     47#include <linux/pci.h>
     48#include <pcmcia/cisreg.h>
     49
     50#include "orinoco.h"
     51#include "orinoco_pci.h"
     52
     53#define COR_OFFSET    (0xe0)	/* COR attribute offset of Prism2 PC card */
     54#define COR_VALUE     (COR_LEVEL_REQ | COR_FUNC_ENA)	/* Enable PC card with interrupt in level trigger */
     55
     56
     57/*
     58 * Do a soft reset of the card using the Configuration Option Register
     59 * We need this to get going...
     60 * This is the part of the code that is strongly inspired from wlan-ng
     61 *
     62 * Note bis : Don't try to access HERMES_CMD during the reset phase.
     63 * It just won't work !
     64 */
     65static int orinoco_nortel_cor_reset(struct orinoco_private *priv)
     66{
     67	struct orinoco_pci_card *card = priv->card;
     68
     69	/* Assert the reset until the card notices */
     70	iowrite16(8, card->bridge_io + 2);
     71	ioread16(card->attr_io + COR_OFFSET);
     72	iowrite16(0x80, card->attr_io + COR_OFFSET);
     73	mdelay(1);
     74
     75	/* Give time for the card to recover from this hard effort */
     76	iowrite16(0, card->attr_io + COR_OFFSET);
     77	iowrite16(0, card->attr_io + COR_OFFSET);
     78	mdelay(1);
     79
     80	/* Set COR as usual */
     81	iowrite16(COR_VALUE, card->attr_io + COR_OFFSET);
     82	iowrite16(COR_VALUE, card->attr_io + COR_OFFSET);
     83	mdelay(1);
     84
     85	iowrite16(0x228, card->bridge_io + 2);
     86
     87	return 0;
     88}
     89
     90static int orinoco_nortel_hw_init(struct orinoco_pci_card *card)
     91{
     92	int i;
     93	u32 reg;
     94
     95	/* Setup bridge */
     96	if (ioread16(card->bridge_io) & 1) {
     97		printk(KERN_ERR PFX "brg1 answer1 wrong\n");
     98		return -EBUSY;
     99	}
    100	iowrite16(0x118, card->bridge_io + 2);
    101	iowrite16(0x108, card->bridge_io + 2);
    102	mdelay(30);
    103	iowrite16(0x8, card->bridge_io + 2);
    104	for (i = 0; i < 30; i++) {
    105		mdelay(30);
    106		if (ioread16(card->bridge_io) & 0x10)
    107			break;
    108	}
    109	if (i == 30) {
    110		printk(KERN_ERR PFX "brg1 timed out\n");
    111		return -EBUSY;
    112	}
    113	if (ioread16(card->attr_io + COR_OFFSET) & 1) {
    114		printk(KERN_ERR PFX "brg2 answer1 wrong\n");
    115		return -EBUSY;
    116	}
    117	if (ioread16(card->attr_io + COR_OFFSET + 2) & 1) {
    118		printk(KERN_ERR PFX "brg2 answer2 wrong\n");
    119		return -EBUSY;
    120	}
    121	if (ioread16(card->attr_io + COR_OFFSET + 4) & 1) {
    122		printk(KERN_ERR PFX "brg2 answer3 wrong\n");
    123		return -EBUSY;
    124	}
    125
    126	/* Set the PCMCIA COR register */
    127	iowrite16(COR_VALUE, card->attr_io + COR_OFFSET);
    128	mdelay(1);
    129	reg = ioread16(card->attr_io + COR_OFFSET);
    130	if (reg != COR_VALUE) {
    131		printk(KERN_ERR PFX "Error setting COR value (reg=%x)\n",
    132		       reg);
    133		return -EBUSY;
    134	}
    135
    136	/* Set LEDs */
    137	iowrite16(1, card->bridge_io + 10);
    138	return 0;
    139}
    140
    141static int orinoco_nortel_init_one(struct pci_dev *pdev,
    142				   const struct pci_device_id *ent)
    143{
    144	int err;
    145	struct orinoco_private *priv;
    146	struct orinoco_pci_card *card;
    147	void __iomem *hermes_io, *bridge_io, *attr_io;
    148
    149	err = pci_enable_device(pdev);
    150	if (err) {
    151		printk(KERN_ERR PFX "Cannot enable PCI device\n");
    152		return err;
    153	}
    154
    155	err = pci_request_regions(pdev, DRIVER_NAME);
    156	if (err) {
    157		printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
    158		goto fail_resources;
    159	}
    160
    161	bridge_io = pci_iomap(pdev, 0, 0);
    162	if (!bridge_io) {
    163		printk(KERN_ERR PFX "Cannot map bridge registers\n");
    164		err = -EIO;
    165		goto fail_map_bridge;
    166	}
    167
    168	attr_io = pci_iomap(pdev, 1, 0);
    169	if (!attr_io) {
    170		printk(KERN_ERR PFX "Cannot map PCMCIA attributes\n");
    171		err = -EIO;
    172		goto fail_map_attr;
    173	}
    174
    175	hermes_io = pci_iomap(pdev, 2, 0);
    176	if (!hermes_io) {
    177		printk(KERN_ERR PFX "Cannot map chipset registers\n");
    178		err = -EIO;
    179		goto fail_map_hermes;
    180	}
    181
    182	/* Allocate network device */
    183	priv = alloc_orinocodev(sizeof(*card), &pdev->dev,
    184				orinoco_nortel_cor_reset, NULL);
    185	if (!priv) {
    186		printk(KERN_ERR PFX "Cannot allocate network device\n");
    187		err = -ENOMEM;
    188		goto fail_alloc;
    189	}
    190
    191	card = priv->card;
    192	card->bridge_io = bridge_io;
    193	card->attr_io = attr_io;
    194
    195	hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
    196
    197	err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
    198			  DRIVER_NAME, priv);
    199	if (err) {
    200		printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
    201		err = -EBUSY;
    202		goto fail_irq;
    203	}
    204
    205	err = orinoco_nortel_hw_init(card);
    206	if (err) {
    207		printk(KERN_ERR PFX "Hardware initialization failed\n");
    208		goto fail;
    209	}
    210
    211	err = orinoco_nortel_cor_reset(priv);
    212	if (err) {
    213		printk(KERN_ERR PFX "Initial reset failed\n");
    214		goto fail;
    215	}
    216
    217	err = orinoco_init(priv);
    218	if (err) {
    219		printk(KERN_ERR PFX "orinoco_init() failed\n");
    220		goto fail;
    221	}
    222
    223	err = orinoco_if_add(priv, 0, 0, NULL);
    224	if (err) {
    225		printk(KERN_ERR PFX "orinoco_if_add() failed\n");
    226		goto fail_wiphy;
    227	}
    228
    229	pci_set_drvdata(pdev, priv);
    230
    231	return 0;
    232
    233 fail_wiphy:
    234	wiphy_unregister(priv_to_wiphy(priv));
    235 fail:
    236	free_irq(pdev->irq, priv);
    237
    238 fail_irq:
    239	free_orinocodev(priv);
    240
    241 fail_alloc:
    242	pci_iounmap(pdev, hermes_io);
    243
    244 fail_map_hermes:
    245	pci_iounmap(pdev, attr_io);
    246
    247 fail_map_attr:
    248	pci_iounmap(pdev, bridge_io);
    249
    250 fail_map_bridge:
    251	pci_release_regions(pdev);
    252
    253 fail_resources:
    254	pci_disable_device(pdev);
    255
    256	return err;
    257}
    258
    259static void orinoco_nortel_remove_one(struct pci_dev *pdev)
    260{
    261	struct orinoco_private *priv = pci_get_drvdata(pdev);
    262	struct orinoco_pci_card *card = priv->card;
    263
    264	/* Clear LEDs */
    265	iowrite16(0, card->bridge_io + 10);
    266
    267	orinoco_if_del(priv);
    268	wiphy_unregister(priv_to_wiphy(priv));
    269	free_irq(pdev->irq, priv);
    270	free_orinocodev(priv);
    271	pci_iounmap(pdev, priv->hw.iobase);
    272	pci_iounmap(pdev, card->attr_io);
    273	pci_iounmap(pdev, card->bridge_io);
    274	pci_release_regions(pdev);
    275	pci_disable_device(pdev);
    276}
    277
    278static const struct pci_device_id orinoco_nortel_id_table[] = {
    279	/* Nortel emobility PCI */
    280	{0x126c, 0x8030, PCI_ANY_ID, PCI_ANY_ID,},
    281	/* Symbol LA-4123 PCI */
    282	{0x1562, 0x0001, PCI_ANY_ID, PCI_ANY_ID,},
    283	{0,},
    284};
    285
    286MODULE_DEVICE_TABLE(pci, orinoco_nortel_id_table);
    287
    288static struct pci_driver orinoco_nortel_driver = {
    289	.name		= DRIVER_NAME,
    290	.id_table	= orinoco_nortel_id_table,
    291	.probe		= orinoco_nortel_init_one,
    292	.remove		= orinoco_nortel_remove_one,
    293	.driver.pm	= &orinoco_pci_pm_ops,
    294};
    295
    296static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
    297	" (Tobias Hoffmann & Christoph Jungegger <disdos@traum404.de>)";
    298MODULE_AUTHOR("Christoph Jungegger <disdos@traum404.de>");
    299MODULE_DESCRIPTION("Driver for wireless LAN cards using the Nortel PCI bridge");
    300MODULE_LICENSE("Dual MPL/GPL");
    301
    302static int __init orinoco_nortel_init(void)
    303{
    304	printk(KERN_DEBUG "%s\n", version);
    305	return pci_register_driver(&orinoco_nortel_driver);
    306}
    307
    308static void __exit orinoco_nortel_exit(void)
    309{
    310	pci_unregister_driver(&orinoco_nortel_driver);
    311}
    312
    313module_init(orinoco_nortel_init);
    314module_exit(orinoco_nortel_exit);