diff options
author | Ayaz Abdulla <aabdulla@nvidia.com> | 2009-02-07 03:23:57 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-02-07 03:23:57 -0500 |
commit | cac1c52c3621b46e3be49cf7887a7cfa393890de (patch) | |
tree | 5dc05a67babb5eefcab00f0f9235fef5ec57099d /drivers/net/forcedeth.c | |
parent | 1f0fa15432e49547c3fa915644c7e0c0975809e7 (diff) |
forcedeth: mgmt unit interface
This patch updates the logic used to communicate with the mgmt unit. It
also adds a version check for a newer mgmt unit firmware.
* Fixed udelay to schedule_timeout_uninterruptible
Signed-off-by: Ayaz Abdulla <aabdulla@nvidia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/forcedeth.c')
-rw-r--r-- | drivers/net/forcedeth.c | 98 |
1 files changed, 82 insertions, 16 deletions
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 7825be7586f3..da7c9ee069b5 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c | |||
@@ -157,6 +157,9 @@ enum { | |||
157 | #define NVREG_XMITCTL_HOST_SEMA_ACQ 0x0000f000 | 157 | #define NVREG_XMITCTL_HOST_SEMA_ACQ 0x0000f000 |
158 | #define NVREG_XMITCTL_HOST_LOADED 0x00004000 | 158 | #define NVREG_XMITCTL_HOST_LOADED 0x00004000 |
159 | #define NVREG_XMITCTL_TX_PATH_EN 0x01000000 | 159 | #define NVREG_XMITCTL_TX_PATH_EN 0x01000000 |
160 | #define NVREG_XMITCTL_DATA_START 0x00100000 | ||
161 | #define NVREG_XMITCTL_DATA_READY 0x00010000 | ||
162 | #define NVREG_XMITCTL_DATA_ERROR 0x00020000 | ||
160 | NvRegTransmitterStatus = 0x088, | 163 | NvRegTransmitterStatus = 0x088, |
161 | #define NVREG_XMITSTAT_BUSY 0x01 | 164 | #define NVREG_XMITSTAT_BUSY 0x01 |
162 | 165 | ||
@@ -289,8 +292,10 @@ enum { | |||
289 | #define NVREG_WAKEUPFLAGS_ACCEPT_LINKCHANGE 0x04 | 292 | #define NVREG_WAKEUPFLAGS_ACCEPT_LINKCHANGE 0x04 |
290 | #define NVREG_WAKEUPFLAGS_ENABLE 0x1111 | 293 | #define NVREG_WAKEUPFLAGS_ENABLE 0x1111 |
291 | 294 | ||
292 | NvRegPatternCRC = 0x204, | 295 | NvRegMgmtUnitGetVersion = 0x204, |
293 | NvRegPatternMask = 0x208, | 296 | #define NVREG_MGMTUNITGETVERSION 0x01 |
297 | NvRegMgmtUnitVersion = 0x208, | ||
298 | #define NVREG_MGMTUNITVERSION 0x08 | ||
294 | NvRegPowerCap = 0x268, | 299 | NvRegPowerCap = 0x268, |
295 | #define NVREG_POWERCAP_D3SUPP (1<<30) | 300 | #define NVREG_POWERCAP_D3SUPP (1<<30) |
296 | #define NVREG_POWERCAP_D2SUPP (1<<26) | 301 | #define NVREG_POWERCAP_D2SUPP (1<<26) |
@@ -303,6 +308,8 @@ enum { | |||
303 | #define NVREG_POWERSTATE_D1 0x0001 | 308 | #define NVREG_POWERSTATE_D1 0x0001 |
304 | #define NVREG_POWERSTATE_D2 0x0002 | 309 | #define NVREG_POWERSTATE_D2 0x0002 |
305 | #define NVREG_POWERSTATE_D3 0x0003 | 310 | #define NVREG_POWERSTATE_D3 0x0003 |
311 | NvRegMgmtUnitControl = 0x278, | ||
312 | #define NVREG_MGMTUNITCONTROL_INUSE 0x20000 | ||
306 | NvRegTxCnt = 0x280, | 313 | NvRegTxCnt = 0x280, |
307 | NvRegTxZeroReXmt = 0x284, | 314 | NvRegTxZeroReXmt = 0x284, |
308 | NvRegTxOneReXmt = 0x288, | 315 | NvRegTxOneReXmt = 0x288, |
@@ -758,6 +765,8 @@ struct fe_priv { | |||
758 | u32 register_size; | 765 | u32 register_size; |
759 | int rx_csum; | 766 | int rx_csum; |
760 | u32 mac_in_use; | 767 | u32 mac_in_use; |
768 | int mgmt_version; | ||
769 | int mgmt_sema; | ||
761 | 770 | ||
762 | void __iomem *base; | 771 | void __iomem *base; |
763 | 772 | ||
@@ -5182,6 +5191,7 @@ static void nv_vlan_rx_register(struct net_device *dev, struct vlan_group *grp) | |||
5182 | /* The mgmt unit and driver use a semaphore to access the phy during init */ | 5191 | /* The mgmt unit and driver use a semaphore to access the phy during init */ |
5183 | static int nv_mgmt_acquire_sema(struct net_device *dev) | 5192 | static int nv_mgmt_acquire_sema(struct net_device *dev) |
5184 | { | 5193 | { |
5194 | struct fe_priv *np = netdev_priv(dev); | ||
5185 | u8 __iomem *base = get_hwbase(dev); | 5195 | u8 __iomem *base = get_hwbase(dev); |
5186 | int i; | 5196 | int i; |
5187 | u32 tx_ctrl, mgmt_sema; | 5197 | u32 tx_ctrl, mgmt_sema; |
@@ -5204,8 +5214,10 @@ static int nv_mgmt_acquire_sema(struct net_device *dev) | |||
5204 | /* verify that semaphore was acquired */ | 5214 | /* verify that semaphore was acquired */ |
5205 | tx_ctrl = readl(base + NvRegTransmitterControl); | 5215 | tx_ctrl = readl(base + NvRegTransmitterControl); |
5206 | if (((tx_ctrl & NVREG_XMITCTL_HOST_SEMA_MASK) == NVREG_XMITCTL_HOST_SEMA_ACQ) && | 5216 | if (((tx_ctrl & NVREG_XMITCTL_HOST_SEMA_MASK) == NVREG_XMITCTL_HOST_SEMA_ACQ) && |
5207 | ((tx_ctrl & NVREG_XMITCTL_MGMT_SEMA_MASK) == NVREG_XMITCTL_MGMT_SEMA_FREE)) | 5217 | ((tx_ctrl & NVREG_XMITCTL_MGMT_SEMA_MASK) == NVREG_XMITCTL_MGMT_SEMA_FREE)) { |
5218 | np->mgmt_sema = 1; | ||
5208 | return 1; | 5219 | return 1; |
5220 | } | ||
5209 | else | 5221 | else |
5210 | udelay(50); | 5222 | udelay(50); |
5211 | } | 5223 | } |
@@ -5213,6 +5225,51 @@ static int nv_mgmt_acquire_sema(struct net_device *dev) | |||
5213 | return 0; | 5225 | return 0; |
5214 | } | 5226 | } |
5215 | 5227 | ||
5228 | static void nv_mgmt_release_sema(struct net_device *dev) | ||
5229 | { | ||
5230 | struct fe_priv *np = netdev_priv(dev); | ||
5231 | u8 __iomem *base = get_hwbase(dev); | ||
5232 | u32 tx_ctrl; | ||
5233 | |||
5234 | if (np->driver_data & DEV_HAS_MGMT_UNIT) { | ||
5235 | if (np->mgmt_sema) { | ||
5236 | tx_ctrl = readl(base + NvRegTransmitterControl); | ||
5237 | tx_ctrl &= ~NVREG_XMITCTL_HOST_SEMA_ACQ; | ||
5238 | writel(tx_ctrl, base + NvRegTransmitterControl); | ||
5239 | } | ||
5240 | } | ||
5241 | } | ||
5242 | |||
5243 | |||
5244 | static int nv_mgmt_get_version(struct net_device *dev) | ||
5245 | { | ||
5246 | struct fe_priv *np = netdev_priv(dev); | ||
5247 | u8 __iomem *base = get_hwbase(dev); | ||
5248 | u32 data_ready = readl(base + NvRegTransmitterControl); | ||
5249 | u32 data_ready2 = 0; | ||
5250 | unsigned long start; | ||
5251 | int ready = 0; | ||
5252 | |||
5253 | writel(NVREG_MGMTUNITGETVERSION, base + NvRegMgmtUnitGetVersion); | ||
5254 | writel(data_ready ^ NVREG_XMITCTL_DATA_START, base + NvRegTransmitterControl); | ||
5255 | start = jiffies; | ||
5256 | while (time_before(jiffies, start + 5*HZ)) { | ||
5257 | data_ready2 = readl(base + NvRegTransmitterControl); | ||
5258 | if ((data_ready & NVREG_XMITCTL_DATA_READY) != (data_ready2 & NVREG_XMITCTL_DATA_READY)) { | ||
5259 | ready = 1; | ||
5260 | break; | ||
5261 | } | ||
5262 | schedule_timeout_uninterruptible(1); | ||
5263 | } | ||
5264 | |||
5265 | if (!ready || (data_ready2 & NVREG_XMITCTL_DATA_ERROR)) | ||
5266 | return 0; | ||
5267 | |||
5268 | np->mgmt_version = readl(base + NvRegMgmtUnitVersion) & NVREG_MGMTUNITVERSION; | ||
5269 | |||
5270 | return 1; | ||
5271 | } | ||
5272 | |||
5216 | static int nv_open(struct net_device *dev) | 5273 | static int nv_open(struct net_device *dev) |
5217 | { | 5274 | { |
5218 | struct fe_priv *np = netdev_priv(dev); | 5275 | struct fe_priv *np = netdev_priv(dev); |
@@ -5784,19 +5841,26 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i | |||
5784 | 5841 | ||
5785 | if (id->driver_data & DEV_HAS_MGMT_UNIT) { | 5842 | if (id->driver_data & DEV_HAS_MGMT_UNIT) { |
5786 | /* management unit running on the mac? */ | 5843 | /* management unit running on the mac? */ |
5787 | if (readl(base + NvRegTransmitterControl) & NVREG_XMITCTL_SYNC_PHY_INIT) { | 5844 | if ((readl(base + NvRegTransmitterControl) & NVREG_XMITCTL_MGMT_ST) && |
5788 | np->mac_in_use = readl(base + NvRegTransmitterControl) & NVREG_XMITCTL_MGMT_ST; | 5845 | (readl(base + NvRegTransmitterControl) & NVREG_XMITCTL_SYNC_PHY_INIT) && |
5789 | dprintk(KERN_INFO "%s: mgmt unit is running. mac in use %x.\n", pci_name(pci_dev), np->mac_in_use); | 5846 | nv_mgmt_acquire_sema(dev) && |
5790 | if (nv_mgmt_acquire_sema(dev)) { | 5847 | nv_mgmt_get_version(dev)) { |
5791 | /* management unit setup the phy already? */ | 5848 | np->mac_in_use = 1; |
5792 | if ((readl(base + NvRegTransmitterControl) & NVREG_XMITCTL_SYNC_MASK) == | 5849 | if (np->mgmt_version > 0) { |
5793 | NVREG_XMITCTL_SYNC_PHY_INIT) { | 5850 | np->mac_in_use = readl(base + NvRegMgmtUnitControl) & NVREG_MGMTUNITCONTROL_INUSE; |
5794 | /* phy is inited by mgmt unit */ | 5851 | } |
5795 | phyinitialized = 1; | 5852 | dprintk(KERN_INFO "%s: mgmt unit is running. mac in use %x.\n", |
5796 | dprintk(KERN_INFO "%s: Phy already initialized by mgmt unit.\n", pci_name(pci_dev)); | 5853 | pci_name(pci_dev), np->mac_in_use); |
5797 | } else { | 5854 | /* management unit setup the phy already? */ |
5798 | /* we need to init the phy */ | 5855 | if (np->mac_in_use && |
5799 | } | 5856 | ((readl(base + NvRegTransmitterControl) & NVREG_XMITCTL_SYNC_MASK) == |
5857 | NVREG_XMITCTL_SYNC_PHY_INIT)) { | ||
5858 | /* phy is inited by mgmt unit */ | ||
5859 | phyinitialized = 1; | ||
5860 | dprintk(KERN_INFO "%s: Phy already initialized by mgmt unit.\n", | ||
5861 | pci_name(pci_dev)); | ||
5862 | } else { | ||
5863 | /* we need to init the phy */ | ||
5800 | } | 5864 | } |
5801 | } | 5865 | } |
5802 | } | 5866 | } |
@@ -5958,6 +6022,8 @@ static void __devexit nv_remove(struct pci_dev *pci_dev) | |||
5958 | /* restore any phy related changes */ | 6022 | /* restore any phy related changes */ |
5959 | nv_restore_phy(dev); | 6023 | nv_restore_phy(dev); |
5960 | 6024 | ||
6025 | nv_mgmt_release_sema(dev); | ||
6026 | |||
5961 | /* free all structures */ | 6027 | /* free all structures */ |
5962 | free_rings(dev); | 6028 | free_rings(dev); |
5963 | iounmap(get_hwbase(dev)); | 6029 | iounmap(get_hwbase(dev)); |