From f2d9d270c15ae0139b54a7e7466d738327e97e03 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 22 Nov 2012 14:11:39 +0100 Subject: mac80211: support VHT association Determine the VHT channel from the AP's VHT operation IE (if present) and configure the hardware to that channel if it is supported. If channel contexts cause a channel to not be usable, try a smaller bandwidth. Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'include/linux') diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index f9c5a787d350..8f690e53dd89 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -1212,6 +1212,21 @@ struct ieee80211_vht_cap { struct ieee80211_vht_mcs_info supp_mcs; } __packed; +/** + * enum ieee80211_vht_chanwidth - VHT channel width + * @IEEE80211_VHT_CHANWIDTH_USE_HT: use the HT operation IE to + * determine the channel width (20 or 40 MHz) + * @IEEE80211_VHT_CHANWIDTH_80MHZ: 80 MHz bandwidth + * @IEEE80211_VHT_CHANWIDTH_160MHZ: 160 MHz bandwidth + * @IEEE80211_VHT_CHANWIDTH_80P80MHZ: 80+80 MHz bandwidth + */ +enum ieee80211_vht_chanwidth { + IEEE80211_VHT_CHANWIDTH_USE_HT = 0, + IEEE80211_VHT_CHANWIDTH_80MHZ = 1, + IEEE80211_VHT_CHANWIDTH_160MHZ = 2, + IEEE80211_VHT_CHANWIDTH_80P80MHZ = 3, +}; + /** * struct ieee80211_vht_operation - VHT operation IE * -- cgit v1.2.3-71-gd317 From 0362063b7be97f6f8e2c644b970f5726489aacdf Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Tue, 27 Nov 2012 00:31:55 +0100 Subject: ssb: extif: fix compile errors If CONFIG_SSB_EMBEDDED or CONFIG_SSB_DRIVER_MIPS is set and CONFIG_SSB_DRIVER_EXTIF is not set, it will cause compile problems because of missing functions. This patch fixes these problems. The mips driver now also uses ssb_chipco_available() instead of checking bus->chipco.dev manually. Signed-off-by: Hauke Mehrtens Signed-off-by: John W. Linville --- drivers/ssb/driver_mipscore.c | 14 ++++++------ include/linux/ssb/ssb_driver_extif.h | 42 ++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/drivers/ssb/driver_mipscore.c b/drivers/ssb/driver_mipscore.c index b918ba922306..5bd05b136d22 100644 --- a/drivers/ssb/driver_mipscore.c +++ b/drivers/ssb/driver_mipscore.c @@ -178,9 +178,9 @@ static void ssb_mips_serial_init(struct ssb_mipscore *mcore) { struct ssb_bus *bus = mcore->dev->bus; - if (bus->extif.dev) + if (ssb_extif_available(&bus->extif)) mcore->nr_serial_ports = ssb_extif_serial_init(&bus->extif, mcore->serial_ports); - else if (bus->chipco.dev) + else if (ssb_chipco_available(&bus->chipco)) mcore->nr_serial_ports = ssb_chipco_serial_init(&bus->chipco, mcore->serial_ports); else mcore->nr_serial_ports = 0; @@ -191,7 +191,7 @@ static void ssb_mips_flash_detect(struct ssb_mipscore *mcore) struct ssb_bus *bus = mcore->dev->bus; /* When there is no chipcommon on the bus there is 4MB flash */ - if (!bus->chipco.dev) { + if (!ssb_chipco_available(&bus->chipco)) { mcore->pflash.present = true; mcore->pflash.buswidth = 2; mcore->pflash.window = SSB_FLASH1; @@ -227,9 +227,9 @@ u32 ssb_cpu_clock(struct ssb_mipscore *mcore) if (bus->chipco.capabilities & SSB_CHIPCO_CAP_PMU) return ssb_pmu_get_cpu_clock(&bus->chipco); - if (bus->extif.dev) { + if (ssb_extif_available(&bus->extif)) { ssb_extif_get_clockcontrol(&bus->extif, &pll_type, &n, &m); - } else if (bus->chipco.dev) { + } else if (ssb_chipco_available(&bus->chipco)) { ssb_chipco_get_clockcpu(&bus->chipco, &pll_type, &n, &m); } else return 0; @@ -265,9 +265,9 @@ void ssb_mipscore_init(struct ssb_mipscore *mcore) hz = 100000000; ns = 1000000000 / hz; - if (bus->extif.dev) + if (ssb_extif_available(&bus->extif)) ssb_extif_timing_init(&bus->extif, ns); - else if (bus->chipco.dev) + else if (ssb_chipco_available(&bus->chipco)) ssb_chipco_timing_init(&bus->chipco, ns); /* Assign IRQs to all cores on the bus, start with irq line 2, because serial usually takes 1 */ diff --git a/include/linux/ssb/ssb_driver_extif.h b/include/linux/ssb/ssb_driver_extif.h index 91161f0aa22b..2604efa7dc4d 100644 --- a/include/linux/ssb/ssb_driver_extif.h +++ b/include/linux/ssb/ssb_driver_extif.h @@ -204,11 +204,53 @@ void ssb_extif_get_clockcontrol(struct ssb_extif *extif, { } +static inline +void ssb_extif_timing_init(struct ssb_extif *extif, unsigned long ns) +{ +} + static inline void ssb_extif_watchdog_timer_set(struct ssb_extif *extif, u32 ticks) { } +static inline u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask) +{ + return 0; +} + +static inline u32 ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, + u32 value) +{ + return 0; +} + +static inline u32 ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, + u32 value) +{ + return 0; +} + +static inline u32 ssb_extif_gpio_polarity(struct ssb_extif *extif, u32 mask, + u32 value) +{ + return 0; +} + +static inline u32 ssb_extif_gpio_intmask(struct ssb_extif *extif, u32 mask, + u32 value) +{ + return 0; +} + +#ifdef CONFIG_SSB_SERIAL +static inline int ssb_extif_serial_init(struct ssb_extif *extif, + struct ssb_serial_port *ports) +{ + return 0; +} +#endif /* CONFIG_SSB_SERIAL */ + #endif /* CONFIG_SSB_DRIVER_EXTIF */ #endif /* LINUX_SSB_EXTIFCORE_H_ */ -- cgit v1.2.3-71-gd317 From bc245cc36c5687dd3fbf6d4a1b3c13d41f9cb189 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Wed, 5 Dec 2012 18:45:58 +0100 Subject: ssb/bcma: add common header for watchdog This adds a common header for watchdog functions, so a watchdog driver just needs to use this and could provide watchdog functionality for ssb and bcma based SoCs. Patches for a watchdog driver using this interface will be send later. Signed-off-by: Hauke Mehrtens Signed-off-by: John W. Linville --- include/linux/bcm47xx_wdt.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 include/linux/bcm47xx_wdt.h (limited to 'include/linux') diff --git a/include/linux/bcm47xx_wdt.h b/include/linux/bcm47xx_wdt.h new file mode 100644 index 000000000000..e5dfc256485b --- /dev/null +++ b/include/linux/bcm47xx_wdt.h @@ -0,0 +1,19 @@ +#ifndef LINUX_BCM47XX_WDT_H_ +#define LINUX_BCM47XX_WDT_H_ + +#include + + +struct bcm47xx_wdt { + u32 (*timer_set)(struct bcm47xx_wdt *, u32); + u32 (*timer_set_ms)(struct bcm47xx_wdt *, u32); + u32 max_timer_ms; + + void *driver_data; +}; + +static inline void *bcm47xx_wdt_get_drvdata(struct bcm47xx_wdt *wdt) +{ + return wdt->driver_data; +} +#endif /* LINUX_BCM47XX_WDT_H_ */ -- cgit v1.2.3-71-gd317 From a22a3114a820ca3eadee6af53d90736e5ca68fa1 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Wed, 5 Dec 2012 18:46:01 +0100 Subject: bcma: add methods for watchdog driver The watchdog driver wants to set the watchdog timeout in ms and not in ticks, which is depending on the SoC type and the clock. Calculate the number of ticks per millisecond and provide two functions for the watchdog driver. Also return the ticks or millisecond the timer was set to in case the provided value was bigger than the max allowed value. Signed-off-by: Hauke Mehrtens Signed-off-by: John W. Linville --- drivers/bcma/driver_chipcommon.c | 38 ++++++++++++++++++++++++++++- include/linux/bcma/bcma_driver_chipcommon.h | 4 +-- 2 files changed, 39 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/drivers/bcma/driver_chipcommon.c b/drivers/bcma/driver_chipcommon.c index 7c132e5eceb0..117222697e1f 100644 --- a/drivers/bcma/driver_chipcommon.c +++ b/drivers/bcma/driver_chipcommon.c @@ -10,6 +10,7 @@ */ #include "bcma_private.h" +#include #include #include @@ -52,6 +53,39 @@ static u32 bcma_chipco_watchdog_get_max_timer(struct bcma_drv_cc *cc) return (1 << nb) - 1; } +static u32 bcma_chipco_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt, + u32 ticks) +{ + struct bcma_drv_cc *cc = bcm47xx_wdt_get_drvdata(wdt); + + return bcma_chipco_watchdog_timer_set(cc, ticks); +} + +static u32 bcma_chipco_watchdog_timer_set_ms_wdt(struct bcm47xx_wdt *wdt, + u32 ms) +{ + struct bcma_drv_cc *cc = bcm47xx_wdt_get_drvdata(wdt); + u32 ticks; + + ticks = bcma_chipco_watchdog_timer_set(cc, cc->ticks_per_ms * ms); + return ticks / cc->ticks_per_ms; +} + +static int bcma_chipco_watchdog_ticks_per_ms(struct bcma_drv_cc *cc) +{ + struct bcma_bus *bus = cc->core->bus; + + if (cc->capabilities & BCMA_CC_CAP_PMU) { + if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) + /* 4706 CC and PMU watchdogs are clocked at 1/4 of ALP clock */ + return bcma_chipco_alp_clock(cc) / 4000; + else + /* based on 32KHz ILP clock */ + return 32; + } else { + return bcma_chipco_alp_clock(cc) / 1000; + } +} void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc) { @@ -100,12 +134,13 @@ void bcma_core_chipcommon_init(struct bcma_drv_cc *cc) ((leddc_on << BCMA_CC_GPIOTIMER_ONTIME_SHIFT) | (leddc_off << BCMA_CC_GPIOTIMER_OFFTIME_SHIFT))); } + cc->ticks_per_ms = bcma_chipco_watchdog_ticks_per_ms(cc); cc->setup_done = true; } /* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */ -void bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks) +u32 bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks) { u32 maxt; enum bcma_clkmode clkmode; @@ -125,6 +160,7 @@ void bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks) /* instant NMI */ bcma_cc_write32(cc, BCMA_CC_WATCHDOG, ticks); } + return ticks; } void bcma_chipco_irq_mask(struct bcma_drv_cc *cc, u32 mask, u32 value) diff --git a/include/linux/bcma/bcma_driver_chipcommon.h b/include/linux/bcma/bcma_driver_chipcommon.h index 145f3c56227f..2f9b01493a90 100644 --- a/include/linux/bcma/bcma_driver_chipcommon.h +++ b/include/linux/bcma/bcma_driver_chipcommon.h @@ -570,6 +570,7 @@ struct bcma_drv_cc { int nr_serial_ports; struct bcma_serial_port serial_ports[4]; #endif /* CONFIG_BCMA_DRIVER_MIPS */ + u32 ticks_per_ms; }; /* Register access */ @@ -593,8 +594,7 @@ extern void bcma_chipco_resume(struct bcma_drv_cc *cc); void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable); -extern void bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, - u32 ticks); +extern u32 bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks); void bcma_chipco_irq_mask(struct bcma_drv_cc *cc, u32 mask, u32 value); -- cgit v1.2.3-71-gd317 From a4855f39d4eb3f550ca5f4aac79bd999da42dc54 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Wed, 5 Dec 2012 18:46:02 +0100 Subject: bcma: register watchdog driver Register the watchdog driver to the system if this is a SoC. Using the watchdog on a non SoC device, like a PCIe card, will make the PCIe card die when the timeout expired, but starting it again is not supported by bcma. Signed-off-by: Hauke Mehrtens Signed-off-by: John W. Linville --- drivers/bcma/bcma_private.h | 2 ++ drivers/bcma/driver_chipcommon.c | 22 ++++++++++++++++++++++ drivers/bcma/main.c | 8 ++++++++ include/linux/bcma/bcma_driver_chipcommon.h | 3 +++ 4 files changed, 35 insertions(+) (limited to 'include/linux') diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h index 169fc58427d3..bcb830ec4bb4 100644 --- a/drivers/bcma/bcma_private.h +++ b/drivers/bcma/bcma_private.h @@ -84,6 +84,8 @@ extern void __exit bcma_host_pci_exit(void); /* driver_pci.c */ u32 bcma_pcie_read(struct bcma_drv_pci *pc, u32 address); +extern int bcma_chipco_watchdog_register(struct bcma_drv_cc *cc); + #ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE bool __devinit bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc); void __devinit bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc); diff --git a/drivers/bcma/driver_chipcommon.c b/drivers/bcma/driver_chipcommon.c index 117222697e1f..d017f2512275 100644 --- a/drivers/bcma/driver_chipcommon.c +++ b/drivers/bcma/driver_chipcommon.c @@ -12,6 +12,7 @@ #include "bcma_private.h" #include #include +#include #include static inline u32 bcma_cc_write32_masked(struct bcma_drv_cc *cc, u16 offset, @@ -87,6 +88,27 @@ static int bcma_chipco_watchdog_ticks_per_ms(struct bcma_drv_cc *cc) } } +int bcma_chipco_watchdog_register(struct bcma_drv_cc *cc) +{ + struct bcm47xx_wdt wdt = {}; + struct platform_device *pdev; + + wdt.driver_data = cc; + wdt.timer_set = bcma_chipco_watchdog_timer_set_wdt; + wdt.timer_set_ms = bcma_chipco_watchdog_timer_set_ms_wdt; + wdt.max_timer_ms = bcma_chipco_watchdog_get_max_timer(cc) / cc->ticks_per_ms; + + pdev = platform_device_register_data(NULL, "bcm47xx-wdt", + cc->core->bus->num, &wdt, + sizeof(wdt)); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); + + cc->watchdog = pdev; + + return 0; +} + void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc) { if (cc->early_setup_done) diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c index a9718893000b..debd4f142f93 100644 --- a/drivers/bcma/main.c +++ b/drivers/bcma/main.c @@ -165,6 +165,12 @@ static int bcma_register_cores(struct bcma_bus *bus) } #endif + if (bus->hosttype == BCMA_HOSTTYPE_SOC) { + err = bcma_chipco_watchdog_register(&bus->drv_cc); + if (err) + bcma_err(bus, "Error registering watchdog driver\n"); + } + return 0; } @@ -177,6 +183,8 @@ static void bcma_unregister_cores(struct bcma_bus *bus) if (core->dev_registered) device_unregister(&core->dev); } + if (bus->hosttype == BCMA_HOSTTYPE_SOC) + platform_device_unregister(bus->drv_cc.watchdog); } int __devinit bcma_bus_register(struct bcma_bus *bus) diff --git a/include/linux/bcma/bcma_driver_chipcommon.h b/include/linux/bcma/bcma_driver_chipcommon.h index 2f9b01493a90..e51359180b6f 100644 --- a/include/linux/bcma/bcma_driver_chipcommon.h +++ b/include/linux/bcma/bcma_driver_chipcommon.h @@ -1,6 +1,8 @@ #ifndef LINUX_BCMA_DRIVER_CC_H_ #define LINUX_BCMA_DRIVER_CC_H_ +#include + /** ChipCommon core registers. **/ #define BCMA_CC_ID 0x0000 #define BCMA_CC_ID_ID 0x0000FFFF @@ -571,6 +573,7 @@ struct bcma_drv_cc { struct bcma_serial_port serial_ports[4]; #endif /* CONFIG_BCMA_DRIVER_MIPS */ u32 ticks_per_ms; + struct platform_device *watchdog; }; /* Register access */ -- cgit v1.2.3-71-gd317 From 7ffbffe37de3979d43c1105e38eb2918bf5d35fe Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Wed, 5 Dec 2012 18:46:05 +0100 Subject: ssb: add methods for watchdog driver The watchdog driver wants to set the watchdog timeout in ms and not in ticks, which is depending on the SoC type and the clock. Calculate the number of ticks per millisecond and provide two functions for the watchdog driver. Also return the ticks or millisecond the timer was set to in case the provided value was bigger than the max allowed value. Signed-off-by: Hauke Mehrtens Signed-off-by: John W. Linville --- drivers/ssb/driver_chipcommon.c | 47 ++++++++++++++++++++++++++++++- drivers/ssb/ssb_private.h | 5 ++++ include/linux/ssb/ssb_driver_chipcommon.h | 5 ++-- 3 files changed, 54 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c index 6e080f6a07a5..95c33a05f434 100644 --- a/drivers/ssb/driver_chipcommon.c +++ b/drivers/ssb/driver_chipcommon.c @@ -4,6 +4,7 @@ * * Copyright 2005, Broadcom Corporation * Copyright 2006, 2007, Michael Buesch + * Copyright 2012, Hauke Mehrtens * * Licensed under the GNU/GPL. See COPYING for details. */ @@ -12,6 +13,7 @@ #include #include #include +#include #include "ssb_private.h" @@ -306,6 +308,43 @@ static u32 ssb_chipco_watchdog_get_max_timer(struct ssb_chipcommon *cc) return (1 << nb) - 1; } +u32 ssb_chipco_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt, u32 ticks) +{ + struct ssb_chipcommon *cc = bcm47xx_wdt_get_drvdata(wdt); + + if (cc->dev->bus->bustype != SSB_BUSTYPE_SSB) + return 0; + + return ssb_chipco_watchdog_timer_set(cc, ticks); +} + +u32 ssb_chipco_watchdog_timer_set_ms(struct bcm47xx_wdt *wdt, u32 ms) +{ + struct ssb_chipcommon *cc = bcm47xx_wdt_get_drvdata(wdt); + u32 ticks; + + if (cc->dev->bus->bustype != SSB_BUSTYPE_SSB) + return 0; + + ticks = ssb_chipco_watchdog_timer_set(cc, cc->ticks_per_ms * ms); + return ticks / cc->ticks_per_ms; +} + +static int ssb_chipco_watchdog_ticks_per_ms(struct ssb_chipcommon *cc) +{ + struct ssb_bus *bus = cc->dev->bus; + + if (cc->capabilities & SSB_CHIPCO_CAP_PMU) { + /* based on 32KHz ILP clock */ + return 32; + } else { + if (cc->dev->id.revision < 18) + return ssb_clockspeed(bus) / 1000; + else + return ssb_chipco_alp_clock(cc) / 1000; + } +} + void ssb_chipcommon_init(struct ssb_chipcommon *cc) { if (!cc->dev) @@ -323,6 +362,11 @@ void ssb_chipcommon_init(struct ssb_chipcommon *cc) chipco_powercontrol_init(cc); ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST); calc_fast_powerup_delay(cc); + + if (cc->dev->bus->bustype == SSB_BUSTYPE_SSB) { + cc->ticks_per_ms = ssb_chipco_watchdog_ticks_per_ms(cc); + cc->max_timer_ms = ssb_chipco_watchdog_get_max_timer(cc) / cc->ticks_per_ms; + } } void ssb_chipco_suspend(struct ssb_chipcommon *cc) @@ -421,7 +465,7 @@ void ssb_chipco_timing_init(struct ssb_chipcommon *cc, } /* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */ -void ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc, u32 ticks) +u32 ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc, u32 ticks) { u32 maxt; enum ssb_clkmode clkmode; @@ -441,6 +485,7 @@ void ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc, u32 ticks) /* instant NMI */ chipco_write32(cc, SSB_CHIPCO_WATCHDOG, ticks); } + return ticks; } void ssb_chipco_irq_mask(struct ssb_chipcommon *cc, u32 mask, u32 value) diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h index 98b2915cd30b..03cc40a71510 100644 --- a/drivers/ssb/ssb_private.h +++ b/drivers/ssb/ssb_private.h @@ -3,6 +3,7 @@ #include #include +#include #define PFX "ssb: " @@ -212,4 +213,8 @@ extern u32 ssb_pmu_get_cpu_clock(struct ssb_chipcommon *cc); extern u32 ssb_pmu_get_controlclock(struct ssb_chipcommon *cc); extern u32 ssb_pmu_get_alp_clock(struct ssb_chipcommon *cc); +extern u32 ssb_chipco_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt, + u32 ticks); +extern u32 ssb_chipco_watchdog_timer_set_ms(struct bcm47xx_wdt *wdt, u32 ms); + #endif /* LINUX_SSB_PRIVATE_H_ */ diff --git a/include/linux/ssb/ssb_driver_chipcommon.h b/include/linux/ssb/ssb_driver_chipcommon.h index c2b02a5c86ae..38339fd68a5f 100644 --- a/include/linux/ssb/ssb_driver_chipcommon.h +++ b/include/linux/ssb/ssb_driver_chipcommon.h @@ -591,6 +591,8 @@ struct ssb_chipcommon { /* Fast Powerup Delay constant */ u16 fast_pwrup_delay; struct ssb_chipcommon_pmu pmu; + u32 ticks_per_ms; + u32 max_timer_ms; }; static inline bool ssb_chipco_available(struct ssb_chipcommon *cc) @@ -630,8 +632,7 @@ enum ssb_clkmode { extern void ssb_chipco_set_clockmode(struct ssb_chipcommon *cc, enum ssb_clkmode mode); -extern void ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc, - u32 ticks); +extern u32 ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc, u32 ticks); void ssb_chipco_irq_mask(struct ssb_chipcommon *cc, u32 mask, u32 value); -- cgit v1.2.3-71-gd317 From 7280b51a29f8e6cc7d449d565182d1e1b6183907 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Wed, 5 Dec 2012 18:46:06 +0100 Subject: ssb: extif: add check for max value before setting watchdog register Prevent the watchdog register on the extif core to be set to a too high value. Signed-off-by: Hauke Mehrtens Signed-off-by: John W. Linville --- drivers/ssb/driver_extif.c | 5 +++-- include/linux/ssb/ssb_driver_extif.h | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/drivers/ssb/driver_extif.c b/drivers/ssb/driver_extif.c index dc47f30e9cf7..0aa4c2a85774 100644 --- a/drivers/ssb/driver_extif.c +++ b/drivers/ssb/driver_extif.c @@ -112,9 +112,10 @@ void ssb_extif_get_clockcontrol(struct ssb_extif *extif, *m = extif_read32(extif, SSB_EXTIF_CLOCK_SB); } -void ssb_extif_watchdog_timer_set(struct ssb_extif *extif, - u32 ticks) +void ssb_extif_watchdog_timer_set(struct ssb_extif *extif, u32 ticks) { + if (ticks > SSB_EXTIF_WATCHDOG_MAX_TIMER) + ticks = SSB_EXTIF_WATCHDOG_MAX_TIMER; extif_write32(extif, SSB_EXTIF_WATCHDOG, ticks); } diff --git a/include/linux/ssb/ssb_driver_extif.h b/include/linux/ssb/ssb_driver_extif.h index 2604efa7dc4d..b618188939d2 100644 --- a/include/linux/ssb/ssb_driver_extif.h +++ b/include/linux/ssb/ssb_driver_extif.h @@ -152,6 +152,7 @@ /* watchdog */ #define SSB_EXTIF_WATCHDOG_CLK 48000000 /* Hz */ +#define SSB_EXTIF_WATCHDOG_MAX_TIMER ((1 << 28) - 1) #ifdef CONFIG_SSB_DRIVER_EXTIF -- cgit v1.2.3-71-gd317 From 9f640a6376e54fa9ae834c32cbe92cefeec970dc Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Wed, 5 Dec 2012 18:46:07 +0100 Subject: ssb: extif: add methods for watchdog driver The watchdog driver wants to set the watchdog timeout in ms and not in ticks, add a method converting ms to ticks before setting the watchdog register. Return the ticks or millisecond the timer was set to in case the provided value was bigger than the max allowed value. Signed-off-by: Hauke Mehrtens Signed-off-by: John W. Linville --- drivers/ssb/driver_extif.c | 21 ++++++++++++++++++++- drivers/ssb/ssb_private.h | 15 +++++++++++++++ include/linux/ssb/ssb_driver_extif.h | 9 +++++---- 3 files changed, 40 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/drivers/ssb/driver_extif.c b/drivers/ssb/driver_extif.c index 0aa4c2a85774..553227a3062d 100644 --- a/drivers/ssb/driver_extif.c +++ b/drivers/ssb/driver_extif.c @@ -112,11 +112,30 @@ void ssb_extif_get_clockcontrol(struct ssb_extif *extif, *m = extif_read32(extif, SSB_EXTIF_CLOCK_SB); } -void ssb_extif_watchdog_timer_set(struct ssb_extif *extif, u32 ticks) +u32 ssb_extif_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt, u32 ticks) +{ + struct ssb_extif *extif = bcm47xx_wdt_get_drvdata(wdt); + + return ssb_extif_watchdog_timer_set(extif, ticks); +} + +u32 ssb_extif_watchdog_timer_set_ms(struct bcm47xx_wdt *wdt, u32 ms) +{ + struct ssb_extif *extif = bcm47xx_wdt_get_drvdata(wdt); + u32 ticks = (SSB_EXTIF_WATCHDOG_CLK / 1000) * ms; + + ticks = ssb_extif_watchdog_timer_set(extif, ticks); + + return (ticks * 1000) / SSB_EXTIF_WATCHDOG_CLK; +} + +u32 ssb_extif_watchdog_timer_set(struct ssb_extif *extif, u32 ticks) { if (ticks > SSB_EXTIF_WATCHDOG_MAX_TIMER) ticks = SSB_EXTIF_WATCHDOG_MAX_TIMER; extif_write32(extif, SSB_EXTIF_WATCHDOG, ticks); + + return ticks; } u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask) diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h index 03cc40a71510..50ea02877777 100644 --- a/drivers/ssb/ssb_private.h +++ b/drivers/ssb/ssb_private.h @@ -217,4 +217,19 @@ extern u32 ssb_chipco_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt, u32 ticks); extern u32 ssb_chipco_watchdog_timer_set_ms(struct bcm47xx_wdt *wdt, u32 ms); +#ifdef CONFIG_SSB_DRIVER_EXTIF +extern u32 ssb_extif_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt, u32 ticks); +extern u32 ssb_extif_watchdog_timer_set_ms(struct bcm47xx_wdt *wdt, u32 ms); +#else +static inline u32 ssb_extif_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt, + u32 ticks) +{ + return 0; +} +static inline u32 ssb_extif_watchdog_timer_set_ms(struct bcm47xx_wdt *wdt, + u32 ms) +{ + return 0; +} +#endif #endif /* LINUX_SSB_PRIVATE_H_ */ diff --git a/include/linux/ssb/ssb_driver_extif.h b/include/linux/ssb/ssb_driver_extif.h index b618188939d2..99511d0e931d 100644 --- a/include/linux/ssb/ssb_driver_extif.h +++ b/include/linux/ssb/ssb_driver_extif.h @@ -153,6 +153,8 @@ #define SSB_EXTIF_WATCHDOG_CLK 48000000 /* Hz */ #define SSB_EXTIF_WATCHDOG_MAX_TIMER ((1 << 28) - 1) +#define SSB_EXTIF_WATCHDOG_MAX_TIMER_MS (SSB_EXTIF_WATCHDOG_MAX_TIMER \ + / (SSB_EXTIF_WATCHDOG_CLK / 1000)) #ifdef CONFIG_SSB_DRIVER_EXTIF @@ -172,8 +174,7 @@ extern void ssb_extif_get_clockcontrol(struct ssb_extif *extif, extern void ssb_extif_timing_init(struct ssb_extif *extif, unsigned long ns); -extern void ssb_extif_watchdog_timer_set(struct ssb_extif *extif, - u32 ticks); +extern u32 ssb_extif_watchdog_timer_set(struct ssb_extif *extif, u32 ticks); /* Extif GPIO pin access */ u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask); @@ -211,9 +212,9 @@ void ssb_extif_timing_init(struct ssb_extif *extif, unsigned long ns) } static inline -void ssb_extif_watchdog_timer_set(struct ssb_extif *extif, - u32 ticks) +u32 ssb_extif_watchdog_timer_set(struct ssb_extif *extif, u32 ticks) { + return 0; } static inline u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask) -- cgit v1.2.3-71-gd317 From bde327eff8a722df1198df9b14464f84f1adfb65 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Wed, 5 Dec 2012 18:46:08 +0100 Subject: ssb: register watchdog driver Register the watchdog driver to the system if it is a SoC. Using the watchdog on a non SoC device, like a PCI card, will make the PCI card die when the timeout expired, but starting it again is not supported by ssb. Signed-off-by: Hauke Mehrtens Signed-off-by: John W. Linville --- drivers/ssb/embedded.c | 35 +++++++++++++++++++++++++++++++++++ drivers/ssb/main.c | 8 ++++++++ drivers/ssb/ssb_private.h | 10 ++++++++++ include/linux/ssb/ssb.h | 2 ++ 4 files changed, 55 insertions(+) (limited to 'include/linux') diff --git a/drivers/ssb/embedded.c b/drivers/ssb/embedded.c index 9ef124f9ee2d..bb18d76f9f2c 100644 --- a/drivers/ssb/embedded.c +++ b/drivers/ssb/embedded.c @@ -4,11 +4,13 @@ * * Copyright 2005-2008, Broadcom Corporation * Copyright 2006-2008, Michael Buesch + * Copyright 2012, Hauke Mehrtens * * Licensed under the GNU/GPL. See COPYING for details. */ #include +#include #include #include #include @@ -32,6 +34,39 @@ int ssb_watchdog_timer_set(struct ssb_bus *bus, u32 ticks) } EXPORT_SYMBOL(ssb_watchdog_timer_set); +int ssb_watchdog_register(struct ssb_bus *bus) +{ + struct bcm47xx_wdt wdt = {}; + struct platform_device *pdev; + + if (ssb_chipco_available(&bus->chipco)) { + wdt.driver_data = &bus->chipco; + wdt.timer_set = ssb_chipco_watchdog_timer_set_wdt; + wdt.timer_set_ms = ssb_chipco_watchdog_timer_set_ms; + wdt.max_timer_ms = bus->chipco.max_timer_ms; + } else if (ssb_extif_available(&bus->extif)) { + wdt.driver_data = &bus->extif; + wdt.timer_set = ssb_extif_watchdog_timer_set_wdt; + wdt.timer_set_ms = ssb_extif_watchdog_timer_set_ms; + wdt.max_timer_ms = SSB_EXTIF_WATCHDOG_MAX_TIMER_MS; + } else { + return -ENODEV; + } + + pdev = platform_device_register_data(NULL, "bcm47xx-wdt", + bus->busnumber, &wdt, + sizeof(wdt)); + if (IS_ERR(pdev)) { + ssb_dprintk(KERN_INFO PFX + "can not register watchdog device, err: %li\n", + PTR_ERR(pdev)); + return PTR_ERR(pdev); + } + + bus->watchdog = pdev; + return 0; +} + u32 ssb_gpio_in(struct ssb_bus *bus, u32 mask) { unsigned long flags; diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index df0f145c22fc..58c7da29a37c 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -433,6 +434,11 @@ static void ssb_devices_unregister(struct ssb_bus *bus) if (sdev->dev) device_unregister(sdev->dev); } + +#ifdef CONFIG_SSB_EMBEDDED + if (bus->bustype == SSB_BUSTYPE_SSB) + platform_device_unregister(bus->watchdog); +#endif } void ssb_bus_unregister(struct ssb_bus *bus) @@ -561,6 +567,8 @@ static int __devinit ssb_attach_queued_buses(void) if (err) goto error; ssb_pcicore_init(&bus->pcicore); + if (bus->bustype == SSB_BUSTYPE_SSB) + ssb_watchdog_register(bus); ssb_bus_may_powerdown(bus); err = ssb_devices_register(bus); diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h index 50ea02877777..8942db1d855a 100644 --- a/drivers/ssb/ssb_private.h +++ b/drivers/ssb/ssb_private.h @@ -232,4 +232,14 @@ static inline u32 ssb_extif_watchdog_timer_set_ms(struct bcm47xx_wdt *wdt, return 0; } #endif + +#ifdef CONFIG_SSB_EMBEDDED +extern int ssb_watchdog_register(struct ssb_bus *bus); +#else /* CONFIG_SSB_EMBEDDED */ +static inline int ssb_watchdog_register(struct ssb_bus *bus) +{ + return 0; +} +#endif /* CONFIG_SSB_EMBEDDED */ + #endif /* LINUX_SSB_PRIVATE_H_ */ diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h index bb674c02f306..1f64e3f1f22b 100644 --- a/include/linux/ssb/ssb.h +++ b/include/linux/ssb/ssb.h @@ -8,6 +8,7 @@ #include #include #include +#include #include @@ -432,6 +433,7 @@ struct ssb_bus { #ifdef CONFIG_SSB_EMBEDDED /* Lock for GPIO register access. */ spinlock_t gpio_lock; + struct platform_device *watchdog; #endif /* EMBEDDED */ /* Internal-only stuff follows. Do not touch. */ -- cgit v1.2.3-71-gd317