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_pci.c (7440B)


      1/* orinoco_pci.c
      2 *
      3 * Driver for Prism 2.5/3 devices that have a direct PCI interface
      4 * (i.e. these are not PCMCIA cards in a PCMCIA-to-PCI bridge).
      5 * The card contains only one PCI region, which contains all the usual
      6 * hermes registers, as well as the COR register.
      7 *
      8 * Current maintainers are:
      9 *	Pavel Roskin <proski AT gnu.org>
     10 * and	David Gibson <hermes AT gibson.dropbear.id.au>
     11 *
     12 * Some of this code is borrowed from orinoco_plx.c
     13 *	Copyright (C) 2001 Daniel Barlow <dan AT telent.net>
     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 * This file originally written by:
     18 *	Copyright (C) 2001 Jean Tourrilhes <jt AT hpl.hp.com>
     19 * And is now maintained by:
     20 *	(C) Copyright David Gibson, IBM Corp. 2002-2003.
     21 *
     22 * The contents of this file are subject to the Mozilla Public License
     23 * Version 1.1 (the "License"); you may not use this file except in
     24 * compliance with the License. You may obtain a copy of the License
     25 * at http://www.mozilla.org/MPL/
     26 *
     27 * Software distributed under the License is distributed on an "AS IS"
     28 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
     29 * the License for the specific language governing rights and
     30 * limitations under the License.
     31 *
     32 * Alternatively, the contents of this file may be used under the
     33 * terms of the GNU General Public License version 2 (the "GPL"), in
     34 * which case the provisions of the GPL are applicable instead of the
     35 * above.  If you wish to allow the use of your version of this file
     36 * only under the terms of the GPL and not to allow others to use your
     37 * version of this file under the MPL, indicate your decision by
     38 * deleting the provisions above and replace them with the notice and
     39 * other provisions required by the GPL.  If you do not delete the
     40 * provisions above, a recipient may use your version of this file
     41 * under either the MPL or the GPL.
     42 */
     43
     44#define DRIVER_NAME "orinoco_pci"
     45#define PFX DRIVER_NAME ": "
     46
     47#include <linux/module.h>
     48#include <linux/kernel.h>
     49#include <linux/init.h>
     50#include <linux/delay.h>
     51#include <linux/pci.h>
     52
     53#include "orinoco.h"
     54#include "orinoco_pci.h"
     55
     56/* Offset of the COR register of the PCI card */
     57#define HERMES_PCI_COR		(0x26)
     58
     59/* Bitmask to reset the card */
     60#define HERMES_PCI_COR_MASK	(0x0080)
     61
     62/* Magic timeouts for doing the reset.
     63 * Those times are straight from wlan-ng, and it is claimed that they
     64 * are necessary. Alan will kill me. Take your time and grab a coffee. */
     65#define HERMES_PCI_COR_ONT	(250)		/* ms */
     66#define HERMES_PCI_COR_OFFT	(500)		/* ms */
     67#define HERMES_PCI_COR_BUSYT	(500)		/* ms */
     68
     69/*
     70 * Do a soft reset of the card using the Configuration Option Register
     71 * We need this to get going...
     72 * This is the part of the code that is strongly inspired from wlan-ng
     73 *
     74 * Note : This code is done with irq enabled. This mean that many
     75 * interrupts will occur while we are there. This is why we use the
     76 * jiffies to regulate time instead of a straight mdelay(). Usually we
     77 * need only around 245 iteration of the loop to do 250 ms delay.
     78 *
     79 * Note bis : Don't try to access HERMES_CMD during the reset phase.
     80 * It just won't work !
     81 */
     82static int orinoco_pci_cor_reset(struct orinoco_private *priv)
     83{
     84	struct hermes *hw = &priv->hw;
     85	unsigned long timeout;
     86	u16 reg;
     87
     88	/* Assert the reset until the card notices */
     89	hermes_write_regn(hw, PCI_COR, HERMES_PCI_COR_MASK);
     90	mdelay(HERMES_PCI_COR_ONT);
     91
     92	/* Give time for the card to recover from this hard effort */
     93	hermes_write_regn(hw, PCI_COR, 0x0000);
     94	mdelay(HERMES_PCI_COR_OFFT);
     95
     96	/* The card is ready when it's no longer busy */
     97	timeout = jiffies + msecs_to_jiffies(HERMES_PCI_COR_BUSYT);
     98	reg = hermes_read_regn(hw, CMD);
     99	while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) {
    100		mdelay(1);
    101		reg = hermes_read_regn(hw, CMD);
    102	}
    103
    104	/* Still busy? */
    105	if (reg & HERMES_CMD_BUSY) {
    106		printk(KERN_ERR PFX "Busy timeout\n");
    107		return -ETIMEDOUT;
    108	}
    109
    110	return 0;
    111}
    112
    113static int orinoco_pci_init_one(struct pci_dev *pdev,
    114				const struct pci_device_id *ent)
    115{
    116	int err;
    117	struct orinoco_private *priv;
    118	struct orinoco_pci_card *card;
    119	void __iomem *hermes_io;
    120
    121	err = pci_enable_device(pdev);
    122	if (err) {
    123		printk(KERN_ERR PFX "Cannot enable PCI device\n");
    124		return err;
    125	}
    126
    127	err = pci_request_regions(pdev, DRIVER_NAME);
    128	if (err) {
    129		printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
    130		goto fail_resources;
    131	}
    132
    133	hermes_io = pci_iomap(pdev, 0, 0);
    134	if (!hermes_io) {
    135		printk(KERN_ERR PFX "Cannot remap chipset registers\n");
    136		err = -EIO;
    137		goto fail_map_hermes;
    138	}
    139
    140	/* Allocate network device */
    141	priv = alloc_orinocodev(sizeof(*card), &pdev->dev,
    142				orinoco_pci_cor_reset, NULL);
    143	if (!priv) {
    144		printk(KERN_ERR PFX "Cannot allocate network device\n");
    145		err = -ENOMEM;
    146		goto fail_alloc;
    147	}
    148
    149	card = priv->card;
    150
    151	hermes_struct_init(&priv->hw, hermes_io, HERMES_32BIT_REGSPACING);
    152
    153	err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
    154			  DRIVER_NAME, priv);
    155	if (err) {
    156		printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
    157		err = -EBUSY;
    158		goto fail_irq;
    159	}
    160
    161	err = orinoco_pci_cor_reset(priv);
    162	if (err) {
    163		printk(KERN_ERR PFX "Initial reset failed\n");
    164		goto fail;
    165	}
    166
    167	err = orinoco_init(priv);
    168	if (err) {
    169		printk(KERN_ERR PFX "orinoco_init() failed\n");
    170		goto fail;
    171	}
    172
    173	err = orinoco_if_add(priv, 0, 0, NULL);
    174	if (err) {
    175		printk(KERN_ERR PFX "orinoco_if_add() failed\n");
    176		goto fail_wiphy;
    177	}
    178
    179	pci_set_drvdata(pdev, priv);
    180
    181	return 0;
    182
    183 fail_wiphy:
    184	wiphy_unregister(priv_to_wiphy(priv));
    185 fail:
    186	free_irq(pdev->irq, priv);
    187
    188 fail_irq:
    189	free_orinocodev(priv);
    190
    191 fail_alloc:
    192	pci_iounmap(pdev, hermes_io);
    193
    194 fail_map_hermes:
    195	pci_release_regions(pdev);
    196
    197 fail_resources:
    198	pci_disable_device(pdev);
    199
    200	return err;
    201}
    202
    203static void orinoco_pci_remove_one(struct pci_dev *pdev)
    204{
    205	struct orinoco_private *priv = pci_get_drvdata(pdev);
    206
    207	orinoco_if_del(priv);
    208	wiphy_unregister(priv_to_wiphy(priv));
    209	free_irq(pdev->irq, priv);
    210	free_orinocodev(priv);
    211	pci_iounmap(pdev, priv->hw.iobase);
    212	pci_release_regions(pdev);
    213	pci_disable_device(pdev);
    214}
    215
    216static const struct pci_device_id orinoco_pci_id_table[] = {
    217	/* Intersil Prism 3 */
    218	{0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID,},
    219	/* Intersil Prism 2.5 */
    220	{0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID,},
    221	/* Samsung MagicLAN SWL-2210P */
    222	{0x167d, 0xa000, PCI_ANY_ID, PCI_ANY_ID,},
    223	{0,},
    224};
    225
    226MODULE_DEVICE_TABLE(pci, orinoco_pci_id_table);
    227
    228static struct pci_driver orinoco_pci_driver = {
    229	.name		= DRIVER_NAME,
    230	.id_table	= orinoco_pci_id_table,
    231	.probe		= orinoco_pci_init_one,
    232	.remove		= orinoco_pci_remove_one,
    233	.driver.pm	= &orinoco_pci_pm_ops,
    234};
    235
    236static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
    237	" (Pavel Roskin <proski@gnu.org>,"
    238	" David Gibson <hermes@gibson.dropbear.id.au> &"
    239	" Jean Tourrilhes <jt@hpl.hp.com>)";
    240MODULE_AUTHOR("Pavel Roskin <proski@gnu.org> &"
    241	      " David Gibson <hermes@gibson.dropbear.id.au>");
    242MODULE_DESCRIPTION("Driver for wireless LAN cards using direct PCI interface");
    243MODULE_LICENSE("Dual MPL/GPL");
    244
    245static int __init orinoco_pci_init(void)
    246{
    247	printk(KERN_DEBUG "%s\n", version);
    248	return pci_register_driver(&orinoco_pci_driver);
    249}
    250
    251static void __exit orinoco_pci_exit(void)
    252{
    253	pci_unregister_driver(&orinoco_pci_driver);
    254}
    255
    256module_init(orinoco_pci_init);
    257module_exit(orinoco_pci_exit);