This patch series adds support for embedded devices like bcm47xx to
bcma. Bcma is used on bcm4716 and bcm4718 SoCs. With these patches my
bcm4716 device boots up till it tries to access the flash, because the
serial flash chip is unsupported for now, this will be my next task.
This adds support for MIPS cores, interrupt configuration and the
serial console.
These patches are based on ssb code, some patches by George Kashperko
and Bernhard Loos and parts of the source code release by ASUS and
Netgear for their devices.
This was tested on a Netgear WNDR3400, but did not work fully because
of serial flash.
This is bases on linux-next next-20110603, to which subsystem
maintainer should I send these patches later, as it is based on the
most recent version of bcma and bcm47xx?
I do not have any normal PCIe based wireless device using this bus, so
I have not tested it with such a device, it will be nice to hear if it
is still working on them.
The parallel flash should work so it could be that it will boot on an
Asus rt-n16, I have not tested that.
An Ethernet driver is not included because the Braodcom source code
available is not licensed under a GPL compatible license and building a
new driver on that based is not possible.
Hauke Mehrtens (10):
bcma: Use array to store cores.
bcma: Make it possible to run bcma_register_cores() later
bcma: add embedded bus
bcma: add mips driver
bcma: add serial support
bcma: get CPU clock
bcma: add pci(e) host mode
bcm47xx: prepare to support different buses
bcm47xx: add support for bcma bus
bcm47xx: fix irq assignment for new SoCs.
arch/mips/Kconfig | 4 +
arch/mips/bcm47xx/gpio.c | 63 +++++---
arch/mips/bcm47xx/irq.c | 8 +
arch/mips/bcm47xx/nvram.c | 21 ++-
arch/mips/bcm47xx/serial.c | 37 ++++-
arch/mips/bcm47xx/setup.c | 55 +++++-
arch/mips/bcm47xx/time.c | 12 +-
arch/mips/bcm47xx/wgt634u.c | 13 +-
arch/mips/include/asm/mach-bcm47xx/bcm47xx.h | 17 ++-
arch/mips/include/asm/mach-bcm47xx/gpio.h | 71 ++++++--
drivers/bcma/Kconfig | 20 ++
drivers/bcma/Makefile | 3 +
drivers/bcma/bcma_private.h | 16 ++
drivers/bcma/driver_chipcommon.c | 62 +++++++
drivers/bcma/driver_chipcommon_pmu.c | 86 +++++++++
drivers/bcma/driver_mips.c | 248 ++++++++++++++++++++++++++
drivers/bcma/driver_pci.c | 12 ++-
drivers/bcma/driver_pci_host.c | 44 +++++
drivers/bcma/host_embedded.c | 93 ++++++++++
drivers/bcma/main.c | 160 +++++++++++++----
drivers/bcma/scan.c | 87 +++++----
drivers/watchdog/bcm47xx_wdt.c | 18 ++-
include/linux/bcma/bcma.h | 24 ++-
include/linux/bcma/bcma_driver_chipcommon.h | 35 ++++
include/linux/bcma/bcma_driver_mips.h | 52 ++++++
include/linux/bcma/bcma_driver_pci.h | 1 +
include/linux/bcma/bcma_embedded.h | 8 +
27 files changed, 1132 insertions(+), 138 deletions(-)
create mode 100644 drivers/bcma/driver_mips.c
create mode 100644 drivers/bcma/driver_pci_host.c
create mode 100644 drivers/bcma/host_embedded.c
create mode 100644 include/linux/bcma/bcma_driver_mips.h
create mode 100644 include/linux/bcma/bcma_embedded.h
--
1.7.4.1
On embedded device we can not allocate memory with kalloc or sleep for
some time, when bcma is initialized, because this is done early in the
boot process. This patch makes it possible to do the
bcma_register_cores() sometime later and not directly after searching
for the cores. The initialization of the PCI(e) core is also done later
as it uses udelay(), which will not work so early. The buses are placed
into a list and bcma_register_cores() will be run when the bcma module
is initialized. When using bcma on a PCI-Bus in a normal PC
bcma_register_cores() is triggered directly after bcma_bus_register().
This patch is based on ssb code.
Signed-off-by: Hauke Mehrtens <[email protected]>
---
drivers/bcma/main.c | 65 ++++++++++++++++++++++++++++++++++++++++++---
include/linux/bcma/bcma.h | 3 ++
2 files changed, 64 insertions(+), 4 deletions(-)
diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c
index b0e7f5e..1afa107 100644
--- a/drivers/bcma/main.c
+++ b/drivers/bcma/main.c
@@ -15,6 +15,16 @@ static int bcma_bus_match(struct device *dev, struct device_driver *drv);
static int bcma_device_probe(struct device *dev);
static int bcma_device_remove(struct device *dev);
+/* Temporary list of yet-to-be-attached buses */
+static LIST_HEAD(attach_queue);
+/* There are differences in the codeflow, if the bus is
+ * initialized from early boot, as various needed services
+ * are not available early. This is a mechanism to delay
+ * these initializations to after early boot has finished.
+ * It's also used to avoid mutex locking, as that's not
+ * available and needed early. */
+static bool bcma_is_early_boot = 1;
+
static ssize_t manuf_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct __bcma_dev_wrapper *wrapper = container_of(dev,
@@ -126,6 +136,36 @@ static int bcma_register_cores(struct bcma_bus *bus)
return 0;
}
+static int bcma_attach_queued_buses(void)
+{
+ struct bcma_bus *bus, *n;
+ int err = 0;
+ int drop_them_all = 0;
+
+ list_for_each_entry_safe(bus, n, &attach_queue, attach_list) {
+ if (drop_them_all) {
+ list_del(&bus->attach_list);
+ continue;
+ }
+ /* Can't init the PCIcore in bcma_bus_register(), as that
+ * is too early in boot for embedded systems
+ * (no udelay() available). So do it here in attach stage.
+ */
+ if (bus->drv_pci.core)
+ bcma_core_pci_init(&bus->drv_pci);
+
+ err = bcma_register_cores(bus);
+ if (err) {
+ drop_them_all = 1;
+ list_del(&bus->attach_list);
+ continue;
+ }
+ list_del(&bus->attach_list);
+ }
+
+ return err;
+}
+
static void bcma_unregister_cores(struct bcma_bus *bus)
{
struct bcma_device *core;
@@ -157,15 +197,20 @@ int bcma_bus_register(struct bcma_bus *bus)
bcma_core_chipcommon_init(&bus->drv_cc);
}
- /* Init PCIE core */
+ /* Find PCIE core */
core = bcma_find_core(bus, BCMA_CORE_PCIE);
if (core) {
+ /* will be initilized in bcma_attach_queued_buses() */
bus->drv_pci.core = core;
- bcma_core_pci_init(&bus->drv_pci);
}
- /* Register found cores */
- bcma_register_cores(bus);
+ /* Queue it for attach.
+ * See the comment at the bcma_is_early_boot definition. */
+ list_add_tail(&bus->attach_list, &attach_queue);
+ if (!bcma_is_early_boot) {
+ /* This is not early boot, so we must attach the bus now */
+ bcma_attach_queued_buses();
+ }
pr_info("Bus registered\n");
@@ -247,10 +292,22 @@ static int __init bcma_modinit(void)
{
int err;
+ /* See the comment at the bcma_is_early_boot definition */
+ bcma_is_early_boot = 0;
+
err = bus_register(&bcma_bus_type);
if (err)
return err;
+ /* Maybe we already registered some buses at early boot.
+ * Check for this and attach them.
+ */
+ err = bcma_attach_queued_buses();
+ if (err) {
+ pr_err("Attaching core registered in early boot failed\n");
+ err = 0;
+ }
+
#ifdef CONFIG_BCMA_HOST_PCI
err = bcma_host_pci_init();
if (err) {
diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h
index 3dc5302..8b6feca 100644
--- a/include/linux/bcma/bcma.h
+++ b/include/linux/bcma/bcma.h
@@ -195,6 +195,9 @@ struct bcma_bus {
struct bcma_drv_cc drv_cc;
struct bcma_drv_pci drv_pci;
+
+ /* Internal-only stuff follows. Do not touch. */
+ struct list_head attach_list;
};
extern inline u32 bcma_read8(struct bcma_device *core, u16 offset)
--
1.7.4.1
W dniu 7 czerwca 2011 00:00 użytkownik Hauke Mehrtens
<[email protected]> napisał:
> On 06/06/2011 12:22 PM, Rafał Miłecki wrote:
>>> + if (bus->hosttype == BCMA_HOSTTYPE_EMBEDDED) {
>>> + iounmap(bus->mmio);
>>> + mmio = ioremap(BCMA_ADDR_BASE, BCMA_CORE_SIZE * bus->nr_cores);
>>> + if (!mmio)
>>> + return -ENOMEM;
>>> + bus->mmio = mmio;
>>> +
>>> + mmio = ioremap(BCMA_WRAP_BASE, BCMA_CORE_SIZE * bus->nr_cores);
>>> + if (!mmio)
>>> + return -ENOMEM;
>>> + bus->host_embedded = mmio;
>>
>> Do we really need both? mmio and host_embedded? What about keeping
>> mmio only and using it in calculation for read/write[8,16,32]?
>
> These are two different memory regions, it should be possible to
> calculate the other address, but I do not like that. As host_embedded is
> in a union this does not waste any memory.
Ah, OK, I can see what does happen here. You are using:
1) bus->mmio for first core
2) bus->host_embedded for first agent/wrapper
I'm not sure if this is a correct approach. Doing "core_index *
BCMA_CORE_SIZE" comes from ssb, where it was the way to calculate
offset. In case of BCMA we are reading all the info from (E)EPROM,
which also includes addresses of the cores.
IMO you should use core->addr and core->wrap for read/write ops. I
believe this is approach Broadcom decided to use for BCMA, when
designing (E)EPROM.
You should not need bus->host_embedded then, maybe you could even do
not set bus->mmio?
--
Rafał
On 06/06/2011 03:03 PM, Arnd Bergmann wrote:
> On Monday 06 June 2011, George Kashperko wrote:
>>> For an interrupt controller, it should be ok to have it initialized
>>> late, as long as it's only responsible for the devices on the same
>>> bus and not for instance for IPI interrupts. Just make sure that you
>>> do the bus scan and the initialization of the IRQ driver before you
>>> initialize any drivers that rely in on the interrupts to be working.
>>
>> Without proper timer init (which requires both the chipcommon and mips
>> cores knowledge) kernel will get hung somewhere inside calibrate_delay.
>> It could get addressed if get bus scan called in arch_init_irq or
>> plat_time_init - both are executed before calibrate_delay and with slab
>> available.
>
> Ok, so you need the interrupt controller to be working for the timer tick,
> right? I think another option (if that's not what you mean already) would
> be to have a simpler way to find a device on the bus that can be called
> before doing a full scan.
>
> Early drivers would then have to know what is there and call a function
> like "bcma_find_device(BCMA_DEV_ID_IRQ)", while drivers that are not
> required to be up just register a regular device driver with a probe
> function that gets called after the bus scan creates device structures.
>
> Arnd
Accessing chip common should be possible without scanning the hole bus
as it is at the first position and initializing most things just needs
chip common. For initializing the interrupts scanning is needed as we do
not know where the mips core is located.
As we can not use kalloc on early boot we could use a function which
uses kalloc under normal conditions and when on early boot the
architecture code which starts the bcma code should also provide a
function which returns a pointer to some memory in its text segment to
use. We need space for 16 cores in the architecture code.
In addition bcma_bus_register(struct bcma_bus *bus) has to be divided
into two parts. The first part will scan the bus and initialize chip
common and mips core. The second part will initialize pci core and
register the devices in the system. When using this under normal
conditions they will be called directly after each other.
Hauke
Add method to return the clock of the CPU. This is needed by the arch
code to calculate the mips_hpt_frequency.
Signed-off-by: Hauke Mehrtens <[email protected]>
---
drivers/bcma/bcma_private.h | 3 +
drivers/bcma/driver_chipcommon_pmu.c | 86 +++++++++++++++++++++++++++
drivers/bcma/driver_mips.c | 12 ++++
include/linux/bcma/bcma_driver_chipcommon.h | 35 +++++++++++
include/linux/bcma/bcma_driver_mips.h | 1 +
5 files changed, 137 insertions(+), 0 deletions(-)
diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h
index c65a6e2..fbabe19 100644
--- a/drivers/bcma/bcma_private.h
+++ b/drivers/bcma/bcma_private.h
@@ -22,6 +22,9 @@ int bcma_bus_scan(struct bcma_bus *bus);
/* driver_mips.c */
extern unsigned int bcma_core_mips_irq(struct bcma_device *dev);
+/* driver_chipcommon_pmu.c */
+extern u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc);
+
/* driver_chipcommon.c */
extern int bcma_chipco_serial_init(struct bcma_drv_cc *cc,
struct bcma_drv_mips_serial_port *ports);
diff --git a/drivers/bcma/driver_chipcommon_pmu.c b/drivers/bcma/driver_chipcommon_pmu.c
index f44177a..4a700f8 100644
--- a/drivers/bcma/driver_chipcommon_pmu.c
+++ b/drivers/bcma/driver_chipcommon_pmu.c
@@ -11,6 +11,13 @@
#include "bcma_private.h"
#include <linux/bcma/bcma.h>
+static u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset)
+{
+ bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
+ bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
+ return bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
+}
+
static void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
u32 offset, u32 mask, u32 set)
{
@@ -132,3 +139,82 @@ void bcma_pmu_init(struct bcma_drv_cc *cc)
bcma_pmu_swreg_init(cc);
bcma_pmu_workarounds(cc);
}
+
+static u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc)
+{
+ struct bcma_bus *bus = cc->core->bus;
+
+ switch (bus->chipinfo.id) {
+ case 0x4716:
+ case 0x4748:
+ case 47162:
+ /* always 20Mhz */
+ return 20000 * 1000;
+ default:
+ pr_warn("No ALP clock specified for %04X device, "
+ "pmu rev. %d, using default %d Hz\n",
+ bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_ALP_CLOCK);
+ }
+ return BCMA_CC_PMU_ALP_CLOCK;
+}
+
+/* Find the output of the "m" pll divider given pll controls that start with
+ * pllreg "pll0" i.e. 12 for main 6 for phy, 0 for misc.
+ */
+static u32 bcma_pmu_clock(struct bcma_drv_cc *cc, u32 pll0, u32 m)
+{
+ u32 tmp, div, ndiv, p1, p2, fc;
+
+ BUG_ON(!m || m > 4);
+
+ BUG_ON((pll0 & 3) || (pll0 > BCMA_CC_PMU4716_MAINPLL_PLL0));
+
+ tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_P1P2_OFF);
+ p1 = (tmp & BCMA_CC_PPL_P1_MASK) >> BCMA_CC_PPL_P1_SHIFT;
+ p2 = (tmp & BCMA_CC_PPL_P2_MASK) >> BCMA_CC_PPL_P2_SHIFT;
+
+ tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_M14_OFF);
+ div = (tmp >> ((m - 1) * BCMA_CC_PPL_MDIV_WIDTH)) & BCMA_CC_PPL_MDIV_MASK;
+
+ tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_NM5_OFF);
+ ndiv = (tmp & BCMA_CC_PPL_NDIV_MASK) >> BCMA_CC_PPL_NDIV_SHIFT;
+
+ /* Do calculation in Mhz */
+ fc = bcma_pmu_alp_clock(cc) / 1000000;
+ fc = (p1 * ndiv * fc) / p2;
+
+ /* Return clock in Hertz */
+ return (fc / div) * 1000000;
+}
+
+/* query bus clock frequency for PMU-enabled chipcommon */
+u32 bcma_pmu_get_clockcontrol(struct bcma_drv_cc *cc)
+{
+ struct bcma_bus *bus = cc->core->bus;
+
+ switch (bus->chipinfo.id) {
+ case 0x4716:
+ case 0x4748:
+ case 47162:
+ return bcma_pmu_clock(cc, BCMA_CC_PMU4716_MAINPLL_PLL0,
+ BCMA_CC_PMU5_MAINPLL_SSB);
+ default:
+ pr_warn("No backplane clock specified for %04X device, "
+ "pmu rev. %d, using default %d Hz\n",
+ bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_HT_CLOCK);
+ }
+ return BCMA_CC_PMU_HT_CLOCK;
+}
+
+/* query cpu clock frequency for PMU-enabled chipcommon */
+u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc)
+{
+ struct bcma_bus *bus = cc->core->bus;
+
+ if ((cc->pmu.rev == 5 || cc->pmu.rev == 6 || cc->pmu.rev == 7) &&
+ (bus->chipinfo.id != 0x4319))
+ return bcma_pmu_clock(cc, BCMA_CC_PMU4716_MAINPLL_PLL0,
+ BCMA_CC_PMU5_MAINPLL_CPU);
+
+ return bcma_pmu_get_clockcontrol(cc);
+}
diff --git a/drivers/bcma/driver_mips.c b/drivers/bcma/driver_mips.c
index 40e4a6d..faaa232 100644
--- a/drivers/bcma/driver_mips.c
+++ b/drivers/bcma/driver_mips.c
@@ -155,6 +155,18 @@ static void bcma_core_mips_dump_irq(struct bcma_bus *bus)
}
}
+u32 bcma_cpu_clock(struct bcma_drv_mips *mcore)
+{
+ struct bcma_bus *bus = mcore->core->bus;
+
+ if (bus->drv_cc.capabilities & BCMA_CC_CAP_PMU)
+ return bcma_pmu_get_clockcpu(&bus->drv_cc);
+
+ pr_err("No PMU available, need this to get the cpu clock\n");
+ return 0;
+}
+EXPORT_SYMBOL(bcma_cpu_clock);
+
static void bcma_core_mips_serial_init(struct bcma_drv_mips *mcore)
{
struct bcma_bus *bus = mcore->core->bus;
diff --git a/include/linux/bcma/bcma_driver_chipcommon.h b/include/linux/bcma/bcma_driver_chipcommon.h
index 083c3b6..77dc08c 100644
--- a/include/linux/bcma/bcma_driver_chipcommon.h
+++ b/include/linux/bcma/bcma_driver_chipcommon.h
@@ -245,6 +245,41 @@
#define BCMA_CC_PLLCTL_ADDR 0x0660
#define BCMA_CC_PLLCTL_DATA 0x0664
+/* Divider allocation in 4716/47162/5356 */
+#define BCMA_CC_PMU5_MAINPLL_CPU 1
+#define BCMA_CC_PMU5_MAINPLL_MEM 2
+#define BCMA_CC_PMU5_MAINPLL_SSB 3
+
+/* PLL usage in 4716/47162 */
+#define BCMA_CC_PMU4716_MAINPLL_PLL0 12
+
+/* ALP clock on pre-PMU chips */
+#define BCMA_CC_PMU_ALP_CLOCK 20000000
+/* HT clock for systems with PMU-enabled chipcommon */
+#define BCMA_CC_PMU_HT_CLOCK 80000000
+
+/* PMU rev 5 (& 6) */
+#define BCMA_CC_PPL_P1P2_OFF 0
+#define BCMA_CC_PPL_P1_MASK 0x0f000000
+#define BCMA_CC_PPL_P1_SHIFT 24
+#define BCMA_CC_PPL_P2_MASK 0x00f00000
+#define BCMA_CC_PPL_P2_SHIFT 20
+#define BCMA_CC_PPL_M14_OFF 1
+#define BCMA_CC_PPL_MDIV_MASK 0x000000ff
+#define BCMA_CC_PPL_MDIV_WIDTH 8
+#define BCMA_CC_PPL_NM5_OFF 2
+#define BCMA_CC_PPL_NDIV_MASK 0xfff00000
+#define BCMA_CC_PPL_NDIV_SHIFT 20
+#define BCMA_CC_PPL_FMAB_OFF 3
+#define BCMA_CC_PPL_MRAT_MASK 0xf0000000
+#define BCMA_CC_PPL_MRAT_SHIFT 28
+#define BCMA_CC_PPL_ABRAT_MASK 0x08000000
+#define BCMA_CC_PPL_ABRAT_SHIFT 27
+#define BCMA_CC_PPL_FDIV_MASK 0x07ffffff
+#define BCMA_CC_PPL_PLLCTL_OFF 4
+#define BCMA_CC_PPL_PCHI_OFF 5
+#define BCMA_CC_PPL_PCHI_MASK 0x0000003f
+
/* Data for the PMU, if available.
* Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
*/
diff --git a/include/linux/bcma/bcma_driver_mips.h b/include/linux/bcma/bcma_driver_mips.h
index 6584e7d..8346fde 100644
--- a/include/linux/bcma/bcma_driver_mips.h
+++ b/include/linux/bcma/bcma_driver_mips.h
@@ -47,5 +47,6 @@ struct bcma_drv_mips {
};
extern void bcma_core_mips_init(struct bcma_drv_mips *mcore);
+extern u32 bcma_cpu_clock(struct bcma_drv_mips *mcore);
#endif /* LINUX_BCMA_DRIVER_MIPS_H_ */
--
1.7.4.1
On 06/06/2011 11:53 PM, Arnd Bergmann wrote:
> On Monday 06 June 2011 23:38:50 Hauke Mehrtens wrote:
>> Accessing chip common should be possible without scanning the hole bus
>> as it is at the first position and initializing most things just needs
>> chip common. For initializing the interrupts scanning is needed as we do
>> not know where the mips core is located.
>>
>> As we can not use kalloc on early boot we could use a function which
>> uses kalloc under normal conditions and when on early boot the
>> architecture code which starts the bcma code should also provide a
>> function which returns a pointer to some memory in its text segment to
>> use. We need space for 16 cores in the architecture code.
>>
>> In addition bcma_bus_register(struct bcma_bus *bus) has to be divided
>> into two parts. The first part will scan the bus and initialize chip
>> common and mips core. The second part will initialize pci core and
>> register the devices in the system. When using this under normal
>> conditions they will be called directly after each other.
> Just split out the minimal low-level function from the bcma_bus_scan
> then, to locate a single device based on some identifier. The
> bcma_bus_scan() function can then repeatedly allocate one device
> and pass it to the low-level function when doing the proper scan,
> while the arch code calls the low-level function directly with static
> data.
If going for this we should pass struct bcma_device_id as match
parameter as that identifies the core appropriately although you
probably only want to match manufacturer and core identifiers.
Gr. AvS
--
Almost nobody dances sober, unless they happen to be insane.
-- H.P. Lovecraft --
On Monday 06 June 2011, George Kashperko wrote:
> > For an interrupt controller, it should be ok to have it initialized
> > late, as long as it's only responsible for the devices on the same
> > bus and not for instance for IPI interrupts. Just make sure that you
> > do the bus scan and the initialization of the IRQ driver before you
> > initialize any drivers that rely in on the interrupts to be working.
>
> Without proper timer init (which requires both the chipcommon and mips
> cores knowledge) kernel will get hung somewhere inside calibrate_delay.
> It could get addressed if get bus scan called in arch_init_irq or
> plat_time_init - both are executed before calibrate_delay and with slab
> available.
Ok, so you need the interrupt controller to be working for the timer tick,
right? I think another option (if that's not what you mean already) would
be to have a simpler way to find a device on the bus that can be called
before doing a full scan.
Early drivers would then have to know what is there and call a function
like "bcma_find_device(BCMA_DEV_ID_IRQ)", while drivers that are not
required to be up just register a regular device driver with a probe
function that gets called after the bus scan creates device structures.
Arnd
On Monday 06 June 2011, Rafał Miłecki wrote:
> Greg, Arnd: could you take a look at this patch, please?
>
> With proposed patch we are going back to this ugly array and wrappers hacks.
>
> I was really happy with our final solution, but it seems it's not
> doable for embedded systems...? Is there something better we can do
> about this?
>
> 2011/6/6 Hauke Mehrtens <[email protected]>:
> > When using bcma on a embedded device it is initialized very early at
> > boot. We have to do so as the cpu and interrupt management and all
> > other devices are attached to this bus and it has to be initialized so
> > early. In that stage we can not allocate memory or sleep, just use the
> > memory on the stack and in the text segment as the kernel is not
> > initialized far enough. This patch removed the kzallocs from the scan
> > code. Some earlier version of the bcma implementation and the normal
> > ssb implementation are doing it like this.
> > The __bcma_dev_wrapper struct is used as the container for the device
> > struct as bcma_device will be too big if it includes struct device.
> >
> > Signed-off-by: Hauke Mehrtens <[email protected]>
If you rely on device scan to find your CPUs and interrupt controllers,
you are screwed already, this won't work.
In that case, it's better to have a few "early" drivers, as few as
possible, that don't go through the bus scan at all but have their
own ways of bootstrapping themselves. I don't know what you mean by
"CPU management", but I can only assume that it's not doing that much,
and you can just put the register values into the device tree.
For an interrupt controller, it should be ok to have it initialized
late, as long as it's only responsible for the devices on the same
bus and not for instance for IPI interrupts. Just make sure that you
do the bus scan and the initialization of the IRQ driver before you
initialize any drivers that rely in on the interrupts to be working.
Arnd
When using bcma on a embedded device it is initialized very early at
boot. We have to do so as the cpu and interrupt management and all
other devices are attached to this bus and it has to be initialized so
early. In that stage we can not allocate memory or sleep, just use the
memory on the stack and in the text segment as the kernel is not
initialized far enough. This patch removed the kzallocs from the scan
code. Some earlier version of the bcma implementation and the normal
ssb implementation are doing it like this.
The __bcma_dev_wrapper struct is used as the container for the device
struct as bcma_device will be too big if it includes struct device.
Signed-off-by: Hauke Mehrtens <[email protected]>
---
drivers/bcma/main.c | 86 ++++++++++++++++++++++++++++----------------
drivers/bcma/scan.c | 58 +++++++++++-------------------
include/linux/bcma/bcma.h | 16 ++++++--
3 files changed, 89 insertions(+), 71 deletions(-)
diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c
index a2f6b18..b0e7f5e 100644
--- a/drivers/bcma/main.c
+++ b/drivers/bcma/main.c
@@ -17,23 +17,27 @@ static int bcma_device_remove(struct device *dev);
static ssize_t manuf_show(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct bcma_device *core = container_of(dev, struct bcma_device, dev);
- return sprintf(buf, "0x%03X\n", core->id.manuf);
+ struct __bcma_dev_wrapper *wrapper = container_of(dev,
+ struct __bcma_dev_wrapper, dev);
+ return sprintf(buf, "0x%03X\n", wrapper->core->id.manuf);
}
static ssize_t id_show(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct bcma_device *core = container_of(dev, struct bcma_device, dev);
- return sprintf(buf, "0x%03X\n", core->id.id);
+ struct __bcma_dev_wrapper *wrapper = container_of(dev,
+ struct __bcma_dev_wrapper, dev);
+ return sprintf(buf, "0x%03X\n", wrapper->core->id.id);
}
static ssize_t rev_show(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct bcma_device *core = container_of(dev, struct bcma_device, dev);
- return sprintf(buf, "0x%02X\n", core->id.rev);
+ struct __bcma_dev_wrapper *wrapper = container_of(dev,
+ struct __bcma_dev_wrapper, dev);
+ return sprintf(buf, "0x%02X\n", wrapper->core->id.rev);
}
static ssize_t class_show(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct bcma_device *core = container_of(dev, struct bcma_device, dev);
- return sprintf(buf, "0x%X\n", core->id.class);
+ struct __bcma_dev_wrapper *wrapper = container_of(dev,
+ struct __bcma_dev_wrapper, dev);
+ return sprintf(buf, "0x%X\n", wrapper->core->id.class);
}
static struct device_attribute bcma_device_attrs[] = {
__ATTR_RO(manuf),
@@ -53,27 +57,30 @@ static struct bus_type bcma_bus_type = {
static struct bcma_device *bcma_find_core(struct bcma_bus *bus, u16 coreid)
{
- struct bcma_device *core;
-
- list_for_each_entry(core, &bus->cores, list) {
- if (core->id.id == coreid)
- return core;
+ u8 i;
+ for (i = 0; i < bus->nr_cores; i++) {
+ if (bus->cores[i].id.id == coreid)
+ return &bus->cores[i];
}
return NULL;
}
static void bcma_release_core_dev(struct device *dev)
{
- struct bcma_device *core = container_of(dev, struct bcma_device, dev);
- kfree(core);
+ struct __bcma_dev_wrapper *wrapper = container_of(dev,
+ struct __bcma_dev_wrapper, dev);
+ kfree(wrapper);
}
static int bcma_register_cores(struct bcma_bus *bus)
{
struct bcma_device *core;
- int err, dev_id = 0;
+ struct __bcma_dev_wrapper *wrapper;
+ int i, err, dev_id = 0;
+
+ for (i = 0; i < bus->nr_cores; i++) {
+ core = &(bus->cores[i]);
- list_for_each_entry(core, &bus->cores, list) {
/* We support that cores ourself */
switch (core->id.id) {
case BCMA_CORE_CHIPCOMMON:
@@ -82,28 +89,37 @@ static int bcma_register_cores(struct bcma_bus *bus)
continue;
}
- core->dev.release = bcma_release_core_dev;
- core->dev.bus = &bcma_bus_type;
- dev_set_name(&core->dev, "bcma%d:%d", 0/*bus->num*/, dev_id);
+ wrapper = kzalloc(sizeof(*wrapper), GFP_KERNEL);
+ if (!wrapper) {
+ pr_err("Could not allocate wrapper for core 0x%03X\n",
+ core->id.id);
+ continue;
+ }
+
+ wrapper->core = core;
+ wrapper->dev.release = bcma_release_core_dev;
+ wrapper->dev.bus = &bcma_bus_type;
+ dev_set_name(&wrapper->dev, "bcma%d:%d", 0/*bus->num*/, dev_id);
switch (bus->hosttype) {
case BCMA_HOSTTYPE_PCI:
- core->dev.parent = &bus->host_pci->dev;
- core->dma_dev = &bus->host_pci->dev;
- core->irq = bus->host_pci->irq;
+ wrapper->dev.parent = &bus->host_pci->dev;
+ wrapper->core->dma_dev = &bus->host_pci->dev;
+ wrapper->core->irq = bus->host_pci->irq;
break;
case BCMA_HOSTTYPE_NONE:
case BCMA_HOSTTYPE_SDIO:
break;
}
- err = device_register(&core->dev);
+ err = device_register(&wrapper->dev);
if (err) {
pr_err("Could not register dev for core 0x%03X\n",
core->id.id);
+ kfree(wrapper);
continue;
}
- core->dev_registered = true;
+ core->dev = &wrapper->dev;
dev_id++;
}
@@ -113,10 +129,12 @@ static int bcma_register_cores(struct bcma_bus *bus)
static void bcma_unregister_cores(struct bcma_bus *bus)
{
struct bcma_device *core;
+ int i;
- list_for_each_entry(core, &bus->cores, list) {
- if (core->dev_registered)
- device_unregister(&core->dev);
+ for (i = 0; i < bus->nr_cores; i++) {
+ core = &(bus->cores[i]);
+ if (core->dev)
+ device_unregister(core->dev);
}
}
@@ -179,7 +197,9 @@ EXPORT_SYMBOL_GPL(bcma_driver_unregister);
static int bcma_bus_match(struct device *dev, struct device_driver *drv)
{
- struct bcma_device *core = container_of(dev, struct bcma_device, dev);
+ struct __bcma_dev_wrapper *wrapper = container_of(dev,
+ struct __bcma_dev_wrapper, dev);
+ struct bcma_device *core = wrapper->core;
struct bcma_driver *adrv = container_of(drv, struct bcma_driver, drv);
const struct bcma_device_id *cid = &core->id;
const struct bcma_device_id *did;
@@ -196,7 +216,9 @@ static int bcma_bus_match(struct device *dev, struct device_driver *drv)
static int bcma_device_probe(struct device *dev)
{
- struct bcma_device *core = container_of(dev, struct bcma_device, dev);
+ struct __bcma_dev_wrapper *wrapper = container_of(dev,
+ struct __bcma_dev_wrapper, dev);
+ struct bcma_device *core = wrapper->core;
struct bcma_driver *adrv = container_of(dev->driver, struct bcma_driver,
drv);
int err = 0;
@@ -209,7 +231,9 @@ static int bcma_device_probe(struct device *dev)
static int bcma_device_remove(struct device *dev)
{
- struct bcma_device *core = container_of(dev, struct bcma_device, dev);
+ struct __bcma_dev_wrapper *wrapper = container_of(dev,
+ struct __bcma_dev_wrapper, dev);
+ struct bcma_device *core = wrapper->core;
struct bcma_driver *adrv = container_of(dev->driver, struct bcma_driver,
drv);
diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c
index 40d7dcc..70b39f7 100644
--- a/drivers/bcma/scan.c
+++ b/drivers/bcma/scan.c
@@ -211,9 +211,6 @@ int bcma_bus_scan(struct bcma_bus *bus)
s32 tmp;
u8 i, j;
- int err;
-
- INIT_LIST_HEAD(&bus->cores);
bus->nr_cores = 0;
bcma_scan_switch_core(bus, BCMA_ADDR_BASE);
@@ -230,11 +227,8 @@ int bcma_bus_scan(struct bcma_bus *bus)
bcma_scan_switch_core(bus, erombase);
while (eromptr < eromend) {
- struct bcma_device *core = kzalloc(sizeof(*core), GFP_KERNEL);
- if (!core)
- return -ENOMEM;
- INIT_LIST_HEAD(&core->list);
- core->bus = bus;
+ struct bcma_device core = { };
+ core.bus = bus;
/* get CIs */
cia = bcma_erom_get_ci(bus, &eromptr);
@@ -242,27 +236,24 @@ int bcma_bus_scan(struct bcma_bus *bus)
bcma_erom_push_ent(&eromptr);
if (bcma_erom_is_end(bus, &eromptr))
break;
- err= -EILSEQ;
- goto out;
+ return -EILSEQ;
}
cib = bcma_erom_get_ci(bus, &eromptr);
- if (cib < 0) {
- err= -EILSEQ;
- goto out;
- }
+ if (cib < 0)
+ return -EILSEQ;
/* parse CIs */
- core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT;
- core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT;
- core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT;
+ core.id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT;
+ core.id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT;
+ core.id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT;
ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT;
ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT;
wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT;
wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT;
- core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT;
+ core.id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT;
- if (((core->id.manuf == BCMA_MANUF_ARM) &&
- (core->id.id == 0xFFF)) ||
+ if (((core.id.manuf == BCMA_MANUF_ARM) &&
+ (core.id.id == 0xFFF)) ||
(ports[1] == 0)) {
bcma_erom_skip_component(bus, &eromptr);
continue;
@@ -285,10 +276,8 @@ int bcma_bus_scan(struct bcma_bus *bus)
/* get & parse master ports */
for (i = 0; i < ports[0]; i++) {
u32 mst_port_d = bcma_erom_get_mst_port(bus, &eromptr);
- if (mst_port_d < 0) {
- err= -EILSEQ;
- goto out;
- }
+ if (mst_port_d < 0)
+ return -EILSEQ;
}
/* get & parse slave ports */
@@ -303,7 +292,7 @@ int bcma_bus_scan(struct bcma_bus *bus)
break;
} else {
if (i == 0 && j == 0)
- core->addr = tmp;
+ core.addr = tmp;
}
}
}
@@ -320,7 +309,7 @@ int bcma_bus_scan(struct bcma_bus *bus)
break;
} else {
if (i == 0 && j == 0)
- core->wrap = tmp;
+ core.wrap = tmp;
}
}
}
@@ -338,22 +327,19 @@ int bcma_bus_scan(struct bcma_bus *bus)
break;
} else {
if (wrappers[0] == 0 && !i && !j)
- core->wrap = tmp;
+ core.wrap = tmp;
}
}
}
pr_info("Core %d found: %s "
"(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
- bus->nr_cores, bcma_device_name(&core->id),
- core->id.manuf, core->id.id, core->id.rev,
- core->id.class);
-
- core->core_index = bus->nr_cores++;
- list_add(&core->list, &bus->cores);
- continue;
-out:
- return err;
+ bus->nr_cores, bcma_device_name(&core.id),
+ core.id.manuf, core.id.id, core.id.rev,
+ core.id.class);
+
+ core.core_index = bus->nr_cores;
+ bus->cores[bus->nr_cores++] = core;
}
return 0;
diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h
index 27a27a7..3dc5302 100644
--- a/include/linux/bcma/bcma.h
+++ b/include/linux/bcma/bcma.h
@@ -118,14 +118,23 @@ struct bcma_host_ops {
#define BCMA_MAX_NR_CORES 16
+/* 1) It is not allowed to put struct device statically in bcma_device
+ * 2) We can not just use pointer to struct device because we use container_of
+ * 3) We do not have pointer to struct bcma_device in struct device
+ * Solution: use such a dummy wrapper
+ */
+struct __bcma_dev_wrapper {
+ struct device dev;
+ struct bcma_device *core;
+};
+
struct bcma_device {
struct bcma_bus *bus;
struct bcma_device_id id;
- struct device dev;
+ struct device *dev;
struct device *dma_dev;
unsigned int irq;
- bool dev_registered;
u8 core_index;
@@ -133,7 +142,6 @@ struct bcma_device {
u32 wrap;
void *drvdata;
- struct list_head list;
};
static inline void *bcma_get_drvdata(struct bcma_device *core)
@@ -182,7 +190,7 @@ struct bcma_bus {
struct bcma_chipinfo chipinfo;
struct bcma_device *mapped_core;
- struct list_head cores;
+ struct bcma_device cores[BCMA_MAX_NR_CORES];
u8 nr_cores;
struct bcma_drv_cc drv_cc;
--
1.7.4.1
On 06/07/2011 12:30 PM, Arend van Spriel wrote:
> On 06/07/2011 02:33 AM, Rafał Miłecki wrote:
>> W dniu 7 czerwca 2011 00:00 użytkownik Hauke Mehrtens
>> <[email protected]> napisał:
>>> On 06/06/2011 12:22 PM, Rafał Miłecki wrote:
>>>>> + if (bus->hosttype == BCMA_HOSTTYPE_EMBEDDED) {
>>>>> + iounmap(bus->mmio);
>>>>> + mmio = ioremap(BCMA_ADDR_BASE, BCMA_CORE_SIZE *
>>>>> bus->nr_cores);
>>>>> + if (!mmio)
>>>>> + return -ENOMEM;
>>>>> + bus->mmio = mmio;
>>>>> +
>>>>> + mmio = ioremap(BCMA_WRAP_BASE, BCMA_CORE_SIZE *
>>>>> bus->nr_cores);
>>>>> + if (!mmio)
>>>>> + return -ENOMEM;
>>>>> + bus->host_embedded = mmio;
>>>> Do we really need both? mmio and host_embedded? What about keeping
>>>> mmio only and using it in calculation for read/write[8,16,32]?
>>> These are two different memory regions, it should be possible to
>>> calculate the other address, but I do not like that. As host_embedded is
>>> in a union this does not waste any memory.
>> Ah, OK, I can see what does happen here. You are using:
>> 1) bus->mmio for first core
>> 2) bus->host_embedded for first agent/wrapper
>>
>> I'm not sure if this is a correct approach. Doing "core_index *
>> BCMA_CORE_SIZE" comes from ssb, where it was the way to calculate
>> offset. In case of BCMA we are reading all the info from (E)EPROM,
>> which also includes addresses of the cores.
>>
>> IMO you should use core->addr and core->wrap for read/write ops. I
>> believe this is approach Broadcom decided to use for BCMA, when
>> designing (E)EPROM.
>
> Agree. There is no guarantee for the core index to relate to the
> physical address. Chip designer may be systematic in this and the
> index*size method may work, but not by design.
>
> Gr. AvS
>
Ok I will use these addresses.
Hauke
R3JlZywgQXJuZDogY291bGQgeW91IHRha2UgYSBsb29rIGF0IHRoaXMgcGF0Y2gsIHBsZWFzZT8K
CldpdGggcHJvcG9zZWQgcGF0Y2ggd2UgYXJlIGdvaW5nIGJhY2sgdG8gdGhpcyB1Z2x5IGFycmF5
IGFuZCB3cmFwcGVycyBoYWNrcy4KCkkgd2FzIHJlYWxseSBoYXBweSB3aXRoIG91ciBmaW5hbCBz
b2x1dGlvbiwgYnV0IGl0IHNlZW1zIGl0J3Mgbm90CmRvYWJsZSBmb3IgZW1iZWRkZWQgc3lzdGVt
cy4uLj8gSXMgdGhlcmUgc29tZXRoaW5nIGJldHRlciB3ZSBjYW4gZG8KYWJvdXQgdGhpcz8KCjIw
MTEvNi82IEhhdWtlIE1laHJ0ZW5zIDxoYXVrZUBoYXVrZS1tLmRlPjoKPiBXaGVuIHVzaW5nIGJj
bWEgb24gYSBlbWJlZGRlZCBkZXZpY2UgaXQgaXMgaW5pdGlhbGl6ZWQgdmVyeSBlYXJseSBhdAo+
IGJvb3QuIFdlIGhhdmUgdG8gZG8gc28gYXMgdGhlIGNwdSBhbmQgaW50ZXJydXB0IG1hbmFnZW1l
bnQgYW5kIGFsbAo+IG90aGVyIGRldmljZXMgYXJlIGF0dGFjaGVkIHRvIHRoaXMgYnVzIGFuZCBp
dCBoYXMgdG8gYmUgaW5pdGlhbGl6ZWQgc28KPiBlYXJseS4gSW4gdGhhdCBzdGFnZSB3ZSBjYW4g
bm90IGFsbG9jYXRlIG1lbW9yeSBvciBzbGVlcCwganVzdCB1c2UgdGhlCj4gbWVtb3J5IG9uIHRo
ZSBzdGFjayBhbmQgaW4gdGhlIHRleHQgc2VnbWVudCBhcyB0aGUga2VybmVsIGlzIG5vdAo+IGlu
aXRpYWxpemVkIGZhciBlbm91Z2guIFRoaXMgcGF0Y2ggcmVtb3ZlZCB0aGUga3phbGxvY3MgZnJv
bSB0aGUgc2Nhbgo+IGNvZGUuIFNvbWUgZWFybGllciB2ZXJzaW9uIG9mIHRoZSBiY21hIGltcGxl
bWVudGF0aW9uIGFuZCB0aGUgbm9ybWFsCj4gc3NiIGltcGxlbWVudGF0aW9uIGFyZSBkb2luZyBp
dCBsaWtlIHRoaXMuCj4gVGhlIF9fYmNtYV9kZXZfd3JhcHBlciBzdHJ1Y3QgaXMgdXNlZCBhcyB0
aGUgY29udGFpbmVyIGZvciB0aGUgZGV2aWNlCj4gc3RydWN0IGFzIGJjbWFfZGV2aWNlIHdpbGwg
YmUgdG9vIGJpZyBpZiBpdCBpbmNsdWRlcyBzdHJ1Y3QgZGV2aWNlLgo+Cj4gU2lnbmVkLW9mZi1i
eTogSGF1a2UgTWVocnRlbnMgPGhhdWtlQGhhdWtlLW0uZGU+Cj4gLS0tCj4gwqBkcml2ZXJzL2Jj
bWEvbWFpbi5jIMKgIMKgIMKgIHwgwqAgODYgKysrKysrKysrKysrKysrKysrKysrKysrKysrKy0t
LS0tLS0tLS0tLS0tLS0KPiDCoGRyaXZlcnMvYmNtYS9zY2FuLmMgwqAgwqAgwqAgfCDCoCA1OCAr
KysrKysrKysrKy0tLS0tLS0tLS0tLS0tLS0tLS0KPiDCoGluY2x1ZGUvbGludXgvYmNtYS9iY21h
LmggfCDCoCAxNiArKysrKystLQo+IMKgMyBmaWxlcyBjaGFuZ2VkLCA4OSBpbnNlcnRpb25zKCsp
LCA3MSBkZWxldGlvbnMoLSkKPgo+IGRpZmYgLS1naXQgYS9kcml2ZXJzL2JjbWEvbWFpbi5jIGIv
ZHJpdmVycy9iY21hL21haW4uYwo+IGluZGV4IGEyZjZiMTguLmIwZTdmNWUgMTAwNjQ0Cj4gLS0t
IGEvZHJpdmVycy9iY21hL21haW4uYwo+ICsrKyBiL2RyaXZlcnMvYmNtYS9tYWluLmMKPiBAQCAt
MTcsMjMgKzE3LDI3IEBAIHN0YXRpYyBpbnQgYmNtYV9kZXZpY2VfcmVtb3ZlKHN0cnVjdCBkZXZp
Y2UgKmRldik7Cj4KPiDCoHN0YXRpYyBzc2l6ZV90IG1hbnVmX3Nob3coc3RydWN0IGRldmljZSAq
ZGV2LCBzdHJ1Y3QgZGV2aWNlX2F0dHJpYnV0ZSAqYXR0ciwgY2hhciAqYnVmKQo+IMKgewo+IC0g
wqAgwqAgwqAgc3RydWN0IGJjbWFfZGV2aWNlICpjb3JlID0gY29udGFpbmVyX29mKGRldiwgc3Ry
dWN0IGJjbWFfZGV2aWNlLCBkZXYpOwo+IC0gwqAgwqAgwqAgcmV0dXJuIHNwcmludGYoYnVmLCAi
MHglMDNYXG4iLCBjb3JlLT5pZC5tYW51Zik7Cj4gKyDCoCDCoCDCoCBzdHJ1Y3QgX19iY21hX2Rl
dl93cmFwcGVyICp3cmFwcGVyID0gY29udGFpbmVyX29mKGRldiwKPiArIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIHN0
cnVjdCBfX2JjbWFfZGV2X3dyYXBwZXIsIGRldik7Cj4gKyDCoCDCoCDCoCByZXR1cm4gc3ByaW50
ZihidWYsICIweCUwM1hcbiIsIHdyYXBwZXItPmNvcmUtPmlkLm1hbnVmKTsKPiDCoH0KPiDCoHN0
YXRpYyBzc2l6ZV90IGlkX3Nob3coc3RydWN0IGRldmljZSAqZGV2LCBzdHJ1Y3QgZGV2aWNlX2F0
dHJpYnV0ZSAqYXR0ciwgY2hhciAqYnVmKQo+IMKgewo+IC0gwqAgwqAgwqAgc3RydWN0IGJjbWFf
ZGV2aWNlICpjb3JlID0gY29udGFpbmVyX29mKGRldiwgc3RydWN0IGJjbWFfZGV2aWNlLCBkZXYp
Owo+IC0gwqAgwqAgwqAgcmV0dXJuIHNwcmludGYoYnVmLCAiMHglMDNYXG4iLCBjb3JlLT5pZC5p
ZCk7Cj4gKyDCoCDCoCDCoCBzdHJ1Y3QgX19iY21hX2Rldl93cmFwcGVyICp3cmFwcGVyID0gY29u
dGFpbmVyX29mKGRldiwKPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIHN0cnVjdCBfX2JjbWFfZGV2X3dyYXBwZXIs
IGRldik7Cj4gKyDCoCDCoCDCoCByZXR1cm4gc3ByaW50ZihidWYsICIweCUwM1hcbiIsIHdyYXBw
ZXItPmNvcmUtPmlkLmlkKTsKPiDCoH0KPiDCoHN0YXRpYyBzc2l6ZV90IHJldl9zaG93KHN0cnVj
dCBkZXZpY2UgKmRldiwgc3RydWN0IGRldmljZV9hdHRyaWJ1dGUgKmF0dHIsIGNoYXIgKmJ1ZikK
PiDCoHsKPiAtIMKgIMKgIMKgIHN0cnVjdCBiY21hX2RldmljZSAqY29yZSA9IGNvbnRhaW5lcl9v
ZihkZXYsIHN0cnVjdCBiY21hX2RldmljZSwgZGV2KTsKPiAtIMKgIMKgIMKgIHJldHVybiBzcHJp
bnRmKGJ1ZiwgIjB4JTAyWFxuIiwgY29yZS0+aWQucmV2KTsKPiArIMKgIMKgIMKgIHN0cnVjdCBf
X2JjbWFfZGV2X3dyYXBwZXIgKndyYXBwZXIgPSBjb250YWluZXJfb2YoZGV2LAo+ICsgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgc3RydWN0IF9fYmNtYV9kZXZfd3JhcHBlciwgZGV2KTsKPiArIMKgIMKgIMKgIHJldHVy
biBzcHJpbnRmKGJ1ZiwgIjB4JTAyWFxuIiwgd3JhcHBlci0+Y29yZS0+aWQucmV2KTsKPiDCoH0K
PiDCoHN0YXRpYyBzc2l6ZV90IGNsYXNzX3Nob3coc3RydWN0IGRldmljZSAqZGV2LCBzdHJ1Y3Qg
ZGV2aWNlX2F0dHJpYnV0ZSAqYXR0ciwgY2hhciAqYnVmKQo+IMKgewo+IC0gwqAgwqAgwqAgc3Ry
dWN0IGJjbWFfZGV2aWNlICpjb3JlID0gY29udGFpbmVyX29mKGRldiwgc3RydWN0IGJjbWFfZGV2
aWNlLCBkZXYpOwo+IC0gwqAgwqAgwqAgcmV0dXJuIHNwcmludGYoYnVmLCAiMHglWFxuIiwgY29y
ZS0+aWQuY2xhc3MpOwo+ICsgwqAgwqAgwqAgc3RydWN0IF9fYmNtYV9kZXZfd3JhcHBlciAqd3Jh
cHBlciA9IGNvbnRhaW5lcl9vZihkZXYsCj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCBzdHJ1Y3QgX19iY21hX2Rl
dl93cmFwcGVyLCBkZXYpOwo+ICsgwqAgwqAgwqAgcmV0dXJuIHNwcmludGYoYnVmLCAiMHglWFxu
Iiwgd3JhcHBlci0+Y29yZS0+aWQuY2xhc3MpOwo+IMKgfQo+IMKgc3RhdGljIHN0cnVjdCBkZXZp
Y2VfYXR0cmlidXRlIGJjbWFfZGV2aWNlX2F0dHJzW10gPSB7Cj4gwqAgwqAgwqAgwqBfX0FUVFJf
Uk8obWFudWYpLAo+IEBAIC01MywyNyArNTcsMzAgQEAgc3RhdGljIHN0cnVjdCBidXNfdHlwZSBi
Y21hX2J1c190eXBlID0gewo+Cj4gwqBzdGF0aWMgc3RydWN0IGJjbWFfZGV2aWNlICpiY21hX2Zp
bmRfY29yZShzdHJ1Y3QgYmNtYV9idXMgKmJ1cywgdTE2IGNvcmVpZCkKPiDCoHsKPiAtIMKgIMKg
IMKgIHN0cnVjdCBiY21hX2RldmljZSAqY29yZTsKPiAtCj4gLSDCoCDCoCDCoCBsaXN0X2Zvcl9l
YWNoX2VudHJ5KGNvcmUsICZidXMtPmNvcmVzLCBsaXN0KSB7Cj4gLSDCoCDCoCDCoCDCoCDCoCDC
oCDCoCBpZiAoY29yZS0+aWQuaWQgPT0gY29yZWlkKQo+IC0gwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgcmV0dXJuIGNvcmU7Cj4gKyDCoCDCoCDCoCB1OCBpOwo+ICsgwqAgwqAgwqAg
Zm9yIChpID0gMDsgaSA8IGJ1cy0+bnJfY29yZXM7IGkrKykgewo+ICsgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgaWYgKGJ1cy0+Y29yZXNbaV0uaWQuaWQgPT0gY29yZWlkKQo+ICsgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgcmV0dXJuICZidXMtPmNvcmVzW2ldOwo+IMKgIMKgIMKgIMKg
fQo+IMKgIMKgIMKgIMKgcmV0dXJuIE5VTEw7Cj4gwqB9Cj4KPiDCoHN0YXRpYyB2b2lkIGJjbWFf
cmVsZWFzZV9jb3JlX2RldihzdHJ1Y3QgZGV2aWNlICpkZXYpCj4gwqB7Cj4gLSDCoCDCoCDCoCBz
dHJ1Y3QgYmNtYV9kZXZpY2UgKmNvcmUgPSBjb250YWluZXJfb2YoZGV2LCBzdHJ1Y3QgYmNtYV9k
ZXZpY2UsIGRldik7Cj4gLSDCoCDCoCDCoCBrZnJlZShjb3JlKTsKPiArIMKgIMKgIMKgIHN0cnVj
dCBfX2JjbWFfZGV2X3dyYXBwZXIgKndyYXBwZXIgPSBjb250YWluZXJfb2YoZGV2LAo+ICsgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgc3RydWN0IF9fYmNtYV9kZXZfd3JhcHBlciwgZGV2KTsKPiArIMKgIMKgIMKgIGtm
cmVlKHdyYXBwZXIpOwo+IMKgfQo+Cj4gwqBzdGF0aWMgaW50IGJjbWFfcmVnaXN0ZXJfY29yZXMo
c3RydWN0IGJjbWFfYnVzICpidXMpCj4gwqB7Cj4gwqAgwqAgwqAgwqBzdHJ1Y3QgYmNtYV9kZXZp
Y2UgKmNvcmU7Cj4gLSDCoCDCoCDCoCBpbnQgZXJyLCBkZXZfaWQgPSAwOwo+ICsgwqAgwqAgwqAg
c3RydWN0IF9fYmNtYV9kZXZfd3JhcHBlciAqd3JhcHBlcjsKPiArIMKgIMKgIMKgIGludCBpLCBl
cnIsIGRldl9pZCA9IDA7Cj4gKwo+ICsgwqAgwqAgwqAgZm9yIChpID0gMDsgaSA8IGJ1cy0+bnJf
Y29yZXM7IGkrKykgewo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgY29yZSA9ICYoYnVzLT5jb3Jl
c1tpXSk7Cj4KPiAtIMKgIMKgIMKgIGxpc3RfZm9yX2VhY2hfZW50cnkoY29yZSwgJmJ1cy0+Y29y
ZXMsIGxpc3QpIHsKPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoC8qIFdlIHN1cHBvcnQgdGhhdCBj
b3JlcyBvdXJzZWxmICovCj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBzd2l0Y2ggKGNvcmUtPmlk
LmlkKSB7Cj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBjYXNlIEJDTUFfQ09SRV9DSElQQ09NTU9O
Ogo+IEBAIC04MiwyOCArODksMzcgQEAgc3RhdGljIGludCBiY21hX3JlZ2lzdGVyX2NvcmVzKHN0
cnVjdCBiY21hX2J1cyAqYnVzKQo+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
Y29udGludWU7Cj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqB9Cj4KPiAtIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIGNvcmUtPmRldi5yZWxlYXNlID0gYmNtYV9yZWxlYXNlX2NvcmVfZGV2Owo+IC0gwqAg
wqAgwqAgwqAgwqAgwqAgwqAgY29yZS0+ZGV2LmJ1cyA9ICZiY21hX2J1c190eXBlOwo+IC0gwqAg
wqAgwqAgwqAgwqAgwqAgwqAgZGV2X3NldF9uYW1lKCZjb3JlLT5kZXYsICJiY21hJWQ6JWQiLCAw
LypidXMtPm51bSovLCBkZXZfaWQpOwo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgd3JhcHBlciA9
IGt6YWxsb2Moc2l6ZW9mKCp3cmFwcGVyKSwgR0ZQX0tFUk5FTCk7Cj4gKyDCoCDCoCDCoCDCoCDC
oCDCoCDCoCBpZiAoIXdyYXBwZXIpIHsKPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIHByX2VycigiQ291bGQgbm90IGFsbG9jYXRlIHdyYXBwZXIgZm9yIGNvcmUgMHglMDNYXG4i
LAo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBjb3JlLT5p
ZC5pZCk7Cj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCBjb250aW51ZTsKPiAr
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIH0KPiArCj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCB3cmFw
cGVyLT5jb3JlID0gY29yZTsKPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIHdyYXBwZXItPmRldi5y
ZWxlYXNlID0gYmNtYV9yZWxlYXNlX2NvcmVfZGV2Owo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
d3JhcHBlci0+ZGV2LmJ1cyA9ICZiY21hX2J1c190eXBlOwo+ICsgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgZGV2X3NldF9uYW1lKCZ3cmFwcGVyLT5kZXYsICJiY21hJWQ6JWQiLCAwLypidXMtPm51bSov
LCBkZXZfaWQpOwo+Cj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBzd2l0Y2ggKGJ1cy0+aG9zdHR5
cGUpIHsKPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoGNhc2UgQkNNQV9IT1NUVFlQRV9QQ0k6Cj4g
LSDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCBjb3JlLT5kZXYucGFyZW50ID0gJmJ1
cy0+aG9zdF9wY2ktPmRldjsKPiAtIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGNv
cmUtPmRtYV9kZXYgPSAmYnVzLT5ob3N0X3BjaS0+ZGV2Owo+IC0gwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgY29yZS0+aXJxID0gYnVzLT5ob3N0X3BjaS0+aXJxOwo+ICsgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgd3JhcHBlci0+ZGV2LnBhcmVudCA9ICZidXMtPmhv
c3RfcGNpLT5kZXY7Cj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCB3cmFwcGVy
LT5jb3JlLT5kbWFfZGV2ID0gJmJ1cy0+aG9zdF9wY2ktPmRldjsKPiArIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIHdyYXBwZXItPmNvcmUtPmlycSA9IGJ1cy0+aG9zdF9wY2ktPmly
cTsKPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoGJyZWFrOwo+IMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgY2FzZSBCQ01BX0hPU1RUWVBFX05PTkU6Cj4gwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqBjYXNlIEJDTUFfSE9TVFRZUEVfU0RJTzoKPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoCDCoGJyZWFrOwo+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgfQo+Cj4gLSDCoCDC
oCDCoCDCoCDCoCDCoCDCoCBlcnIgPSBkZXZpY2VfcmVnaXN0ZXIoJmNvcmUtPmRldik7Cj4gKyDC
oCDCoCDCoCDCoCDCoCDCoCDCoCBlcnIgPSBkZXZpY2VfcmVnaXN0ZXIoJndyYXBwZXItPmRldik7
Cj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBpZiAoZXJyKSB7Cj4gwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqBwcl9lcnIoIkNvdWxkIG5vdCByZWdpc3RlciBkZXYgZm9yIGNvcmUg
MHglMDNYXG4iLAo+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IGNvcmUtPmlkLmlkKTsKPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGtmcmVl
KHdyYXBwZXIpOwo+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgY29udGludWU7
Cj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqB9Cj4gLSDCoCDCoCDCoCDCoCDCoCDCoCDCoCBjb3Jl
LT5kZXZfcmVnaXN0ZXJlZCA9IHRydWU7Cj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCBjb3JlLT5k
ZXYgPSAmd3JhcHBlci0+ZGV2Owo+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgZGV2X2lkKys7Cj4g
wqAgwqAgwqAgwqB9Cj4KPiBAQCAtMTEzLDEwICsxMjksMTIgQEAgc3RhdGljIGludCBiY21hX3Jl
Z2lzdGVyX2NvcmVzKHN0cnVjdCBiY21hX2J1cyAqYnVzKQo+IMKgc3RhdGljIHZvaWQgYmNtYV91
bnJlZ2lzdGVyX2NvcmVzKHN0cnVjdCBiY21hX2J1cyAqYnVzKQo+IMKgewo+IMKgIMKgIMKgIMKg
c3RydWN0IGJjbWFfZGV2aWNlICpjb3JlOwo+ICsgwqAgwqAgwqAgaW50IGk7Cj4KPiAtIMKgIMKg
IMKgIGxpc3RfZm9yX2VhY2hfZW50cnkoY29yZSwgJmJ1cy0+Y29yZXMsIGxpc3QpIHsKPiAtIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIGlmIChjb3JlLT5kZXZfcmVnaXN0ZXJlZCkKPiAtIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGRldmljZV91bnJlZ2lzdGVyKCZjb3JlLT5kZXYpOwo+
ICsgwqAgwqAgwqAgZm9yIChpID0gMDsgaSA8IGJ1cy0+bnJfY29yZXM7IGkrKykgewo+ICsgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgY29yZSA9ICYoYnVzLT5jb3Jlc1tpXSk7Cj4gKyDCoCDCoCDCoCDC
oCDCoCDCoCDCoCBpZiAoY29yZS0+ZGV2KQo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgZGV2aWNlX3VucmVnaXN0ZXIoY29yZS0+ZGV2KTsKPiDCoCDCoCDCoCDCoH0KPiDCoH0K
Pgo+IEBAIC0xNzksNyArMTk3LDkgQEAgRVhQT1JUX1NZTUJPTF9HUEwoYmNtYV9kcml2ZXJfdW5y
ZWdpc3Rlcik7Cj4KPiDCoHN0YXRpYyBpbnQgYmNtYV9idXNfbWF0Y2goc3RydWN0IGRldmljZSAq
ZGV2LCBzdHJ1Y3QgZGV2aWNlX2RyaXZlciAqZHJ2KQo+IMKgewo+IC0gwqAgwqAgwqAgc3RydWN0
IGJjbWFfZGV2aWNlICpjb3JlID0gY29udGFpbmVyX29mKGRldiwgc3RydWN0IGJjbWFfZGV2aWNl
LCBkZXYpOwo+ICsgwqAgwqAgwqAgc3RydWN0IF9fYmNtYV9kZXZfd3JhcHBlciAqd3JhcHBlciA9
IGNvbnRhaW5lcl9vZihkZXYsCj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCBzdHJ1Y3QgX19iY21hX2Rldl93cmFw
cGVyLCBkZXYpOwo+ICsgwqAgwqAgwqAgc3RydWN0IGJjbWFfZGV2aWNlICpjb3JlID0gd3JhcHBl
ci0+Y29yZTsKPiDCoCDCoCDCoCDCoHN0cnVjdCBiY21hX2RyaXZlciAqYWRydiA9IGNvbnRhaW5l
cl9vZihkcnYsIHN0cnVjdCBiY21hX2RyaXZlciwgZHJ2KTsKPiDCoCDCoCDCoCDCoGNvbnN0IHN0
cnVjdCBiY21hX2RldmljZV9pZCAqY2lkID0gJmNvcmUtPmlkOwo+IMKgIMKgIMKgIMKgY29uc3Qg
c3RydWN0IGJjbWFfZGV2aWNlX2lkICpkaWQ7Cj4gQEAgLTE5Niw3ICsyMTYsOSBAQCBzdGF0aWMg
aW50IGJjbWFfYnVzX21hdGNoKHN0cnVjdCBkZXZpY2UgKmRldiwgc3RydWN0IGRldmljZV9kcml2
ZXIgKmRydikKPgo+IMKgc3RhdGljIGludCBiY21hX2RldmljZV9wcm9iZShzdHJ1Y3QgZGV2aWNl
ICpkZXYpCj4gwqB7Cj4gLSDCoCDCoCDCoCBzdHJ1Y3QgYmNtYV9kZXZpY2UgKmNvcmUgPSBjb250
YWluZXJfb2YoZGV2LCBzdHJ1Y3QgYmNtYV9kZXZpY2UsIGRldik7Cj4gKyDCoCDCoCDCoCBzdHJ1
Y3QgX19iY21hX2Rldl93cmFwcGVyICp3cmFwcGVyID0gY29udGFpbmVyX29mKGRldiwKPiArIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIHN0cnVjdCBfX2JjbWFfZGV2X3dyYXBwZXIsIGRldik7Cj4gKyDCoCDCoCDCoCBz
dHJ1Y3QgYmNtYV9kZXZpY2UgKmNvcmUgPSB3cmFwcGVyLT5jb3JlOwo+IMKgIMKgIMKgIMKgc3Ry
dWN0IGJjbWFfZHJpdmVyICphZHJ2ID0gY29udGFpbmVyX29mKGRldi0+ZHJpdmVyLCBzdHJ1Y3Qg
YmNtYV9kcml2ZXIsCj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgZHJ2KTsKPiDCoCDCoCDCoCDCoGludCBlcnIgPSAw
Owo+IEBAIC0yMDksNyArMjMxLDkgQEAgc3RhdGljIGludCBiY21hX2RldmljZV9wcm9iZShzdHJ1
Y3QgZGV2aWNlICpkZXYpCj4KPiDCoHN0YXRpYyBpbnQgYmNtYV9kZXZpY2VfcmVtb3ZlKHN0cnVj
dCBkZXZpY2UgKmRldikKPiDCoHsKPiAtIMKgIMKgIMKgIHN0cnVjdCBiY21hX2RldmljZSAqY29y
ZSA9IGNvbnRhaW5lcl9vZihkZXYsIHN0cnVjdCBiY21hX2RldmljZSwgZGV2KTsKPiArIMKgIMKg
IMKgIHN0cnVjdCBfX2JjbWFfZGV2X3dyYXBwZXIgKndyYXBwZXIgPSBjb250YWluZXJfb2YoZGV2
LAo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgc3RydWN0IF9fYmNtYV9kZXZfd3JhcHBlciwgZGV2KTsKPiArIMKg
IMKgIMKgIHN0cnVjdCBiY21hX2RldmljZSAqY29yZSA9IHdyYXBwZXItPmNvcmU7Cj4gwqAgwqAg
wqAgwqBzdHJ1Y3QgYmNtYV9kcml2ZXIgKmFkcnYgPSBjb250YWluZXJfb2YoZGV2LT5kcml2ZXIs
IHN0cnVjdCBiY21hX2RyaXZlciwKPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCBkcnYpOwo+Cj4gZGlmZiAtLWdpdCBh
L2RyaXZlcnMvYmNtYS9zY2FuLmMgYi9kcml2ZXJzL2JjbWEvc2Nhbi5jCj4gaW5kZXggNDBkN2Rj
Yy4uNzBiMzlmNyAxMDA2NDQKPiAtLS0gYS9kcml2ZXJzL2JjbWEvc2Nhbi5jCj4gKysrIGIvZHJp
dmVycy9iY21hL3NjYW4uYwo+IEBAIC0yMTEsOSArMjExLDYgQEAgaW50IGJjbWFfYnVzX3NjYW4o
c3RydWN0IGJjbWFfYnVzICpidXMpCj4gwqAgwqAgwqAgwqBzMzIgdG1wOwo+IMKgIMKgIMKgIMKg
dTggaSwgajsKPgo+IC0gwqAgwqAgwqAgaW50IGVycjsKPiAtCj4gLSDCoCDCoCDCoCBJTklUX0xJ
U1RfSEVBRCgmYnVzLT5jb3Jlcyk7Cj4gwqAgwqAgwqAgwqBidXMtPm5yX2NvcmVzID0gMDsKPgo+
IMKgIMKgIMKgIMKgYmNtYV9zY2FuX3N3aXRjaF9jb3JlKGJ1cywgQkNNQV9BRERSX0JBU0UpOwo+
IEBAIC0yMzAsMTEgKzIyNyw4IEBAIGludCBiY21hX2J1c19zY2FuKHN0cnVjdCBiY21hX2J1cyAq
YnVzKQo+IMKgIMKgIMKgIMKgYmNtYV9zY2FuX3N3aXRjaF9jb3JlKGJ1cywgZXJvbWJhc2UpOwo+
Cj4gwqAgwqAgwqAgwqB3aGlsZSAoZXJvbXB0ciA8IGVyb21lbmQpIHsKPiAtIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIHN0cnVjdCBiY21hX2RldmljZSAqY29yZSA9IGt6YWxsb2Moc2l6ZW9mKCpjb3Jl
KSwgR0ZQX0tFUk5FTCk7Cj4gLSDCoCDCoCDCoCDCoCDCoCDCoCDCoCBpZiAoIWNvcmUpCj4gLSDC
oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCByZXR1cm4gLUVOT01FTTsKPiAtIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIElOSVRfTElTVF9IRUFEKCZjb3JlLT5saXN0KTsKPiAtIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIGNvcmUtPmJ1cyA9IGJ1czsKPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIHN0
cnVjdCBiY21hX2RldmljZSBjb3JlID0geyB9Owo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgY29y
ZS5idXMgPSBidXM7Cj4KPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoC8qIGdldCBDSXMgKi8KPiDC
oCDCoCDCoCDCoCDCoCDCoCDCoCDCoGNpYSA9IGJjbWFfZXJvbV9nZXRfY2koYnVzLCAmZXJvbXB0
cik7Cj4gQEAgLTI0MiwyNyArMjM2LDI0IEBAIGludCBiY21hX2J1c19zY2FuKHN0cnVjdCBiY21h
X2J1cyAqYnVzKQo+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgYmNtYV9lcm9t
X3B1c2hfZW50KCZlcm9tcHRyKTsKPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oGlmIChiY21hX2Vyb21faXNfZW5kKGJ1cywgJmVyb21wdHIpKQo+IMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgYnJlYWs7Cj4gLSDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoCDCoCDCoCBlcnI9IC1FSUxTRVE7Cj4gLSDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoCBnb3RvIG91dDsKPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IHJldHVybiAtRUlMU0VROwo+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgfQo+IMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgY2liID0gYmNtYV9lcm9tX2dldF9jaShidXMsICZlcm9tcHRyKTsKPiAtIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIGlmIChjaWIgPCAwKSB7Cj4gLSDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoCDCoCBlcnI9IC1FSUxTRVE7Cj4gLSDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCBnb3RvIG91dDsKPiAtIMKgIMKgIMKgIMKgIMKgIMKgIMKgIH0KPiArIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIGlmIChjaWIgPCAwKQo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgcmV0dXJuIC1FSUxTRVE7Cj4KPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoC8qIHBhcnNl
IENJcyAqLwo+IC0gwqAgwqAgwqAgwqAgwqAgwqAgwqAgY29yZS0+aWQuY2xhc3MgPSAoY2lhICYg
U0NBTl9DSUFfQ0xBU1MpID4+IFNDQU5fQ0lBX0NMQVNTX1NISUZUOwo+IC0gwqAgwqAgwqAgwqAg
wqAgwqAgwqAgY29yZS0+aWQuaWQgPSAoY2lhICYgU0NBTl9DSUFfSUQpID4+IFNDQU5fQ0lBX0lE
X1NISUZUOwo+IC0gwqAgwqAgwqAgwqAgwqAgwqAgwqAgY29yZS0+aWQubWFudWYgPSAoY2lhICYg
U0NBTl9DSUFfTUFOVUYpID4+IFNDQU5fQ0lBX01BTlVGX1NISUZUOwo+ICsgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgY29yZS5pZC5jbGFzcyA9IChjaWEgJiBTQ0FOX0NJQV9DTEFTUykgPj4gU0NBTl9D
SUFfQ0xBU1NfU0hJRlQ7Cj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCBjb3JlLmlkLmlkID0gKGNp
YSAmIFNDQU5fQ0lBX0lEKSA+PiBTQ0FOX0NJQV9JRF9TSElGVDsKPiArIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIGNvcmUuaWQubWFudWYgPSAoY2lhICYgU0NBTl9DSUFfTUFOVUYpID4+IFNDQU5fQ0lB
X01BTlVGX1NISUZUOwo+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgcG9ydHNbMF0gPSAoY2liICYg
U0NBTl9DSUJfTk1QKSA+PiBTQ0FOX0NJQl9OTVBfU0hJRlQ7Cj4gwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqBwb3J0c1sxXSA9IChjaWIgJiBTQ0FOX0NJQl9OU1ApID4+IFNDQU5fQ0lCX05TUF9TSElG
VDsKPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoHdyYXBwZXJzWzBdID0gKGNpYiAmIFNDQU5fQ0lC
X05NVykgPj4gU0NBTl9DSUJfTk1XX1NISUZUOwo+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgd3Jh
cHBlcnNbMV0gPSAoY2liICYgU0NBTl9DSUJfTlNXKSA+PiBTQ0FOX0NJQl9OU1dfU0hJRlQ7Cj4g
LSDCoCDCoCDCoCDCoCDCoCDCoCDCoCBjb3JlLT5pZC5yZXYgPSAoY2liICYgU0NBTl9DSUJfUkVW
KSA+PiBTQ0FOX0NJQl9SRVZfU0hJRlQ7Cj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCBjb3JlLmlk
LnJldiA9IChjaWIgJiBTQ0FOX0NJQl9SRVYpID4+IFNDQU5fQ0lCX1JFVl9TSElGVDsKPgo+IC0g
wqAgwqAgwqAgwqAgwqAgwqAgwqAgaWYgKCgoY29yZS0+aWQubWFudWYgPT0gQkNNQV9NQU5VRl9B
Uk0pICYmCj4gLSDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoChjb3JlLT5pZC5pZCA9PSAw
eEZGRikpIHx8Cj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCBpZiAoKChjb3JlLmlkLm1hbnVmID09
IEJDTUFfTUFOVUZfQVJNKSAmJgo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAoY29y
ZS5pZC5pZCA9PSAweEZGRikpIHx8Cj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAocG9y
dHNbMV0gPT0gMCkpIHsKPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoGJjbWFf
ZXJvbV9za2lwX2NvbXBvbmVudChidXMsICZlcm9tcHRyKTsKPiDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoCDCoCDCoGNvbnRpbnVlOwo+IEBAIC0yODUsMTAgKzI3Niw4IEBAIGludCBiY21h
X2J1c19zY2FuKHN0cnVjdCBiY21hX2J1cyAqYnVzKQo+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
LyogZ2V0ICYgcGFyc2UgbWFzdGVyIHBvcnRzICovCj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBm
b3IgKGkgPSAwOyBpIDwgcG9ydHNbMF07IGkrKykgewo+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgdTMyIG1zdF9wb3J0X2QgPSBiY21hX2Vyb21fZ2V0X21zdF9wb3J0KGJ1cywg
JmVyb21wdHIpOwo+IC0gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgaWYgKG1zdF9w
b3J0X2QgPCAwKSB7Cj4gLSDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCBlcnI9IC1FSUxTRVE7Cj4gLSDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoCBnb3RvIG91dDsKPiAtIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IH0KPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGlmIChtc3RfcG9ydF9kIDwg
MCkKPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIHJldHVy
biAtRUlMU0VROwo+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgfQo+Cj4gwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAvKiBnZXQgJiBwYXJzZSBzbGF2ZSBwb3J0cyAqLwo+IEBAIC0zMDMsNyArMjkyLDcg
QEAgaW50IGJjbWFfYnVzX3NjYW4oc3RydWN0IGJjbWFfYnVzICpidXMpCj4gwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBicmVhazsKPiDC
oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoH0gZWxzZSB7Cj4g
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqBpZiAoaSA9PSAwICYmIGogPT0gMCkKPiAtIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGNvcmUtPmFkZHIgPSB0bXA7
Cj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoCDCoCDCoCBjb3JlLmFkZHIgPSB0bXA7Cj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqB9Cj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqB9Cj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqB9Cj4gQEAgLTMyMCw3ICszMDksNyBA
QCBpbnQgYmNtYV9idXNfc2NhbihzdHJ1Y3QgYmNtYV9idXMgKmJ1cykKPiDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoGJyZWFrOwo+IMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgfSBlbHNlIHsKPiDC
oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oGlmIChpID09IDAgJiYgaiA9PSAwKQo+IC0gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgY29yZS0+d3JhcCA9IHRtcDsK
PiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIGNvcmUud3JhcCA9IHRtcDsKPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoH0KPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoH0KPiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoH0KPiBAQCAtMzM4LDIyICszMjcsMTkg
QEAgaW50IGJjbWFfYnVzX3NjYW4oc3RydWN0IGJjbWFfYnVzICpidXMpCj4gwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBicmVhazsKPiDC
oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoH0gZWxzZSB7Cj4g
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqBpZiAod3JhcHBlcnNbMF0gPT0gMCAmJiAhaSAmJiAhaikKPiAtIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGNvcmUt
PndyYXAgPSB0bXA7Cj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCBjb3JlLndyYXAgPSB0bXA7Cj4gwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqB9Cj4gwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqB9Cj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqB9Cj4KPiDCoCDC
oCDCoCDCoCDCoCDCoCDCoCDCoHByX2luZm8oIkNvcmUgJWQgZm91bmQ6ICVzICIKPiDCoCDCoCDC
oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCIobWFudWYgMHglMDNYLCBpZCAweCUwM1gsIHJl
diAweCUwMlgsIGNsYXNzIDB4JVgpXG4iLAo+IC0gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgYnVzLT5ucl9jb3JlcywgYmNtYV9kZXZpY2VfbmFtZSgmY29yZS0+aWQpLAo+IC0gwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgY29yZS0+aWQubWFudWYsIGNvcmUtPmlkLmlk
LCBjb3JlLT5pZC5yZXYsCj4gLSDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCBjb3Jl
LT5pZC5jbGFzcyk7Cj4gLQo+IC0gwqAgwqAgwqAgwqAgwqAgwqAgwqAgY29yZS0+Y29yZV9pbmRl
eCA9IGJ1cy0+bnJfY29yZXMrKzsKPiAtIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGxpc3RfYWRkKCZj
b3JlLT5saXN0LCAmYnVzLT5jb3Jlcyk7Cj4gLSDCoCDCoCDCoCDCoCDCoCDCoCDCoCBjb250aW51
ZTsKPiAtb3V0Ogo+IC0gwqAgwqAgwqAgwqAgwqAgwqAgwqAgcmV0dXJuIGVycjsKPiArIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGJ1cy0+bnJfY29yZXMsIGJjbWFfZGV2aWNlX25h
bWUoJmNvcmUuaWQpLAo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgY29yZS5p
ZC5tYW51ZiwgY29yZS5pZC5pZCwgY29yZS5pZC5yZXYsCj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoCDCoCBjb3JlLmlkLmNsYXNzKTsKPiArCj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDC
oCBjb3JlLmNvcmVfaW5kZXggPSBidXMtPm5yX2NvcmVzOwo+ICsgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgYnVzLT5jb3Jlc1tidXMtPm5yX2NvcmVzKytdID0gY29yZTsKPiDCoCDCoCDCoCDCoH0KPgo+
IMKgIMKgIMKgIMKgcmV0dXJuIDA7Cj4gZGlmZiAtLWdpdCBhL2luY2x1ZGUvbGludXgvYmNtYS9i
Y21hLmggYi9pbmNsdWRlL2xpbnV4L2JjbWEvYmNtYS5oCj4gaW5kZXggMjdhMjdhNy4uM2RjNTMw
MiAxMDA2NDQKPiAtLS0gYS9pbmNsdWRlL2xpbnV4L2JjbWEvYmNtYS5oCj4gKysrIGIvaW5jbHVk
ZS9saW51eC9iY21hL2JjbWEuaAo+IEBAIC0xMTgsMTQgKzExOCwyMyBAQCBzdHJ1Y3QgYmNtYV9o
b3N0X29wcyB7Cj4KPiDCoCNkZWZpbmUgQkNNQV9NQVhfTlJfQ09SRVMgwqAgwqAgwqAgwqAgwqAg
wqAgwqAxNgo+Cj4gKy8qIDEpIEl0IGlzIG5vdCBhbGxvd2VkIHRvIHB1dCBzdHJ1Y3QgZGV2aWNl
IHN0YXRpY2FsbHkgaW4gYmNtYV9kZXZpY2UKPiArICogMikgV2UgY2FuIG5vdCBqdXN0IHVzZSBw
b2ludGVyIHRvIHN0cnVjdCBkZXZpY2UgYmVjYXVzZSB3ZSB1c2UgY29udGFpbmVyX29mCj4gKyAq
IDMpIFdlIGRvIG5vdCBoYXZlIHBvaW50ZXIgdG8gc3RydWN0IGJjbWFfZGV2aWNlIGluIHN0cnVj
dCBkZXZpY2UKPiArICogU29sdXRpb246IHVzZSBzdWNoIGEgZHVtbXkgd3JhcHBlcgo+ICsgKi8K
PiArc3RydWN0IF9fYmNtYV9kZXZfd3JhcHBlciB7Cj4gKyDCoCDCoCDCoCBzdHJ1Y3QgZGV2aWNl
IGRldjsKPiArIMKgIMKgIMKgIHN0cnVjdCBiY21hX2RldmljZSAqY29yZTsKPiArfTsKPiArCj4g
wqBzdHJ1Y3QgYmNtYV9kZXZpY2Ugewo+IMKgIMKgIMKgIMKgc3RydWN0IGJjbWFfYnVzICpidXM7
Cj4gwqAgwqAgwqAgwqBzdHJ1Y3QgYmNtYV9kZXZpY2VfaWQgaWQ7Cj4KPiAtIMKgIMKgIMKgIHN0
cnVjdCBkZXZpY2UgZGV2Owo+ICsgwqAgwqAgwqAgc3RydWN0IGRldmljZSAqZGV2Owo+IMKgIMKg
IMKgIMKgc3RydWN0IGRldmljZSAqZG1hX2RldjsKPiDCoCDCoCDCoCDCoHVuc2lnbmVkIGludCBp
cnE7Cj4gLSDCoCDCoCDCoCBib29sIGRldl9yZWdpc3RlcmVkOwo+Cj4gwqAgwqAgwqAgwqB1OCBj
b3JlX2luZGV4Owo+Cj4gQEAgLTEzMyw3ICsxNDIsNiBAQCBzdHJ1Y3QgYmNtYV9kZXZpY2Ugewo+
IMKgIMKgIMKgIMKgdTMyIHdyYXA7Cj4KPiDCoCDCoCDCoCDCoHZvaWQgKmRydmRhdGE7Cj4gLSDC
oCDCoCDCoCBzdHJ1Y3QgbGlzdF9oZWFkIGxpc3Q7Cj4gwqB9Owo+Cj4gwqBzdGF0aWMgaW5saW5l
IHZvaWQgKmJjbWFfZ2V0X2RydmRhdGEoc3RydWN0IGJjbWFfZGV2aWNlICpjb3JlKQo+IEBAIC0x
ODIsNyArMTkwLDcgQEAgc3RydWN0IGJjbWFfYnVzIHsKPiDCoCDCoCDCoCDCoHN0cnVjdCBiY21h
X2NoaXBpbmZvIGNoaXBpbmZvOwo+Cj4gwqAgwqAgwqAgwqBzdHJ1Y3QgYmNtYV9kZXZpY2UgKm1h
cHBlZF9jb3JlOwo+IC0gwqAgwqAgwqAgc3RydWN0IGxpc3RfaGVhZCBjb3JlczsKPiArIMKgIMKg
IMKgIHN0cnVjdCBiY21hX2RldmljZSBjb3Jlc1tCQ01BX01BWF9OUl9DT1JFU107Cj4gwqAgwqAg
wqAgwqB1OCBucl9jb3JlczsKPgo+IMKgIMKgIMKgIMKgc3RydWN0IGJjbWFfZHJ2X2NjIGRydl9j
YzsKPiAtLQo+IDEuNy40LjEK
On 06/06/2011 12:07 AM, Hauke Mehrtens wrote:
> When using bcma on a embedded device it is initialized very early at
> boot. We have to do so as the cpu and interrupt management and all
> other devices are attached to this bus and it has to be initialized so
> early. In that stage we can not allocate memory or sleep, just use the
> memory on the stack and in the text segment as the kernel is not
> initialized far enough. This patch removed the kzallocs from the scan
> code. Some earlier version of the bcma implementation and the normal
> ssb implementation are doing it like this.
> The __bcma_dev_wrapper struct is used as the container for the device
> struct as bcma_device will be too big if it includes struct device.
Does this prevent using list_for_each() and friends to be used on the
device list? If so, could you consider a different approach. There were
good reasons to get rid of the bcma_dev_wrapper struct if I recall
discussions on the mailing list correctly. I also see tendency to use
ssb solutions without considering alternatives. For this particular
example, please consider adding a bcma_zalloc(), which does kzalloc for
non-embedded platforms and returns array pointers for embedded platform.
You could also consider this behavior for the embedded bus only.
Gr. AvS
--
Almost nobody dances sober, unless they happen to be insane.
-- H.P. Lovecraft --
The ssb bus is not hod directly any more. there is now a union which
contains all the supported buses, now just ssb. As just one system bus
can be used at a time the union does not cause any problems.
Signed-off-by: Hauke Mehrtens <[email protected]>
---
arch/mips/bcm47xx/gpio.c | 56 ++++++++++++++++----------
arch/mips/bcm47xx/nvram.c | 15 +++++--
arch/mips/bcm47xx/serial.c | 13 +++++-
arch/mips/bcm47xx/setup.c | 32 +++++++++++---
arch/mips/bcm47xx/time.c | 9 +++-
arch/mips/bcm47xx/wgt634u.c | 13 ++++--
arch/mips/include/asm/mach-bcm47xx/bcm47xx.h | 14 ++++++-
arch/mips/include/asm/mach-bcm47xx/gpio.h | 53 +++++++++++++++++-------
drivers/watchdog/bcm47xx_wdt.c | 12 +++++-
9 files changed, 156 insertions(+), 61 deletions(-)
diff --git a/arch/mips/bcm47xx/gpio.c b/arch/mips/bcm47xx/gpio.c
index e4a5ee9..2f6d2df 100644
--- a/arch/mips/bcm47xx/gpio.c
+++ b/arch/mips/bcm47xx/gpio.c
@@ -20,42 +20,54 @@ static DECLARE_BITMAP(gpio_in_use, BCM47XX_EXTIF_GPIO_LINES);
int gpio_request(unsigned gpio, const char *tag)
{
- if (ssb_chipco_available(&ssb_bcm47xx.chipco) &&
- ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
- return -EINVAL;
+ switch (bcm47xx_active_bus_type) {
+ case BCM47XX_BUS_TYPE_SSB:
+ if (ssb_chipco_available(&bcm47xx_bus.ssb.chipco) &&
+ ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
+ return -EINVAL;
- if (ssb_extif_available(&ssb_bcm47xx.extif) &&
- ((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES))
- return -EINVAL;
+ if (ssb_extif_available(&bcm47xx_bus.ssb.extif) &&
+ ((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES))
+ return -EINVAL;
- if (test_and_set_bit(gpio, gpio_in_use))
- return -EBUSY;
+ if (test_and_set_bit(gpio, gpio_in_use))
+ return -EBUSY;
- return 0;
+ return 0;
+ }
+ return -EINVAL;
}
EXPORT_SYMBOL(gpio_request);
void gpio_free(unsigned gpio)
{
- if (ssb_chipco_available(&ssb_bcm47xx.chipco) &&
- ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
- return;
+ switch (bcm47xx_active_bus_type) {
+ case BCM47XX_BUS_TYPE_SSB:
+ if (ssb_chipco_available(&bcm47xx_bus.ssb.chipco) &&
+ ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
+ return;
- if (ssb_extif_available(&ssb_bcm47xx.extif) &&
- ((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES))
- return;
+ if (ssb_extif_available(&bcm47xx_bus.ssb.extif) &&
+ ((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES))
+ return;
- clear_bit(gpio, gpio_in_use);
+ clear_bit(gpio, gpio_in_use);
+ return;
+ }
}
EXPORT_SYMBOL(gpio_free);
int gpio_to_irq(unsigned gpio)
{
- if (ssb_chipco_available(&ssb_bcm47xx.chipco))
- return ssb_mips_irq(ssb_bcm47xx.chipco.dev) + 2;
- else if (ssb_extif_available(&ssb_bcm47xx.extif))
- return ssb_mips_irq(ssb_bcm47xx.extif.dev) + 2;
- else
- return -EINVAL;
+ switch (bcm47xx_active_bus_type) {
+ case BCM47XX_BUS_TYPE_SSB:
+ if (ssb_chipco_available(&bcm47xx_bus.ssb.chipco))
+ return ssb_mips_irq(bcm47xx_bus.ssb.chipco.dev) + 2;
+ else if (ssb_extif_available(&bcm47xx_bus.ssb.extif))
+ return ssb_mips_irq(bcm47xx_bus.ssb.extif.dev) + 2;
+ else
+ return -EINVAL;
+ }
+ return -EINVAL;
}
EXPORT_SYMBOL_GPL(gpio_to_irq);
diff --git a/arch/mips/bcm47xx/nvram.c b/arch/mips/bcm47xx/nvram.c
index 54db815..d2304d0 100644
--- a/arch/mips/bcm47xx/nvram.c
+++ b/arch/mips/bcm47xx/nvram.c
@@ -26,14 +26,21 @@ static char nvram_buf[NVRAM_SPACE];
/* Probe for NVRAM header */
static void early_nvram_init(void)
{
- struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore;
+ struct ssb_mipscore *mcore_ssb;
struct nvram_header *header;
int i;
- u32 base, lim, off;
+ u32 base = 0;
+ u32 lim = 0;
+ u32 off;
u32 *src, *dst;
- base = mcore->flash_window;
- lim = mcore->flash_window_size;
+ switch (bcm47xx_active_bus_type) {
+ case BCM47XX_BUS_TYPE_SSB:
+ mcore_ssb = &bcm47xx_bus.ssb.mipscore;
+ base = mcore_ssb->flash_window;
+ lim = mcore_ssb->flash_window_size;
+ break;
+ }
off = FLASH_MIN;
while (off <= lim) {
diff --git a/arch/mips/bcm47xx/serial.c b/arch/mips/bcm47xx/serial.c
index 59c11af..87c2c5e 100644
--- a/arch/mips/bcm47xx/serial.c
+++ b/arch/mips/bcm47xx/serial.c
@@ -23,10 +23,10 @@ static struct platform_device uart8250_device = {
},
};
-static int __init uart8250_init(void)
+static int __init uart8250_init_ssb(void)
{
int i;
- struct ssb_mipscore *mcore = &(ssb_bcm47xx.mipscore);
+ struct ssb_mipscore *mcore = &(bcm47xx_bus.ssb.mipscore);
memset(&uart8250_data, 0, sizeof(uart8250_data));
@@ -45,6 +45,15 @@ static int __init uart8250_init(void)
return platform_device_register(&uart8250_device);
}
+static int __init uart8250_init(void)
+{
+ switch (bcm47xx_active_bus_type) {
+ case BCM47XX_BUS_TYPE_SSB:
+ return uart8250_init_ssb();
+ }
+ return -EINVAL;
+}
+
module_init(uart8250_init);
MODULE_AUTHOR("Aurelien Jarno <[email protected]>");
diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c
index 73b529b..c64b76d 100644
--- a/arch/mips/bcm47xx/setup.c
+++ b/arch/mips/bcm47xx/setup.c
@@ -35,15 +35,21 @@
#include <bcm47xx.h>
#include <asm/mach-bcm47xx/nvram.h>
-struct ssb_bus ssb_bcm47xx;
-EXPORT_SYMBOL(ssb_bcm47xx);
+union bcm47xx_bus bcm47xx_bus;
+EXPORT_SYMBOL(bcm47xx_bus);
+
+enum bcm47xx_bus_type bcm47xx_active_bus_type;
static void bcm47xx_machine_restart(char *command)
{
printk(KERN_ALERT "Please stand by while rebooting the system...\n");
local_irq_disable();
/* Set the watchdog timer to reset immediately */
- ssb_watchdog_timer_set(&ssb_bcm47xx, 1);
+ switch (bcm47xx_active_bus_type) {
+ case BCM47XX_BUS_TYPE_SSB:
+ ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 1);
+ break;
+ }
while (1)
cpu_relax();
}
@@ -52,7 +58,11 @@ static void bcm47xx_machine_halt(void)
{
/* Disable interrupts and watchdog and spin forever */
local_irq_disable();
- ssb_watchdog_timer_set(&ssb_bcm47xx, 0);
+ switch (bcm47xx_active_bus_type) {
+ case BCM47XX_BUS_TYPE_SSB:
+ ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0);
+ break;
+ }
while (1)
cpu_relax();
}
@@ -247,7 +257,7 @@ static int bcm47xx_get_invariants(struct ssb_bus *bus,
return 0;
}
-void __init plat_mem_setup(void)
+static void __init bcm47xx_register_ssb(void)
{
int err;
char buf[100];
@@ -258,12 +268,12 @@ void __init plat_mem_setup(void)
printk(KERN_WARNING "bcm47xx: someone else already registered"
" a ssb SPROM callback handler (err %d)\n", err);
- err = ssb_bus_ssbbus_register(&ssb_bcm47xx, SSB_ENUM_BASE,
+ err = ssb_bus_ssbbus_register(&(bcm47xx_bus.ssb), SSB_ENUM_BASE,
bcm47xx_get_invariants);
if (err)
panic("Failed to initialize SSB bus (err %d)\n", err);
- mcore = &ssb_bcm47xx.mipscore;
+ mcore = &bcm47xx_bus.ssb.mipscore;
if (nvram_getenv("kernel_args", buf, sizeof(buf)) >= 0) {
if (strstr(buf, "console=ttyS1")) {
struct ssb_serial_port port;
@@ -276,6 +286,14 @@ void __init plat_mem_setup(void)
memcpy(&mcore->serial_ports[1], &port, sizeof(port));
}
}
+}
+
+void __init plat_mem_setup(void)
+{
+ struct cpuinfo_mips *c = ¤t_cpu_data;
+
+ bcm47xx_active_bus_type = BCM47XX_BUS_TYPE_SSB;
+ bcm47xx_register_ssb();
_machine_restart = bcm47xx_machine_restart;
_machine_halt = bcm47xx_machine_halt;
diff --git a/arch/mips/bcm47xx/time.c b/arch/mips/bcm47xx/time.c
index 0c6f47b..a7be993 100644
--- a/arch/mips/bcm47xx/time.c
+++ b/arch/mips/bcm47xx/time.c
@@ -30,7 +30,7 @@
void __init plat_time_init(void)
{
- unsigned long hz;
+ unsigned long hz = 0;
/*
* Use deterministic values for initial counter interrupt
@@ -39,7 +39,12 @@ void __init plat_time_init(void)
write_c0_count(0);
write_c0_compare(0xffff);
- hz = ssb_cpu_clock(&ssb_bcm47xx.mipscore) / 2;
+ switch (bcm47xx_active_bus_type) {
+ case BCM47XX_BUS_TYPE_SSB:
+ hz = ssb_cpu_clock(&bcm47xx_bus.ssb.mipscore) / 2;
+ break;
+ }
+
if (!hz)
hz = 100000000;
diff --git a/arch/mips/bcm47xx/wgt634u.c b/arch/mips/bcm47xx/wgt634u.c
index 74d0696..79ecd0a 100644
--- a/arch/mips/bcm47xx/wgt634u.c
+++ b/arch/mips/bcm47xx/wgt634u.c
@@ -108,7 +108,7 @@ static irqreturn_t gpio_interrupt(int irq, void *ignored)
/* Interrupts are shared, check if the current one is
a GPIO interrupt. */
- if (!ssb_chipco_irq_status(&ssb_bcm47xx.chipco,
+ if (!ssb_chipco_irq_status(&bcm47xx_bus.ssb.chipco,
SSB_CHIPCO_IRQ_GPIO))
return IRQ_NONE;
@@ -133,21 +133,24 @@ static int __init wgt634u_init(void)
* been allocated ranges 00:09:5b:xx:xx:xx and 00:0f:b5:xx:xx:xx.
*/
- u8 *et0mac = ssb_bcm47xx.sprom.et0mac;
+ if (bcm47xx_active_bus_type != BCM47XX_BUS_TYPE_SSB)
+ return -ENODEV;
+
+ u8 *et0mac = bcm47xx_bus.ssb.sprom.et0mac;
if (et0mac[0] == 0x00 &&
((et0mac[1] == 0x09 && et0mac[2] == 0x5b) ||
(et0mac[1] == 0x0f && et0mac[2] == 0xb5))) {
- struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore;
+ struct ssb_mipscore *mcore = &bcm47xx_bus.ssb.mipscore;
printk(KERN_INFO "WGT634U machine detected.\n");
if (!request_irq(gpio_to_irq(WGT634U_GPIO_RESET),
gpio_interrupt, IRQF_SHARED,
- "WGT634U GPIO", &ssb_bcm47xx.chipco)) {
+ "WGT634U GPIO", &bcm47xx_bus.ssb.chipco)) {
gpio_direction_input(WGT634U_GPIO_RESET);
gpio_intmask(WGT634U_GPIO_RESET, 1);
- ssb_chipco_irq_mask(&ssb_bcm47xx.chipco,
+ ssb_chipco_irq_mask(&bcm47xx_bus.ssb.chipco,
SSB_CHIPCO_IRQ_GPIO,
SSB_CHIPCO_IRQ_GPIO);
}
diff --git a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
index d008f47..4be8b95 100644
--- a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
+++ b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
@@ -19,7 +19,17 @@
#ifndef __ASM_BCM47XX_H
#define __ASM_BCM47XX_H
-/* SSB bus */
-extern struct ssb_bus ssb_bcm47xx;
+#include <linux/ssb/ssb.h>
+
+enum bcm47xx_bus_type {
+ BCM47XX_BUS_TYPE_SSB,
+};
+
+union bcm47xx_bus {
+ struct ssb_bus ssb;
+};
+
+extern union bcm47xx_bus bcm47xx_bus;
+extern enum bcm47xx_bus_type bcm47xx_active_bus_type;
#endif /* __ASM_BCM47XX_H */
diff --git a/arch/mips/include/asm/mach-bcm47xx/gpio.h b/arch/mips/include/asm/mach-bcm47xx/gpio.h
index 9850414..16d6c19 100644
--- a/arch/mips/include/asm/mach-bcm47xx/gpio.h
+++ b/arch/mips/include/asm/mach-bcm47xx/gpio.h
@@ -21,41 +21,64 @@ extern int gpio_to_irq(unsigned gpio);
static inline int gpio_get_value(unsigned gpio)
{
- return ssb_gpio_in(&ssb_bcm47xx, 1 << gpio);
+ switch (bcm47xx_active_bus_type) {
+ case BCM47XX_BUS_TYPE_SSB:
+ return ssb_gpio_in(&bcm47xx_bus.ssb, 1 << gpio);
+ }
+ return -EINVAL;
}
static inline void gpio_set_value(unsigned gpio, int value)
{
- ssb_gpio_out(&ssb_bcm47xx, 1 << gpio, value ? 1 << gpio : 0);
+ switch (bcm47xx_active_bus_type) {
+ case BCM47XX_BUS_TYPE_SSB:
+ ssb_gpio_out(&bcm47xx_bus.ssb, 1 << gpio, value ? 1 << gpio : 0);
+ }
}
static inline int gpio_direction_input(unsigned gpio)
{
- ssb_gpio_outen(&ssb_bcm47xx, 1 << gpio, 0);
- return 0;
+ switch (bcm47xx_active_bus_type) {
+ case BCM47XX_BUS_TYPE_SSB:
+ ssb_gpio_outen(&bcm47xx_bus.ssb, 1 << gpio, 0);
+ return 0;
+ }
+ return -EINVAL;
}
static inline int gpio_direction_output(unsigned gpio, int value)
{
- /* first set the gpio out value */
- ssb_gpio_out(&ssb_bcm47xx, 1 << gpio, value ? 1 << gpio : 0);
- /* then set the gpio mode */
- ssb_gpio_outen(&ssb_bcm47xx, 1 << gpio, 1 << gpio);
- return 0;
+ switch (bcm47xx_active_bus_type) {
+ case BCM47XX_BUS_TYPE_SSB:
+ /* first set the gpio out value */
+ ssb_gpio_out(&bcm47xx_bus.ssb, 1 << gpio, value ? 1 << gpio : 0);
+ /* then set the gpio mode */
+ ssb_gpio_outen(&bcm47xx_bus.ssb, 1 << gpio, 1 << gpio);
+ return 0;
+ }
+ return -EINVAL;
}
static inline int gpio_intmask(unsigned gpio, int value)
{
- ssb_gpio_intmask(&ssb_bcm47xx, 1 << gpio,
- value ? 1 << gpio : 0);
- return 0;
+ switch (bcm47xx_active_bus_type) {
+ case BCM47XX_BUS_TYPE_SSB:
+ ssb_gpio_intmask(&bcm47xx_bus.ssb, 1 << gpio,
+ value ? 1 << gpio : 0);
+ return 0;
+ }
+ return -EINVAL;
}
static inline int gpio_polarity(unsigned gpio, int value)
{
- ssb_gpio_polarity(&ssb_bcm47xx, 1 << gpio,
- value ? 1 << gpio : 0);
- return 0;
+ switch (bcm47xx_active_bus_type) {
+ case BCM47XX_BUS_TYPE_SSB:
+ ssb_gpio_polarity(&bcm47xx_bus.ssb, 1 << gpio,
+ value ? 1 << gpio : 0);
+ return 0;
+ }
+ return -EINVAL;
}
diff --git a/drivers/watchdog/bcm47xx_wdt.c b/drivers/watchdog/bcm47xx_wdt.c
index bd44417..7e4e063 100644
--- a/drivers/watchdog/bcm47xx_wdt.c
+++ b/drivers/watchdog/bcm47xx_wdt.c
@@ -54,12 +54,20 @@ static atomic_t ticks;
static inline void bcm47xx_wdt_hw_start(void)
{
/* this is 2,5s on 100Mhz clock and 2s on 133 Mhz */
- ssb_watchdog_timer_set(&ssb_bcm47xx, 0xfffffff);
+ switch (bcm47xx_active_bus_type) {
+ case BCM47XX_BUS_TYPE_SSB:
+ ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0xfffffff);
+ break;
+ }
}
static inline int bcm47xx_wdt_hw_stop(void)
{
- return ssb_watchdog_timer_set(&ssb_bcm47xx, 0);
+ switch (bcm47xx_active_bus_type) {
+ case BCM47XX_BUS_TYPE_SSB:
+ return ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0);
+ }
+ return -EINVAL;
}
static void bcm47xx_timer_tick(unsigned long unused)
--
1.7.4.1
2011/6/7 Hauke Mehrtens <[email protected]>:
> On 06/07/2011 12:12 PM, Arend van Spriel wrote:
>> On 06/06/2011 11:53 PM, Arnd Bergmann wrote:
>>> On Monday 06 June 2011 23:38:50 Hauke Mehrtens wrote:
>>>> Accessing chip common should be possible without scanning the hole bus
>>>> as it is at the first position and initializing most things just needs
>>>> chip common. For initializing the interrupts scanning is needed as we do
>>>> not know where the mips core is located.
>>>>
>>>> As we can not use kalloc on early boot we could use a function which
>>>> uses kalloc under normal conditions and when on early boot the
>>>> architecture code which starts the bcma code should also provide a
>>>> function which returns a pointer to some memory in its text segment to
>>>> use. We need space for 16 cores in the architecture code.
>>>>
>>>> In addition bcma_bus_register(struct bcma_bus *bus) has to be divided
>>>> into two parts. The first part will scan the bus and initialize chip
>>>> common and mips core. The second part will initialize pci core and
>>>> register the devices in the system. When using this under normal
>>>> conditions they will be called directly after each other.
>>> Just split out the minimal low-level function from the bcma_bus_scan
>>> then, to locate a single device based on some identifier. The
>>> bcma_bus_scan() function can then repeatedly allocate one device
>>> and pass it to the low-level function when doing the proper scan,
>>> while the arch code calls the low-level function directly with static
>>> data.
>>
>> If going for this we should pass struct bcma_device_id as match
>> parameter as that identifies the core appropriately although you
>> probably only want to match manufacturer and core identifiers.
>>
>> Gr. AvS
>>
>
> What is the problem with scanning the full bus?
Because full scanning needs one of the following:
1) Working alloc - not possible for SoCs
2) Hacks with wrappers, static cores info, lack of optimization (list)
> A special scan function would just skip the wrong cores so I do not see
> any advantage in that.
>
> We could build a scan function which searches for one core and uses a
> struct bcma_core stored on the stack and returns the struct bcma_core if
> it found the wanted one.
Yeah, this should be quite easy.
struct bcma_device core = bcma_early_find_core(bus, CC);
bcma_cc_init(core);
> Then we could search for chipcommon and mips
> and store then in arch code in arch/mips/bcm47xx and use them.
Not sure about this one. You have drivers for chipcommon and mips as
part of bcma. Do you need to involve arch/mips/bcm47xx to this?
> When boot
> is ready and we are searching the complete bus there is probably
> something differences in the init process from normal init as we already
> initialized chipcommon sometime earlier.
Nothing hard to handle.
> I Would prefer to scan the bus
> completely and initialize chipcommon and mips in early boot.
Really, I've nothing against scanning and splitting init into "early"
and "late". It's going back to static fields and wrappers that I don't
like :(
--
Rafał
On 06/07/2011 12:12 PM, Arend van Spriel wrote:
> On 06/06/2011 11:53 PM, Arnd Bergmann wrote:
>> On Monday 06 June 2011 23:38:50 Hauke Mehrtens wrote:
>>> Accessing chip common should be possible without scanning the hole bus
>>> as it is at the first position and initializing most things just needs
>>> chip common. For initializing the interrupts scanning is needed as we do
>>> not know where the mips core is located.
>>>
>>> As we can not use kalloc on early boot we could use a function which
>>> uses kalloc under normal conditions and when on early boot the
>>> architecture code which starts the bcma code should also provide a
>>> function which returns a pointer to some memory in its text segment to
>>> use. We need space for 16 cores in the architecture code.
>>>
>>> In addition bcma_bus_register(struct bcma_bus *bus) has to be divided
>>> into two parts. The first part will scan the bus and initialize chip
>>> common and mips core. The second part will initialize pci core and
>>> register the devices in the system. When using this under normal
>>> conditions they will be called directly after each other.
>> Just split out the minimal low-level function from the bcma_bus_scan
>> then, to locate a single device based on some identifier. The
>> bcma_bus_scan() function can then repeatedly allocate one device
>> and pass it to the low-level function when doing the proper scan,
>> while the arch code calls the low-level function directly with static
>> data.
>
> If going for this we should pass struct bcma_device_id as match
> parameter as that identifies the core appropriately although you
> probably only want to match manufacturer and core identifiers.
>
> Gr. AvS
>
What is the problem with scanning the full bus? Scanning in general
works for embedded devices, just allocating memory with kalloc does not
work at that time, but the architecture code (something in
arch/mips/bcm47xx/) could provide some memory to store the struct
bcma_core, like it does for struct bcma_bus. We could just provide
memory for chipcommon and mips core or memory for all possible 16 cores,
the maximum number, as most embedded devices have ~9 cores providing
memory for 16 cores is not a big vast of memory and then we could use
the normal scan function.
A special scan function would just skip the wrong cores so I do not see
any advantage in that.
We could build a scan function which searches for one core and uses a
struct bcma_core stored on the stack and returns the struct bcma_core if
it found the wanted one. Then we could search for chipcommon and mips
and store then in arch code in arch/mips/bcm47xx and use them. When boot
is ready and we are searching the complete bus there is probably
something differences in the init process from normal init as we already
initialized chipcommon sometime earlier. I Would prefer to scan the bus
completely and initialize chipcommon and mips in early boot.
Hauke
On 06/06/2011 11:42 AM, Rafał Miłecki wrote:
> Greg, Arnd: could you take a look at this patch, please?
>
> With proposed patch we are going back to this ugly array and wrappers hacks.
>
> I was really happy with our final solution, but it seems it's not
> doable for embedded systems...? Is there something better we can do
> about this?
I do agree with Rafał that we should look for another alternative. I
posted a suggestion earlier regarding this patch. Can anyone tell me
whether that could prevent need for the array/wrapper hack.
Gr. AvS
--
Almost nobody dances sober, unless they happen to be insane.
-- H.P. Lovecraft --
This adds some stub for a pci(e) host controller. This controller is
found on some embedded devices to attach other chips.
Signed-off-by: Hauke Mehrtens <[email protected]>
---
drivers/bcma/Kconfig | 6 ++++
drivers/bcma/Makefile | 1 +
drivers/bcma/bcma_private.h | 6 ++++
drivers/bcma/driver_pci.c | 12 ++++++++-
drivers/bcma/driver_pci_host.c | 44 ++++++++++++++++++++++++++++++++++
include/linux/bcma/bcma_driver_pci.h | 1 +
6 files changed, 69 insertions(+), 1 deletions(-)
create mode 100644 drivers/bcma/driver_pci_host.c
diff --git a/drivers/bcma/Kconfig b/drivers/bcma/Kconfig
index 568d30b..c863a87 100644
--- a/drivers/bcma/Kconfig
+++ b/drivers/bcma/Kconfig
@@ -27,6 +27,12 @@ config BCMA_HOST_PCI
bool "Support for BCMA on PCI-host bus"
depends on BCMA_HOST_PCI_POSSIBLE
+config BCMA_PCICORE_HOSTMODE
+ bool "Hostmode support for BCMA PCI core"
+ depends on BCMA_DRIVER_MIPS
+ help
+ PCIcore hostmode operation (external PCI bus).
+
config BCMA_HOST_EMBEDDED
bool
depends on BCMA_DRIVER_MIPS
diff --git a/drivers/bcma/Makefile b/drivers/bcma/Makefile
index 50ddab8..f99abfe 100644
--- a/drivers/bcma/Makefile
+++ b/drivers/bcma/Makefile
@@ -1,6 +1,7 @@
bcma-y += main.o scan.o core.o
bcma-y += driver_chipcommon.o driver_chipcommon_pmu.o
bcma-y += driver_pci.o
+bcma-$(CONFIG_BCMA_PCICORE_HOSTMODE) += driver_pci_host.o
bcma-$(CONFIG_BCMA_DRIVER_MIPS) += driver_mips.o
bcma-$(CONFIG_BCMA_HOST_PCI) += host_pci.o
bcma-$(CONFIG_BCMA_HOST_EMBEDDED) += host_embedded.o
diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h
index fbabe19..13cf25a 100644
--- a/drivers/bcma/bcma_private.h
+++ b/drivers/bcma/bcma_private.h
@@ -29,6 +29,12 @@ extern u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc);
extern int bcma_chipco_serial_init(struct bcma_drv_cc *cc,
struct bcma_drv_mips_serial_port *ports);
+#ifdef CONFIG_BCMA_PCICORE_HOSTMODE
+/* driver_pci_host.c */
+extern int bcma_pcicore_is_in_hostmode(struct bcma_drv_pci *pc);
+extern void bcma_pcicore_init_hostmode(struct bcma_drv_pci *pc);
+#endif /* CONFIG_BCMA_PCICORE_HOSTMODE */
+
#ifdef CONFIG_BCMA_HOST_PCI
/* host_pci.c */
extern int __init bcma_host_pci_init(void);
diff --git a/drivers/bcma/driver_pci.c b/drivers/bcma/driver_pci.c
index 789d68b..cf8cbe0 100644
--- a/drivers/bcma/driver_pci.c
+++ b/drivers/bcma/driver_pci.c
@@ -159,7 +159,17 @@ static void bcma_pcicore_serdes_workaround(struct bcma_drv_pci *pc)
void bcma_core_pci_init(struct bcma_drv_pci *pc)
{
- bcma_pcicore_serdes_workaround(pc);
+ struct bcma_device *core = pc->core;
+
+ if (!bcma_core_is_enabled(core))
+ bcma_core_enable(core, 0);
+#ifdef CONFIG_BCMA_PCICORE_HOSTMODE
+ pc->hostmode = bcma_pcicore_is_in_hostmode(pc);
+ if (pc->hostmode)
+ bcma_pcicore_init_hostmode(pc);
+#endif /* CONFIG_BCMA_PCICORE_HOSTMODE */
+ if (!pc->hostmode)
+ bcma_pcicore_serdes_workaround(pc);
}
int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core,
diff --git a/drivers/bcma/driver_pci_host.c b/drivers/bcma/driver_pci_host.c
new file mode 100644
index 0000000..b52c6c9
--- /dev/null
+++ b/drivers/bcma/driver_pci_host.c
@@ -0,0 +1,44 @@
+/*
+ * Broadcom specific AMBA
+ * PCI Core
+ *
+ * Copyright 2005, Broadcom Corporation
+ * Copyright 2006, 2007, Michael Buesch <[email protected]>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include "bcma_private.h"
+#include <linux/bcma/bcma.h>
+
+#include <asm/paccess.h>
+/* Probe a 32bit value on the bus and catch bus exceptions.
+ * Returns nonzero on a bus exception.
+ * This is MIPS specific */
+#define mips_busprobe32(val, addr) get_dbe((val), ((u32 *)(addr)))
+
+
+void bcma_pcicore_init_hostmode(struct bcma_drv_pci *pc)
+{
+ /* TODO: implement PCI host mode */
+}
+
+int bcma_pcicore_is_in_hostmode(struct bcma_drv_pci *pc)
+{
+ struct bcma_bus *bus = pc->core->bus;
+ u16 chipid_top;
+ u32 tmp;
+
+ chipid_top = (bus->chipinfo.id & 0xFF00);
+ if (chipid_top != 0x4700 &&
+ chipid_top != 0x5300)
+ return 0;
+
+/* TODO: add when sprom is available
+ * if (bus->sprom.boardflags_lo & SSB_PCICORE_BFL_NOPCI)
+ * return 0;
+ */
+
+ return !mips_busprobe32(tmp, (bus->mmio + (pc->core->core_index *
+ BCMA_CORE_SIZE)));
+}
diff --git a/include/linux/bcma/bcma_driver_pci.h b/include/linux/bcma/bcma_driver_pci.h
index b7e191c..5bbc58f 100644
--- a/include/linux/bcma/bcma_driver_pci.h
+++ b/include/linux/bcma/bcma_driver_pci.h
@@ -78,6 +78,7 @@ struct pci_dev;
struct bcma_drv_pci {
struct bcma_device *core;
u8 setup_done:1;
+ u8 hostmode:1;
};
/* Register access */
--
1.7.4.1
On 06/06/2011 01:23 PM, Rafał Miłecki wrote:
> 2011/6/6 Hauke Mehrtens <[email protected]>:
>> +/* driver_mips.c */
>> +extern unsigned int bcma_core_mips_irq(struct bcma_device *dev);
>
> Does it compile without CONFIG_BCMA_DRIVER_MIPS?
No ;-) Thought about it after sending these patches, some other patches
will have the same problem.
>
>
>> +/* Get the MIPS IRQ assignment for a specified device.
>> + * If unassigned, 0 is returned.
>> + * If disabled, 5 is returned.
>> + * If not supported, 6 is returned.
>> + */
>
> Does it ever return 6?
Some old comment, will fix this.
>
>> +unsigned int bcma_core_mips_irq(struct bcma_device *dev)
>> +{
>> + struct bcma_device *mdev = dev->bus->drv_mips.core;
>> + u32 irqflag;
>> + unsigned int irq;
>> +
>> + irqflag = bcma_core_mips_irqflag(dev);
>> +
>> + for (irq = 1; irq <= 4; irq++)
>> + if (bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq)) & (1 << irqflag))
>> + break;
>
> Use scripts/checkpatch*. Braces around "for" and split line to match
> 80 chars width.
Will check all patches with scripts/checkpatch.sh
>
> Why don't you just use "return irq;" instead of break?
yes this will be better.
>
>
>> +
>> + if (irq == 5)
>> + irq = 0;
>> +
>> + return irq;
>
> You can just make it "return 0;" after changing break to return.
agree
>
>
>> + for (i = 0; i < bus->nr_cores; i++)
>> + if ((1 << bcma_core_mips_irqflag(&bus->cores[i])) == oldirqflag) {
>> + bcma_core_mips_set_irq(&bus->cores[i], 0);
>> + break;
>> + }
>
> Braces for "for".
Is this needed after the coding guildlines? Shouldn't they be removed if
they are not needed?
>
>> + pr_info("after irq reconfiguration\n");
>
> Make first letter uppercase. I'm not English expert, but doesn't
> something like "IRQ reconfiguration done" sound better?
>
Sounds better.
This patch add support for the bcma bus. Broadcom uses only Mips 74K
CPUs on the new SoC and on the old ons using ssb bus there are no Mips
74K CPUs.
Signed-off-by: Hauke Mehrtens <[email protected]>
---
arch/mips/Kconfig | 4 +++
arch/mips/bcm47xx/gpio.c | 9 ++++++++
arch/mips/bcm47xx/nvram.c | 6 +++++
arch/mips/bcm47xx/serial.c | 24 +++++++++++++++++++++++
arch/mips/bcm47xx/setup.c | 27 ++++++++++++++++++++++++-
arch/mips/bcm47xx/time.c | 3 ++
arch/mips/include/asm/mach-bcm47xx/bcm47xx.h | 3 ++
arch/mips/include/asm/mach-bcm47xx/gpio.h | 18 +++++++++++++++++
drivers/watchdog/bcm47xx_wdt.c | 6 +++++
9 files changed, 98 insertions(+), 2 deletions(-)
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 653da62..bdb0341 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -100,6 +100,10 @@ config BCM47XX
select SSB_EMBEDDED
select SSB_B43_PCI_BRIDGE if PCI
select SSB_PCICORE_HOSTMODE if PCI
+ select BCMA
+ select BCMA_HOST_EMBEDDED
+ select BCMA_DRIVER_MIPS
+ select BCMA_PCICORE_HOSTMODE
select GENERIC_GPIO
select SYS_HAS_EARLY_PRINTK
select CFE
diff --git a/arch/mips/bcm47xx/gpio.c b/arch/mips/bcm47xx/gpio.c
index 2f6d2df..42af3f8 100644
--- a/arch/mips/bcm47xx/gpio.c
+++ b/arch/mips/bcm47xx/gpio.c
@@ -34,6 +34,9 @@ int gpio_request(unsigned gpio, const char *tag)
return -EBUSY;
return 0;
+ case BCM47XX_BUS_TYPE_BCMA:
+ /* Not implemenmted yet */
+ return -EINVAL;
}
return -EINVAL;
}
@@ -53,6 +56,9 @@ void gpio_free(unsigned gpio)
clear_bit(gpio, gpio_in_use);
return;
+ case BCM47XX_BUS_TYPE_BCMA:
+ /* Not implemenmted yet */
+ return;
}
}
EXPORT_SYMBOL(gpio_free);
@@ -67,6 +73,9 @@ int gpio_to_irq(unsigned gpio)
return ssb_mips_irq(bcm47xx_bus.ssb.extif.dev) + 2;
else
return -EINVAL;
+ case BCM47XX_BUS_TYPE_BCMA:
+ /* Not implemenmted yet */
+ return -EINVAL;
}
return -EINVAL;
}
diff --git a/arch/mips/bcm47xx/nvram.c b/arch/mips/bcm47xx/nvram.c
index d2304d0..75c36c4 100644
--- a/arch/mips/bcm47xx/nvram.c
+++ b/arch/mips/bcm47xx/nvram.c
@@ -27,6 +27,7 @@ static char nvram_buf[NVRAM_SPACE];
static void early_nvram_init(void)
{
struct ssb_mipscore *mcore_ssb;
+ struct bcma_drv_mips *mcore_bcma;
struct nvram_header *header;
int i;
u32 base = 0;
@@ -40,6 +41,11 @@ static void early_nvram_init(void)
base = mcore_ssb->flash_window;
lim = mcore_ssb->flash_window_size;
break;
+ case BCM47XX_BUS_TYPE_BCMA:
+ mcore_bcma = &bcm47xx_bus.bcma.drv_mips;
+ base = mcore_bcma->flash_window;
+ lim = mcore_bcma->flash_window_size;
+ break;
}
off = FLASH_MIN;
diff --git a/arch/mips/bcm47xx/serial.c b/arch/mips/bcm47xx/serial.c
index 87c2c5e..ed74d975 100644
--- a/arch/mips/bcm47xx/serial.c
+++ b/arch/mips/bcm47xx/serial.c
@@ -45,11 +45,35 @@ static int __init uart8250_init_ssb(void)
return platform_device_register(&uart8250_device);
}
+static int __init uart8250_init_bcma(void)
+{
+ int i;
+ struct bcma_drv_mips *mcore = &(bcm47xx_bus.bcma.drv_mips);
+
+ memset(&uart8250_data, 0, sizeof(uart8250_data));
+
+ for (i = 0; i < mcore->nr_serial_ports; i++) {
+ struct plat_serial8250_port *p = &(uart8250_data[i]);
+ struct bcma_drv_mips_serial_port *bcma_port = &(mcore->serial_ports[i]);
+
+ p->mapbase = (unsigned int) bcma_port->regs;
+ p->membase = (void *) bcma_port->regs;
+ p->irq = bcma_port->irq + 2;
+ p->uartclk = bcma_port->baud_base;
+ p->regshift = bcma_port->reg_shift;
+ p->iotype = UPIO_MEM;
+ p->flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
+ }
+ return platform_device_register(&uart8250_device);
+}
+
static int __init uart8250_init(void)
{
switch (bcm47xx_active_bus_type) {
case BCM47XX_BUS_TYPE_SSB:
return uart8250_init_ssb();
+ case BCM47XX_BUS_TYPE_BCMA:
+ return uart8250_init_bcma();
}
return -EINVAL;
}
diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c
index c64b76d..8dd82f3 100644
--- a/arch/mips/bcm47xx/setup.c
+++ b/arch/mips/bcm47xx/setup.c
@@ -29,6 +29,7 @@
#include <linux/types.h>
#include <linux/ssb/ssb.h>
#include <linux/ssb/ssb_embedded.h>
+#include <linux/bcma/bcma_embedded.h>
#include <asm/bootinfo.h>
#include <asm/reboot.h>
#include <asm/time.h>
@@ -49,6 +50,9 @@ static void bcm47xx_machine_restart(char *command)
case BCM47XX_BUS_TYPE_SSB:
ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 1);
break;
+ case BCM47XX_BUS_TYPE_BCMA:
+ bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.drv_cc, 1);
+ break;
}
while (1)
cpu_relax();
@@ -62,6 +66,9 @@ static void bcm47xx_machine_halt(void)
case BCM47XX_BUS_TYPE_SSB:
ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0);
break;
+ case BCM47XX_BUS_TYPE_BCMA:
+ bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.drv_cc, 0);
+ break;
}
while (1)
cpu_relax();
@@ -288,12 +295,28 @@ static void __init bcm47xx_register_ssb(void)
}
}
+static void __init bcm47xx_register_bcma(void)
+{
+ int err;
+
+ err = bcma_host_bcma_register(&bcm47xx_bus.bcma);
+ if (err)
+ panic("Failed to initialize BCMA bus (err %d)\n", err);
+}
+
void __init plat_mem_setup(void)
{
struct cpuinfo_mips *c = ¤t_cpu_data;
- bcm47xx_active_bus_type = BCM47XX_BUS_TYPE_SSB;
- bcm47xx_register_ssb();
+ if (c->cputype == CPU_74K) {
+ printk(KERN_INFO "bcm47xx: using bcma bus\n");
+ bcm47xx_active_bus_type = BCM47XX_BUS_TYPE_BCMA;
+ bcm47xx_register_bcma();
+ } else {
+ printk(KERN_INFO "bcm47xx: using ssb bus\n");
+ bcm47xx_active_bus_type = BCM47XX_BUS_TYPE_SSB;
+ bcm47xx_register_ssb();
+ }
_machine_restart = bcm47xx_machine_restart;
_machine_halt = bcm47xx_machine_halt;
diff --git a/arch/mips/bcm47xx/time.c b/arch/mips/bcm47xx/time.c
index a7be993..ace3ba2 100644
--- a/arch/mips/bcm47xx/time.c
+++ b/arch/mips/bcm47xx/time.c
@@ -43,6 +43,9 @@ void __init plat_time_init(void)
case BCM47XX_BUS_TYPE_SSB:
hz = ssb_cpu_clock(&bcm47xx_bus.ssb.mipscore) / 2;
break;
+ case BCM47XX_BUS_TYPE_BCMA:
+ hz = bcma_cpu_clock(&bcm47xx_bus.bcma.drv_mips) / 2;
+ break;
}
if (!hz)
diff --git a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
index 4be8b95..3e6ccb9 100644
--- a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
+++ b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
@@ -20,13 +20,16 @@
#define __ASM_BCM47XX_H
#include <linux/ssb/ssb.h>
+#include <linux/bcma/bcma.h>
enum bcm47xx_bus_type {
BCM47XX_BUS_TYPE_SSB,
+ BCM47XX_BUS_TYPE_BCMA,
};
union bcm47xx_bus {
struct ssb_bus ssb;
+ struct bcma_bus bcma;
};
extern union bcm47xx_bus bcm47xx_bus;
diff --git a/arch/mips/include/asm/mach-bcm47xx/gpio.h b/arch/mips/include/asm/mach-bcm47xx/gpio.h
index 16d6c19..e8629a8 100644
--- a/arch/mips/include/asm/mach-bcm47xx/gpio.h
+++ b/arch/mips/include/asm/mach-bcm47xx/gpio.h
@@ -24,6 +24,9 @@ static inline int gpio_get_value(unsigned gpio)
switch (bcm47xx_active_bus_type) {
case BCM47XX_BUS_TYPE_SSB:
return ssb_gpio_in(&bcm47xx_bus.ssb, 1 << gpio);
+ case BCM47XX_BUS_TYPE_BCMA:
+ /* Not implemenmted yet */
+ return -EINVAL;
}
return -EINVAL;
}
@@ -33,6 +36,9 @@ static inline void gpio_set_value(unsigned gpio, int value)
switch (bcm47xx_active_bus_type) {
case BCM47XX_BUS_TYPE_SSB:
ssb_gpio_out(&bcm47xx_bus.ssb, 1 << gpio, value ? 1 << gpio : 0);
+ case BCM47XX_BUS_TYPE_BCMA:
+ /* Not implemenmted yet */
+ return;
}
}
@@ -42,6 +48,9 @@ static inline int gpio_direction_input(unsigned gpio)
case BCM47XX_BUS_TYPE_SSB:
ssb_gpio_outen(&bcm47xx_bus.ssb, 1 << gpio, 0);
return 0;
+ case BCM47XX_BUS_TYPE_BCMA:
+ /* Not implemenmted yet */
+ return -EINVAL;
}
return -EINVAL;
}
@@ -55,6 +64,9 @@ static inline int gpio_direction_output(unsigned gpio, int value)
/* then set the gpio mode */
ssb_gpio_outen(&bcm47xx_bus.ssb, 1 << gpio, 1 << gpio);
return 0;
+ case BCM47XX_BUS_TYPE_BCMA:
+ /* Not implemenmted yet */
+ return -EINVAL;
}
return -EINVAL;
}
@@ -66,6 +78,9 @@ static inline int gpio_intmask(unsigned gpio, int value)
ssb_gpio_intmask(&bcm47xx_bus.ssb, 1 << gpio,
value ? 1 << gpio : 0);
return 0;
+ case BCM47XX_BUS_TYPE_BCMA:
+ /* Not implemenmted yet */
+ return -EINVAL;
}
return -EINVAL;
}
@@ -77,6 +92,9 @@ static inline int gpio_polarity(unsigned gpio, int value)
ssb_gpio_polarity(&bcm47xx_bus.ssb, 1 << gpio,
value ? 1 << gpio : 0);
return 0;
+ case BCM47XX_BUS_TYPE_BCMA:
+ /* Not implemenmted yet */
+ return -EINVAL;
}
return -EINVAL;
}
diff --git a/drivers/watchdog/bcm47xx_wdt.c b/drivers/watchdog/bcm47xx_wdt.c
index 7e4e063..8a31494 100644
--- a/drivers/watchdog/bcm47xx_wdt.c
+++ b/drivers/watchdog/bcm47xx_wdt.c
@@ -58,6 +58,9 @@ static inline void bcm47xx_wdt_hw_start(void)
case BCM47XX_BUS_TYPE_SSB:
ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0xfffffff);
break;
+ case BCM47XX_BUS_TYPE_BCMA:
+ bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.drv_cc, 0xfffffff);
+ break;
}
}
@@ -66,6 +69,9 @@ static inline int bcm47xx_wdt_hw_stop(void)
switch (bcm47xx_active_bus_type) {
case BCM47XX_BUS_TYPE_SSB:
return ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0);
+ case BCM47XX_BUS_TYPE_BCMA:
+ bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.drv_cc, 0);
+ return 0;
}
return -EINVAL;
}
--
1.7.4.1
W dniu 6 czerwca 2011 12:32 użytkownik George Kashperko
<[email protected]> napisał:
> Hi,
>
>> Hauke,
>>
>> My idea for naming schema was to use:
>> bcma_host_TYPE_*
>>
>> Like:
>> bcma_host_pci_*
>> bcma_host_sdio_*
>>
>> You are using:
>> bcma_host_bcma_*
>>
>> What do you think about changing this to:
>> bcma_host_embedded_*
>> or just some:
>> bcma_host_emb_*
>> ?
>>
>> Does it make more sense to you? I was trying to keep names in bcma
>> really clear, so every first-time-reader can see differences between
>> hosts, host and driver, etc.
>
> how about bcma_host_soc ?
We get then inconsistency with "BCMA_HOSTTYPE_EMBEDDED". I'd like to
1) See something like bcma_host_emb...
xor
2) Use bcma_host_soc_* and BCMA_HOSTTYPE_SOC
--
Rafał
On 06/08/2011 10:20 AM, Michael Büsch wrote:
> On Wed, 8 Jun 2011 02:06:11 +0200
> Rafał Miłecki <[email protected]> wrote:
>
>> Because full scanning needs one of the following:
>> 1) Working alloc - not possible for SoCs
>
> Isn't there a bootmem allocator available on MIPS?
The bootmem allocator is working on mips, but it is initialized after
plat_mem_setup() was called. To use it we have to move the start of bcma
to some other place in the bcm47xx code.
We need access to the common and mips core for different functions in
the bcm47xx code and these functions are getting called by the mips
code, so we can not store these struct bcma_devices on the stack.
I would use this struct on the embedded device and use it in the text
segment of the bcm47xx code.
In include/linux/bcma/bcma.h:
struct bcma_soc {
struct bcma_bus bus;
struct bcma_device core_cc;
struct bcma_device core_mips;
};
In arch/mips/bcm47xx/setup.c
struct bcma_soc bus;
The chipcommon and mips core can be initilized early without the need
use of any alloc. The bcm47xx code will call
bcma_bus_early_register(struct bcma_soc *soc) and this code will find
these two cores, add then to the list of cores in bcma_bus and run the
init code for them. After that we have all we need to boot up the
device. After the kernel page allocator is fully set up we would search
for all the other cores and add them to the list of cores and do the
initialization for them. The two cores in struct bcma_soc will never be
accessed directly but only through struct bcma_bus so that there is no
difference from early boot and normal mode.
Hauke
2011/6/6 Hauke Mehrtens <[email protected]>:
> + if ((ccrev >= 11) && (ccrev != 15) && (ccrev != 20)) {
> + ....
> + } else
> + pr_err("serial not supported on this device ccrev: 0x%x\n",
> + ccrev);
Please use scripts/checkpatch* for your patches. I believe it will
alert you about lacking brackets for "else" (kernel coding style).
--
Rafał
On 06/06/2011 01:32 PM, Rafał Miłecki wrote:
> 2011/6/6 Hauke Mehrtens <[email protected]>:
>> +config BCMA_PCICORE_HOSTMODE
>> + bool "Hostmode support for BCMA PCI core"
>> + depends on BCMA_DRIVER_MIPS
>> + help
>> + PCIcore hostmode operation (external PCI bus).
>
> I think you started to use BCMA_DRIVER_corename. Could you stick to it
> (one schema), please? Maybe just
> BCMA_DRIVER_PCI_HOSTMODE
> ?
>
Yes sounds better.
>
>> +#ifdef CONFIG_BCMA_PCICORE_HOSTMODE
>> + pc->hostmode = bcma_pcicore_is_in_hostmode(pc);
>> + if (pc->hostmode)
>> + bcma_pcicore_init_hostmode(pc);
>> +#endif /* CONFIG_BCMA_PCICORE_HOSTMODE */
>> + if (!pc->hostmode)
>> + bcma_pcicore_serdes_workaround(pc);
>
> Does it make sense to init hostmode PCI like clientmode if we just
> disable CONFIG_BCMA_PCICORE_HOSTMODE?
>
> I think we should always check if core is host or client mode and use
> correct initialization only. We should not init it as clientmode just
> because we do not have driver for host mode.
Yes we should not initialize a host mode pci core with client init code
as it will break my device. ;-) I will place
bcma_pcicore_is_in_hostmode() into the normal PCI driver code so it is
available all the time.
>
>
>> diff --git a/drivers/bcma/driver_pci_host.c b/drivers/bcma/driver_pci_host.c
>> new file mode 100644
>> index 0000000..b52c6c9
>> --- /dev/null
>> +++ b/drivers/bcma/driver_pci_host.c
>> @@ -0,0 +1,44 @@
>> +/*
>> + * Broadcom specific AMBA
>> + * PCI Core
>
> Please rename "PCI Core", add something about hostmode.
>
Missed that while copy and past.
Hauke
2011/6/6 Hauke Mehrtens <[email protected]>:
> +/* driver_mips.c */
> +extern unsigned int bcma_core_mips_irq(struct bcma_device *dev);
Does it compile without CONFIG_BCMA_DRIVER_MIPS?
> +/* Get the MIPS IRQ assignment for a specified device.
> + * If unassigned, 0 is returned.
> + * If disabled, 5 is returned.
> + * If not supported, 6 is returned.
> + */
Does it ever return 6?
> +unsigned int bcma_core_mips_irq(struct bcma_device *dev)
> +{
> + struct bcma_device *mdev = dev->bus->drv_mips.core;
> + u32 irqflag;
> + unsigned int irq;
> +
> + irqflag = bcma_core_mips_irqflag(dev);
> +
> + for (irq = 1; irq <= 4; irq++)
> + if (bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq)) & (1 << irqflag))
> + break;
Use scripts/checkpatch*. Braces around "for" and split line to match
80 chars width.
Why don't you just use "return irq;" instead of break?
> +
> + if (irq == 5)
> + irq = 0;
> +
> + return irq;
You can just make it "return 0;" after changing break to return.
> + for (i = 0; i < bus->nr_cores; i++)
> + if ((1 << bcma_core_mips_irqflag(&bus->cores[i])) == oldirqflag) {
> + bcma_core_mips_set_irq(&bus->cores[i], 0);
> + break;
> + }
Braces for "for".
> + pr_info("after irq reconfiguration\n");
Make first letter uppercase. I'm not English expert, but doesn't
something like "IRQ reconfiguration done" sound better?
--
Rafał
On 06/06/2011 12:51 PM, Rafał Miłecki wrote:
> W dniu 6 czerwca 2011 12:32 użytkownik George Kashperko
> <[email protected]> napisał:
>> Hi,
>>
>>> Hauke,
>>>
>>> My idea for naming schema was to use:
>>> bcma_host_TYPE_*
>>>
>>> Like:
>>> bcma_host_pci_*
>>> bcma_host_sdio_*
>>>
>>> You are using:
>>> bcma_host_bcma_*
>>>
>>> What do you think about changing this to:
>>> bcma_host_embedded_*
>>> or just some:
>>> bcma_host_emb_*
>>> ?
>>>
>>> Does it make more sense to you? I was trying to keep names in bcma
>>> really clear, so every first-time-reader can see differences between
>>> hosts, host and driver, etc.
>> how about bcma_host_soc ?
> We get then inconsistency with "BCMA_HOSTTYPE_EMBEDDED". I'd like to
> 1) See something like bcma_host_emb...
> xor
> 2) Use bcma_host_soc_* and BCMA_HOSTTYPE_SOC
>
I would go for option 2). It more clearly says what it is. Embedded is a
broader term. As an example, a handset is an embedded device, but it may
use BCMA_HOSTTYPE_SDIO.
Gr. AvS
--
Almost nobody dances sober, unless they happen to be insane.
-- H.P. Lovecraft --
VyBkbml1IDcgY3plcndjYSAyMDExIDAwOjA2IHXFvHl0a293bmlrIEhhdWtlIE1laHJ0ZW5zCjxo
YXVrZUBoYXVrZS1tLmRlPiBuYXBpc2HFgjoKPiBPbiAwNi8wNi8yMDExIDAxOjIzIFBNLCBSYWZh
xYIgTWnFgmVja2kgd3JvdGU6Cj4+PiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IGZvciAoaSA9IDA7IGkgPCBidXMtPm5yX2NvcmVzOyBpKyspCj4+PiArIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGlmICgoMSA8PCBiY21hX2NvcmVfbWlwc19p
cnFmbGFnKCZidXMtPmNvcmVzW2ldKSkgPT0gb2xkaXJxZmxhZykgewo+Pj4gKyDCoCDCoCDCoCDC
oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCBiY21hX2NvcmVf
bWlwc19zZXRfaXJxKCZidXMtPmNvcmVzW2ldLCAwKTsKPj4+ICsgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgYnJlYWs7Cj4+PiArIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIH0KPj4KPj4gQnJhY2VzIGZv
ciAiZm9yIi4KPiBJcyB0aGlzIG5lZWRlZCBhZnRlciB0aGUgY29kaW5nIGd1aWxkbGluZXM/IFNo
b3VsZG4ndCB0aGV5IGJlIHJlbW92ZWQgaWYKPiB0aGV5IGFyZSBub3QgbmVlZGVkPwoKV2hvb3Bz
LCBhZnRlciByZS1jaGVja2luZyBjb2Rpbmcgc3R5bGUgaXQgc2VlbXMgSSB3YXMgd3JvbmcuCgot
LSAKUmFmYcWCCg==
This adds a mips driver to bcma. This is only found on embedded
devices. For now the driver just initializes the irqs used on this
system.
Signed-off-by: Hauke Mehrtens <[email protected]>
---
drivers/bcma/Kconfig | 11 ++-
drivers/bcma/Makefile | 1 +
drivers/bcma/bcma_private.h | 3 +
drivers/bcma/driver_mips.c | 227 +++++++++++++++++++++++++++++++++
drivers/bcma/main.c | 8 +
include/linux/bcma/bcma.h | 2 +
include/linux/bcma/bcma_driver_mips.h | 40 ++++++
7 files changed, 291 insertions(+), 1 deletions(-)
create mode 100644 drivers/bcma/driver_mips.c
create mode 100644 include/linux/bcma/bcma_driver_mips.h
diff --git a/drivers/bcma/Kconfig b/drivers/bcma/Kconfig
index 0390e32..568d30b 100644
--- a/drivers/bcma/Kconfig
+++ b/drivers/bcma/Kconfig
@@ -29,9 +29,18 @@ config BCMA_HOST_PCI
config BCMA_HOST_EMBEDDED
bool
- depends on BCMA && MIPS
+ depends on BCMA_DRIVER_MIPS
default n
+config BCMA_DRIVER_MIPS
+ bool "BCMA Broadcom MIPS core driver"
+ depends on BCMA && MIPS
+ help
+ Driver for the Broadcom MIPS core attached to Broadcom specific
+ Advanced Microcontroller Bus.
+
+ If unsure, say N
+
config BCMA_DEBUG
bool "BCMA debugging"
depends on BCMA
diff --git a/drivers/bcma/Makefile b/drivers/bcma/Makefile
index e509b1b..50ddab8 100644
--- a/drivers/bcma/Makefile
+++ b/drivers/bcma/Makefile
@@ -1,6 +1,7 @@
bcma-y += main.o scan.o core.o
bcma-y += driver_chipcommon.o driver_chipcommon_pmu.o
bcma-y += driver_pci.o
+bcma-$(CONFIG_BCMA_DRIVER_MIPS) += driver_mips.o
bcma-$(CONFIG_BCMA_HOST_PCI) += host_pci.o
bcma-$(CONFIG_BCMA_HOST_EMBEDDED) += host_embedded.o
obj-$(CONFIG_BCMA) += bcma.o
diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h
index 2f72e9c..842ee17 100644
--- a/drivers/bcma/bcma_private.h
+++ b/drivers/bcma/bcma_private.h
@@ -19,6 +19,9 @@ extern void bcma_bus_unregister(struct bcma_bus *bus);
/* scan.c */
int bcma_bus_scan(struct bcma_bus *bus);
+/* driver_mips.c */
+extern unsigned int bcma_core_mips_irq(struct bcma_device *dev);
+
#ifdef CONFIG_BCMA_HOST_PCI
/* host_pci.c */
extern int __init bcma_host_pci_init(void);
diff --git a/drivers/bcma/driver_mips.c b/drivers/bcma/driver_mips.c
new file mode 100644
index 0000000..0a6c217
--- /dev/null
+++ b/drivers/bcma/driver_mips.c
@@ -0,0 +1,227 @@
+/*
+ * Sonics Silicon Backplane
+ * Broadcom MIPS core driver
+ *
+ * Copyright 2005, Broadcom Corporation
+ * Copyright 2006, 2007, Michael Buesch <[email protected]>
+ * Copyright 2010, Bernhard Loos <[email protected]>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <linux/bcma/bcma.h>
+
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/serial_reg.h>
+#include <linux/time.h>
+
+#include "bcma_private.h"
+
+/* The 47162a0 hangs when reading its registers */
+static inline bool bcma_core_mips_bcm47162a0_quirk(struct bcma_device *dev)
+{
+ return dev->bus->chipinfo.id == 47162 && dev->bus->chipinfo.rev == 0 &&
+ dev->id.id == BCMA_CORE_MIPS_74K;
+}
+
+static inline u32 mips_read32(struct bcma_drv_mips *mcore,
+ u16 offset)
+{
+ return bcma_read32(mcore->core, offset);
+}
+
+static inline void mips_write32(struct bcma_drv_mips *mcore,
+ u16 offset,
+ u32 value)
+{
+ bcma_write32(mcore->core, offset, value);
+}
+
+static const u32 ipsflag_irq_mask[] = {
+ 0,
+ BCMA_MIPS_IPSFLAG_IRQ1,
+ BCMA_MIPS_IPSFLAG_IRQ2,
+ BCMA_MIPS_IPSFLAG_IRQ3,
+ BCMA_MIPS_IPSFLAG_IRQ4,
+};
+
+static const u32 ipsflag_irq_shift[] = {
+ 0,
+ BCMA_MIPS_IPSFLAG_IRQ1_SHIFT,
+ BCMA_MIPS_IPSFLAG_IRQ2_SHIFT,
+ BCMA_MIPS_IPSFLAG_IRQ3_SHIFT,
+ BCMA_MIPS_IPSFLAG_IRQ4_SHIFT,
+};
+
+static u32 bcma_core_mips_irqflag(struct bcma_device *dev)
+{
+ u32 flag;
+
+ if (bcma_core_mips_bcm47162a0_quirk(dev))
+ return dev->core_index;
+ flag = bcma_aread32(dev, BCMA_MIPS_OOBSELOUTA30);
+
+ return flag & 0x1F;
+}
+
+
+/* Get the MIPS IRQ assignment for a specified device.
+ * If unassigned, 0 is returned.
+ * If disabled, 5 is returned.
+ * If not supported, 6 is returned.
+ */
+unsigned int bcma_core_mips_irq(struct bcma_device *dev)
+{
+ struct bcma_device *mdev = dev->bus->drv_mips.core;
+ u32 irqflag;
+ unsigned int irq;
+
+ irqflag = bcma_core_mips_irqflag(dev);
+
+ for (irq = 1; irq <= 4; irq++)
+ if (bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq)) & (1 << irqflag))
+ break;
+
+ if (irq == 5)
+ irq = 0;
+
+ return irq;
+}
+
+static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq)
+{
+ unsigned int oldirq = bcma_core_mips_irq(dev);
+ struct bcma_bus *bus = dev->bus;
+ struct bcma_device *mdev = bus->drv_mips.core;
+ u32 irqflag;
+
+ irqflag = bcma_core_mips_irqflag(dev);
+ BUG_ON(oldirq == 6);
+
+ dev->irq = irq + 2;
+
+ /* clear the old irq */
+ if (oldirq == 0)
+ bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
+ bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) &
+ ~(1 << irqflag));
+ else
+ bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq), 0);
+
+ /* assign the new one */
+ if (irq == 0) {
+ bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
+ bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) |
+ (1 << irqflag));
+ } else {
+ u32 oldirqflag = bcma_read32(mdev,
+ BCMA_MIPS_MIPS74K_INTMASK(irq));
+ if (oldirqflag) {
+ int i;
+ /* backplane irq line is in use, find out who uses
+ * it and set user to irq 0
+ */
+ for (i = 0; i < bus->nr_cores; i++)
+ if ((1 << bcma_core_mips_irqflag(&bus->cores[i])) == oldirqflag) {
+ bcma_core_mips_set_irq(&bus->cores[i], 0);
+ break;
+ }
+ }
+ bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq), 1 << irqflag);
+ }
+
+ pr_info("set_irq: core 0x%04x, irq %d => %d\n",
+ dev->id.id, oldirq + 2, irq + 2);
+}
+
+static void bcma_core_mips_print_irq(struct bcma_device *dev, unsigned int irq)
+{
+ int i;
+ static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"};
+ printk(KERN_INFO KBUILD_MODNAME ": core 0x%04x, irq :", dev->id.id);
+ for (i = 0; i <= 6; i++)
+ printk(" %s%s", irq_name[i], i == irq ? "*" : " ");
+ printk("\n");
+}
+
+static void bcma_core_mips_dump_irq(struct bcma_bus *bus)
+{
+ int i;
+ for (i = 0; i < bus->nr_cores; i++) {
+ struct bcma_device *dev;
+ dev = &(bus->cores[i]);
+ bcma_core_mips_print_irq(dev, bcma_core_mips_irq(dev));
+ }
+}
+
+static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
+{
+ struct bcma_bus *bus = mcore->core->bus;
+
+ mcore->flash_buswidth = 2;
+ if (bus->drv_cc.core) {
+ mcore->flash_window = 0x1c000000;
+ mcore->flash_window_size = 0x02000000;
+ switch (bus->drv_cc.capabilities & BCMA_CC_CAP_FLASHT) {
+ case BCMA_CC_FLASHT_STSER:
+ case BCMA_CC_FLASHT_ATSER:
+ pr_err("Serial flash not supported.\n");
+ break;
+ case BCMA_CC_FLASHT_PARA:
+ if ((bcma_read32(bus->drv_cc.core, BCMA_CC_FLASH_CFG) &
+ BCMA_CC_OTPS) == 0)
+ mcore->flash_buswidth = 1;
+ break;
+ }
+ } else {
+ mcore->flash_window = 0x1fc00000;
+ mcore->flash_window_size = 0x00400000;
+ }
+}
+
+void bcma_core_mips_init(struct bcma_drv_mips *mcore)
+{
+ struct bcma_bus *bus;
+ struct bcma_device *dev;
+ unsigned int irq, i;
+
+ if (!mcore->core)
+ return; /* We don't have a MIPS core */
+
+ pr_info("Initializing MIPS core...\n");
+
+ bus = mcore->core->bus;
+
+ /* Assign IRQs to all cores on the bus */
+ for (irq = 1, i = 0; i < bus->nr_cores; i++) {
+ int mips_irq;
+ dev = &(bus->cores[i]);
+ mips_irq = bcma_core_mips_irq(dev);
+ if (mips_irq > 4)
+ dev->irq = 0;
+ else
+ dev->irq = mips_irq + 2;
+ if (dev->irq > 5)
+ continue;
+ switch (dev->id.id) {
+ case BCMA_CORE_PCI:
+ case BCMA_CORE_PCIE:
+ case BCMA_CORE_ETHERNET:
+ case BCMA_CORE_ETHERNET_GBIT:
+ case BCMA_CORE_MAC_GBIT:
+ case BCMA_CORE_80211:
+ case BCMA_CORE_USB20_HOST:
+ /* These devices get their own IRQ line if available,
+ * the rest goes on IRQ0
+ */
+ if (irq <= 4)
+ bcma_core_mips_set_irq(dev, irq++);
+ break;
+ }
+ }
+ pr_info("after irq reconfiguration\n");
+ bcma_core_mips_dump_irq(bus);
+
+ bcma_core_mips_flash_detect(mcore);
+}
diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c
index c5bcb5f..0b4e26d 100644
--- a/drivers/bcma/main.c
+++ b/drivers/bcma/main.c
@@ -96,6 +96,7 @@ static int bcma_register_cores(struct bcma_bus *bus)
case BCMA_CORE_CHIPCOMMON:
case BCMA_CORE_PCI:
case BCMA_CORE_PCIE:
+ case BCMA_CORE_MIPS_74K:
continue;
}
@@ -198,6 +199,13 @@ int bcma_bus_register(struct bcma_bus *bus)
bcma_core_chipcommon_init(&bus->drv_cc);
}
+ /* Init MIPS core */
+ core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
+ if (core) {
+ bus->drv_mips.core = core;
+ bcma_core_mips_init(&bus->drv_mips);
+ }
+
/* Find PCIE core */
core = bcma_find_core(bus, BCMA_CORE_PCIE);
if (core) {
diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h
index 192c4ae..c5d7d4d 100644
--- a/include/linux/bcma/bcma.h
+++ b/include/linux/bcma/bcma.h
@@ -6,6 +6,7 @@
#include <linux/bcma/bcma_driver_chipcommon.h>
#include <linux/bcma/bcma_driver_pci.h>
+#include <linux/bcma/bcma_driver_mips.h>
#include "bcma_regs.h"
@@ -198,6 +199,7 @@ struct bcma_bus {
struct bcma_drv_cc drv_cc;
struct bcma_drv_pci drv_pci;
+ struct bcma_drv_mips drv_mips;
/* Internal-only stuff follows. Do not touch. */
struct list_head attach_list;
diff --git a/include/linux/bcma/bcma_driver_mips.h b/include/linux/bcma/bcma_driver_mips.h
new file mode 100644
index 0000000..5faf30c
--- /dev/null
+++ b/include/linux/bcma/bcma_driver_mips.h
@@ -0,0 +1,40 @@
+#ifndef LINUX_BCMA_DRIVER_MIPS_H_
+#define LINUX_BCMA_DRIVER_MIPS_H_
+
+#define BCMA_MIPS_IPSFLAG 0x0F08
+#define BCMA_MIPS_IPSFLAG_IRQ1 0x0000003F /* which sbflags get routed to mips interrupt 1 */
+#define BCMA_MIPS_IPSFLAG_IRQ1_SHIFT 0
+#define BCMA_MIPS_IPSFLAG_IRQ2 0x00003F00 /* which sbflags get routed to mips interrupt 2 */
+#define BCMA_MIPS_IPSFLAG_IRQ2_SHIFT 8
+#define BCMA_MIPS_IPSFLAG_IRQ3 0x003F0000 /* which sbflags get routed to mips interrupt 3 */
+#define BCMA_MIPS_IPSFLAG_IRQ3_SHIFT 16
+#define BCMA_MIPS_IPSFLAG_IRQ4 0x3F000000 /* which sbflags get routed to mips interrupt 4 */
+#define BCMA_MIPS_IPSFLAG_IRQ4_SHIFT 24
+
+/* MIPS 74K core registers */
+#define BCMA_MIPS_MIPS74K_CORECTL 0x0000
+#define BCMA_MIPS_MIPS74K_EXCEPTBASE 0x0004
+#define BCMA_MIPS_MIPS74K_BIST 0x000C
+#define BCMA_MIPS_MIPS74K_INTMASK_INT0 0x0014
+#define BCMA_MIPS_MIPS74K_INTMASK(int) ((int) * 4 + BCMA_MIPS_MIPS74K_INTMASK_INT0)
+#define BCMA_MIPS_MIPS74K_NMIMASK 0x002C
+#define BCMA_MIPS_MIPS74K_GPIOSEL 0x0040
+#define BCMA_MIPS_MIPS74K_GPIOOUT 0x0044
+#define BCMA_MIPS_MIPS74K_GPIOEN 0x0048
+#define BCMA_MIPS_MIPS74K_CLKCTLST 0x01E0
+
+#define BCMA_MIPS_OOBSELOUTA30 0x100
+
+struct bcma_device;
+
+struct bcma_drv_mips {
+ struct bcma_device *core;
+
+ u8 flash_buswidth;
+ u32 flash_window;
+ u32 flash_window_size;
+};
+
+extern void bcma_core_mips_init(struct bcma_drv_mips *mcore);
+
+#endif /* LINUX_BCMA_DRIVER_MIPS_H_ */
--
1.7.4.1
This adds support for serial console to bcma, when operating on an
embedded device.
Signed-off-by: Hauke Mehrtens <[email protected]>
---
drivers/bcma/bcma_private.h | 4 ++
drivers/bcma/driver_chipcommon.c | 62 +++++++++++++++++++++++++++++++++
drivers/bcma/driver_mips.c | 9 +++++
include/linux/bcma/bcma_driver_mips.h | 11 ++++++
4 files changed, 86 insertions(+), 0 deletions(-)
diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h
index 842ee17..c65a6e2 100644
--- a/drivers/bcma/bcma_private.h
+++ b/drivers/bcma/bcma_private.h
@@ -22,6 +22,10 @@ int bcma_bus_scan(struct bcma_bus *bus);
/* driver_mips.c */
extern unsigned int bcma_core_mips_irq(struct bcma_device *dev);
+/* driver_chipcommon.c */
+extern int bcma_chipco_serial_init(struct bcma_drv_cc *cc,
+ struct bcma_drv_mips_serial_port *ports);
+
#ifdef CONFIG_BCMA_HOST_PCI
/* host_pci.c */
extern int __init bcma_host_pci_init(void);
diff --git a/drivers/bcma/driver_chipcommon.c b/drivers/bcma/driver_chipcommon.c
index 6061022..b582570 100644
--- a/drivers/bcma/driver_chipcommon.c
+++ b/drivers/bcma/driver_chipcommon.c
@@ -87,3 +87,65 @@ u32 bcma_chipco_gpio_polarity(struct bcma_drv_cc *cc, u32 mask, u32 value)
{
return bcma_cc_write32_masked(cc, BCMA_CC_GPIOPOL, mask, value);
}
+
+int bcma_chipco_serial_init(struct bcma_drv_cc *cc,
+ struct bcma_drv_mips_serial_port *ports)
+{
+ int nr_ports = 0;
+ u32 plltype;
+ unsigned int irq;
+ u32 baud_base, div;
+ u32 i, n;
+ unsigned int ccrev = cc->core->id.rev;
+
+ plltype = (cc->capabilities & BCMA_CC_CAP_PLLT);
+ irq = bcma_core_mips_irq(cc->core);
+
+ if ((ccrev >= 11) && (ccrev != 15) && (ccrev != 20)) {
+ /* Fixed ALP clock */
+ baud_base = 20000000;
+ if (cc->capabilities & BCMA_CC_CAP_PMU) {
+ /* FIXME: baud_base is different for devices with a PMU */
+ WARN_ON(1);
+ }
+ div = 1;
+ if (ccrev >= 21) {
+ /* Turn off UART clock before switching clocksource. */
+ bcma_cc_write32(cc, BCMA_CC_CORECTL,
+ bcma_cc_read32(cc, BCMA_CC_CORECTL)
+ & ~BCMA_CC_CORECTL_UARTCLKEN);
+ }
+ /* Set the override bit so we don't divide it */
+ bcma_cc_write32(cc, BCMA_CC_CORECTL,
+ bcma_cc_read32(cc, BCMA_CC_CORECTL)
+ | BCMA_CC_CORECTL_UARTCLK0);
+ if (ccrev >= 21) {
+ /* Re-enable the UART clock. */
+ bcma_cc_write32(cc, BCMA_CC_CORECTL,
+ bcma_cc_read32(cc, BCMA_CC_CORECTL)
+ | BCMA_CC_CORECTL_UARTCLKEN);
+ }
+ } else
+ pr_err("serial not supported on this device ccrev: 0x%x\n",
+ ccrev);
+
+ /* Determine the registers of the UARTs */
+ n = (cc->capabilities & BCMA_CC_CAP_NRUART);
+ for (i = 0; i < n; i++) {
+ void __iomem *cc_mmio;
+ void __iomem *uart_regs;
+
+ cc_mmio = cc->core->bus->mmio +
+ (cc->core->core_index * BCMA_CORE_SIZE);
+ uart_regs = cc_mmio + BCMA_CC_UART0_DATA;
+ uart_regs += (i * 256);
+
+ nr_ports++;
+ ports[i].regs = uart_regs;
+ ports[i].irq = irq;
+ ports[i].baud_base = baud_base;
+ ports[i].reg_shift = 0;
+ }
+
+ return nr_ports;
+}
diff --git a/drivers/bcma/driver_mips.c b/drivers/bcma/driver_mips.c
index 0a6c217..40e4a6d 100644
--- a/drivers/bcma/driver_mips.c
+++ b/drivers/bcma/driver_mips.c
@@ -155,6 +155,14 @@ static void bcma_core_mips_dump_irq(struct bcma_bus *bus)
}
}
+static void bcma_core_mips_serial_init(struct bcma_drv_mips *mcore)
+{
+ struct bcma_bus *bus = mcore->core->bus;
+
+ mcore->nr_serial_ports = bcma_chipco_serial_init(&bus->drv_cc,
+ mcore->serial_ports);
+}
+
static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
{
struct bcma_bus *bus = mcore->core->bus;
@@ -223,5 +231,6 @@ void bcma_core_mips_init(struct bcma_drv_mips *mcore)
pr_info("after irq reconfiguration\n");
bcma_core_mips_dump_irq(bus);
+ bcma_core_mips_serial_init(mcore);
bcma_core_mips_flash_detect(mcore);
}
diff --git a/include/linux/bcma/bcma_driver_mips.h b/include/linux/bcma/bcma_driver_mips.h
index 5faf30c..6584e7d 100644
--- a/include/linux/bcma/bcma_driver_mips.h
+++ b/include/linux/bcma/bcma_driver_mips.h
@@ -27,9 +27,20 @@
struct bcma_device;
+struct bcma_drv_mips_serial_port {
+ void *regs;
+ unsigned long clockspeed;
+ unsigned int irq;
+ unsigned int baud_base;
+ unsigned int reg_shift;
+};
+
struct bcma_drv_mips {
struct bcma_device *core;
+ int nr_serial_ports;
+ struct bcma_drv_mips_serial_port serial_ports[4];
+
u8 flash_buswidth;
u32 flash_window;
u32 flash_window_size;
--
1.7.4.1
On 06/07/2011 02:33 AM, Rafał Miłecki wrote:
> W dniu 7 czerwca 2011 00:00 użytkownik Hauke Mehrtens
> <[email protected]> napisał:
>> On 06/06/2011 12:22 PM, Rafał Miłecki wrote:
>>>> + if (bus->hosttype == BCMA_HOSTTYPE_EMBEDDED) {
>>>> + iounmap(bus->mmio);
>>>> + mmio = ioremap(BCMA_ADDR_BASE, BCMA_CORE_SIZE * bus->nr_cores);
>>>> + if (!mmio)
>>>> + return -ENOMEM;
>>>> + bus->mmio = mmio;
>>>> +
>>>> + mmio = ioremap(BCMA_WRAP_BASE, BCMA_CORE_SIZE * bus->nr_cores);
>>>> + if (!mmio)
>>>> + return -ENOMEM;
>>>> + bus->host_embedded = mmio;
>>> Do we really need both? mmio and host_embedded? What about keeping
>>> mmio only and using it in calculation for read/write[8,16,32]?
>> These are two different memory regions, it should be possible to
>> calculate the other address, but I do not like that. As host_embedded is
>> in a union this does not waste any memory.
> Ah, OK, I can see what does happen here. You are using:
> 1) bus->mmio for first core
> 2) bus->host_embedded for first agent/wrapper
>
> I'm not sure if this is a correct approach. Doing "core_index *
> BCMA_CORE_SIZE" comes from ssb, where it was the way to calculate
> offset. In case of BCMA we are reading all the info from (E)EPROM,
> which also includes addresses of the cores.
>
> IMO you should use core->addr and core->wrap for read/write ops. I
> believe this is approach Broadcom decided to use for BCMA, when
> designing (E)EPROM.
Agree. There is no guarantee for the core index to relate to the
physical address. Chip designer may be systematic in this and the
index*size method may work, but not by design.
Gr. AvS
--
Almost nobody dances sober, unless they happen to be insane.
-- H.P. Lovecraft --
W dniu 6 czerwca 2011 12:34 użytkownik Rafał Miłecki <[email protected]> napisał:
> 2011/6/6 Hauke Mehrtens <[email protected]>:
>> +u32 bcma_cpu_clock(struct bcma_drv_mips *mcore)
>> +{
>> + struct bcma_bus *bus = mcore->core->bus;
>> +
>> + if (bus->drv_cc.capabilities & BCMA_CC_CAP_PMU)
>> + return bcma_pmu_get_clockcpu(&bus->drv_cc);
>> +
>> + pr_err("No PMU available, need this to get the cpu clock\n");
>> + return 0;
>> +}
>> +EXPORT_SYMBOL(bcma_cpu_clock);
>
> Are you really going to use this in some separated driver? If you're,
> I heard that exporting symbol should go in pair with patch enabling
> usage of such a symbol.
I've just read patch 09/10, sorry for the noise :)
--
Rafał
On Wed, 8 Jun 2011 02:06:11 +0200
Rafał Miłecki <[email protected]> wrote:
> Because full scanning needs one of the following:
> 1) Working alloc - not possible for SoCs
Isn't there a bootmem allocator available on MIPS?
Hauke,
My idea for naming schema was to use:
bcma_host_TYPE_*
Like:
bcma_host_pci_*
bcma_host_sdio_*
You are using:
bcma_host_bcma_*
What do you think about changing this to:
bcma_host_embedded_*
or just some:
bcma_host_emb_*
?
Does it make more sense to you? I was trying to keep names in bcma
really clear, so every first-time-reader can see differences between
hosts, host and driver, etc.
2011/6/6 Hauke Mehrtens <[email protected]>:
> --- /dev/null
> +++ b/drivers/bcma/host_embedded.c
> @@ -0,0 +1,93 @@
> +/*
> + * Broadcom specific AMBA
> + * PCI Host
s/PCI/Embedded/
> +int bcma_host_bcma_register(struct bcma_bus *bus)
> +{
> + u32 __iomem *mmio;
> + /* iomap only first core. We have to read some register on this core
> + * to get the number of cores. This is sone in bcma_scan()
> + */
> + mmio = ioremap(BCMA_ADDR_BASE, BCMA_CORE_SIZE * 1);
> + if (!mmio)
> + return -ENOMEM;
> + bus->mmio = mmio;
Maybe just:
bus->mmio = ioremap(...);
? :)
> + /* Host specific */
> + bus->hosttype = BCMA_HOSTTYPE_EMBEDDED;
> + bus->ops = &bcma_host_bcma_ops;
> +
> + /* Register */
> + return bcma_bus_register(bus);
> +}
> diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c
> index 1afa107..c5bcb5f 100644
> --- a/drivers/bcma/main.c
> +++ b/drivers/bcma/main.c
> @@ -119,6 +119,7 @@ static int bcma_register_cores(struct bcma_bus *bus)
> break;
> case BCMA_HOSTTYPE_NONE:
> case BCMA_HOSTTYPE_SDIO:
> + case BCMA_HOSTTYPE_EMBEDDED:
> break;
> }
>
> diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c
> index 70b39f7..9229615 100644
> --- a/drivers/bcma/scan.c
> +++ b/drivers/bcma/scan.c
> @@ -203,7 +203,7 @@ static s32 bcma_erom_get_addr_desc(struct bcma_bus *bus, u32 **eromptr,
> int bcma_bus_scan(struct bcma_bus *bus)
> {
> u32 erombase;
> - u32 __iomem *eromptr, *eromend;
> + u32 __iomem *eromptr, *eromend, *mmio;
>
> s32 cia, cib;
> u8 ports[2], wrappers[2];
> @@ -219,9 +219,34 @@ int bcma_bus_scan(struct bcma_bus *bus)
> bus->chipinfo.id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT;
> bus->chipinfo.rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT;
> bus->chipinfo.pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT;
> + bus->nr_cores = (tmp & BCMA_CC_ID_NRCORES) >> BCMA_CC_ID_NRCORES_SHIFT;
I'd use different variable as Julian suggested.
> +
> + /* If we are an embedded device we now know the number of avaliable
> + * core and ioremap the correct space.
> + */
Typo: avaliable
> + if (bus->hosttype == BCMA_HOSTTYPE_EMBEDDED) {
> + iounmap(bus->mmio);
> + mmio = ioremap(BCMA_ADDR_BASE, BCMA_CORE_SIZE * bus->nr_cores);
> + if (!mmio)
> + return -ENOMEM;
> + bus->mmio = mmio;
> +
> + mmio = ioremap(BCMA_WRAP_BASE, BCMA_CORE_SIZE * bus->nr_cores);
> + if (!mmio)
> + return -ENOMEM;
> + bus->host_embedded = mmio;
Do we really need both? mmio and host_embedded? What about keeping
mmio only and using it in calculation for read/write[8,16,32]?
> + }
> + /* reset it to 0 as we use it for counting */
> + bus->nr_cores = 0;
>
> erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
> - eromptr = bus->mmio;
> + if (bus->hosttype == BCMA_HOSTTYPE_EMBEDDED) {
> + eromptr = ioremap(erombase, BCMA_CORE_SIZE);
> + if (!eromptr)
> + return -ENOMEM;
> + } else
> + eromptr = bus->mmio;
I though eromptr = bus->mmio; will do the trick for embedded as well.
I think I need some time to read about IO mapping and understand that.
--
Rafał
On Monday 06 June 2011 23:38:50 Hauke Mehrtens wrote:
> Accessing chip common should be possible without scanning the hole bus
> as it is at the first position and initializing most things just needs
> chip common. For initializing the interrupts scanning is needed as we do
> not know where the mips core is located.
>
> As we can not use kalloc on early boot we could use a function which
> uses kalloc under normal conditions and when on early boot the
> architecture code which starts the bcma code should also provide a
> function which returns a pointer to some memory in its text segment to
> use. We need space for 16 cores in the architecture code.
>
> In addition bcma_bus_register(struct bcma_bus *bus) has to be divided
> into two parts. The first part will scan the bus and initialize chip
> common and mips core. The second part will initialize pci core and
> register the devices in the system. When using this under normal
> conditions they will be called directly after each other.
Just split out the minimal low-level function from the bcma_bus_scan
then, to locate a single device based on some identifier. The
bcma_bus_scan() function can then repeatedly allocate one device
and pass it to the low-level function when doing the proper scan,
while the arch code calls the low-level function directly with static
data.
Arnd
Hello.
On 06-06-2011 2:07, Hauke Mehrtens wrote:
> Signed-off-by: Hauke Mehrtens<[email protected]>
> ---
> arch/mips/bcm47xx/irq.c | 8 ++++++++
> 1 files changed, 8 insertions(+), 0 deletions(-)
> diff --git a/arch/mips/bcm47xx/irq.c b/arch/mips/bcm47xx/irq.c
> index 325757a..3642cee 100644
> --- a/arch/mips/bcm47xx/irq.c
> +++ b/arch/mips/bcm47xx/irq.c
[...]
> @@ -51,5 +52,12 @@ void plat_irq_dispatch(void)
>
> void __init arch_init_irq(void)
> {
> + if (bcm47xx_active_bus_type == BCM47XX_BUS_TYPE_BCMA) {
> + bcma_write32(bcm47xx_bus.bcma.drv_mips.core,
> + BCMA_MIPS_MIPS74K_INTMASK(5), 1<< 31);
> + /* the kernel reads the timer irq from some register and thinks
> + * it's #5, but we offset it by 2 and route to #7 */
The preferred style for the multi-line comments is this:
/*
* bla
* bla
*/
WBR, Sergei
This patch adds support for using bcma on an embedded bus. An embedded
system like the bcm4716 could register this bus and it searches for the
bcma cores then.
Signed-off-by: Hauke Mehrtens <[email protected]>
---
drivers/bcma/Kconfig | 5 ++
drivers/bcma/Makefile | 1 +
drivers/bcma/host_embedded.c | 93 ++++++++++++++++++++++++++++++++++++
drivers/bcma/main.c | 1 +
drivers/bcma/scan.c | 29 ++++++++++-
include/linux/bcma/bcma.h | 3 +
include/linux/bcma/bcma_embedded.h | 8 +++
7 files changed, 138 insertions(+), 2 deletions(-)
create mode 100644 drivers/bcma/host_embedded.c
create mode 100644 include/linux/bcma/bcma_embedded.h
diff --git a/drivers/bcma/Kconfig b/drivers/bcma/Kconfig
index 83e9adf..0390e32 100644
--- a/drivers/bcma/Kconfig
+++ b/drivers/bcma/Kconfig
@@ -27,6 +27,11 @@ config BCMA_HOST_PCI
bool "Support for BCMA on PCI-host bus"
depends on BCMA_HOST_PCI_POSSIBLE
+config BCMA_HOST_EMBEDDED
+ bool
+ depends on BCMA && MIPS
+ default n
+
config BCMA_DEBUG
bool "BCMA debugging"
depends on BCMA
diff --git a/drivers/bcma/Makefile b/drivers/bcma/Makefile
index 0d56245..e509b1b 100644
--- a/drivers/bcma/Makefile
+++ b/drivers/bcma/Makefile
@@ -2,6 +2,7 @@ bcma-y += main.o scan.o core.o
bcma-y += driver_chipcommon.o driver_chipcommon_pmu.o
bcma-y += driver_pci.o
bcma-$(CONFIG_BCMA_HOST_PCI) += host_pci.o
+bcma-$(CONFIG_BCMA_HOST_EMBEDDED) += host_embedded.o
obj-$(CONFIG_BCMA) += bcma.o
ccflags-$(CONFIG_BCMA_DEBUG) := -DDEBUG
diff --git a/drivers/bcma/host_embedded.c b/drivers/bcma/host_embedded.c
new file mode 100644
index 0000000..6942440
--- /dev/null
+++ b/drivers/bcma/host_embedded.c
@@ -0,0 +1,93 @@
+/*
+ * Broadcom specific AMBA
+ * PCI Host
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include "bcma_private.h"
+#include "scan.h"
+#include <linux/bcma/bcma.h>
+
+static u8 bcma_host_bcma_read8(struct bcma_device *core, u16 offset)
+{
+ offset += core->core_index * BCMA_CORE_SIZE;
+ return readb(core->bus->mmio + offset);
+}
+
+static u16 bcma_host_bcma_read16(struct bcma_device *core, u16 offset)
+{
+ offset += core->core_index * BCMA_CORE_SIZE;
+ return readw(core->bus->mmio + offset);
+}
+
+static u32 bcma_host_bcma_read32(struct bcma_device *core, u16 offset)
+{
+ offset += core->core_index * BCMA_CORE_SIZE;
+ return readl(core->bus->mmio + offset);
+}
+
+static void bcma_host_bcma_write8(struct bcma_device *core, u16 offset,
+ u8 value)
+{
+ offset += core->core_index * BCMA_CORE_SIZE;
+ writeb(value, core->bus->mmio + offset);
+}
+
+static void bcma_host_bcma_write16(struct bcma_device *core, u16 offset,
+ u16 value)
+{
+ offset += core->core_index * BCMA_CORE_SIZE;
+ writew(value, core->bus->mmio + offset);
+}
+
+static void bcma_host_bcma_write32(struct bcma_device *core, u16 offset,
+ u32 value)
+{
+ offset += core->core_index * BCMA_CORE_SIZE;
+ writel(value, core->bus->mmio + offset);
+}
+
+static u32 bcma_host_bcma_aread32(struct bcma_device *core, u16 offset)
+{
+ offset += core->core_index * BCMA_CORE_SIZE;
+ return readl(core->bus->host_embedded + offset);
+}
+
+static void bcma_host_bcma_awrite32(struct bcma_device *core, u16 offset,
+ u32 value)
+{
+ offset += core->core_index * BCMA_CORE_SIZE;
+ writel(value, core->bus->host_embedded + offset);
+}
+
+const struct bcma_host_ops bcma_host_bcma_ops = {
+ .read8 = bcma_host_bcma_read8,
+ .read16 = bcma_host_bcma_read16,
+ .read32 = bcma_host_bcma_read32,
+ .write8 = bcma_host_bcma_write8,
+ .write16 = bcma_host_bcma_write16,
+ .write32 = bcma_host_bcma_write32,
+ .aread32 = bcma_host_bcma_aread32,
+ .awrite32 = bcma_host_bcma_awrite32,
+};
+
+int bcma_host_bcma_register(struct bcma_bus *bus)
+{
+ u32 __iomem *mmio;
+
+ /* iomap only first core. We have to read some register on this core
+ * to get the number of cores. This is sone in bcma_scan()
+ */
+ mmio = ioremap(BCMA_ADDR_BASE, BCMA_CORE_SIZE * 1);
+ if (!mmio)
+ return -ENOMEM;
+ bus->mmio = mmio;
+
+ /* Host specific */
+ bus->hosttype = BCMA_HOSTTYPE_EMBEDDED;
+ bus->ops = &bcma_host_bcma_ops;
+
+ /* Register */
+ return bcma_bus_register(bus);
+}
diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c
index 1afa107..c5bcb5f 100644
--- a/drivers/bcma/main.c
+++ b/drivers/bcma/main.c
@@ -119,6 +119,7 @@ static int bcma_register_cores(struct bcma_bus *bus)
break;
case BCMA_HOSTTYPE_NONE:
case BCMA_HOSTTYPE_SDIO:
+ case BCMA_HOSTTYPE_EMBEDDED:
break;
}
diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c
index 70b39f7..9229615 100644
--- a/drivers/bcma/scan.c
+++ b/drivers/bcma/scan.c
@@ -203,7 +203,7 @@ static s32 bcma_erom_get_addr_desc(struct bcma_bus *bus, u32 **eromptr,
int bcma_bus_scan(struct bcma_bus *bus)
{
u32 erombase;
- u32 __iomem *eromptr, *eromend;
+ u32 __iomem *eromptr, *eromend, *mmio;
s32 cia, cib;
u8 ports[2], wrappers[2];
@@ -219,9 +219,34 @@ int bcma_bus_scan(struct bcma_bus *bus)
bus->chipinfo.id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT;
bus->chipinfo.rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT;
bus->chipinfo.pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT;
+ bus->nr_cores = (tmp & BCMA_CC_ID_NRCORES) >> BCMA_CC_ID_NRCORES_SHIFT;
+
+ /* If we are an embedded device we now know the number of avaliable
+ * core and ioremap the correct space.
+ */
+ if (bus->hosttype == BCMA_HOSTTYPE_EMBEDDED) {
+ iounmap(bus->mmio);
+ mmio = ioremap(BCMA_ADDR_BASE, BCMA_CORE_SIZE * bus->nr_cores);
+ if (!mmio)
+ return -ENOMEM;
+ bus->mmio = mmio;
+
+ mmio = ioremap(BCMA_WRAP_BASE, BCMA_CORE_SIZE * bus->nr_cores);
+ if (!mmio)
+ return -ENOMEM;
+ bus->host_embedded = mmio;
+ }
+ /* reset it to 0 as we use it for counting */
+ bus->nr_cores = 0;
erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
- eromptr = bus->mmio;
+ if (bus->hosttype == BCMA_HOSTTYPE_EMBEDDED) {
+ eromptr = ioremap(erombase, BCMA_CORE_SIZE);
+ if (!eromptr)
+ return -ENOMEM;
+ } else
+ eromptr = bus->mmio;
+
eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
bcma_scan_switch_core(bus, erombase);
diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h
index 8b6feca..192c4ae 100644
--- a/include/linux/bcma/bcma.h
+++ b/include/linux/bcma/bcma.h
@@ -16,6 +16,7 @@ enum bcma_hosttype {
BCMA_HOSTTYPE_NONE,
BCMA_HOSTTYPE_PCI,
BCMA_HOSTTYPE_SDIO,
+ BCMA_HOSTTYPE_EMBEDDED,
};
struct bcma_chipinfo {
@@ -185,6 +186,8 @@ struct bcma_bus {
struct pci_dev *host_pci;
/* Pointer to the SDIO device (only for BCMA_HOSTTYPE_SDIO) */
struct sdio_func *host_sdio;
+ /* Pointer to the embedded iomem (only for BCMA_HOSTTYPE_EMBEDDED) */
+ void __iomem *host_embedded;
};
struct bcma_chipinfo chipinfo;
diff --git a/include/linux/bcma/bcma_embedded.h b/include/linux/bcma/bcma_embedded.h
new file mode 100644
index 0000000..0faf46d
--- /dev/null
+++ b/include/linux/bcma/bcma_embedded.h
@@ -0,0 +1,8 @@
+#ifndef LINUX_BCMA_EMBEDDED_H_
+#define LINUX_BCMA_EMBEDDED_H_
+
+#include <linux/bcma/bcma.h>
+
+extern int bcma_host_bcma_register(struct bcma_bus *bus);
+
+#endif /* LINUX_BCMA_EMBEDDED_H_ */
--
1.7.4.1
2011/6/6 Hauke Mehrtens <[email protected]>:
> +#ifdef CONFIG_BCMA_PCICORE_HOSTMODE
> +/* driver_pci_host.c */
> +extern int bcma_pcicore_is_in_hostmode(struct bcma_drv_pci *pc);
> +extern void bcma_pcicore_init_hostmode(struct bcma_drv_pci *pc);
> +#endif /* CONFIG_BCMA_PCICORE_HOSTMODE */
I don't know if I'm overreacting, but I really don't like naming mess
in the ssb.
Why don't you use bcma_core_pci_* to be consistent?
--
Rafał
2011/6/6 Hauke Mehrtens <[email protected]>:
> +u32 bcma_cpu_clock(struct bcma_drv_mips *mcore)
> +{
> + struct bcma_bus *bus = mcore->core->bus;
> +
> + if (bus->drv_cc.capabilities & BCMA_CC_CAP_PMU)
> + return bcma_pmu_get_clockcpu(&bus->drv_cc);
> +
> + pr_err("No PMU available, need this to get the cpu clock\n");
> + return 0;
> +}
> +EXPORT_SYMBOL(bcma_cpu_clock);
Are you really going to use this in some separated driver? If you're,
I heard that exporting symbol should go in pair with patch enabling
usage of such a symbol.
--
Rafał
W dniu 6 czerwca 2011 12:55 użytkownik Arend van Spriel
<[email protected]> napisał:
> On 06/06/2011 12:51 PM, Rafał Miłecki wrote:
>>
>> W dniu 6 czerwca 2011 12:32 użytkownik George Kashperko
>> <[email protected]> napisał:
>>>
>>> Hi,
>>>
>>>> Hauke,
>>>>
>>>> My idea for naming schema was to use:
>>>> bcma_host_TYPE_*
>>>>
>>>> Like:
>>>> bcma_host_pci_*
>>>> bcma_host_sdio_*
>>>>
>>>> You are using:
>>>> bcma_host_bcma_*
>>>>
>>>> What do you think about changing this to:
>>>> bcma_host_embedded_*
>>>> or just some:
>>>> bcma_host_emb_*
>>>> ?
>>>>
>>>> Does it make more sense to you? I was trying to keep names in bcma
>>>> really clear, so every first-time-reader can see differences between
>>>> hosts, host and driver, etc.
>>>
>>> how about bcma_host_soc ?
>>
>> We get then inconsistency with "BCMA_HOSTTYPE_EMBEDDED". I'd like to
>> 1) See something like bcma_host_emb...
>> xor
>> 2) Use bcma_host_soc_* and BCMA_HOSTTYPE_SOC
>>
>
> I would go for option 2). It more clearly says what it is. Embedded is a
> broader term. As an example, a handset is an embedded device, but it may use
> BCMA_HOSTTYPE_SDIO.
Good point, agree.
--
Rafał
2011/6/6 Hauke Mehrtens <[email protected]>:
> +config BCMA_PCICORE_HOSTMODE
> + bool "Hostmode support for BCMA PCI core"
> + depends on BCMA_DRIVER_MIPS
> + help
> + PCIcore hostmode operation (external PCI bus).
I think you started to use BCMA_DRIVER_corename. Could you stick to it
(one schema), please? Maybe just
BCMA_DRIVER_PCI_HOSTMODE
?
> +#ifdef CONFIG_BCMA_PCICORE_HOSTMODE
> + pc->hostmode = bcma_pcicore_is_in_hostmode(pc);
> + if (pc->hostmode)
> + bcma_pcicore_init_hostmode(pc);
> +#endif /* CONFIG_BCMA_PCICORE_HOSTMODE */
> + if (!pc->hostmode)
> + bcma_pcicore_serdes_workaround(pc);
Does it make sense to init hostmode PCI like clientmode if we just
disable CONFIG_BCMA_PCICORE_HOSTMODE?
I think we should always check if core is host or client mode and use
correct initialization only. We should not init it as clientmode just
because we do not have driver for host mode.
> diff --git a/drivers/bcma/driver_pci_host.c b/drivers/bcma/driver_pci_host.c
> new file mode 100644
> index 0000000..b52c6c9
> --- /dev/null
> +++ b/drivers/bcma/driver_pci_host.c
> @@ -0,0 +1,44 @@
> +/*
> + * Broadcom specific AMBA
> + * PCI Core
Please rename "PCI Core", add something about hostmode.
--
Rafał
2011/6/6 Hauke Mehrtens <[email protected]>:
> This patch add support for the bcma bus. Broadcom uses only Mips 74K
> CPUs on the new SoC and on the old ons using ssb bus there are no Mips
> 74K CPUs.
>
> Signed-off-by: Hauke Mehrtens <[email protected]>
> ---
> arch/mips/Kconfig | 4 +++
> arch/mips/bcm47xx/gpio.c | 9 ++++++++
> arch/mips/bcm47xx/nvram.c | 6 +++++
> arch/mips/bcm47xx/serial.c | 24 +++++++++++++++++++++++
> arch/mips/bcm47xx/setup.c | 27 ++++++++++++++++++++++++-
> arch/mips/bcm47xx/time.c | 3 ++
> arch/mips/include/asm/mach-bcm47xx/bcm47xx.h | 3 ++
> arch/mips/include/asm/mach-bcm47xx/gpio.h | 18 +++++++++++++++++
> drivers/watchdog/bcm47xx_wdt.c | 6 +++++
> 9 files changed, 98 insertions(+), 2 deletions(-)
>
> diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
> index 653da62..bdb0341 100644
> --- a/arch/mips/Kconfig
> +++ b/arch/mips/Kconfig
> @@ -100,6 +100,10 @@ config BCM47XX
> select SSB_EMBEDDED
> select SSB_B43_PCI_BRIDGE if PCI
> select SSB_PCICORE_HOSTMODE if PCI
> + select BCMA
> + select BCMA_HOST_EMBEDDED
> + select BCMA_DRIVER_MIPS
> + select BCMA_PCICORE_HOSTMODE
I'm not involved in development for embedded devices but I believe
that space is quite important for them.
You force compiling both: ssb and bcma for every device using bcm47xx.
I think ppl may want to compile only one bus driver.
--
Rafał
Hi,
> On Monday 06 June 2011, Rafał Miłecki wrote:
> > Greg, Arnd: could you take a look at this patch, please?
> >
> > With proposed patch we are going back to this ugly array and wrappers hacks.
> >
> > I was really happy with our final solution, but it seems it's not
> > doable for embedded systems...? Is there something better we can do
> > about this?
> >
> > 2011/6/6 Hauke Mehrtens <[email protected]>:
> > > When using bcma on a embedded device it is initialized very early at
> > > boot. We have to do so as the cpu and interrupt management and all
> > > other devices are attached to this bus and it has to be initialized so
> > > early. In that stage we can not allocate memory or sleep, just use the
> > > memory on the stack and in the text segment as the kernel is not
> > > initialized far enough. This patch removed the kzallocs from the scan
> > > code. Some earlier version of the bcma implementation and the normal
> > > ssb implementation are doing it like this.
> > > The __bcma_dev_wrapper struct is used as the container for the device
> > > struct as bcma_device will be too big if it includes struct device.
> > >
> > > Signed-off-by: Hauke Mehrtens <[email protected]>
>
> If you rely on device scan to find your CPUs and interrupt controllers,
> you are screwed already, this won't work.
>
> In that case, it's better to have a few "early" drivers, as few as
> possible, that don't go through the bus scan at all but have their
> own ways of bootstrapping themselves. I don't know what you mean by
> "CPU management", but I can only assume that it's not doing that much,
> and you can just put the register values into the device tree.
GPIOs, flash and UART could get initialized early without erom scanning
as Chipcommon seems always to be the #0 core on the amba interconnect.
>
> For an interrupt controller, it should be ok to have it initialized
> late, as long as it's only responsible for the devices on the same
> bus and not for instance for IPI interrupts. Just make sure that you
> do the bus scan and the initialization of the IRQ driver before you
> initialize any drivers that rely in on the interrupts to be working.
Without proper timer init (which requires both the chipcommon and mips
cores knowledge) kernel will get hung somewhere inside calibrate_delay.
It could get addressed if get bus scan called in arch_init_irq or
plat_time_init - both are executed before calibrate_delay and with slab
available.
Have nice day,
George
On 06/06/2011 01:07 PM, Rafał Miłecki wrote:
> 2011/6/6 Hauke Mehrtens <[email protected]>:
>> This patch add support for the bcma bus. Broadcom uses only Mips 74K
>> CPUs on the new SoC and on the old ons using ssb bus there are no Mips
>> 74K CPUs.
>>
>> Signed-off-by: Hauke Mehrtens <[email protected]>
>> ---
>> arch/mips/Kconfig | 4 +++
>> arch/mips/bcm47xx/gpio.c | 9 ++++++++
>> arch/mips/bcm47xx/nvram.c | 6 +++++
>> arch/mips/bcm47xx/serial.c | 24 +++++++++++++++++++++++
>> arch/mips/bcm47xx/setup.c | 27 ++++++++++++++++++++++++-
>> arch/mips/bcm47xx/time.c | 3 ++
>> arch/mips/include/asm/mach-bcm47xx/bcm47xx.h | 3 ++
>> arch/mips/include/asm/mach-bcm47xx/gpio.h | 18 +++++++++++++++++
>> drivers/watchdog/bcm47xx_wdt.c | 6 +++++
>> 9 files changed, 98 insertions(+), 2 deletions(-)
>>
>> diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
>> index 653da62..bdb0341 100644
>> --- a/arch/mips/Kconfig
>> +++ b/arch/mips/Kconfig
>> @@ -100,6 +100,10 @@ config BCM47XX
>> select SSB_EMBEDDED
>> select SSB_B43_PCI_BRIDGE if PCI
>> select SSB_PCICORE_HOSTMODE if PCI
>> + select BCMA
>> + select BCMA_HOST_EMBEDDED
>> + select BCMA_DRIVER_MIPS
>> + select BCMA_PCICORE_HOSTMODE
>
> I'm not involved in development for embedded devices but I believe
> that space is quite important for them.
>
> You force compiling both: ssb and bcma for every device using bcm47xx.
> I think ppl may want to compile only one bus driver.
>
Yes that has to be improved as there should also be an option to use the
compiler optimazions for the new MIPS 74K CPU core.
Hauke
On 06/06/2011 12:22 PM, Rafał Miłecki wrote:
> Hauke,
>
> My idea for naming schema was to use:
> bcma_host_TYPE_*
>
> Like:
> bcma_host_pci_*
> bcma_host_sdio_*
>
> You are using:
> bcma_host_bcma_*
>
> What do you think about changing this to:
> bcma_host_embedded_*
> or just some:
> bcma_host_emb_*
> ?
>
> Does it make more sense to you? I was trying to keep names in bcma
> really clear, so every first-time-reader can see differences between
> hosts, host and driver, etc.
>
At first I named it bcma_host_bcma_ but then renamed the file name, but
forgot the function names. I will rename it all to bcma_host_soc_*
host_sco.c and so on.
> 2011/6/6 Hauke Mehrtens <[email protected]>:
>> --- /dev/null
>> +++ b/drivers/bcma/host_embedded.c
>> @@ -0,0 +1,93 @@
>> +/*
>> + * Broadcom specific AMBA
>> + * PCI Host
>
> s/PCI/Embedded/
>
>
>> +int bcma_host_bcma_register(struct bcma_bus *bus)
>> +{
>> + u32 __iomem *mmio;
>> + /* iomap only first core. We have to read some register on this core
>> + * to get the number of cores. This is sone in bcma_scan()
>> + */
>> + mmio = ioremap(BCMA_ADDR_BASE, BCMA_CORE_SIZE * 1);
>> + if (!mmio)
>> + return -ENOMEM;
>> + bus->mmio = mmio;
>
> Maybe just:
> bus->mmio = ioremap(...);
> ? :)
yes makes sens.
>
>> + /* Host specific */
>> + bus->hosttype = BCMA_HOSTTYPE_EMBEDDED;
>> + bus->ops = &bcma_host_bcma_ops;
>> +
>> + /* Register */
>> + return bcma_bus_register(bus);
>> +}
>> diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c
>> index 1afa107..c5bcb5f 100644
>> --- a/drivers/bcma/main.c
>> +++ b/drivers/bcma/main.c
>> @@ -119,6 +119,7 @@ static int bcma_register_cores(struct bcma_bus *bus)
>> break;
>> case BCMA_HOSTTYPE_NONE:
>> case BCMA_HOSTTYPE_SDIO:
>> + case BCMA_HOSTTYPE_EMBEDDED:
>> break;
>> }
>>
>> diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c
>> index 70b39f7..9229615 100644
>> --- a/drivers/bcma/scan.c
>> +++ b/drivers/bcma/scan.c
>> @@ -203,7 +203,7 @@ static s32 bcma_erom_get_addr_desc(struct bcma_bus *bus, u32 **eromptr,
>> int bcma_bus_scan(struct bcma_bus *bus)
>> {
>> u32 erombase;
>> - u32 __iomem *eromptr, *eromend;
>> + u32 __iomem *eromptr, *eromend, *mmio;
>>
>> s32 cia, cib;
>> u8 ports[2], wrappers[2];
>> @@ -219,9 +219,34 @@ int bcma_bus_scan(struct bcma_bus *bus)
>> bus->chipinfo.id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT;
>> bus->chipinfo.rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT;
>> bus->chipinfo.pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT;
>> + bus->nr_cores = (tmp & BCMA_CC_ID_NRCORES) >> BCMA_CC_ID_NRCORES_SHIFT;
>
> I'd use different variable as Julian suggested.
yes
>
>
>> +
>> + /* If we are an embedded device we now know the number of avaliable
>> + * core and ioremap the correct space.
>> + */
>
> Typo: avaliable
my favorite typo ;-)
>
>
>> + if (bus->hosttype == BCMA_HOSTTYPE_EMBEDDED) {
>> + iounmap(bus->mmio);
>> + mmio = ioremap(BCMA_ADDR_BASE, BCMA_CORE_SIZE * bus->nr_cores);
>> + if (!mmio)
>> + return -ENOMEM;
>> + bus->mmio = mmio;
>> +
>> + mmio = ioremap(BCMA_WRAP_BASE, BCMA_CORE_SIZE * bus->nr_cores);
>> + if (!mmio)
>> + return -ENOMEM;
>> + bus->host_embedded = mmio;
>
> Do we really need both? mmio and host_embedded? What about keeping
> mmio only and using it in calculation for read/write[8,16,32]?
These are two different memory regions, it should be possible to
calculate the other address, but I do not like that. As host_embedded is
in a union this does not waste any memory.
>
>> + }
>> + /* reset it to 0 as we use it for counting */
>> + bus->nr_cores = 0;
>>
>> erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
>> - eromptr = bus->mmio;
>> + if (bus->hosttype == BCMA_HOSTTYPE_EMBEDDED) {
>> + eromptr = ioremap(erombase, BCMA_CORE_SIZE);
>> + if (!eromptr)
>> + return -ENOMEM;
>> + } else
>> + eromptr = bus->mmio;
>
> I though eromptr = bus->mmio; will do the trick for embedded as well.
> I think I need some time to read about IO mapping and understand that.
>
No they are different eromptr is 0x1810e000 and bus->mmio is 0xb8000000
for example on my device. I tried using eromptr = bus->mmio; on embedded
and it did not work.
Hauke
Hi,
> Hauke,
>
> My idea for naming schema was to use:
> bcma_host_TYPE_*
>
> Like:
> bcma_host_pci_*
> bcma_host_sdio_*
>
> You are using:
> bcma_host_bcma_*
>
> What do you think about changing this to:
> bcma_host_embedded_*
> or just some:
> bcma_host_emb_*
> ?
>
> Does it make more sense to you? I was trying to keep names in bcma
> really clear, so every first-time-reader can see differences between
> hosts, host and driver, etc.
how about bcma_host_soc ?
>
>
> 2011/6/6 Hauke Mehrtens <[email protected]>:
> > --- /dev/null
> > +++ b/drivers/bcma/host_embedded.c
> > @@ -0,0 +1,93 @@
> > +/*
> > + * Broadcom specific AMBA
> > + * PCI Host
>
> s/PCI/Embedded/
>
>
> > +int bcma_host_bcma_register(struct bcma_bus *bus)
> > +{
> > + u32 __iomem *mmio;
> > + /* iomap only first core. We have to read some register on this core
> > + * to get the number of cores. This is sone in bcma_scan()
> > + */
> > + mmio = ioremap(BCMA_ADDR_BASE, BCMA_CORE_SIZE * 1);
> > + if (!mmio)
> > + return -ENOMEM;
> > + bus->mmio = mmio;
>
> Maybe just:
> bus->mmio = ioremap(...);
> ? :)
>
>
> > + /* Host specific */
> > + bus->hosttype = BCMA_HOSTTYPE_EMBEDDED;
> > + bus->ops = &bcma_host_bcma_ops;
> > +
> > + /* Register */
> > + return bcma_bus_register(bus);
> > +}
> > diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c
> > index 1afa107..c5bcb5f 100644
> > --- a/drivers/bcma/main.c
> > +++ b/drivers/bcma/main.c
> > @@ -119,6 +119,7 @@ static int bcma_register_cores(struct bcma_bus *bus)
> > break;
> > case BCMA_HOSTTYPE_NONE:
> > case BCMA_HOSTTYPE_SDIO:
> > + case BCMA_HOSTTYPE_EMBEDDED:
> > break;
> > }
> >
> > diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c
> > index 70b39f7..9229615 100644
> > --- a/drivers/bcma/scan.c
> > +++ b/drivers/bcma/scan.c
> > @@ -203,7 +203,7 @@ static s32 bcma_erom_get_addr_desc(struct bcma_bus *bus, u32 **eromptr,
> > int bcma_bus_scan(struct bcma_bus *bus)
> > {
> > u32 erombase;
> > - u32 __iomem *eromptr, *eromend;
> > + u32 __iomem *eromptr, *eromend, *mmio;
> >
> > s32 cia, cib;
> > u8 ports[2], wrappers[2];
> > @@ -219,9 +219,34 @@ int bcma_bus_scan(struct bcma_bus *bus)
> > bus->chipinfo.id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT;
> > bus->chipinfo.rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT;
> > bus->chipinfo.pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT;
> > + bus->nr_cores = (tmp & BCMA_CC_ID_NRCORES) >> BCMA_CC_ID_NRCORES_SHIFT;
>
To avoid using wrapper struct and at the same time to save on embedded
reservations you could let the bus get scanned twice on SoC - first time
discovering just system devices (chipcommon and mips core) required for
early setup (you will never register those to the linux device subsystem
so you can have them marked as __initdata and have no ->release callback
therefore), second time full scan with registering the whole bus when
done.
Have nice day,
George
Signed-off-by: Hauke Mehrtens <[email protected]>
---
arch/mips/bcm47xx/irq.c | 8 ++++++++
1 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/arch/mips/bcm47xx/irq.c b/arch/mips/bcm47xx/irq.c
index 325757a..3642cee 100644
--- a/arch/mips/bcm47xx/irq.c
+++ b/arch/mips/bcm47xx/irq.c
@@ -26,6 +26,7 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <asm/irq_cpu.h>
+#include <bcm47xx.h>
void plat_irq_dispatch(void)
{
@@ -51,5 +52,12 @@ void plat_irq_dispatch(void)
void __init arch_init_irq(void)
{
+ if (bcm47xx_active_bus_type == BCM47XX_BUS_TYPE_BCMA) {
+ bcma_write32(bcm47xx_bus.bcma.drv_mips.core,
+ BCMA_MIPS_MIPS74K_INTMASK(5), 1 << 31);
+ /* the kernel reads the timer irq from some register and thinks
+ * it's #5, but we offset it by 2 and route to #7 */
+ cp0_compare_irq = 7;
+ }
mips_cpu_irq_init();
}
--
1.7.4.1
On 06/06/2011 01:22 AM, Julian Calaby wrote:
> Hauke,
>
> Minor nit:
>
> On Mon, Jun 6, 2011 at 08:07, Hauke Mehrtens <[email protected]> wrote:
>> This patch adds support for using bcma on an embedded bus. An embedded
>> system like the bcm4716 could register this bus and it searches for the
>> bcma cores then.
>>
>> Signed-off-by: Hauke Mehrtens <[email protected]>
>> ---
>> diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c
>> index 70b39f7..9229615 100644
>> --- a/drivers/bcma/scan.c
>> +++ b/drivers/bcma/scan.c
>> @@ -219,9 +219,34 @@ int bcma_bus_scan(struct bcma_bus *bus)
>> bus->chipinfo.id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT;
>> bus->chipinfo.rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT;
>> bus->chipinfo.pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT;
>> + bus->nr_cores = (tmp & BCMA_CC_ID_NRCORES) >> BCMA_CC_ID_NRCORES_SHIFT;
>> +
>> + /* If we are an embedded device we now know the number of avaliable
>> + * core and ioremap the correct space.
>> + */
>> + if (bus->hosttype == BCMA_HOSTTYPE_EMBEDDED) {
>> + iounmap(bus->mmio);
>> + mmio = ioremap(BCMA_ADDR_BASE, BCMA_CORE_SIZE * bus->nr_cores);
>> + if (!mmio)
>> + return -ENOMEM;
>> + bus->mmio = mmio;
>> +
>> + mmio = ioremap(BCMA_WRAP_BASE, BCMA_CORE_SIZE * bus->nr_cores);
>> + if (!mmio)
>> + return -ENOMEM;
>> + bus->host_embedded = mmio;
>> + }
>> + /* reset it to 0 as we use it for counting */
>> + bus->nr_cores = 0;
>
> Would it make sense to use a local variable for nr_cores, and only use
> it within the BCMA_HOSTTYPE_EMBEDDED if statement, rather than
> re-using bus->nr_cores and having to reset it?
Yes that looks better.
Hauke
Hauke,
Minor nit:
On Mon, Jun 6, 2011 at 08:07, Hauke Mehrtens <[email protected]> wrote:
> This patch adds support for using bcma on an embedded bus. An embedded
> system like the bcm4716 could register this bus and it searches for the
> bcma cores then.
>
> Signed-off-by: Hauke Mehrtens <[email protected]>
> ---
> diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c
> index 70b39f7..9229615 100644
> --- a/drivers/bcma/scan.c
> +++ b/drivers/bcma/scan.c
> @@ -219,9 +219,34 @@ int bcma_bus_scan(struct bcma_bus *bus)
> ? ? ? ?bus->chipinfo.id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT;
> ? ? ? ?bus->chipinfo.rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT;
> ? ? ? ?bus->chipinfo.pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT;
> + ? ? ? bus->nr_cores = (tmp & BCMA_CC_ID_NRCORES) >> BCMA_CC_ID_NRCORES_SHIFT;
> +
> + ? ? ? /* If we are an embedded device we now know the number of avaliable
> + ? ? ? ?* core and ioremap the correct space.
> + ? ? ? ?*/
> + ? ? ? if (bus->hosttype == BCMA_HOSTTYPE_EMBEDDED) {
> + ? ? ? ? ? ? ? iounmap(bus->mmio);
> + ? ? ? ? ? ? ? mmio = ioremap(BCMA_ADDR_BASE, BCMA_CORE_SIZE * bus->nr_cores);
> + ? ? ? ? ? ? ? if (!mmio)
> + ? ? ? ? ? ? ? ? ? ? ? return -ENOMEM;
> + ? ? ? ? ? ? ? bus->mmio = mmio;
> +
> + ? ? ? ? ? ? ? mmio = ioremap(BCMA_WRAP_BASE, BCMA_CORE_SIZE * bus->nr_cores);
> + ? ? ? ? ? ? ? if (!mmio)
> + ? ? ? ? ? ? ? ? ? ? ? return -ENOMEM;
> + ? ? ? ? ? ? ? bus->host_embedded = mmio;
> + ? ? ? }
> + ? ? ? /* reset it to 0 as we use it for counting */
> + ? ? ? bus->nr_cores = 0;
Would it make sense to use a local variable for nr_cores, and only use
it within the BCMA_HOSTTYPE_EMBEDDED if statement, rather than
re-using bus->nr_cores and having to reset it?
Thanks,
--
Julian Calaby
Email: [email protected]
Profile: http://www.google.com/profiles/julian.calaby/
.Plan: http://sites.google.com/site/juliancalaby/