From: Rafał Miłecki Date: Mon, 16 Nov 2015 06:55:38 +0000 (+0000) Subject: kernel: backport ssb changes from 4.4-rc1 X-Git-Tag: v19.07.0-rc1~12194 X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=b2dab45aa776f8cacef8606af05cc657c8f99323;p=openwrt%2Fstaging%2Fhauke.git kernel: backport ssb changes from 4.4-rc1 Signed-off-by: Rafał Miłecki SVN-Revision: 47483 --- diff --git a/package/kernel/mac80211/patches/315-ssb-pick-PCMCIA-host-code-support-from-b43-driver.patch b/package/kernel/mac80211/patches/315-ssb-pick-PCMCIA-host-code-support-from-b43-driver.patch new file mode 100644 index 0000000000..64601ddf45 --- /dev/null +++ b/package/kernel/mac80211/patches/315-ssb-pick-PCMCIA-host-code-support-from-b43-driver.patch @@ -0,0 +1,485 @@ +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Thu, 15 Oct 2015 07:23:25 +0200 +Subject: [PATCH] ssb: pick PCMCIA host code support from b43 driver +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +ssb bus can be found on various "host" devices like PCI/PCMCIA/SDIO. +Every ssb bus contains cores AKA devices. +The main idea is to have ssb driver scan/initialize bus and register +ready-to-use cores. This way ssb drivers can operate on a single core +mostly ignoring underlaying details. + +For some reason PCMCIA support was split between ssb and b43. We got +PCMCIA host device probing in b43, then bus scanning in ssb and then +wireless core probing back in b43. The truth is it's very unlikely we +will ever see PCMCIA ssb device with no 802.11 core but I still don't +see any advantage of the current architecture. + +With proposed change we get the same functionality with a simpler +architecture, less Kconfig symbols, one killed EXPORT and hopefully +cleaner b43. Since b43 supports both: ssb & bcma I prefer to keep ssb +specific code in ssb driver. + +This mostly moves code from b43's pcmcia.c to bridge_pcmcia_80211.c. We +already use similar solution with b43_pci_bridge.c. I didn't use "b43" +in name of this new file as in theory any driver can operate on wireless +core. + +Signed-off-by: Rafał Miłecki +Signed-off-by: Kalle Valo +--- + delete mode 100644 drivers/net/wireless/b43/pcmcia.c + delete mode 100644 drivers/net/wireless/b43/pcmcia.h + create mode 100644 drivers/ssb/bridge_pcmcia_80211.c + +--- a/drivers/net/wireless/b43/Kconfig ++++ b/drivers/net/wireless/b43/Kconfig +@@ -72,26 +72,6 @@ config B43_PCICORE_AUTOSELECT + select SSB_DRIVER_PCICORE + default y + +-config B43_PCMCIA +- bool "Broadcom 43xx PCMCIA device support" +- depends on B43 && B43_SSB && SSB_PCMCIAHOST_POSSIBLE +- select SSB_PCMCIAHOST +- ---help--- +- Broadcom 43xx PCMCIA device support. +- +- Support for 16bit PCMCIA devices. +- Please note that most PC-CARD devices are _NOT_ 16bit PCMCIA +- devices, but 32bit CardBUS devices. CardBUS devices are supported +- out of the box by b43. +- +- With this config option you can drive b43 cards in +- CompactFlash formfactor in a PCMCIA adaptor. +- CF b43 cards can sometimes be found in handheld PCs. +- +- It's safe to select Y here, even if you don't have a B43 PCMCIA device. +- +- If unsure, say N. +- + config B43_SDIO + bool "Broadcom 43xx SDIO device support" + depends on B43 && B43_SSB && SSB_SDIOHOST_POSSIBLE +--- a/drivers/net/wireless/b43/Makefile ++++ b/drivers/net/wireless/b43/Makefile +@@ -21,7 +21,6 @@ b43-y += pio.o + b43-y += rfkill.o + b43-y += ppr.o + b43-$(CPTCFG_B43_LEDS) += leds.o +-b43-$(CPTCFG_B43_PCMCIA) += pcmcia.o + b43-$(CPTCFG_B43_SDIO) += sdio.o + b43-$(CPTCFG_B43_DEBUG) += debugfs.o + +--- a/drivers/net/wireless/b43/main.c ++++ b/drivers/net/wireless/b43/main.c +@@ -56,7 +56,6 @@ + #include "sysfs.h" + #include "xmit.h" + #include "lo.h" +-#include "pcmcia.h" + #include "sdio.h" + #include + +@@ -5850,12 +5849,9 @@ static int __init b43_init(void) + int err; + + b43_debugfs_init(); +- err = b43_pcmcia_init(); +- if (err) +- goto err_dfs_exit; + err = b43_sdio_init(); + if (err) +- goto err_pcmcia_exit; ++ goto err_dfs_exit; + #ifdef CPTCFG_B43_BCMA + err = bcma_driver_register(&b43_bcma_driver); + if (err) +@@ -5878,8 +5874,6 @@ err_bcma_driver_exit: + err_sdio_exit: + #endif + b43_sdio_exit(); +-err_pcmcia_exit: +- b43_pcmcia_exit(); + err_dfs_exit: + b43_debugfs_exit(); + return err; +@@ -5894,7 +5888,6 @@ static void __exit b43_exit(void) + bcma_driver_unregister(&b43_bcma_driver); + #endif + b43_sdio_exit(); +- b43_pcmcia_exit(); + b43_debugfs_exit(); + } + +--- a/drivers/net/wireless/b43/pcmcia.h ++++ /dev/null +@@ -1,20 +0,0 @@ +-#ifndef B43_PCMCIA_H_ +-#define B43_PCMCIA_H_ +- +-#ifdef CPTCFG_B43_PCMCIA +- +-int b43_pcmcia_init(void); +-void b43_pcmcia_exit(void); +- +-#else /* CPTCFG_B43_PCMCIA */ +- +-static inline int b43_pcmcia_init(void) +-{ +- return 0; +-} +-static inline void b43_pcmcia_exit(void) +-{ +-} +- +-#endif /* CPTCFG_B43_PCMCIA */ +-#endif /* B43_PCMCIA_H_ */ +--- a/drivers/ssb/Makefile ++++ b/drivers/ssb/Makefile +@@ -5,7 +5,7 @@ ssb-$(CPTCFG_SSB_SPROM) += sprom.o + + # host support + ssb-$(CPTCFG_SSB_PCIHOST) += pci.o pcihost_wrapper.o +-ssb-$(CPTCFG_SSB_PCMCIAHOST) += pcmcia.o ++ssb-$(CPTCFG_SSB_PCMCIAHOST) += pcmcia.o bridge_pcmcia_80211.o + ssb-$(CPTCFG_SSB_SDIOHOST) += sdio.o + + # built-in drivers +--- /dev/null ++++ b/drivers/ssb/bridge_pcmcia_80211.c +@@ -0,0 +1,128 @@ ++/* ++ * Broadcom 43xx PCMCIA-SSB bridge module ++ * ++ * Copyright (c) 2007 Michael Buesch ++ * ++ * Licensed under the GNU/GPL. See COPYING for details. ++ */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include "ssb_private.h" ++ ++static const struct pcmcia_device_id ssb_host_pcmcia_tbl[] = { ++ PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x448), ++ PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x476), ++ PCMCIA_DEVICE_NULL, ++}; ++ ++MODULE_DEVICE_TABLE(pcmcia, ssb_host_pcmcia_tbl); ++ ++static int ssb_host_pcmcia_probe(struct pcmcia_device *dev) ++{ ++ struct ssb_bus *ssb; ++ int err = -ENOMEM; ++ int res = 0; ++ ++ ssb = kzalloc(sizeof(*ssb), GFP_KERNEL); ++ if (!ssb) ++ goto out_error; ++ ++ err = -ENODEV; ++ ++ dev->config_flags |= CONF_ENABLE_IRQ; ++ ++ dev->resource[2]->flags |= WIN_ENABLE | WIN_DATA_WIDTH_16 | ++ WIN_USE_WAIT; ++ dev->resource[2]->start = 0; ++ dev->resource[2]->end = SSB_CORE_SIZE; ++ res = pcmcia_request_window(dev, dev->resource[2], 250); ++ if (res != 0) ++ goto err_kfree_ssb; ++ ++ res = pcmcia_map_mem_page(dev, dev->resource[2], 0); ++ if (res != 0) ++ goto err_disable; ++ ++ if (!dev->irq) ++ goto err_disable; ++ ++ res = pcmcia_enable_device(dev); ++ if (res != 0) ++ goto err_disable; ++ ++ err = ssb_bus_pcmciabus_register(ssb, dev, dev->resource[2]->start); ++ if (err) ++ goto err_disable; ++ dev->priv = ssb; ++ ++ return 0; ++ ++err_disable: ++ pcmcia_disable_device(dev); ++err_kfree_ssb: ++ kfree(ssb); ++out_error: ++ ssb_err("Initialization failed (%d, %d)\n", res, err); ++ return err; ++} ++ ++static void ssb_host_pcmcia_remove(struct pcmcia_device *dev) ++{ ++ struct ssb_bus *ssb = dev->priv; ++ ++ ssb_bus_unregister(ssb); ++ pcmcia_disable_device(dev); ++ kfree(ssb); ++ dev->priv = NULL; ++} ++ ++#ifdef CPTCFG_PM ++static int ssb_host_pcmcia_suspend(struct pcmcia_device *dev) ++{ ++ struct ssb_bus *ssb = dev->priv; ++ ++ return ssb_bus_suspend(ssb); ++} ++ ++static int ssb_host_pcmcia_resume(struct pcmcia_device *dev) ++{ ++ struct ssb_bus *ssb = dev->priv; ++ ++ return ssb_bus_resume(ssb); ++} ++#else /* CPTCFG_PM */ ++# define ssb_host_pcmcia_suspend NULL ++# define ssb_host_pcmcia_resume NULL ++#endif /* CPTCFG_PM */ ++ ++static struct pcmcia_driver ssb_host_pcmcia_driver = { ++ .owner = THIS_MODULE, ++ .name = "ssb-pcmcia", ++ .id_table = ssb_host_pcmcia_tbl, ++ .probe = ssb_host_pcmcia_probe, ++ .remove = ssb_host_pcmcia_remove, ++ .suspend = ssb_host_pcmcia_suspend, ++ .resume = ssb_host_pcmcia_resume, ++}; ++ ++/* ++ * These are not module init/exit functions! ++ * The module_pcmcia_driver() helper cannot be used here. ++ */ ++int ssb_host_pcmcia_init(void) ++{ ++ return pcmcia_register_driver(&ssb_host_pcmcia_driver); ++} ++ ++void ssb_host_pcmcia_exit(void) ++{ ++ pcmcia_unregister_driver(&ssb_host_pcmcia_driver); ++} +--- a/drivers/ssb/main.c ++++ b/drivers/ssb/main.c +@@ -906,7 +906,6 @@ int ssb_bus_pcmciabus_register(struct ss + + return err; + } +-EXPORT_SYMBOL(ssb_bus_pcmciabus_register); + #endif /* CPTCFG_SSB_PCMCIAHOST */ + + #ifdef CPTCFG_SSB_SDIOHOST +@@ -1474,6 +1473,12 @@ static int __init ssb_modinit(void) + /* don't fail SSB init because of this */ + err = 0; + } ++ err = ssb_host_pcmcia_init(); ++ if (err) { ++ ssb_err("PCMCIA host initialization failed\n"); ++ /* don't fail SSB init because of this */ ++ err = 0; ++ } + err = ssb_gige_init(); + if (err) { + ssb_err("SSB Broadcom Gigabit Ethernet driver initialization failed\n"); +@@ -1491,6 +1496,7 @@ fs_initcall(ssb_modinit); + static void __exit ssb_modexit(void) + { + ssb_gige_exit(); ++ ssb_host_pcmcia_exit(); + b43_pci_ssb_bridge_exit(); + bus_unregister(&ssb_bustype); + } +--- a/drivers/ssb/ssb_private.h ++++ b/drivers/ssb/ssb_private.h +@@ -94,6 +94,8 @@ extern int ssb_pcmcia_get_invariants(str + extern int ssb_pcmcia_hardware_setup(struct ssb_bus *bus); + extern void ssb_pcmcia_exit(struct ssb_bus *bus); + extern int ssb_pcmcia_init(struct ssb_bus *bus); ++extern int ssb_host_pcmcia_init(void); ++extern void ssb_host_pcmcia_exit(void); + extern const struct ssb_bus_ops ssb_pcmcia_ops; + #else /* CPTCFG_SSB_PCMCIAHOST */ + static inline int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus, +@@ -117,6 +119,13 @@ static inline int ssb_pcmcia_init(struct + { + return 0; + } ++static inline int ssb_host_pcmcia_init(void) ++{ ++ return 0; ++} ++static inline void ssb_host_pcmcia_exit(void) ++{ ++} + #endif /* CPTCFG_SSB_PCMCIAHOST */ + + /* sdio.c */ +--- a/drivers/net/wireless/b43/pcmcia.c ++++ /dev/null +@@ -1,145 +0,0 @@ +-/* +- +- Broadcom B43 wireless driver +- +- Copyright (c) 2007 Michael Buesch +- +- 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. +- +- This program is distributed in the hope that it will be useful, +- but WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- GNU General Public License for more details. +- +- You should have received a copy of the GNU General Public License +- along with this program; see the file COPYING. If not, write to +- the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, +- Boston, MA 02110-1301, USA. +- +-*/ +- +-#include "pcmcia.h" +- +-#include +-#include +-#include +- +-#include +-#include +-#include +-#include +- +- +-static const struct pcmcia_device_id b43_pcmcia_tbl[] = { +- PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x448), +- PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x476), +- PCMCIA_DEVICE_NULL, +-}; +- +-MODULE_DEVICE_TABLE(pcmcia, b43_pcmcia_tbl); +- +-#ifdef CONFIG_PM +-static int b43_pcmcia_suspend(struct pcmcia_device *dev) +-{ +- struct ssb_bus *ssb = dev->priv; +- +- return ssb_bus_suspend(ssb); +-} +- +-static int b43_pcmcia_resume(struct pcmcia_device *dev) +-{ +- struct ssb_bus *ssb = dev->priv; +- +- return ssb_bus_resume(ssb); +-} +-#else /* CONFIG_PM */ +-# define b43_pcmcia_suspend NULL +-# define b43_pcmcia_resume NULL +-#endif /* CONFIG_PM */ +- +-static int b43_pcmcia_probe(struct pcmcia_device *dev) +-{ +- struct ssb_bus *ssb; +- int err = -ENOMEM; +- int res = 0; +- +- ssb = kzalloc(sizeof(*ssb), GFP_KERNEL); +- if (!ssb) +- goto out_error; +- +- err = -ENODEV; +- +- dev->config_flags |= CONF_ENABLE_IRQ; +- +- dev->resource[2]->flags |= WIN_ENABLE | WIN_DATA_WIDTH_16 | +- WIN_USE_WAIT; +- dev->resource[2]->start = 0; +- dev->resource[2]->end = SSB_CORE_SIZE; +- res = pcmcia_request_window(dev, dev->resource[2], 250); +- if (res != 0) +- goto err_kfree_ssb; +- +- res = pcmcia_map_mem_page(dev, dev->resource[2], 0); +- if (res != 0) +- goto err_disable; +- +- if (!dev->irq) +- goto err_disable; +- +- res = pcmcia_enable_device(dev); +- if (res != 0) +- goto err_disable; +- +- err = ssb_bus_pcmciabus_register(ssb, dev, dev->resource[2]->start); +- if (err) +- goto err_disable; +- dev->priv = ssb; +- +- return 0; +- +-err_disable: +- pcmcia_disable_device(dev); +-err_kfree_ssb: +- kfree(ssb); +-out_error: +- printk(KERN_ERR "b43-pcmcia: Initialization failed (%d, %d)\n", +- res, err); +- return err; +-} +- +-static void b43_pcmcia_remove(struct pcmcia_device *dev) +-{ +- struct ssb_bus *ssb = dev->priv; +- +- ssb_bus_unregister(ssb); +- pcmcia_disable_device(dev); +- kfree(ssb); +- dev->priv = NULL; +-} +- +-static struct pcmcia_driver b43_pcmcia_driver = { +- .owner = THIS_MODULE, +- .name = "b43-pcmcia", +- .id_table = b43_pcmcia_tbl, +- .probe = b43_pcmcia_probe, +- .remove = b43_pcmcia_remove, +- .suspend = b43_pcmcia_suspend, +- .resume = b43_pcmcia_resume, +-}; +- +-/* +- * These are not module init/exit functions! +- * The module_pcmcia_driver() helper cannot be used here. +- */ +-int b43_pcmcia_init(void) +-{ +- return pcmcia_register_driver(&b43_pcmcia_driver); +-} +- +-void b43_pcmcia_exit(void) +-{ +- pcmcia_unregister_driver(&b43_pcmcia_driver); +-} diff --git a/package/kernel/mac80211/patches/805-b43-gpio-mask-module-option.patch b/package/kernel/mac80211/patches/805-b43-gpio-mask-module-option.patch index 3993c6e8de..6de31dd60f 100644 --- a/package/kernel/mac80211/patches/805-b43-gpio-mask-module-option.patch +++ b/package/kernel/mac80211/patches/805-b43-gpio-mask-module-option.patch @@ -10,7 +10,7 @@ struct b43_phy phy; --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c -@@ -76,6 +76,11 @@ MODULE_FIRMWARE("b43/ucode16_mimo.fw"); +@@ -75,6 +75,11 @@ MODULE_FIRMWARE("b43/ucode16_mimo.fw"); MODULE_FIRMWARE("b43/ucode5.fw"); MODULE_FIRMWARE("b43/ucode9.fw"); @@ -22,7 +22,7 @@ static int modparam_bad_frames_preempt; module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444); MODULE_PARM_DESC(bad_frames_preempt, -@@ -2883,10 +2888,10 @@ static int b43_gpio_init(struct b43_wlde +@@ -2882,10 +2887,10 @@ static int b43_gpio_init(struct b43_wlde u32 mask, set; b43_maskset32(dev, B43_MMIO_MACCTL, ~B43_MACCTL_GPOUTSMSK, 0); diff --git a/package/kernel/mac80211/patches/810-b43_no_pio.patch b/package/kernel/mac80211/patches/810-b43_no_pio.patch index d99f3cef4f..79175528ed 100644 --- a/package/kernel/mac80211/patches/810-b43_no_pio.patch +++ b/package/kernel/mac80211/patches/810-b43_no_pio.patch @@ -11,7 +11,7 @@ b43-$(CPTCFG_B43_LEDS) += leds.o --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c -@@ -2009,10 +2009,12 @@ static void b43_do_interrupt_thread(stru +@@ -2008,10 +2008,12 @@ static void b43_do_interrupt_thread(stru dma_reason[0], dma_reason[1], dma_reason[2], dma_reason[3], dma_reason[4], dma_reason[5]); @@ -75,7 +75,7 @@ #endif /* B43_PIO_H_ */ --- a/drivers/net/wireless/b43/Kconfig +++ b/drivers/net/wireless/b43/Kconfig -@@ -118,7 +118,7 @@ config B43_BCMA_PIO +@@ -98,7 +98,7 @@ config B43_BCMA_PIO default y config B43_PIO diff --git a/package/kernel/mac80211/patches/820-b43-add-antenna-control.patch b/package/kernel/mac80211/patches/820-b43-add-antenna-control.patch index 4f06d8eb13..dd82ce5032 100644 --- a/package/kernel/mac80211/patches/820-b43-add-antenna-control.patch +++ b/package/kernel/mac80211/patches/820-b43-add-antenna-control.patch @@ -1,6 +1,6 @@ --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c -@@ -1649,7 +1649,7 @@ static void b43_write_beacon_template(st +@@ -1648,7 +1648,7 @@ static void b43_write_beacon_template(st len, ram_offset, shm_size_offset, rate); /* Write the PHY TX control parameters. */ @@ -9,7 +9,7 @@ antenna = b43_antenna_to_phyctl(antenna); ctl = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL); /* We can't send beacons with short preamble. Would get PHY errors. */ -@@ -3301,8 +3301,8 @@ static int b43_chip_init(struct b43_wlde +@@ -3300,8 +3300,8 @@ static int b43_chip_init(struct b43_wlde /* Select the antennae */ if (phy->ops->set_rx_antenna) @@ -20,7 +20,7 @@ if (phy->type == B43_PHYTYPE_B) { value16 = b43_read16(dev, 0x005E); -@@ -4002,7 +4002,6 @@ static int b43_op_config(struct ieee8021 +@@ -4001,7 +4001,6 @@ static int b43_op_config(struct ieee8021 struct b43_wldev *dev = wl->current_dev; struct b43_phy *phy = &dev->phy; struct ieee80211_conf *conf = &hw->conf; @@ -28,7 +28,7 @@ int err = 0; mutex_lock(&wl->mutex); -@@ -4045,11 +4044,9 @@ static int b43_op_config(struct ieee8021 +@@ -4044,11 +4043,9 @@ static int b43_op_config(struct ieee8021 } /* Antennas for RX and management frame TX. */ @@ -42,7 +42,7 @@ if (wl->radio_enabled != phy->radio_on) { if (wl->radio_enabled) { -@@ -5210,6 +5207,47 @@ static int b43_op_get_survey(struct ieee +@@ -5209,6 +5206,47 @@ static int b43_op_get_survey(struct ieee return 0; } @@ -90,7 +90,7 @@ static const struct ieee80211_ops b43_hw_ops = { .tx = b43_op_tx, .conf_tx = b43_op_conf_tx, -@@ -5231,6 +5269,8 @@ static const struct ieee80211_ops b43_hw +@@ -5230,6 +5268,8 @@ static const struct ieee80211_ops b43_hw .sw_scan_complete = b43_op_sw_scan_complete_notifier, .get_survey = b43_op_get_survey, .rfkill_poll = b43_rfkill_poll, @@ -99,7 +99,7 @@ }; /* Hard-reset the chip. Do not call this directly. -@@ -5539,6 +5579,8 @@ static int b43_one_core_attach(struct b4 +@@ -5538,6 +5578,8 @@ static int b43_one_core_attach(struct b4 if (!wldev) goto out; @@ -108,7 +108,7 @@ wldev->use_pio = b43_modparam_pio; wldev->dev = dev; wldev->wl = wl; -@@ -5629,6 +5671,9 @@ static struct b43_wl *b43_wireless_init( +@@ -5628,6 +5670,9 @@ static struct b43_wl *b43_wireless_init( hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; diff --git a/package/kernel/mac80211/patches/845-b43-only-use-gpio-0-1-for-led.patch b/package/kernel/mac80211/patches/845-b43-only-use-gpio-0-1-for-led.patch index ab06b6e94c..d4f9a8892b 100644 --- a/package/kernel/mac80211/patches/845-b43-only-use-gpio-0-1-for-led.patch +++ b/package/kernel/mac80211/patches/845-b43-only-use-gpio-0-1-for-led.patch @@ -1,6 +1,6 @@ --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c -@@ -2900,6 +2900,14 @@ static int b43_gpio_init(struct b43_wlde +@@ -2899,6 +2899,14 @@ static int b43_gpio_init(struct b43_wlde } else if (dev->dev->chip_id == 0x5354) { /* Don't allow overtaking buttons GPIOs */ set &= 0x2; /* 0x2 is LED GPIO on BCM5354 */ diff --git a/package/kernel/mac80211/patches/847-b43-always-take-overlapping-devs.patch b/package/kernel/mac80211/patches/847-b43-always-take-overlapping-devs.patch index 9d1d419460..e3b8133483 100644 --- a/package/kernel/mac80211/patches/847-b43-always-take-overlapping-devs.patch +++ b/package/kernel/mac80211/patches/847-b43-always-take-overlapping-devs.patch @@ -1,6 +1,6 @@ --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c -@@ -118,7 +118,7 @@ static int b43_modparam_pio = 0; +@@ -117,7 +117,7 @@ static int b43_modparam_pio = 0; module_param_named(pio, b43_modparam_pio, int, 0644); MODULE_PARM_DESC(pio, "Use PIO accesses by default: 0=DMA, 1=PIO"); diff --git a/target/linux/generic/patches-4.1/020-ssb-backport.patch b/target/linux/generic/patches-4.1/020-ssb-backport.patch new file mode 100644 index 0000000000..e96480b021 --- /dev/null +++ b/target/linux/generic/patches-4.1/020-ssb-backport.patch @@ -0,0 +1,686 @@ +--- a/arch/mips/bcm47xx/Kconfig ++++ b/arch/mips/bcm47xx/Kconfig +@@ -4,6 +4,7 @@ config BCM47XX_SSB + bool "SSB Support for Broadcom BCM47XX" + select SYS_HAS_CPU_BMIPS32_3300 + select SSB ++ select SSB_HOST_SOC + select SSB_DRIVER_MIPS + select SSB_DRIVER_EXTIF + select SSB_EMBEDDED +--- a/drivers/ssb/Kconfig ++++ b/drivers/ssb/Kconfig +@@ -80,6 +80,15 @@ config SSB_SDIOHOST + + If unsure, say N + ++config SSB_HOST_SOC ++ bool "Support for SSB bus on SoC" ++ depends on SSB ++ help ++ Host interface for a SSB directly mapped into memory. This is ++ for some Broadcom SoCs from the BCM47xx and BCM53xx lines. ++ ++ If unsure, say N ++ + config SSB_SILENT + bool "No SSB kernel messages" + depends on SSB && EXPERT +--- a/drivers/ssb/Makefile ++++ b/drivers/ssb/Makefile +@@ -5,8 +5,9 @@ ssb-$(CONFIG_SSB_SPROM) += sprom.o + + # host support + ssb-$(CONFIG_SSB_PCIHOST) += pci.o pcihost_wrapper.o +-ssb-$(CONFIG_SSB_PCMCIAHOST) += pcmcia.o ++ssb-$(CONFIG_SSB_PCMCIAHOST) += pcmcia.o bridge_pcmcia_80211.o + ssb-$(CONFIG_SSB_SDIOHOST) += sdio.o ++ssb-$(CONFIG_SSB_HOST_SOC) += host_soc.o + + # built-in drivers + ssb-y += driver_chipcommon.o +--- /dev/null ++++ b/drivers/ssb/bridge_pcmcia_80211.c +@@ -0,0 +1,128 @@ ++/* ++ * Broadcom 43xx PCMCIA-SSB bridge module ++ * ++ * Copyright (c) 2007 Michael Buesch ++ * ++ * Licensed under the GNU/GPL. See COPYING for details. ++ */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include "ssb_private.h" ++ ++static const struct pcmcia_device_id ssb_host_pcmcia_tbl[] = { ++ PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x448), ++ PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x476), ++ PCMCIA_DEVICE_NULL, ++}; ++ ++MODULE_DEVICE_TABLE(pcmcia, ssb_host_pcmcia_tbl); ++ ++static int ssb_host_pcmcia_probe(struct pcmcia_device *dev) ++{ ++ struct ssb_bus *ssb; ++ int err = -ENOMEM; ++ int res = 0; ++ ++ ssb = kzalloc(sizeof(*ssb), GFP_KERNEL); ++ if (!ssb) ++ goto out_error; ++ ++ err = -ENODEV; ++ ++ dev->config_flags |= CONF_ENABLE_IRQ; ++ ++ dev->resource[2]->flags |= WIN_ENABLE | WIN_DATA_WIDTH_16 | ++ WIN_USE_WAIT; ++ dev->resource[2]->start = 0; ++ dev->resource[2]->end = SSB_CORE_SIZE; ++ res = pcmcia_request_window(dev, dev->resource[2], 250); ++ if (res != 0) ++ goto err_kfree_ssb; ++ ++ res = pcmcia_map_mem_page(dev, dev->resource[2], 0); ++ if (res != 0) ++ goto err_disable; ++ ++ if (!dev->irq) ++ goto err_disable; ++ ++ res = pcmcia_enable_device(dev); ++ if (res != 0) ++ goto err_disable; ++ ++ err = ssb_bus_pcmciabus_register(ssb, dev, dev->resource[2]->start); ++ if (err) ++ goto err_disable; ++ dev->priv = ssb; ++ ++ return 0; ++ ++err_disable: ++ pcmcia_disable_device(dev); ++err_kfree_ssb: ++ kfree(ssb); ++out_error: ++ ssb_err("Initialization failed (%d, %d)\n", res, err); ++ return err; ++} ++ ++static void ssb_host_pcmcia_remove(struct pcmcia_device *dev) ++{ ++ struct ssb_bus *ssb = dev->priv; ++ ++ ssb_bus_unregister(ssb); ++ pcmcia_disable_device(dev); ++ kfree(ssb); ++ dev->priv = NULL; ++} ++ ++#ifdef CONFIG_PM ++static int ssb_host_pcmcia_suspend(struct pcmcia_device *dev) ++{ ++ struct ssb_bus *ssb = dev->priv; ++ ++ return ssb_bus_suspend(ssb); ++} ++ ++static int ssb_host_pcmcia_resume(struct pcmcia_device *dev) ++{ ++ struct ssb_bus *ssb = dev->priv; ++ ++ return ssb_bus_resume(ssb); ++} ++#else /* CONFIG_PM */ ++# define ssb_host_pcmcia_suspend NULL ++# define ssb_host_pcmcia_resume NULL ++#endif /* CONFIG_PM */ ++ ++static struct pcmcia_driver ssb_host_pcmcia_driver = { ++ .owner = THIS_MODULE, ++ .name = "ssb-pcmcia", ++ .id_table = ssb_host_pcmcia_tbl, ++ .probe = ssb_host_pcmcia_probe, ++ .remove = ssb_host_pcmcia_remove, ++ .suspend = ssb_host_pcmcia_suspend, ++ .resume = ssb_host_pcmcia_resume, ++}; ++ ++/* ++ * These are not module init/exit functions! ++ * The module_pcmcia_driver() helper cannot be used here. ++ */ ++int ssb_host_pcmcia_init(void) ++{ ++ return pcmcia_register_driver(&ssb_host_pcmcia_driver); ++} ++ ++void ssb_host_pcmcia_exit(void) ++{ ++ pcmcia_unregister_driver(&ssb_host_pcmcia_driver); ++} +--- /dev/null ++++ b/drivers/ssb/host_soc.c +@@ -0,0 +1,173 @@ ++/* ++ * Sonics Silicon Backplane SoC host related functions. ++ * Subsystem core ++ * ++ * Copyright 2005, Broadcom Corporation ++ * Copyright 2006, 2007, Michael Buesch ++ * ++ * Licensed under the GNU/GPL. See COPYING for details. ++ */ ++ ++#include ++ ++#include "ssb_private.h" ++ ++static u8 ssb_host_soc_read8(struct ssb_device *dev, u16 offset) ++{ ++ struct ssb_bus *bus = dev->bus; ++ ++ offset += dev->core_index * SSB_CORE_SIZE; ++ return readb(bus->mmio + offset); ++} ++ ++static u16 ssb_host_soc_read16(struct ssb_device *dev, u16 offset) ++{ ++ struct ssb_bus *bus = dev->bus; ++ ++ offset += dev->core_index * SSB_CORE_SIZE; ++ return readw(bus->mmio + offset); ++} ++ ++static u32 ssb_host_soc_read32(struct ssb_device *dev, u16 offset) ++{ ++ struct ssb_bus *bus = dev->bus; ++ ++ offset += dev->core_index * SSB_CORE_SIZE; ++ return readl(bus->mmio + offset); ++} ++ ++#ifdef CONFIG_SSB_BLOCKIO ++static void ssb_host_soc_block_read(struct ssb_device *dev, void *buffer, ++ size_t count, u16 offset, u8 reg_width) ++{ ++ struct ssb_bus *bus = dev->bus; ++ void __iomem *addr; ++ ++ offset += dev->core_index * SSB_CORE_SIZE; ++ addr = bus->mmio + offset; ++ ++ switch (reg_width) { ++ case sizeof(u8): { ++ u8 *buf = buffer; ++ ++ while (count) { ++ *buf = __raw_readb(addr); ++ buf++; ++ count--; ++ } ++ break; ++ } ++ case sizeof(u16): { ++ __le16 *buf = buffer; ++ ++ SSB_WARN_ON(count & 1); ++ while (count) { ++ *buf = (__force __le16)__raw_readw(addr); ++ buf++; ++ count -= 2; ++ } ++ break; ++ } ++ case sizeof(u32): { ++ __le32 *buf = buffer; ++ ++ SSB_WARN_ON(count & 3); ++ while (count) { ++ *buf = (__force __le32)__raw_readl(addr); ++ buf++; ++ count -= 4; ++ } ++ break; ++ } ++ default: ++ SSB_WARN_ON(1); ++ } ++} ++#endif /* CONFIG_SSB_BLOCKIO */ ++ ++static void ssb_host_soc_write8(struct ssb_device *dev, u16 offset, u8 value) ++{ ++ struct ssb_bus *bus = dev->bus; ++ ++ offset += dev->core_index * SSB_CORE_SIZE; ++ writeb(value, bus->mmio + offset); ++} ++ ++static void ssb_host_soc_write16(struct ssb_device *dev, u16 offset, u16 value) ++{ ++ struct ssb_bus *bus = dev->bus; ++ ++ offset += dev->core_index * SSB_CORE_SIZE; ++ writew(value, bus->mmio + offset); ++} ++ ++static void ssb_host_soc_write32(struct ssb_device *dev, u16 offset, u32 value) ++{ ++ struct ssb_bus *bus = dev->bus; ++ ++ offset += dev->core_index * SSB_CORE_SIZE; ++ writel(value, bus->mmio + offset); ++} ++ ++#ifdef CONFIG_SSB_BLOCKIO ++static void ssb_host_soc_block_write(struct ssb_device *dev, const void *buffer, ++ size_t count, u16 offset, u8 reg_width) ++{ ++ struct ssb_bus *bus = dev->bus; ++ void __iomem *addr; ++ ++ offset += dev->core_index * SSB_CORE_SIZE; ++ addr = bus->mmio + offset; ++ ++ switch (reg_width) { ++ case sizeof(u8): { ++ const u8 *buf = buffer; ++ ++ while (count) { ++ __raw_writeb(*buf, addr); ++ buf++; ++ count--; ++ } ++ break; ++ } ++ case sizeof(u16): { ++ const __le16 *buf = buffer; ++ ++ SSB_WARN_ON(count & 1); ++ while (count) { ++ __raw_writew((__force u16)(*buf), addr); ++ buf++; ++ count -= 2; ++ } ++ break; ++ } ++ case sizeof(u32): { ++ const __le32 *buf = buffer; ++ ++ SSB_WARN_ON(count & 3); ++ while (count) { ++ __raw_writel((__force u32)(*buf), addr); ++ buf++; ++ count -= 4; ++ } ++ break; ++ } ++ default: ++ SSB_WARN_ON(1); ++ } ++} ++#endif /* CONFIG_SSB_BLOCKIO */ ++ ++/* Ops for the plain SSB bus without a host-device (no PCI or PCMCIA). */ ++const struct ssb_bus_ops ssb_host_soc_ops = { ++ .read8 = ssb_host_soc_read8, ++ .read16 = ssb_host_soc_read16, ++ .read32 = ssb_host_soc_read32, ++ .write8 = ssb_host_soc_write8, ++ .write16 = ssb_host_soc_write16, ++ .write32 = ssb_host_soc_write32, ++#ifdef CONFIG_SSB_BLOCKIO ++ .block_read = ssb_host_soc_block_read, ++ .block_write = ssb_host_soc_block_write, ++#endif ++}; +--- a/drivers/ssb/main.c ++++ b/drivers/ssb/main.c +@@ -596,166 +596,6 @@ error: + return err; + } + +-static u8 ssb_ssb_read8(struct ssb_device *dev, u16 offset) +-{ +- struct ssb_bus *bus = dev->bus; +- +- offset += dev->core_index * SSB_CORE_SIZE; +- return readb(bus->mmio + offset); +-} +- +-static u16 ssb_ssb_read16(struct ssb_device *dev, u16 offset) +-{ +- struct ssb_bus *bus = dev->bus; +- +- offset += dev->core_index * SSB_CORE_SIZE; +- return readw(bus->mmio + offset); +-} +- +-static u32 ssb_ssb_read32(struct ssb_device *dev, u16 offset) +-{ +- struct ssb_bus *bus = dev->bus; +- +- offset += dev->core_index * SSB_CORE_SIZE; +- return readl(bus->mmio + offset); +-} +- +-#ifdef CONFIG_SSB_BLOCKIO +-static void ssb_ssb_block_read(struct ssb_device *dev, void *buffer, +- size_t count, u16 offset, u8 reg_width) +-{ +- struct ssb_bus *bus = dev->bus; +- void __iomem *addr; +- +- offset += dev->core_index * SSB_CORE_SIZE; +- addr = bus->mmio + offset; +- +- switch (reg_width) { +- case sizeof(u8): { +- u8 *buf = buffer; +- +- while (count) { +- *buf = __raw_readb(addr); +- buf++; +- count--; +- } +- break; +- } +- case sizeof(u16): { +- __le16 *buf = buffer; +- +- SSB_WARN_ON(count & 1); +- while (count) { +- *buf = (__force __le16)__raw_readw(addr); +- buf++; +- count -= 2; +- } +- break; +- } +- case sizeof(u32): { +- __le32 *buf = buffer; +- +- SSB_WARN_ON(count & 3); +- while (count) { +- *buf = (__force __le32)__raw_readl(addr); +- buf++; +- count -= 4; +- } +- break; +- } +- default: +- SSB_WARN_ON(1); +- } +-} +-#endif /* CONFIG_SSB_BLOCKIO */ +- +-static void ssb_ssb_write8(struct ssb_device *dev, u16 offset, u8 value) +-{ +- struct ssb_bus *bus = dev->bus; +- +- offset += dev->core_index * SSB_CORE_SIZE; +- writeb(value, bus->mmio + offset); +-} +- +-static void ssb_ssb_write16(struct ssb_device *dev, u16 offset, u16 value) +-{ +- struct ssb_bus *bus = dev->bus; +- +- offset += dev->core_index * SSB_CORE_SIZE; +- writew(value, bus->mmio + offset); +-} +- +-static void ssb_ssb_write32(struct ssb_device *dev, u16 offset, u32 value) +-{ +- struct ssb_bus *bus = dev->bus; +- +- offset += dev->core_index * SSB_CORE_SIZE; +- writel(value, bus->mmio + offset); +-} +- +-#ifdef CONFIG_SSB_BLOCKIO +-static void ssb_ssb_block_write(struct ssb_device *dev, const void *buffer, +- size_t count, u16 offset, u8 reg_width) +-{ +- struct ssb_bus *bus = dev->bus; +- void __iomem *addr; +- +- offset += dev->core_index * SSB_CORE_SIZE; +- addr = bus->mmio + offset; +- +- switch (reg_width) { +- case sizeof(u8): { +- const u8 *buf = buffer; +- +- while (count) { +- __raw_writeb(*buf, addr); +- buf++; +- count--; +- } +- break; +- } +- case sizeof(u16): { +- const __le16 *buf = buffer; +- +- SSB_WARN_ON(count & 1); +- while (count) { +- __raw_writew((__force u16)(*buf), addr); +- buf++; +- count -= 2; +- } +- break; +- } +- case sizeof(u32): { +- const __le32 *buf = buffer; +- +- SSB_WARN_ON(count & 3); +- while (count) { +- __raw_writel((__force u32)(*buf), addr); +- buf++; +- count -= 4; +- } +- break; +- } +- default: +- SSB_WARN_ON(1); +- } +-} +-#endif /* CONFIG_SSB_BLOCKIO */ +- +-/* Ops for the plain SSB bus without a host-device (no PCI or PCMCIA). */ +-static const struct ssb_bus_ops ssb_ssb_ops = { +- .read8 = ssb_ssb_read8, +- .read16 = ssb_ssb_read16, +- .read32 = ssb_ssb_read32, +- .write8 = ssb_ssb_write8, +- .write16 = ssb_ssb_write16, +- .write32 = ssb_ssb_write32, +-#ifdef CONFIG_SSB_BLOCKIO +- .block_read = ssb_ssb_block_read, +- .block_write = ssb_ssb_block_write, +-#endif +-}; +- + static int ssb_fetch_invariants(struct ssb_bus *bus, + ssb_invariants_func_t get_invariants) + { +@@ -876,7 +716,6 @@ int ssb_bus_pcibus_register(struct ssb_b + + return err; + } +-EXPORT_SYMBOL(ssb_bus_pcibus_register); + #endif /* CONFIG_SSB_PCIHOST */ + + #ifdef CONFIG_SSB_PCMCIAHOST +@@ -898,7 +737,6 @@ int ssb_bus_pcmciabus_register(struct ss + + return err; + } +-EXPORT_SYMBOL(ssb_bus_pcmciabus_register); + #endif /* CONFIG_SSB_PCMCIAHOST */ + + #ifdef CONFIG_SSB_SDIOHOST +@@ -923,13 +761,14 @@ int ssb_bus_sdiobus_register(struct ssb_ + EXPORT_SYMBOL(ssb_bus_sdiobus_register); + #endif /* CONFIG_SSB_PCMCIAHOST */ + ++#ifdef CONFIG_SSB_HOST_SOC + int ssb_bus_ssbbus_register(struct ssb_bus *bus, unsigned long baseaddr, + ssb_invariants_func_t get_invariants) + { + int err; + + bus->bustype = SSB_BUSTYPE_SSB; +- bus->ops = &ssb_ssb_ops; ++ bus->ops = &ssb_host_soc_ops; + + err = ssb_bus_register(bus, get_invariants, baseaddr); + if (!err) { +@@ -939,6 +778,7 @@ int ssb_bus_ssbbus_register(struct ssb_b + + return err; + } ++#endif + + int __ssb_driver_register(struct ssb_driver *drv, struct module *owner) + { +@@ -1465,6 +1305,12 @@ static int __init ssb_modinit(void) + /* don't fail SSB init because of this */ + err = 0; + } ++ err = ssb_host_pcmcia_init(); ++ if (err) { ++ ssb_err("PCMCIA host initialization failed\n"); ++ /* don't fail SSB init because of this */ ++ err = 0; ++ } + err = ssb_gige_init(); + if (err) { + ssb_err("SSB Broadcom Gigabit Ethernet driver initialization failed\n"); +@@ -1482,6 +1328,7 @@ fs_initcall(ssb_modinit); + static void __exit ssb_modexit(void) + { + ssb_gige_exit(); ++ ssb_host_pcmcia_exit(); + b43_pci_ssb_bridge_exit(); + bus_unregister(&ssb_bustype); + } +--- a/drivers/ssb/pcmcia.c ++++ b/drivers/ssb/pcmcia.c +@@ -147,8 +147,7 @@ error: + return err; + } + +-int ssb_pcmcia_switch_core(struct ssb_bus *bus, +- struct ssb_device *dev) ++static int ssb_pcmcia_switch_core(struct ssb_bus *bus, struct ssb_device *dev) + { + int err; + +--- a/drivers/ssb/sdio.c ++++ b/drivers/ssb/sdio.c +@@ -200,7 +200,7 @@ out: + } + + /* host must be already claimed */ +-int ssb_sdio_switch_core(struct ssb_bus *bus, struct ssb_device *dev) ++static int ssb_sdio_switch_core(struct ssb_bus *bus, struct ssb_device *dev) + { + u8 coreidx = dev->core_index; + u32 sbaddr; +--- a/drivers/ssb/ssb_private.h ++++ b/drivers/ssb/ssb_private.h +@@ -85,8 +85,6 @@ static inline int ssb_pci_init(struct ss + + /* pcmcia.c */ + #ifdef CONFIG_SSB_PCMCIAHOST +-extern int ssb_pcmcia_switch_core(struct ssb_bus *bus, +- struct ssb_device *dev); + extern int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus, + u8 coreidx); + extern int ssb_pcmcia_switch_segment(struct ssb_bus *bus, +@@ -96,13 +94,10 @@ extern int ssb_pcmcia_get_invariants(str + extern int ssb_pcmcia_hardware_setup(struct ssb_bus *bus); + extern void ssb_pcmcia_exit(struct ssb_bus *bus); + extern int ssb_pcmcia_init(struct ssb_bus *bus); ++extern int ssb_host_pcmcia_init(void); ++extern void ssb_host_pcmcia_exit(void); + extern const struct ssb_bus_ops ssb_pcmcia_ops; + #else /* CONFIG_SSB_PCMCIAHOST */ +-static inline int ssb_pcmcia_switch_core(struct ssb_bus *bus, +- struct ssb_device *dev) +-{ +- return 0; +-} + static inline int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus, + u8 coreidx) + { +@@ -124,6 +119,13 @@ static inline int ssb_pcmcia_init(struct + { + return 0; + } ++static inline int ssb_host_pcmcia_init(void) ++{ ++ return 0; ++} ++static inline void ssb_host_pcmcia_exit(void) ++{ ++} + #endif /* CONFIG_SSB_PCMCIAHOST */ + + /* sdio.c */ +@@ -132,9 +134,7 @@ extern int ssb_sdio_get_invariants(struc + struct ssb_init_invariants *iv); + + extern u32 ssb_sdio_scan_read32(struct ssb_bus *bus, u16 offset); +-extern int ssb_sdio_switch_core(struct ssb_bus *bus, struct ssb_device *dev); + extern int ssb_sdio_scan_switch_coreidx(struct ssb_bus *bus, u8 coreidx); +-extern int ssb_sdio_hardware_setup(struct ssb_bus *bus); + extern void ssb_sdio_exit(struct ssb_bus *bus); + extern int ssb_sdio_init(struct ssb_bus *bus); + +@@ -144,19 +144,10 @@ static inline u32 ssb_sdio_scan_read32(s + { + return 0; + } +-static inline int ssb_sdio_switch_core(struct ssb_bus *bus, +- struct ssb_device *dev) +-{ +- return 0; +-} + static inline int ssb_sdio_scan_switch_coreidx(struct ssb_bus *bus, u8 coreidx) + { + return 0; + } +-static inline int ssb_sdio_hardware_setup(struct ssb_bus *bus) +-{ +- return 0; +-} + static inline void ssb_sdio_exit(struct ssb_bus *bus) + { + } +@@ -166,6 +157,13 @@ static inline int ssb_sdio_init(struct s + } + #endif /* CONFIG_SSB_SDIOHOST */ + ++/************************************************** ++ * host_soc.c ++ **************************************************/ ++ ++#ifdef CONFIG_SSB_HOST_SOC ++extern const struct ssb_bus_ops ssb_host_soc_ops; ++#endif + + /* scan.c */ + extern const char *ssb_core_name(u16 coreid); diff --git a/target/linux/generic/patches-4.3/020-ssb-backport.patch b/target/linux/generic/patches-4.3/020-ssb-backport.patch new file mode 100644 index 0000000000..e96480b021 --- /dev/null +++ b/target/linux/generic/patches-4.3/020-ssb-backport.patch @@ -0,0 +1,686 @@ +--- a/arch/mips/bcm47xx/Kconfig ++++ b/arch/mips/bcm47xx/Kconfig +@@ -4,6 +4,7 @@ config BCM47XX_SSB + bool "SSB Support for Broadcom BCM47XX" + select SYS_HAS_CPU_BMIPS32_3300 + select SSB ++ select SSB_HOST_SOC + select SSB_DRIVER_MIPS + select SSB_DRIVER_EXTIF + select SSB_EMBEDDED +--- a/drivers/ssb/Kconfig ++++ b/drivers/ssb/Kconfig +@@ -80,6 +80,15 @@ config SSB_SDIOHOST + + If unsure, say N + ++config SSB_HOST_SOC ++ bool "Support for SSB bus on SoC" ++ depends on SSB ++ help ++ Host interface for a SSB directly mapped into memory. This is ++ for some Broadcom SoCs from the BCM47xx and BCM53xx lines. ++ ++ If unsure, say N ++ + config SSB_SILENT + bool "No SSB kernel messages" + depends on SSB && EXPERT +--- a/drivers/ssb/Makefile ++++ b/drivers/ssb/Makefile +@@ -5,8 +5,9 @@ ssb-$(CONFIG_SSB_SPROM) += sprom.o + + # host support + ssb-$(CONFIG_SSB_PCIHOST) += pci.o pcihost_wrapper.o +-ssb-$(CONFIG_SSB_PCMCIAHOST) += pcmcia.o ++ssb-$(CONFIG_SSB_PCMCIAHOST) += pcmcia.o bridge_pcmcia_80211.o + ssb-$(CONFIG_SSB_SDIOHOST) += sdio.o ++ssb-$(CONFIG_SSB_HOST_SOC) += host_soc.o + + # built-in drivers + ssb-y += driver_chipcommon.o +--- /dev/null ++++ b/drivers/ssb/bridge_pcmcia_80211.c +@@ -0,0 +1,128 @@ ++/* ++ * Broadcom 43xx PCMCIA-SSB bridge module ++ * ++ * Copyright (c) 2007 Michael Buesch ++ * ++ * Licensed under the GNU/GPL. See COPYING for details. ++ */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include "ssb_private.h" ++ ++static const struct pcmcia_device_id ssb_host_pcmcia_tbl[] = { ++ PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x448), ++ PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x476), ++ PCMCIA_DEVICE_NULL, ++}; ++ ++MODULE_DEVICE_TABLE(pcmcia, ssb_host_pcmcia_tbl); ++ ++static int ssb_host_pcmcia_probe(struct pcmcia_device *dev) ++{ ++ struct ssb_bus *ssb; ++ int err = -ENOMEM; ++ int res = 0; ++ ++ ssb = kzalloc(sizeof(*ssb), GFP_KERNEL); ++ if (!ssb) ++ goto out_error; ++ ++ err = -ENODEV; ++ ++ dev->config_flags |= CONF_ENABLE_IRQ; ++ ++ dev->resource[2]->flags |= WIN_ENABLE | WIN_DATA_WIDTH_16 | ++ WIN_USE_WAIT; ++ dev->resource[2]->start = 0; ++ dev->resource[2]->end = SSB_CORE_SIZE; ++ res = pcmcia_request_window(dev, dev->resource[2], 250); ++ if (res != 0) ++ goto err_kfree_ssb; ++ ++ res = pcmcia_map_mem_page(dev, dev->resource[2], 0); ++ if (res != 0) ++ goto err_disable; ++ ++ if (!dev->irq) ++ goto err_disable; ++ ++ res = pcmcia_enable_device(dev); ++ if (res != 0) ++ goto err_disable; ++ ++ err = ssb_bus_pcmciabus_register(ssb, dev, dev->resource[2]->start); ++ if (err) ++ goto err_disable; ++ dev->priv = ssb; ++ ++ return 0; ++ ++err_disable: ++ pcmcia_disable_device(dev); ++err_kfree_ssb: ++ kfree(ssb); ++out_error: ++ ssb_err("Initialization failed (%d, %d)\n", res, err); ++ return err; ++} ++ ++static void ssb_host_pcmcia_remove(struct pcmcia_device *dev) ++{ ++ struct ssb_bus *ssb = dev->priv; ++ ++ ssb_bus_unregister(ssb); ++ pcmcia_disable_device(dev); ++ kfree(ssb); ++ dev->priv = NULL; ++} ++ ++#ifdef CONFIG_PM ++static int ssb_host_pcmcia_suspend(struct pcmcia_device *dev) ++{ ++ struct ssb_bus *ssb = dev->priv; ++ ++ return ssb_bus_suspend(ssb); ++} ++ ++static int ssb_host_pcmcia_resume(struct pcmcia_device *dev) ++{ ++ struct ssb_bus *ssb = dev->priv; ++ ++ return ssb_bus_resume(ssb); ++} ++#else /* CONFIG_PM */ ++# define ssb_host_pcmcia_suspend NULL ++# define ssb_host_pcmcia_resume NULL ++#endif /* CONFIG_PM */ ++ ++static struct pcmcia_driver ssb_host_pcmcia_driver = { ++ .owner = THIS_MODULE, ++ .name = "ssb-pcmcia", ++ .id_table = ssb_host_pcmcia_tbl, ++ .probe = ssb_host_pcmcia_probe, ++ .remove = ssb_host_pcmcia_remove, ++ .suspend = ssb_host_pcmcia_suspend, ++ .resume = ssb_host_pcmcia_resume, ++}; ++ ++/* ++ * These are not module init/exit functions! ++ * The module_pcmcia_driver() helper cannot be used here. ++ */ ++int ssb_host_pcmcia_init(void) ++{ ++ return pcmcia_register_driver(&ssb_host_pcmcia_driver); ++} ++ ++void ssb_host_pcmcia_exit(void) ++{ ++ pcmcia_unregister_driver(&ssb_host_pcmcia_driver); ++} +--- /dev/null ++++ b/drivers/ssb/host_soc.c +@@ -0,0 +1,173 @@ ++/* ++ * Sonics Silicon Backplane SoC host related functions. ++ * Subsystem core ++ * ++ * Copyright 2005, Broadcom Corporation ++ * Copyright 2006, 2007, Michael Buesch ++ * ++ * Licensed under the GNU/GPL. See COPYING for details. ++ */ ++ ++#include ++ ++#include "ssb_private.h" ++ ++static u8 ssb_host_soc_read8(struct ssb_device *dev, u16 offset) ++{ ++ struct ssb_bus *bus = dev->bus; ++ ++ offset += dev->core_index * SSB_CORE_SIZE; ++ return readb(bus->mmio + offset); ++} ++ ++static u16 ssb_host_soc_read16(struct ssb_device *dev, u16 offset) ++{ ++ struct ssb_bus *bus = dev->bus; ++ ++ offset += dev->core_index * SSB_CORE_SIZE; ++ return readw(bus->mmio + offset); ++} ++ ++static u32 ssb_host_soc_read32(struct ssb_device *dev, u16 offset) ++{ ++ struct ssb_bus *bus = dev->bus; ++ ++ offset += dev->core_index * SSB_CORE_SIZE; ++ return readl(bus->mmio + offset); ++} ++ ++#ifdef CONFIG_SSB_BLOCKIO ++static void ssb_host_soc_block_read(struct ssb_device *dev, void *buffer, ++ size_t count, u16 offset, u8 reg_width) ++{ ++ struct ssb_bus *bus = dev->bus; ++ void __iomem *addr; ++ ++ offset += dev->core_index * SSB_CORE_SIZE; ++ addr = bus->mmio + offset; ++ ++ switch (reg_width) { ++ case sizeof(u8): { ++ u8 *buf = buffer; ++ ++ while (count) { ++ *buf = __raw_readb(addr); ++ buf++; ++ count--; ++ } ++ break; ++ } ++ case sizeof(u16): { ++ __le16 *buf = buffer; ++ ++ SSB_WARN_ON(count & 1); ++ while (count) { ++ *buf = (__force __le16)__raw_readw(addr); ++ buf++; ++ count -= 2; ++ } ++ break; ++ } ++ case sizeof(u32): { ++ __le32 *buf = buffer; ++ ++ SSB_WARN_ON(count & 3); ++ while (count) { ++ *buf = (__force __le32)__raw_readl(addr); ++ buf++; ++ count -= 4; ++ } ++ break; ++ } ++ default: ++ SSB_WARN_ON(1); ++ } ++} ++#endif /* CONFIG_SSB_BLOCKIO */ ++ ++static void ssb_host_soc_write8(struct ssb_device *dev, u16 offset, u8 value) ++{ ++ struct ssb_bus *bus = dev->bus; ++ ++ offset += dev->core_index * SSB_CORE_SIZE; ++ writeb(value, bus->mmio + offset); ++} ++ ++static void ssb_host_soc_write16(struct ssb_device *dev, u16 offset, u16 value) ++{ ++ struct ssb_bus *bus = dev->bus; ++ ++ offset += dev->core_index * SSB_CORE_SIZE; ++ writew(value, bus->mmio + offset); ++} ++ ++static void ssb_host_soc_write32(struct ssb_device *dev, u16 offset, u32 value) ++{ ++ struct ssb_bus *bus = dev->bus; ++ ++ offset += dev->core_index * SSB_CORE_SIZE; ++ writel(value, bus->mmio + offset); ++} ++ ++#ifdef CONFIG_SSB_BLOCKIO ++static void ssb_host_soc_block_write(struct ssb_device *dev, const void *buffer, ++ size_t count, u16 offset, u8 reg_width) ++{ ++ struct ssb_bus *bus = dev->bus; ++ void __iomem *addr; ++ ++ offset += dev->core_index * SSB_CORE_SIZE; ++ addr = bus->mmio + offset; ++ ++ switch (reg_width) { ++ case sizeof(u8): { ++ const u8 *buf = buffer; ++ ++ while (count) { ++ __raw_writeb(*buf, addr); ++ buf++; ++ count--; ++ } ++ break; ++ } ++ case sizeof(u16): { ++ const __le16 *buf = buffer; ++ ++ SSB_WARN_ON(count & 1); ++ while (count) { ++ __raw_writew((__force u16)(*buf), addr); ++ buf++; ++ count -= 2; ++ } ++ break; ++ } ++ case sizeof(u32): { ++ const __le32 *buf = buffer; ++ ++ SSB_WARN_ON(count & 3); ++ while (count) { ++ __raw_writel((__force u32)(*buf), addr); ++ buf++; ++ count -= 4; ++ } ++ break; ++ } ++ default: ++ SSB_WARN_ON(1); ++ } ++} ++#endif /* CONFIG_SSB_BLOCKIO */ ++ ++/* Ops for the plain SSB bus without a host-device (no PCI or PCMCIA). */ ++const struct ssb_bus_ops ssb_host_soc_ops = { ++ .read8 = ssb_host_soc_read8, ++ .read16 = ssb_host_soc_read16, ++ .read32 = ssb_host_soc_read32, ++ .write8 = ssb_host_soc_write8, ++ .write16 = ssb_host_soc_write16, ++ .write32 = ssb_host_soc_write32, ++#ifdef CONFIG_SSB_BLOCKIO ++ .block_read = ssb_host_soc_block_read, ++ .block_write = ssb_host_soc_block_write, ++#endif ++}; +--- a/drivers/ssb/main.c ++++ b/drivers/ssb/main.c +@@ -596,166 +596,6 @@ error: + return err; + } + +-static u8 ssb_ssb_read8(struct ssb_device *dev, u16 offset) +-{ +- struct ssb_bus *bus = dev->bus; +- +- offset += dev->core_index * SSB_CORE_SIZE; +- return readb(bus->mmio + offset); +-} +- +-static u16 ssb_ssb_read16(struct ssb_device *dev, u16 offset) +-{ +- struct ssb_bus *bus = dev->bus; +- +- offset += dev->core_index * SSB_CORE_SIZE; +- return readw(bus->mmio + offset); +-} +- +-static u32 ssb_ssb_read32(struct ssb_device *dev, u16 offset) +-{ +- struct ssb_bus *bus = dev->bus; +- +- offset += dev->core_index * SSB_CORE_SIZE; +- return readl(bus->mmio + offset); +-} +- +-#ifdef CONFIG_SSB_BLOCKIO +-static void ssb_ssb_block_read(struct ssb_device *dev, void *buffer, +- size_t count, u16 offset, u8 reg_width) +-{ +- struct ssb_bus *bus = dev->bus; +- void __iomem *addr; +- +- offset += dev->core_index * SSB_CORE_SIZE; +- addr = bus->mmio + offset; +- +- switch (reg_width) { +- case sizeof(u8): { +- u8 *buf = buffer; +- +- while (count) { +- *buf = __raw_readb(addr); +- buf++; +- count--; +- } +- break; +- } +- case sizeof(u16): { +- __le16 *buf = buffer; +- +- SSB_WARN_ON(count & 1); +- while (count) { +- *buf = (__force __le16)__raw_readw(addr); +- buf++; +- count -= 2; +- } +- break; +- } +- case sizeof(u32): { +- __le32 *buf = buffer; +- +- SSB_WARN_ON(count & 3); +- while (count) { +- *buf = (__force __le32)__raw_readl(addr); +- buf++; +- count -= 4; +- } +- break; +- } +- default: +- SSB_WARN_ON(1); +- } +-} +-#endif /* CONFIG_SSB_BLOCKIO */ +- +-static void ssb_ssb_write8(struct ssb_device *dev, u16 offset, u8 value) +-{ +- struct ssb_bus *bus = dev->bus; +- +- offset += dev->core_index * SSB_CORE_SIZE; +- writeb(value, bus->mmio + offset); +-} +- +-static void ssb_ssb_write16(struct ssb_device *dev, u16 offset, u16 value) +-{ +- struct ssb_bus *bus = dev->bus; +- +- offset += dev->core_index * SSB_CORE_SIZE; +- writew(value, bus->mmio + offset); +-} +- +-static void ssb_ssb_write32(struct ssb_device *dev, u16 offset, u32 value) +-{ +- struct ssb_bus *bus = dev->bus; +- +- offset += dev->core_index * SSB_CORE_SIZE; +- writel(value, bus->mmio + offset); +-} +- +-#ifdef CONFIG_SSB_BLOCKIO +-static void ssb_ssb_block_write(struct ssb_device *dev, const void *buffer, +- size_t count, u16 offset, u8 reg_width) +-{ +- struct ssb_bus *bus = dev->bus; +- void __iomem *addr; +- +- offset += dev->core_index * SSB_CORE_SIZE; +- addr = bus->mmio + offset; +- +- switch (reg_width) { +- case sizeof(u8): { +- const u8 *buf = buffer; +- +- while (count) { +- __raw_writeb(*buf, addr); +- buf++; +- count--; +- } +- break; +- } +- case sizeof(u16): { +- const __le16 *buf = buffer; +- +- SSB_WARN_ON(count & 1); +- while (count) { +- __raw_writew((__force u16)(*buf), addr); +- buf++; +- count -= 2; +- } +- break; +- } +- case sizeof(u32): { +- const __le32 *buf = buffer; +- +- SSB_WARN_ON(count & 3); +- while (count) { +- __raw_writel((__force u32)(*buf), addr); +- buf++; +- count -= 4; +- } +- break; +- } +- default: +- SSB_WARN_ON(1); +- } +-} +-#endif /* CONFIG_SSB_BLOCKIO */ +- +-/* Ops for the plain SSB bus without a host-device (no PCI or PCMCIA). */ +-static const struct ssb_bus_ops ssb_ssb_ops = { +- .read8 = ssb_ssb_read8, +- .read16 = ssb_ssb_read16, +- .read32 = ssb_ssb_read32, +- .write8 = ssb_ssb_write8, +- .write16 = ssb_ssb_write16, +- .write32 = ssb_ssb_write32, +-#ifdef CONFIG_SSB_BLOCKIO +- .block_read = ssb_ssb_block_read, +- .block_write = ssb_ssb_block_write, +-#endif +-}; +- + static int ssb_fetch_invariants(struct ssb_bus *bus, + ssb_invariants_func_t get_invariants) + { +@@ -876,7 +716,6 @@ int ssb_bus_pcibus_register(struct ssb_b + + return err; + } +-EXPORT_SYMBOL(ssb_bus_pcibus_register); + #endif /* CONFIG_SSB_PCIHOST */ + + #ifdef CONFIG_SSB_PCMCIAHOST +@@ -898,7 +737,6 @@ int ssb_bus_pcmciabus_register(struct ss + + return err; + } +-EXPORT_SYMBOL(ssb_bus_pcmciabus_register); + #endif /* CONFIG_SSB_PCMCIAHOST */ + + #ifdef CONFIG_SSB_SDIOHOST +@@ -923,13 +761,14 @@ int ssb_bus_sdiobus_register(struct ssb_ + EXPORT_SYMBOL(ssb_bus_sdiobus_register); + #endif /* CONFIG_SSB_PCMCIAHOST */ + ++#ifdef CONFIG_SSB_HOST_SOC + int ssb_bus_ssbbus_register(struct ssb_bus *bus, unsigned long baseaddr, + ssb_invariants_func_t get_invariants) + { + int err; + + bus->bustype = SSB_BUSTYPE_SSB; +- bus->ops = &ssb_ssb_ops; ++ bus->ops = &ssb_host_soc_ops; + + err = ssb_bus_register(bus, get_invariants, baseaddr); + if (!err) { +@@ -939,6 +778,7 @@ int ssb_bus_ssbbus_register(struct ssb_b + + return err; + } ++#endif + + int __ssb_driver_register(struct ssb_driver *drv, struct module *owner) + { +@@ -1465,6 +1305,12 @@ static int __init ssb_modinit(void) + /* don't fail SSB init because of this */ + err = 0; + } ++ err = ssb_host_pcmcia_init(); ++ if (err) { ++ ssb_err("PCMCIA host initialization failed\n"); ++ /* don't fail SSB init because of this */ ++ err = 0; ++ } + err = ssb_gige_init(); + if (err) { + ssb_err("SSB Broadcom Gigabit Ethernet driver initialization failed\n"); +@@ -1482,6 +1328,7 @@ fs_initcall(ssb_modinit); + static void __exit ssb_modexit(void) + { + ssb_gige_exit(); ++ ssb_host_pcmcia_exit(); + b43_pci_ssb_bridge_exit(); + bus_unregister(&ssb_bustype); + } +--- a/drivers/ssb/pcmcia.c ++++ b/drivers/ssb/pcmcia.c +@@ -147,8 +147,7 @@ error: + return err; + } + +-int ssb_pcmcia_switch_core(struct ssb_bus *bus, +- struct ssb_device *dev) ++static int ssb_pcmcia_switch_core(struct ssb_bus *bus, struct ssb_device *dev) + { + int err; + +--- a/drivers/ssb/sdio.c ++++ b/drivers/ssb/sdio.c +@@ -200,7 +200,7 @@ out: + } + + /* host must be already claimed */ +-int ssb_sdio_switch_core(struct ssb_bus *bus, struct ssb_device *dev) ++static int ssb_sdio_switch_core(struct ssb_bus *bus, struct ssb_device *dev) + { + u8 coreidx = dev->core_index; + u32 sbaddr; +--- a/drivers/ssb/ssb_private.h ++++ b/drivers/ssb/ssb_private.h +@@ -85,8 +85,6 @@ static inline int ssb_pci_init(struct ss + + /* pcmcia.c */ + #ifdef CONFIG_SSB_PCMCIAHOST +-extern int ssb_pcmcia_switch_core(struct ssb_bus *bus, +- struct ssb_device *dev); + extern int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus, + u8 coreidx); + extern int ssb_pcmcia_switch_segment(struct ssb_bus *bus, +@@ -96,13 +94,10 @@ extern int ssb_pcmcia_get_invariants(str + extern int ssb_pcmcia_hardware_setup(struct ssb_bus *bus); + extern void ssb_pcmcia_exit(struct ssb_bus *bus); + extern int ssb_pcmcia_init(struct ssb_bus *bus); ++extern int ssb_host_pcmcia_init(void); ++extern void ssb_host_pcmcia_exit(void); + extern const struct ssb_bus_ops ssb_pcmcia_ops; + #else /* CONFIG_SSB_PCMCIAHOST */ +-static inline int ssb_pcmcia_switch_core(struct ssb_bus *bus, +- struct ssb_device *dev) +-{ +- return 0; +-} + static inline int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus, + u8 coreidx) + { +@@ -124,6 +119,13 @@ static inline int ssb_pcmcia_init(struct + { + return 0; + } ++static inline int ssb_host_pcmcia_init(void) ++{ ++ return 0; ++} ++static inline void ssb_host_pcmcia_exit(void) ++{ ++} + #endif /* CONFIG_SSB_PCMCIAHOST */ + + /* sdio.c */ +@@ -132,9 +134,7 @@ extern int ssb_sdio_get_invariants(struc + struct ssb_init_invariants *iv); + + extern u32 ssb_sdio_scan_read32(struct ssb_bus *bus, u16 offset); +-extern int ssb_sdio_switch_core(struct ssb_bus *bus, struct ssb_device *dev); + extern int ssb_sdio_scan_switch_coreidx(struct ssb_bus *bus, u8 coreidx); +-extern int ssb_sdio_hardware_setup(struct ssb_bus *bus); + extern void ssb_sdio_exit(struct ssb_bus *bus); + extern int ssb_sdio_init(struct ssb_bus *bus); + +@@ -144,19 +144,10 @@ static inline u32 ssb_sdio_scan_read32(s + { + return 0; + } +-static inline int ssb_sdio_switch_core(struct ssb_bus *bus, +- struct ssb_device *dev) +-{ +- return 0; +-} + static inline int ssb_sdio_scan_switch_coreidx(struct ssb_bus *bus, u8 coreidx) + { + return 0; + } +-static inline int ssb_sdio_hardware_setup(struct ssb_bus *bus) +-{ +- return 0; +-} + static inline void ssb_sdio_exit(struct ssb_bus *bus) + { + } +@@ -166,6 +157,13 @@ static inline int ssb_sdio_init(struct s + } + #endif /* CONFIG_SSB_SDIOHOST */ + ++/************************************************** ++ * host_soc.c ++ **************************************************/ ++ ++#ifdef CONFIG_SSB_HOST_SOC ++extern const struct ssb_bus_ops ssb_host_soc_ops; ++#endif + + /* scan.c */ + extern const char *ssb_core_name(u16 coreid);