Commit 8829d55e authored by Michael Buesch's avatar Michael Buesch Committed by John W. Linville

[PATCH] bcm43xx: fix pctl slowclock limit calculation

This fixes coverity bug:
http://marc.theaimsgroup.com/?l=linux-netdev&m=114417628413880&w=2Signed-off-by: default avatarMichael Buesch <mb@bu3sch.de>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 2230daa0
...@@ -35,77 +35,101 @@ ...@@ -35,77 +35,101 @@
#include "bcm43xx_main.h" #include "bcm43xx_main.h"
/* Get the Slow Clock Source */
static int bcm43xx_pctl_get_slowclksrc(struct bcm43xx_private *bcm)
{
u32 tmp;
int err;
assert(bcm->current_core == &bcm->core_chipcommon);
if (bcm->current_core->rev < 6) {
if (bcm->bustype == BCM43xx_BUSTYPE_PCMCIA ||
bcm->bustype == BCM43xx_BUSTYPE_SB)
return BCM43xx_PCTL_CLKSRC_XTALOS;
if (bcm->bustype == BCM43xx_BUSTYPE_PCI) {
err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUT, &tmp);
assert(!err);
if (tmp & 0x10)
return BCM43xx_PCTL_CLKSRC_PCI;
return BCM43xx_PCTL_CLKSRC_XTALOS;
}
}
if (bcm->current_core->rev < 10) {
tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL);
tmp &= 0x7;
if (tmp == 0)
return BCM43xx_PCTL_CLKSRC_LOPWROS;
if (tmp == 1)
return BCM43xx_PCTL_CLKSRC_XTALOS;
if (tmp == 2)
return BCM43xx_PCTL_CLKSRC_PCI;
}
return BCM43xx_PCTL_CLKSRC_XTALOS;
}
/* Get max/min slowclock frequency /* Get max/min slowclock frequency
* as described in http://bcm-specs.sipsolutions.net/PowerControl * as described in http://bcm-specs.sipsolutions.net/PowerControl
*/ */
static int bcm43xx_pctl_clockfreqlimit(struct bcm43xx_private *bcm, static int bcm43xx_pctl_clockfreqlimit(struct bcm43xx_private *bcm,
int get_max) int get_max)
{ {
int limit = 0; int limit;
int clocksrc;
int divisor; int divisor;
int selection;
int err;
u32 tmp; u32 tmp;
struct bcm43xx_coreinfo *old_core;
if (!(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL)) assert(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL);
goto out; assert(bcm->current_core == &bcm->core_chipcommon);
old_core = bcm->current_core;
err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
if (err)
goto out;
clocksrc = bcm43xx_pctl_get_slowclksrc(bcm);
if (bcm->current_core->rev < 6) { if (bcm->current_core->rev < 6) {
if ((bcm->bustype == BCM43xx_BUSTYPE_PCMCIA) || switch (clocksrc) {
(bcm->bustype == BCM43xx_BUSTYPE_SB)) { case BCM43xx_PCTL_CLKSRC_PCI:
selection = 1;
divisor = 32;
} else {
err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUT, &tmp);
if (err) {
printk(KERN_ERR PFX "clockfreqlimit pcicfg read failure\n");
goto out_switchback;
}
if (tmp & 0x10) {
/* PCI */
selection = 2;
divisor = 64; divisor = 64;
} else { break;
/* XTAL */ case BCM43xx_PCTL_CLKSRC_XTALOS:
selection = 1;
divisor = 32; divisor = 32;
} break;
default:
assert(0);
divisor = 1;
} }
} else if (bcm->current_core->rev < 10) { } else if (bcm->current_core->rev < 10) {
selection = (tmp & 0x07); switch (clocksrc) {
if (selection) { case BCM43xx_PCTL_CLKSRC_LOPWROS:
divisor = 1;
break;
case BCM43xx_PCTL_CLKSRC_XTALOS:
case BCM43xx_PCTL_CLKSRC_PCI:
tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL); tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL);
divisor = 4 * (1 + ((tmp & 0xFFFF0000) >> 16)); divisor = ((tmp & 0xFFFF0000) >> 16) + 1;
} else divisor *= 4;
break;
default:
assert(0);
divisor = 1; divisor = 1;
}
} else { } else {
tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SYSCLKCTL); tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SYSCLKCTL);
divisor = 4 * (1 + ((tmp & 0xFFFF0000) >> 16)); divisor = ((tmp & 0xFFFF0000) >> 16) + 1;
selection = 1; divisor *= 4;
} }
switch (selection) { switch (clocksrc) {
case 0: case BCM43xx_PCTL_CLKSRC_LOPWROS:
/* LPO */
if (get_max) if (get_max)
limit = 43000; limit = 43000;
else else
limit = 25000; limit = 25000;
break; break;
case 1: case BCM43xx_PCTL_CLKSRC_XTALOS:
/* XTAL */
if (get_max) if (get_max)
limit = 20200000; limit = 20200000;
else else
limit = 19800000; limit = 19800000;
break; break;
case 2: case BCM43xx_PCTL_CLKSRC_PCI:
/* PCI */
if (get_max) if (get_max)
limit = 34000000; limit = 34000000;
else else
...@@ -113,17 +137,14 @@ static int bcm43xx_pctl_clockfreqlimit(struct bcm43xx_private *bcm, ...@@ -113,17 +137,14 @@ static int bcm43xx_pctl_clockfreqlimit(struct bcm43xx_private *bcm,
break; break;
default: default:
assert(0); assert(0);
limit = 0;
} }
limit /= divisor; limit /= divisor;
out_switchback:
err = bcm43xx_switch_core(bcm, old_core);
assert(err == 0);
out:
return limit; return limit;
} }
/* init power control /* init power control
* as described in http://bcm-specs.sipsolutions.net/PowerControl * as described in http://bcm-specs.sipsolutions.net/PowerControl
*/ */
......
...@@ -33,6 +33,15 @@ ...@@ -33,6 +33,15 @@
#include <linux/types.h> #include <linux/types.h>
/* Clock sources */
enum {
/* PCI clock */
BCM43xx_PCTL_CLKSRC_PCI,
/* Crystal slow clock oscillator */
BCM43xx_PCTL_CLKSRC_XTALOS,
/* Low power oscillator */
BCM43xx_PCTL_CLKSRC_LOPWROS,
};
struct bcm43xx_private; struct bcm43xx_private;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment