2010-03-30 17:53:53

by Rafał Miłecki

[permalink] [raw]
Subject: [RFC][PATCH][WIP] b43: N-PHY: set band width

---
I've problem with deciding how to keep some data needed by band width setting
code. Generally these band width-related routines are considered "common", to
be used by more than just N-PHY. So probably the most /correct/ way should be
to add some variables like maccontrol, wake_override, clk and other to struct
b43_phy which is shared between all PHYs. However we would not use these vars
in anything except N-PHY, so we would just waste users memory.

Could you help me decide correct way to handle this?
---
drivers/net/wireless/b43/b43.h | 1 +
drivers/net/wireless/b43/phy_common.c | 186 +++++++++++++++++++++++++++++++++
drivers/net/wireless/b43/phy_common.h | 7 ++
drivers/net/wireless/b43/phy_n.c | 4 +-
drivers/net/wireless/b43/phy_n.h | 1 +
5 files changed, 197 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index 3a003e6..d75926f 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -57,6 +57,7 @@
#define B43_MMIO_TSF_CFP_REP 0x188
#define B43_MMIO_TSF_CFP_START 0x18C
#define B43_MMIO_TSF_CFP_MAXDUR 0x190
+#define B43_MMIO_CLKCTL 0x1E0 /* clock control status */

/* 32-bit DMA */
#define B43_MMIO_DMA32_BASE0 0x200
diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c
index 8f7d7ef..f46135f 100644
--- a/drivers/net/wireless/b43/phy_common.c
+++ b/drivers/net/wireless/b43/phy_common.c
@@ -466,3 +466,189 @@ struct b43_c32 b43_cordic(int theta)

return ret;
}
+
+/* http://bcm-v4.sipsolutions.net/802.11/Mhf */
+void b43_mhf(struct b43_wldev *dev, u8 idx, u16 sel, u16 val, u8 band)
+{
+ ; /* TODO */
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/NcClkCtlCc */
+static bool b43_no_check_clock_control_chip_common(struct b43_wldev *dev, u32 mode)
+{
+ /* TODO: this is temporary hack */
+ return (mode == 0);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/ClkCtlCc */
+static bool b43_clock_control_chip_common(struct b43_wldev *dev, u32 mode)
+{
+ struct ssb_bus *bus = dev->dev->bus;
+ u16 chip_id = bus->chip_id;
+ u16 chip_rev = bus->chip_rev;
+ /* TODO: specs distinguish PCI and PCIe */
+ bool pci = (bus->bustype == SSB_BUSTYPE_PCI);
+
+ if (dev->dev->id.revision < 6)
+ return false;
+ if (pci && ((chip_id == 0x4311 && chip_rev < 2) ||
+ (pci && chip_id == 0x4321) ||
+ (pci && chip_id == 0x4716)))
+ return (mode == 0);
+ return b43_no_check_clock_control_chip_common(dev, mode);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/BmacWaitForWake */
+static void b43_phy_bmac_wait_for_wake(struct b43_wldev *dev)
+{
+ u8 core_rev = dev->dev->bus->pcicore.dev->id.revision;
+ u16 tmp, i;
+
+ if (core_rev == 4) {
+ udelay(5);
+ return;
+ }
+
+ if (dev->phy.type == B43_PHYTYPE_G && core_rev == 5)
+ udelay(2000);
+ else
+ udelay(40);
+
+ for (i = 0; i < 1500; i++) {
+ tmp = b43_shm_read16(dev, B43_SHM_SHARED,
+ B43_SHM_SH_UCODESTAT);
+ if (tmp == B43_SHM_SH_UCODESTAT_SLEEP) {
+ i = 0;
+ break;
+ }
+ udelay(10);
+ }
+ if (i)
+ b43err(dev->wl, "ucode wake up timeout\n");
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/MctrlWrite */
+static void b43_phy_mac_control_write(struct b43_wldev *dev)
+{
+ struct b43_phy_n *nphy = dev->phy.n;
+
+ u32 tmp = nphy->maccontrol;
+ if (nphy->wake_override)
+ tmp |= B43_MACCTL_AWAKE;
+ if (nphy->mute_override)
+ tmp &= ~B43_MACCTL_AP;
+ tmp |= B43_MACCTL_INFRA;
+ b43_write32(dev, B43_MMIO_MACCTL, tmp);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/UcodeWakeOverrideSet */
+static void b43_ucode_wake_override_set(struct b43_wldev *dev, u32 override)
+{
+ struct b43_phy_n *nphy = dev->phy.n;
+
+ nphy->wake_override |= override;
+ if (nphy->wake_override || maccontrol & B43_MACCTL_AWAKE)
+ return;
+ b43_phy_mac_control_write(dev);
+ b43_phy_bmac_wait_for_wake(dev);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/UcodeWakeOverrideClear */
+static void b43_ucode_wake_override_clear(struct b43_wldev *dev, u32 override)
+{
+ struct b43_phy_n *nphy = dev->phy.n;
+
+ nphy->wake_override &= ~override;
+ if (nphy->wake_override != nphy->maccontrol & B43_MACCTL_AWAKE)
+ return;
+ b43_phy_mac_control_write(dev);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/ClkCtlClk */
+static void b43_clock_control(struct b43_wldev *dev, u32 mode)
+{
+ struct ssb_bus *bus = dev->dev->bus;
+ struct b43_phy_n *nphy = dev->phy.n;
+ u8 core_rev = bus->pcicore.dev->id.revision;
+ u16 i;
+ u32 clkctl;
+ bool wakeup;
+
+ if (bus->chipco.capabilities & SSB_CHIPCO_CAP_PMU) { /* PMU Present */
+ B43_WARN_ON(core_rev < 20);
+ if (nphy->clk) {
+ bool tmp = (bus->chipco.pmu.rev == 0 &&
+ (b43_read32(dev, B43_MMIO_CLKCTL) & 0x12));
+
+ if (mode == 0) {
+ clkctl = b43_read32(dev, B43_MMIO_CLKCTL);
+ clkctl |= 0x2;
+ b43_write32(dev, B43_MMIO_CLKCTL, clkctl);
+ udelay(33);
+ }
+
+ if (mode == 0 || tmp) {
+ for (i = 0; i < 1500; i++) {
+ clkctl = b43_read32(dev, B43_MMIO_CLKCTL);
+ if ((clkctl & 0x20000) == 0) {
+ i = 0;
+ break;
+ }
+ udelay(10);
+ }
+ if (i)
+ b43err(dev->wl, "clock timeout\n");
+ }
+
+ if (mode != 0 && tmp) {
+ clkctl = b43_read32(dev, B43_MMIO_CLKCTL);
+ clkctl &= ~0x2;
+ b43_write32(dev, B43_MMIO_CLKCTL, clkctl);
+ }
+ }
+ nphy->forcefastclk = (mode == 0);
+ } else {
+ B43_WARN_ON(core_rev >= 20);
+
+ wakeup = (core_rev < 9);
+ if (nphy->up && wakeup)
+ b43_ucode_wake_override_set(dev, 1);
+
+ nphy->forcefastclk = b43_clock_control_chip_common(dev, mode);
+ if (core_rev < 11) {
+ if (nphy->forcefastclk)
+ b43_mhf(dev, 0, 0x400, 0x400, 3);
+ else
+ b43_mhf(dev, 0, 0x400, 0, 3);
+ }
+ if (core_rev > 4 && nphy->forcefastclk && nphy->clk) {
+ if (nphy->forcefastclk)
+ nphy->wake_override |= 0x10;
+ else
+ nphy->wake_override &= ~0x10;
+ }
+
+ if (nphy->up && wakeup)
+ b43_ucode_wake_override_clear(dev, 1);
+ }
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/BmacBwSet */
+void b43_bmac_set_b_width(struct b43_wldev *dev, u8 b_width)
+{
+ struct b43_phy_n *nphy = dev->phy.n;
+ bool fast;
+
+ /* Generally it is common routine, but we use it only for N-PHY now */
+ B43_WARN_ON(dev->phy.type != B43_PHYTYPE_N);
+
+ fast = nphy->forcefastclk;
+ if (!fast)
+ b43_clock_control(dev, 0);
+ nphy->b_width = b_width;
+ b43_read32(dev, B43_MMIO_MACCTL); /* flush writes */
+ /* TODO: Call PHY BMAC Reset */
+ dev->phy.ops->init(dev);
+ if (fast)
+ b43_clock_control(dev, 2);
+}
diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h
index bd480b4..215fb05 100644
--- a/drivers/net/wireless/b43/phy_common.h
+++ b/drivers/net/wireless/b43/phy_common.h
@@ -429,4 +429,11 @@ void b43_phyop_switch_analog_generic(struct b43_wldev *dev, bool on);

struct b43_c32 b43_cordic(int theta);

+void b43_mhf(struct b43_wldev *dev, u8 idx, u16 sel, u16 val, u8 band);
+
+/**
+ * b43_bmac_set_b_width - Set band width
+ */
+void b43_bmac_set_b_width(struct b43_wldev *dev, u8 b_width);
+
#endif /* LINUX_B43_PHY_COMMON_H_ */
diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c
index 1ae232c..b19922d 100644
--- a/drivers/net/wireless/b43/phy_n.c
+++ b/drivers/net/wireless/b43/phy_n.c
@@ -1096,7 +1096,7 @@ static void b43_nphy_workarounds(struct b43_wldev *dev)

if (dev->phy.rev < 2) {
if (b43_phy_read(dev, B43_NPHY_RXCTL) & 0x2)
- ; /*TODO: b43_mhf(dev, 2, 0x0010, 0x0010, 3);*/
+ b43_mhf(dev, 2, 0x0010, 0x0010, 3);
} else if (dev->phy.rev == 2) {
b43_phy_write(dev, B43_NPHY_CRSCHECK2, 0);
b43_phy_write(dev, B43_NPHY_CRSCHECK3, 0);
@@ -3356,7 +3356,7 @@ static int b43_nphy_set_chanspec(struct b43_wldev *dev,
nphy->radio_chanspec = chanspec;

if (chanspec.b_width != nphy->b_width)
- ; /* TODO: BMAC BW Set (chanspec.b_width) */
+ b43_bmac_set_b_width(chanspec.b_width);

/* TODO: use defines */
if (chanspec.b_width == 3) {
diff --git a/drivers/net/wireless/b43/phy_n.h b/drivers/net/wireless/b43/phy_n.h
index 8b6d570..1ec768e 100644
--- a/drivers/net/wireless/b43/phy_n.h
+++ b/drivers/net/wireless/b43/phy_n.h
@@ -987,6 +987,7 @@ struct b43_phy_n {
u8 b_width;
struct b43_chanspec radio_chanspec;

+ bool forcefastclk;
bool gain_boost;
bool elna_gain_config;
bool band5g_pwrgain;
--
1.6.4.2



2010-03-30 18:06:58

by Larry Finger

[permalink] [raw]
Subject: Re: [RFC][PATCH][WIP] b43: N-PHY: set band width

On 03/30/2010 12:54 PM, Rafał Miłecki wrote:
> ---
> I've problem with deciding how to keep some data needed by band width setting
> code. Generally these band width-related routines are considered "common", to
> be used by more than just N-PHY. So probably the most /correct/ way should be
> to add some variables like maccontrol, wake_override, clk and other to struct
> b43_phy which is shared between all PHYs. However we would not use these vars
> in anything except N-PHY, so we would just waste users memory.
>
> Could you help me decide correct way to handle this?

I have not done the RE yet, but the SSLPN PHY is multi-band and will likely need
all the band width parameters needed by the N PHY. I would vote for putting them
in a "common" struct.

Larry