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

airport.c (6287B)


      1/* airport.c
      2 *
      3 * A driver for "Hermes" chipset based Apple Airport wireless
      4 * card.
      5 *
      6 * Copyright notice & release notes in file main.c
      7 *
      8 * Note specific to airport stub:
      9 *
     10 *  0.05 : first version of the new split driver
     11 *  0.06 : fix possible hang on powerup, add sleep support
     12 */
     13
     14#define DRIVER_NAME "airport"
     15#define PFX DRIVER_NAME ": "
     16
     17#include <linux/module.h>
     18#include <linux/kernel.h>
     19#include <linux/init.h>
     20#include <linux/delay.h>
     21#include <linux/of_device.h>
     22#include <asm/pmac_feature.h>
     23
     24#include "orinoco.h"
     25
     26#define AIRPORT_IO_LEN	(0x1000)	/* one page */
     27
     28struct airport {
     29	struct macio_dev *mdev;
     30	void __iomem *vaddr;
     31	unsigned int irq;
     32	int irq_requested;
     33	int ndev_registered;
     34};
     35
     36static int
     37airport_suspend(struct macio_dev *mdev, pm_message_t state)
     38{
     39	struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev);
     40	struct net_device *dev = priv->ndev;
     41	struct airport *card = priv->card;
     42	unsigned long flags;
     43	int err;
     44
     45	printk(KERN_DEBUG "%s: Airport entering sleep mode\n", dev->name);
     46
     47	err = orinoco_lock(priv, &flags);
     48	if (err) {
     49		printk(KERN_ERR "%s: hw_unavailable on PBOOK_SLEEP_NOW\n",
     50		       dev->name);
     51		return 0;
     52	}
     53
     54	orinoco_down(priv);
     55	orinoco_unlock(priv, &flags);
     56
     57	disable_irq(card->irq);
     58	pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE,
     59			  macio_get_of_node(mdev), 0, 0);
     60
     61	return 0;
     62}
     63
     64static int
     65airport_resume(struct macio_dev *mdev)
     66{
     67	struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev);
     68	struct net_device *dev = priv->ndev;
     69	struct airport *card = priv->card;
     70	unsigned long flags;
     71	int err;
     72
     73	printk(KERN_DEBUG "%s: Airport waking up\n", dev->name);
     74
     75	pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE,
     76			  macio_get_of_node(mdev), 0, 1);
     77	msleep(200);
     78
     79	enable_irq(card->irq);
     80
     81	priv->hw.ops->lock_irqsave(&priv->lock, &flags);
     82	err = orinoco_up(priv);
     83	priv->hw.ops->unlock_irqrestore(&priv->lock, &flags);
     84
     85	return err;
     86}
     87
     88static int
     89airport_detach(struct macio_dev *mdev)
     90{
     91	struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev);
     92	struct airport *card = priv->card;
     93
     94	if (card->ndev_registered)
     95		orinoco_if_del(priv);
     96	card->ndev_registered = 0;
     97
     98	if (card->irq_requested)
     99		free_irq(card->irq, priv);
    100	card->irq_requested = 0;
    101
    102	if (card->vaddr)
    103		iounmap(card->vaddr);
    104	card->vaddr = NULL;
    105
    106	macio_release_resource(mdev, 0);
    107
    108	pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE,
    109			  macio_get_of_node(mdev), 0, 0);
    110	ssleep(1);
    111
    112	macio_set_drvdata(mdev, NULL);
    113	free_orinocodev(priv);
    114
    115	return 0;
    116}
    117
    118static int airport_hard_reset(struct orinoco_private *priv)
    119{
    120	/* It would be nice to power cycle the Airport for a real hard
    121	 * reset, but for some reason although it appears to
    122	 * re-initialize properly, it falls in a screaming heap
    123	 * shortly afterwards. */
    124#if 0
    125	struct airport *card = priv->card;
    126
    127	/* Vitally important.  If we don't do this it seems we get an
    128	 * interrupt somewhere during the power cycle, since
    129	 * hw_unavailable is already set it doesn't get ACKed, we get
    130	 * into an interrupt loop and the PMU decides to turn us
    131	 * off. */
    132	disable_irq(card->irq);
    133
    134	pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE,
    135			  macio_get_of_node(card->mdev), 0, 0);
    136	ssleep(1);
    137	pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE,
    138			  macio_get_of_node(card->mdev), 0, 1);
    139	ssleep(1);
    140
    141	enable_irq(card->irq);
    142	ssleep(1);
    143#endif
    144
    145	return 0;
    146}
    147
    148static int
    149airport_attach(struct macio_dev *mdev, const struct of_device_id *match)
    150{
    151	struct orinoco_private *priv;
    152	struct airport *card;
    153	unsigned long phys_addr;
    154	struct hermes *hw;
    155
    156	if (macio_resource_count(mdev) < 1 || macio_irq_count(mdev) < 1) {
    157		printk(KERN_ERR PFX "Wrong interrupt/addresses in OF tree\n");
    158		return -ENODEV;
    159	}
    160
    161	/* Allocate space for private device-specific data */
    162	priv = alloc_orinocodev(sizeof(*card), &mdev->ofdev.dev,
    163				airport_hard_reset, NULL);
    164	if (!priv) {
    165		printk(KERN_ERR PFX "Cannot allocate network device\n");
    166		return -ENODEV;
    167	}
    168	card = priv->card;
    169
    170	hw = &priv->hw;
    171	card->mdev = mdev;
    172
    173	if (macio_request_resource(mdev, 0, DRIVER_NAME)) {
    174		printk(KERN_ERR PFX "can't request IO resource !\n");
    175		free_orinocodev(priv);
    176		return -EBUSY;
    177	}
    178
    179	macio_set_drvdata(mdev, priv);
    180
    181	/* Setup interrupts & base address */
    182	card->irq = macio_irq(mdev, 0);
    183	phys_addr = macio_resource_start(mdev, 0);  /* Physical address */
    184	printk(KERN_DEBUG PFX "Physical address %lx\n", phys_addr);
    185	card->vaddr = ioremap(phys_addr, AIRPORT_IO_LEN);
    186	if (!card->vaddr) {
    187		printk(KERN_ERR PFX "ioremap() failed\n");
    188		goto failed;
    189	}
    190
    191	hermes_struct_init(hw, card->vaddr, HERMES_16BIT_REGSPACING);
    192
    193	/* Power up card */
    194	pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE,
    195			  macio_get_of_node(mdev), 0, 1);
    196	ssleep(1);
    197
    198	/* Reset it before we get the interrupt */
    199	hw->ops->init(hw);
    200
    201	if (request_irq(card->irq, orinoco_interrupt, 0, DRIVER_NAME, priv)) {
    202		printk(KERN_ERR PFX "Couldn't get IRQ %d\n", card->irq);
    203		goto failed;
    204	}
    205	card->irq_requested = 1;
    206
    207	/* Initialise the main driver */
    208	if (orinoco_init(priv) != 0) {
    209		printk(KERN_ERR PFX "orinoco_init() failed\n");
    210		goto failed;
    211	}
    212
    213	/* Register an interface with the stack */
    214	if (orinoco_if_add(priv, phys_addr, card->irq, NULL) != 0) {
    215		printk(KERN_ERR PFX "orinoco_if_add() failed\n");
    216		goto failed;
    217	}
    218	card->ndev_registered = 1;
    219	return 0;
    220 failed:
    221	airport_detach(mdev);
    222	return -ENODEV;
    223}				/* airport_attach */
    224
    225
    226static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
    227	" (Benjamin Herrenschmidt <benh@kernel.crashing.org>)";
    228MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
    229MODULE_DESCRIPTION("Driver for the Apple Airport wireless card.");
    230MODULE_LICENSE("Dual MPL/GPL");
    231
    232static const struct of_device_id airport_match[] = {
    233	{
    234	.name		= "radio",
    235	},
    236	{},
    237};
    238
    239MODULE_DEVICE_TABLE(of, airport_match);
    240
    241static struct macio_driver airport_driver = {
    242	.driver = {
    243		.name		= DRIVER_NAME,
    244		.owner		= THIS_MODULE,
    245		.of_match_table	= airport_match,
    246	},
    247	.probe		= airport_attach,
    248	.remove		= airport_detach,
    249	.suspend	= airport_suspend,
    250	.resume		= airport_resume,
    251};
    252
    253static int __init
    254init_airport(void)
    255{
    256	printk(KERN_DEBUG "%s\n", version);
    257
    258	return macio_register_driver(&airport_driver);
    259}
    260
    261static void __exit
    262exit_airport(void)
    263{
    264	macio_unregister_driver(&airport_driver);
    265}
    266
    267module_init(init_airport);
    268module_exit(exit_airport);