diff options
author | Gabor Juhos <juhosg@openwrt.org> | 2009-01-14 14:17:06 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-01-29 16:00:31 -0500 |
commit | 6baff7f9a6c571dcd9a59820e3c094f7490cb0fd (patch) | |
tree | 17345f71c943ec94cdd16826c7f5be8bc03a416d /drivers/net/wireless/ath9k | |
parent | 39c3c2f2de6bccf698bfb5b9c4f56ddf99de0dbc (diff) |
ath9k: move PCI code into separate file
Now that we have converted all bus specific routines to replaceable, we
can move the PCI specific codes into a separate file.
Changes-licensed-under: ISC
Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
Tested-by: Pavel Roskin <proski@gnu.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath9k')
-rw-r--r-- | drivers/net/wireless/ath9k/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ath9k/core.h | 19 | ||||
-rw-r--r-- | drivers/net/wireless/ath9k/main.c | 300 | ||||
-rw-r--r-- | drivers/net/wireless/ath9k/pci.c | 287 |
4 files changed, 328 insertions, 279 deletions
diff --git a/drivers/net/wireless/ath9k/Makefile b/drivers/net/wireless/ath9k/Makefile index 1209d14613ac..af3f39bbddd5 100644 --- a/drivers/net/wireless/ath9k/Makefile +++ b/drivers/net/wireless/ath9k/Makefile | |||
@@ -11,6 +11,7 @@ ath9k-y += hw.o \ | |||
11 | xmit.o \ | 11 | xmit.o \ |
12 | rc.o | 12 | rc.o |
13 | 13 | ||
14 | ath9k-$(CONFIG_PCI) += pci.o | ||
14 | ath9k-$(CONFIG_ATH9K_DEBUG) += debug.o | 15 | ath9k-$(CONFIG_ATH9K_DEBUG) += debug.o |
15 | 16 | ||
16 | obj-$(CONFIG_ATH9K) += ath9k.o | 17 | obj-$(CONFIG_ATH9K) += ath9k.o |
diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index f9fa5c64c77b..1e86a9cbe42b 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h | |||
@@ -18,7 +18,7 @@ | |||
18 | #define CORE_H | 18 | #define CORE_H |
19 | 19 | ||
20 | #include <linux/etherdevice.h> | 20 | #include <linux/etherdevice.h> |
21 | #include <linux/pci.h> | 21 | #include <linux/device.h> |
22 | #include <net/mac80211.h> | 22 | #include <net/mac80211.h> |
23 | #include <linux/leds.h> | 23 | #include <linux/leds.h> |
24 | #include <linux/rfkill.h> | 24 | #include <linux/rfkill.h> |
@@ -767,4 +767,21 @@ static inline void ath_bus_cleanup(struct ath_softc *sc) | |||
767 | sc->bus_ops->cleanup(sc); | 767 | sc->bus_ops->cleanup(sc); |
768 | } | 768 | } |
769 | 769 | ||
770 | extern struct ieee80211_ops ath9k_ops; | ||
771 | |||
772 | irqreturn_t ath_isr(int irq, void *dev); | ||
773 | void ath_cleanup(struct ath_softc *sc); | ||
774 | int ath_attach(u16 devid, struct ath_softc *sc); | ||
775 | void ath_detach(struct ath_softc *sc); | ||
776 | const char *ath_mac_bb_name(u32 mac_bb_version); | ||
777 | const char *ath_rf_name(u16 rf_version); | ||
778 | |||
779 | #ifdef CONFIG_PCI | ||
780 | int ath_pci_init(void); | ||
781 | void ath_pci_exit(void); | ||
782 | #else | ||
783 | static inline int ath_pci_init(void) { return 0; }; | ||
784 | static inline void ath_pci_exit(void) {}; | ||
785 | #endif | ||
786 | |||
770 | #endif /* CORE_H */ | 787 | #endif /* CORE_H */ |
diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index dd2be2644cad..6257790e49da 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c | |||
@@ -28,39 +28,6 @@ MODULE_DESCRIPTION("Support for Atheros 802.11n wireless LAN cards."); | |||
28 | MODULE_SUPPORTED_DEVICE("Atheros 802.11n WLAN cards"); | 28 | MODULE_SUPPORTED_DEVICE("Atheros 802.11n WLAN cards"); |
29 | MODULE_LICENSE("Dual BSD/GPL"); | 29 | MODULE_LICENSE("Dual BSD/GPL"); |
30 | 30 | ||
31 | static struct pci_device_id ath_pci_id_table[] __devinitdata = { | ||
32 | { PCI_VDEVICE(ATHEROS, 0x0023) }, /* PCI */ | ||
33 | { PCI_VDEVICE(ATHEROS, 0x0024) }, /* PCI-E */ | ||
34 | { PCI_VDEVICE(ATHEROS, 0x0027) }, /* PCI */ | ||
35 | { PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI */ | ||
36 | { PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */ | ||
37 | { PCI_VDEVICE(ATHEROS, 0x002B) }, /* PCI-E */ | ||
38 | { 0 } | ||
39 | }; | ||
40 | |||
41 | static void ath_detach(struct ath_softc *sc); | ||
42 | static void ath_cleanup(struct ath_softc *sc); | ||
43 | |||
44 | /* return bus cachesize in 4B word units */ | ||
45 | |||
46 | static void ath_pci_read_cachesize(struct ath_softc *sc, int *csz) | ||
47 | { | ||
48 | u8 u8tmp; | ||
49 | |||
50 | pci_read_config_byte(to_pci_dev(sc->dev), PCI_CACHE_LINE_SIZE, | ||
51 | (u8 *)&u8tmp); | ||
52 | *csz = (int)u8tmp; | ||
53 | |||
54 | /* | ||
55 | * This check was put in to avoid "unplesant" consequences if | ||
56 | * the bootrom has not fully initialized all PCI devices. | ||
57 | * Sometimes the cache line size register is not set | ||
58 | */ | ||
59 | |||
60 | if (*csz == 0) | ||
61 | *csz = DEFAULT_CACHELINE >> 2; /* Use the default size */ | ||
62 | } | ||
63 | |||
64 | static void ath_cache_conf_rate(struct ath_softc *sc, | 31 | static void ath_cache_conf_rate(struct ath_softc *sc, |
65 | struct ieee80211_conf *conf) | 32 | struct ieee80211_conf *conf) |
66 | { | 33 | { |
@@ -500,7 +467,7 @@ static void ath9k_tasklet(unsigned long data) | |||
500 | ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask); | 467 | ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask); |
501 | } | 468 | } |
502 | 469 | ||
503 | static irqreturn_t ath_isr(int irq, void *dev) | 470 | irqreturn_t ath_isr(int irq, void *dev) |
504 | { | 471 | { |
505 | struct ath_softc *sc = dev; | 472 | struct ath_softc *sc = dev; |
506 | struct ath_hal *ah = sc->sc_ah; | 473 | struct ath_hal *ah = sc->sc_ah; |
@@ -1279,7 +1246,7 @@ static int ath_start_rfkill_poll(struct ath_softc *sc) | |||
1279 | } | 1246 | } |
1280 | #endif /* CONFIG_RFKILL */ | 1247 | #endif /* CONFIG_RFKILL */ |
1281 | 1248 | ||
1282 | static void ath_cleanup(struct ath_softc *sc) | 1249 | void ath_cleanup(struct ath_softc *sc) |
1283 | { | 1250 | { |
1284 | ath_detach(sc); | 1251 | ath_detach(sc); |
1285 | free_irq(sc->irq, sc); | 1252 | free_irq(sc->irq, sc); |
@@ -1287,7 +1254,7 @@ static void ath_cleanup(struct ath_softc *sc) | |||
1287 | ieee80211_free_hw(sc->hw); | 1254 | ieee80211_free_hw(sc->hw); |
1288 | } | 1255 | } |
1289 | 1256 | ||
1290 | static void ath_detach(struct ath_softc *sc) | 1257 | void ath_detach(struct ath_softc *sc) |
1291 | { | 1258 | { |
1292 | struct ieee80211_hw *hw = sc->hw; | 1259 | struct ieee80211_hw *hw = sc->hw; |
1293 | int i = 0; | 1260 | int i = 0; |
@@ -1541,7 +1508,7 @@ bad: | |||
1541 | return error; | 1508 | return error; |
1542 | } | 1509 | } |
1543 | 1510 | ||
1544 | static int ath_attach(u16 devid, struct ath_softc *sc) | 1511 | int ath_attach(u16 devid, struct ath_softc *sc) |
1545 | { | 1512 | { |
1546 | struct ieee80211_hw *hw = sc->hw; | 1513 | struct ieee80211_hw *hw = sc->hw; |
1547 | int error = 0; | 1514 | int error = 0; |
@@ -2462,7 +2429,7 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, | |||
2462 | return ret; | 2429 | return ret; |
2463 | } | 2430 | } |
2464 | 2431 | ||
2465 | static struct ieee80211_ops ath9k_ops = { | 2432 | struct ieee80211_ops ath9k_ops = { |
2466 | .tx = ath9k_tx, | 2433 | .tx = ath9k_tx, |
2467 | .start = ath9k_start, | 2434 | .start = ath9k_start, |
2468 | .stop = ath9k_stop, | 2435 | .stop = ath9k_stop, |
@@ -2506,7 +2473,7 @@ static struct { | |||
2506 | /* | 2473 | /* |
2507 | * Return the MAC/BB name. "????" is returned if the MAC/BB is unknown. | 2474 | * Return the MAC/BB name. "????" is returned if the MAC/BB is unknown. |
2508 | */ | 2475 | */ |
2509 | static const char * | 2476 | const char * |
2510 | ath_mac_bb_name(u32 mac_bb_version) | 2477 | ath_mac_bb_name(u32 mac_bb_version) |
2511 | { | 2478 | { |
2512 | int i; | 2479 | int i; |
@@ -2523,7 +2490,7 @@ ath_mac_bb_name(u32 mac_bb_version) | |||
2523 | /* | 2490 | /* |
2524 | * Return the RF name. "????" is returned if the RF is unknown. | 2491 | * Return the RF name. "????" is returned if the RF is unknown. |
2525 | */ | 2492 | */ |
2526 | static const char * | 2493 | const char * |
2527 | ath_rf_name(u16 rf_version) | 2494 | ath_rf_name(u16 rf_version) |
2528 | { | 2495 | { |
2529 | int i; | 2496 | int i; |
@@ -2537,234 +2504,7 @@ ath_rf_name(u16 rf_version) | |||
2537 | return "????"; | 2504 | return "????"; |
2538 | } | 2505 | } |
2539 | 2506 | ||
2540 | static void ath_pci_cleanup(struct ath_softc *sc) | 2507 | static int __init ath9k_init(void) |
2541 | { | ||
2542 | struct pci_dev *pdev = to_pci_dev(sc->dev); | ||
2543 | |||
2544 | pci_iounmap(pdev, sc->mem); | ||
2545 | pci_release_region(pdev, 0); | ||
2546 | pci_disable_device(pdev); | ||
2547 | } | ||
2548 | |||
2549 | static struct ath_bus_ops ath_pci_bus_ops = { | ||
2550 | .read_cachesize = ath_pci_read_cachesize, | ||
2551 | .cleanup = ath_pci_cleanup, | ||
2552 | }; | ||
2553 | |||
2554 | static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) | ||
2555 | { | ||
2556 | void __iomem *mem; | ||
2557 | struct ath_softc *sc; | ||
2558 | struct ieee80211_hw *hw; | ||
2559 | u8 csz; | ||
2560 | u32 val; | ||
2561 | int ret = 0; | ||
2562 | struct ath_hal *ah; | ||
2563 | |||
2564 | if (pci_enable_device(pdev)) | ||
2565 | return -EIO; | ||
2566 | |||
2567 | ret = pci_set_dma_mask(pdev, DMA_32BIT_MASK); | ||
2568 | |||
2569 | if (ret) { | ||
2570 | printk(KERN_ERR "ath9k: 32-bit DMA not available\n"); | ||
2571 | goto bad; | ||
2572 | } | ||
2573 | |||
2574 | ret = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); | ||
2575 | |||
2576 | if (ret) { | ||
2577 | printk(KERN_ERR "ath9k: 32-bit DMA consistent " | ||
2578 | "DMA enable failed\n"); | ||
2579 | goto bad; | ||
2580 | } | ||
2581 | |||
2582 | /* | ||
2583 | * Cache line size is used to size and align various | ||
2584 | * structures used to communicate with the hardware. | ||
2585 | */ | ||
2586 | pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &csz); | ||
2587 | if (csz == 0) { | ||
2588 | /* | ||
2589 | * Linux 2.4.18 (at least) writes the cache line size | ||
2590 | * register as a 16-bit wide register which is wrong. | ||
2591 | * We must have this setup properly for rx buffer | ||
2592 | * DMA to work so force a reasonable value here if it | ||
2593 | * comes up zero. | ||
2594 | */ | ||
2595 | csz = L1_CACHE_BYTES / sizeof(u32); | ||
2596 | pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz); | ||
2597 | } | ||
2598 | /* | ||
2599 | * The default setting of latency timer yields poor results, | ||
2600 | * set it to the value used by other systems. It may be worth | ||
2601 | * tweaking this setting more. | ||
2602 | */ | ||
2603 | pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xa8); | ||
2604 | |||
2605 | pci_set_master(pdev); | ||
2606 | |||
2607 | /* | ||
2608 | * Disable the RETRY_TIMEOUT register (0x41) to keep | ||
2609 | * PCI Tx retries from interfering with C3 CPU state. | ||
2610 | */ | ||
2611 | pci_read_config_dword(pdev, 0x40, &val); | ||
2612 | if ((val & 0x0000ff00) != 0) | ||
2613 | pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); | ||
2614 | |||
2615 | ret = pci_request_region(pdev, 0, "ath9k"); | ||
2616 | if (ret) { | ||
2617 | dev_err(&pdev->dev, "PCI memory region reserve error\n"); | ||
2618 | ret = -ENODEV; | ||
2619 | goto bad; | ||
2620 | } | ||
2621 | |||
2622 | mem = pci_iomap(pdev, 0, 0); | ||
2623 | if (!mem) { | ||
2624 | printk(KERN_ERR "PCI memory map error\n") ; | ||
2625 | ret = -EIO; | ||
2626 | goto bad1; | ||
2627 | } | ||
2628 | |||
2629 | hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops); | ||
2630 | if (hw == NULL) { | ||
2631 | printk(KERN_ERR "ath_pci: no memory for ieee80211_hw\n"); | ||
2632 | goto bad2; | ||
2633 | } | ||
2634 | |||
2635 | SET_IEEE80211_DEV(hw, &pdev->dev); | ||
2636 | pci_set_drvdata(pdev, hw); | ||
2637 | |||
2638 | sc = hw->priv; | ||
2639 | sc->hw = hw; | ||
2640 | sc->dev = &pdev->dev; | ||
2641 | sc->mem = mem; | ||
2642 | sc->bus_ops = &ath_pci_bus_ops; | ||
2643 | |||
2644 | if (ath_attach(id->device, sc) != 0) { | ||
2645 | ret = -ENODEV; | ||
2646 | goto bad3; | ||
2647 | } | ||
2648 | |||
2649 | /* setup interrupt service routine */ | ||
2650 | |||
2651 | if (request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath", sc)) { | ||
2652 | printk(KERN_ERR "%s: request_irq failed\n", | ||
2653 | wiphy_name(hw->wiphy)); | ||
2654 | ret = -EIO; | ||
2655 | goto bad4; | ||
2656 | } | ||
2657 | |||
2658 | sc->irq = pdev->irq; | ||
2659 | |||
2660 | ah = sc->sc_ah; | ||
2661 | printk(KERN_INFO | ||
2662 | "%s: Atheros AR%s MAC/BB Rev:%x " | ||
2663 | "AR%s RF Rev:%x: mem=0x%lx, irq=%d\n", | ||
2664 | wiphy_name(hw->wiphy), | ||
2665 | ath_mac_bb_name(ah->ah_macVersion), | ||
2666 | ah->ah_macRev, | ||
2667 | ath_rf_name((ah->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR)), | ||
2668 | ah->ah_phyRev, | ||
2669 | (unsigned long)mem, pdev->irq); | ||
2670 | |||
2671 | return 0; | ||
2672 | bad4: | ||
2673 | ath_detach(sc); | ||
2674 | bad3: | ||
2675 | ieee80211_free_hw(hw); | ||
2676 | bad2: | ||
2677 | pci_iounmap(pdev, mem); | ||
2678 | bad1: | ||
2679 | pci_release_region(pdev, 0); | ||
2680 | bad: | ||
2681 | pci_disable_device(pdev); | ||
2682 | return ret; | ||
2683 | } | ||
2684 | |||
2685 | static void ath_pci_remove(struct pci_dev *pdev) | ||
2686 | { | ||
2687 | struct ieee80211_hw *hw = pci_get_drvdata(pdev); | ||
2688 | struct ath_softc *sc = hw->priv; | ||
2689 | |||
2690 | ath_cleanup(sc); | ||
2691 | } | ||
2692 | |||
2693 | #ifdef CONFIG_PM | ||
2694 | |||
2695 | static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state) | ||
2696 | { | ||
2697 | struct ieee80211_hw *hw = pci_get_drvdata(pdev); | ||
2698 | struct ath_softc *sc = hw->priv; | ||
2699 | |||
2700 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); | ||
2701 | |||
2702 | #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) | ||
2703 | if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) | ||
2704 | cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); | ||
2705 | #endif | ||
2706 | |||
2707 | pci_save_state(pdev); | ||
2708 | pci_disable_device(pdev); | ||
2709 | pci_set_power_state(pdev, PCI_D3hot); | ||
2710 | |||
2711 | return 0; | ||
2712 | } | ||
2713 | |||
2714 | static int ath_pci_resume(struct pci_dev *pdev) | ||
2715 | { | ||
2716 | struct ieee80211_hw *hw = pci_get_drvdata(pdev); | ||
2717 | struct ath_softc *sc = hw->priv; | ||
2718 | u32 val; | ||
2719 | int err; | ||
2720 | |||
2721 | err = pci_enable_device(pdev); | ||
2722 | if (err) | ||
2723 | return err; | ||
2724 | pci_restore_state(pdev); | ||
2725 | /* | ||
2726 | * Suspend/Resume resets the PCI configuration space, so we have to | ||
2727 | * re-disable the RETRY_TIMEOUT register (0x41) to keep | ||
2728 | * PCI Tx retries from interfering with C3 CPU state | ||
2729 | */ | ||
2730 | pci_read_config_dword(pdev, 0x40, &val); | ||
2731 | if ((val & 0x0000ff00) != 0) | ||
2732 | pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); | ||
2733 | |||
2734 | /* Enable LED */ | ||
2735 | ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN, | ||
2736 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); | ||
2737 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); | ||
2738 | |||
2739 | #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) | ||
2740 | /* | ||
2741 | * check the h/w rfkill state on resume | ||
2742 | * and start the rfkill poll timer | ||
2743 | */ | ||
2744 | if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) | ||
2745 | queue_delayed_work(sc->hw->workqueue, | ||
2746 | &sc->rf_kill.rfkill_poll, 0); | ||
2747 | #endif | ||
2748 | |||
2749 | return 0; | ||
2750 | } | ||
2751 | |||
2752 | #endif /* CONFIG_PM */ | ||
2753 | |||
2754 | MODULE_DEVICE_TABLE(pci, ath_pci_id_table); | ||
2755 | |||
2756 | static struct pci_driver ath_pci_driver = { | ||
2757 | .name = "ath9k", | ||
2758 | .id_table = ath_pci_id_table, | ||
2759 | .probe = ath_pci_probe, | ||
2760 | .remove = ath_pci_remove, | ||
2761 | #ifdef CONFIG_PM | ||
2762 | .suspend = ath_pci_suspend, | ||
2763 | .resume = ath_pci_resume, | ||
2764 | #endif /* CONFIG_PM */ | ||
2765 | }; | ||
2766 | |||
2767 | static int __init init_ath_pci(void) | ||
2768 | { | 2508 | { |
2769 | int error; | 2509 | int error; |
2770 | 2510 | ||
@@ -2776,26 +2516,30 @@ static int __init init_ath_pci(void) | |||
2776 | printk(KERN_ERR | 2516 | printk(KERN_ERR |
2777 | "Unable to register rate control algorithm: %d\n", | 2517 | "Unable to register rate control algorithm: %d\n", |
2778 | error); | 2518 | error); |
2779 | ath_rate_control_unregister(); | 2519 | goto err_out; |
2780 | return error; | ||
2781 | } | 2520 | } |
2782 | 2521 | ||
2783 | if (pci_register_driver(&ath_pci_driver) < 0) { | 2522 | error = ath_pci_init(); |
2523 | if (error < 0) { | ||
2784 | printk(KERN_ERR | 2524 | printk(KERN_ERR |
2785 | "ath_pci: No devices found, driver not installed.\n"); | 2525 | "ath_pci: No devices found, driver not installed.\n"); |
2786 | ath_rate_control_unregister(); | 2526 | error = -ENODEV; |
2787 | pci_unregister_driver(&ath_pci_driver); | 2527 | goto err_rate_unregister; |
2788 | return -ENODEV; | ||
2789 | } | 2528 | } |
2790 | 2529 | ||
2791 | return 0; | 2530 | return 0; |
2531 | |||
2532 | err_rate_unregister: | ||
2533 | ath_rate_control_unregister(); | ||
2534 | err_out: | ||
2535 | return error; | ||
2792 | } | 2536 | } |
2793 | module_init(init_ath_pci); | 2537 | module_init(ath9k_init); |
2794 | 2538 | ||
2795 | static void __exit exit_ath_pci(void) | 2539 | static void __exit ath9k_exit(void) |
2796 | { | 2540 | { |
2541 | ath_pci_exit(); | ||
2797 | ath_rate_control_unregister(); | 2542 | ath_rate_control_unregister(); |
2798 | pci_unregister_driver(&ath_pci_driver); | ||
2799 | printk(KERN_INFO "%s: Driver unloaded\n", dev_info); | 2543 | printk(KERN_INFO "%s: Driver unloaded\n", dev_info); |
2800 | } | 2544 | } |
2801 | module_exit(exit_ath_pci); | 2545 | module_exit(ath9k_exit); |
diff --git a/drivers/net/wireless/ath9k/pci.c b/drivers/net/wireless/ath9k/pci.c new file mode 100644 index 000000000000..4ff1caa9ba99 --- /dev/null +++ b/drivers/net/wireless/ath9k/pci.c | |||
@@ -0,0 +1,287 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2008 Atheros Communications Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include <linux/nl80211.h> | ||
18 | #include <linux/pci.h> | ||
19 | #include "core.h" | ||
20 | #include "reg.h" | ||
21 | #include "hw.h" | ||
22 | |||
23 | static struct pci_device_id ath_pci_id_table[] __devinitdata = { | ||
24 | { PCI_VDEVICE(ATHEROS, 0x0023) }, /* PCI */ | ||
25 | { PCI_VDEVICE(ATHEROS, 0x0024) }, /* PCI-E */ | ||
26 | { PCI_VDEVICE(ATHEROS, 0x0027) }, /* PCI */ | ||
27 | { PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI */ | ||
28 | { PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */ | ||
29 | { PCI_VDEVICE(ATHEROS, 0x002B) }, /* PCI-E */ | ||
30 | { 0 } | ||
31 | }; | ||
32 | |||
33 | /* return bus cachesize in 4B word units */ | ||
34 | static void ath_pci_read_cachesize(struct ath_softc *sc, int *csz) | ||
35 | { | ||
36 | u8 u8tmp; | ||
37 | |||
38 | pci_read_config_byte(to_pci_dev(sc->dev), PCI_CACHE_LINE_SIZE, | ||
39 | (u8 *)&u8tmp); | ||
40 | *csz = (int)u8tmp; | ||
41 | |||
42 | /* | ||
43 | * This check was put in to avoid "unplesant" consequences if | ||
44 | * the bootrom has not fully initialized all PCI devices. | ||
45 | * Sometimes the cache line size register is not set | ||
46 | */ | ||
47 | |||
48 | if (*csz == 0) | ||
49 | *csz = DEFAULT_CACHELINE >> 2; /* Use the default size */ | ||
50 | } | ||
51 | |||
52 | static void ath_pci_cleanup(struct ath_softc *sc) | ||
53 | { | ||
54 | struct pci_dev *pdev = to_pci_dev(sc->dev); | ||
55 | |||
56 | pci_iounmap(pdev, sc->mem); | ||
57 | pci_release_region(pdev, 0); | ||
58 | pci_disable_device(pdev); | ||
59 | } | ||
60 | |||
61 | static struct ath_bus_ops ath_pci_bus_ops = { | ||
62 | .read_cachesize = ath_pci_read_cachesize, | ||
63 | .cleanup = ath_pci_cleanup, | ||
64 | }; | ||
65 | |||
66 | static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) | ||
67 | { | ||
68 | void __iomem *mem; | ||
69 | struct ath_softc *sc; | ||
70 | struct ieee80211_hw *hw; | ||
71 | u8 csz; | ||
72 | u32 val; | ||
73 | int ret = 0; | ||
74 | struct ath_hal *ah; | ||
75 | |||
76 | if (pci_enable_device(pdev)) | ||
77 | return -EIO; | ||
78 | |||
79 | ret = pci_set_dma_mask(pdev, DMA_32BIT_MASK); | ||
80 | |||
81 | if (ret) { | ||
82 | printk(KERN_ERR "ath9k: 32-bit DMA not available\n"); | ||
83 | goto bad; | ||
84 | } | ||
85 | |||
86 | ret = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); | ||
87 | |||
88 | if (ret) { | ||
89 | printk(KERN_ERR "ath9k: 32-bit DMA consistent " | ||
90 | "DMA enable failed\n"); | ||
91 | goto bad; | ||
92 | } | ||
93 | |||
94 | /* | ||
95 | * Cache line size is used to size and align various | ||
96 | * structures used to communicate with the hardware. | ||
97 | */ | ||
98 | pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &csz); | ||
99 | if (csz == 0) { | ||
100 | /* | ||
101 | * Linux 2.4.18 (at least) writes the cache line size | ||
102 | * register as a 16-bit wide register which is wrong. | ||
103 | * We must have this setup properly for rx buffer | ||
104 | * DMA to work so force a reasonable value here if it | ||
105 | * comes up zero. | ||
106 | */ | ||
107 | csz = L1_CACHE_BYTES / sizeof(u32); | ||
108 | pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz); | ||
109 | } | ||
110 | /* | ||
111 | * The default setting of latency timer yields poor results, | ||
112 | * set it to the value used by other systems. It may be worth | ||
113 | * tweaking this setting more. | ||
114 | */ | ||
115 | pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xa8); | ||
116 | |||
117 | pci_set_master(pdev); | ||
118 | |||
119 | /* | ||
120 | * Disable the RETRY_TIMEOUT register (0x41) to keep | ||
121 | * PCI Tx retries from interfering with C3 CPU state. | ||
122 | */ | ||
123 | pci_read_config_dword(pdev, 0x40, &val); | ||
124 | if ((val & 0x0000ff00) != 0) | ||
125 | pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); | ||
126 | |||
127 | ret = pci_request_region(pdev, 0, "ath9k"); | ||
128 | if (ret) { | ||
129 | dev_err(&pdev->dev, "PCI memory region reserve error\n"); | ||
130 | ret = -ENODEV; | ||
131 | goto bad; | ||
132 | } | ||
133 | |||
134 | mem = pci_iomap(pdev, 0, 0); | ||
135 | if (!mem) { | ||
136 | printk(KERN_ERR "PCI memory map error\n") ; | ||
137 | ret = -EIO; | ||
138 | goto bad1; | ||
139 | } | ||
140 | |||
141 | hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops); | ||
142 | if (hw == NULL) { | ||
143 | printk(KERN_ERR "ath_pci: no memory for ieee80211_hw\n"); | ||
144 | goto bad2; | ||
145 | } | ||
146 | |||
147 | SET_IEEE80211_DEV(hw, &pdev->dev); | ||
148 | pci_set_drvdata(pdev, hw); | ||
149 | |||
150 | sc = hw->priv; | ||
151 | sc->hw = hw; | ||
152 | sc->dev = &pdev->dev; | ||
153 | sc->mem = mem; | ||
154 | sc->bus_ops = &ath_pci_bus_ops; | ||
155 | |||
156 | if (ath_attach(id->device, sc) != 0) { | ||
157 | ret = -ENODEV; | ||
158 | goto bad3; | ||
159 | } | ||
160 | |||
161 | /* setup interrupt service routine */ | ||
162 | |||
163 | if (request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath", sc)) { | ||
164 | printk(KERN_ERR "%s: request_irq failed\n", | ||
165 | wiphy_name(hw->wiphy)); | ||
166 | ret = -EIO; | ||
167 | goto bad4; | ||
168 | } | ||
169 | |||
170 | sc->irq = pdev->irq; | ||
171 | |||
172 | ah = sc->sc_ah; | ||
173 | printk(KERN_INFO | ||
174 | "%s: Atheros AR%s MAC/BB Rev:%x " | ||
175 | "AR%s RF Rev:%x: mem=0x%lx, irq=%d\n", | ||
176 | wiphy_name(hw->wiphy), | ||
177 | ath_mac_bb_name(ah->ah_macVersion), | ||
178 | ah->ah_macRev, | ||
179 | ath_rf_name((ah->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR)), | ||
180 | ah->ah_phyRev, | ||
181 | (unsigned long)mem, pdev->irq); | ||
182 | |||
183 | return 0; | ||
184 | bad4: | ||
185 | ath_detach(sc); | ||
186 | bad3: | ||
187 | ieee80211_free_hw(hw); | ||
188 | bad2: | ||
189 | pci_iounmap(pdev, mem); | ||
190 | bad1: | ||
191 | pci_release_region(pdev, 0); | ||
192 | bad: | ||
193 | pci_disable_device(pdev); | ||
194 | return ret; | ||
195 | } | ||
196 | |||
197 | static void ath_pci_remove(struct pci_dev *pdev) | ||
198 | { | ||
199 | struct ieee80211_hw *hw = pci_get_drvdata(pdev); | ||
200 | struct ath_softc *sc = hw->priv; | ||
201 | |||
202 | ath_cleanup(sc); | ||
203 | } | ||
204 | |||
205 | #ifdef CONFIG_PM | ||
206 | |||
207 | static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state) | ||
208 | { | ||
209 | struct ieee80211_hw *hw = pci_get_drvdata(pdev); | ||
210 | struct ath_softc *sc = hw->priv; | ||
211 | |||
212 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); | ||
213 | |||
214 | #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) | ||
215 | if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) | ||
216 | cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); | ||
217 | #endif | ||
218 | |||
219 | pci_save_state(pdev); | ||
220 | pci_disable_device(pdev); | ||
221 | pci_set_power_state(pdev, PCI_D3hot); | ||
222 | |||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | static int ath_pci_resume(struct pci_dev *pdev) | ||
227 | { | ||
228 | struct ieee80211_hw *hw = pci_get_drvdata(pdev); | ||
229 | struct ath_softc *sc = hw->priv; | ||
230 | u32 val; | ||
231 | int err; | ||
232 | |||
233 | err = pci_enable_device(pdev); | ||
234 | if (err) | ||
235 | return err; | ||
236 | pci_restore_state(pdev); | ||
237 | /* | ||
238 | * Suspend/Resume resets the PCI configuration space, so we have to | ||
239 | * re-disable the RETRY_TIMEOUT register (0x41) to keep | ||
240 | * PCI Tx retries from interfering with C3 CPU state | ||
241 | */ | ||
242 | pci_read_config_dword(pdev, 0x40, &val); | ||
243 | if ((val & 0x0000ff00) != 0) | ||
244 | pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); | ||
245 | |||
246 | /* Enable LED */ | ||
247 | ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN, | ||
248 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); | ||
249 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); | ||
250 | |||
251 | #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) | ||
252 | /* | ||
253 | * check the h/w rfkill state on resume | ||
254 | * and start the rfkill poll timer | ||
255 | */ | ||
256 | if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) | ||
257 | queue_delayed_work(sc->hw->workqueue, | ||
258 | &sc->rf_kill.rfkill_poll, 0); | ||
259 | #endif | ||
260 | |||
261 | return 0; | ||
262 | } | ||
263 | |||
264 | #endif /* CONFIG_PM */ | ||
265 | |||
266 | MODULE_DEVICE_TABLE(pci, ath_pci_id_table); | ||
267 | |||
268 | static struct pci_driver ath_pci_driver = { | ||
269 | .name = "ath9k", | ||
270 | .id_table = ath_pci_id_table, | ||
271 | .probe = ath_pci_probe, | ||
272 | .remove = ath_pci_remove, | ||
273 | #ifdef CONFIG_PM | ||
274 | .suspend = ath_pci_suspend, | ||
275 | .resume = ath_pci_resume, | ||
276 | #endif /* CONFIG_PM */ | ||
277 | }; | ||
278 | |||
279 | int __init ath_pci_init(void) | ||
280 | { | ||
281 | return pci_register_driver(&ath_pci_driver); | ||
282 | } | ||
283 | |||
284 | void ath_pci_exit(void) | ||
285 | { | ||
286 | pci_unregister_driver(&ath_pci_driver); | ||
287 | } | ||