From caa06b619f20f21c741e0d7457a0ef633d50ba70 Mon Sep 17 00:00:00 2001 From: Graham Gower Date: Mon, 16 Jan 2006 16:41:37 -0500 Subject: [PATCH 01/76] [PATCH] prism54/islpci_eth.c: dev_kfree_skb used with interrupts disabled dev_kfree_skb should not be used with interrupts disabled. Change to use dev_kfree_skb_irq instead. Signed-off-by: Graham Gower Signed-off-by: John W. Linville --- drivers/net/wireless/prism54/islpci_eth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/prism54/islpci_eth.c b/drivers/net/wireless/prism54/islpci_eth.c index 33d64d2ee53f..a8261d8454dd 100644 --- a/drivers/net/wireless/prism54/islpci_eth.c +++ b/drivers/net/wireless/prism54/islpci_eth.c @@ -177,7 +177,7 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev) #endif newskb->dev = skb->dev; - dev_kfree_skb(skb); + dev_kfree_skb_irq(skb); skb = newskb; } } From 0b8d3256a0c1d75bbe8ef5b0de64843e3fc9f47b Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Thu, 12 Jan 2006 22:17:43 -0800 Subject: [PATCH 02/76] [PATCH] iw_handler.h: SIOCSIWNAME -> SIOCSIWCOMMIT in comment The ioctl was renamed from SIOCSIWNAME to SIOCSIWCOMMIT. Signed-off-by: Pete Zaitcev Signed-off-by: John W. Linville --- include/net/iw_handler.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/net/iw_handler.h b/include/net/iw_handler.h index d67c8393a343..a2c5e0b88422 100644 --- a/include/net/iw_handler.h +++ b/include/net/iw_handler.h @@ -327,7 +327,7 @@ struct iw_handler_def __u16 num_private_args; /* Array of handlers for standard ioctls - * We will call dev->wireless_handlers->standard[ioctl - SIOCSIWNAME] + * We will call dev->wireless_handlers->standard[ioctl - SIOCSIWCOMMIT] */ const iw_handler * standard; From d834a41c966c6a20368fadb59248740935e6fbae Mon Sep 17 00:00:00 2001 From: Olaf Kirch Date: Mon, 9 Jan 2006 17:00:37 +0100 Subject: [PATCH 03/76] [PATCH] ipw2200: do not sleep in ipw_request_direct_scan Drivers should not sleep for very long inside an ioctl - so return EAGAIN and let wpa_supplicant handle the problem. Signed-off-by: Olaf Kirch Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2200.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 819be2b6b7df..4c28e332ecc3 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -8936,14 +8936,12 @@ static int ipw_request_direct_scan(struct ipw_priv *priv, char *essid, IPW_DEBUG_HC("starting request direct scan!\n"); if (priv->status & (STATUS_SCANNING | STATUS_SCAN_ABORTING)) { - err = wait_event_interruptible(priv->wait_state, - !(priv-> - status & (STATUS_SCANNING | - STATUS_SCAN_ABORTING))); - if (err) { - IPW_DEBUG_HC("aborting direct scan"); - goto done; - } + /* We should not sleep here; otherwise we will block most + * of the system (for instance, we hold rtnl_lock when we + * get here). + */ + err = -EAGAIN; + goto done; } memset(&scan, 0, sizeof(scan)); From a485cde662f5b6b2299ee01a7e9e2c11683f807b Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Fri, 30 Dec 2005 18:22:26 -0500 Subject: [PATCH 04/76] [PATCH] hostap: allow flashing firmware Host AP driver has code to support writing firmware to non-volatile memory, a.k.a. flash. This code has been extensively tested when Host AP was a standalone driver. Add a configuration option to the kernel to allow enabling this functionality. Improve the description of the RAM download option. Mention cards that require it. Remove obsolete scary comment. Signed-off-by: Pavel Roskin Signed-off-by: John W. Linville --- drivers/net/wireless/hostap/Kconfig | 22 +++++++++++++++++---- drivers/net/wireless/hostap/hostap_config.h | 13 ++++-------- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/hostap/Kconfig b/drivers/net/wireless/hostap/Kconfig index 56f41c714d38..c8f6286dd35f 100644 --- a/drivers/net/wireless/hostap/Kconfig +++ b/drivers/net/wireless/hostap/Kconfig @@ -26,11 +26,25 @@ config HOSTAP_FIRMWARE depends on HOSTAP ---help--- Configure Host AP driver to include support for firmware image - download. Current version supports only downloading to volatile, i.e., - RAM memory. Flash upgrade is not yet supported. + download. This option by itself only enables downloading to the + volatile memory, i.e. the card RAM. This option is required to + support cards that don't have firmware in flash, such as D-Link + DWL-520 rev E and D-Link DWL-650 rev P. - Firmware image downloading needs user space tool, prism2_srec. It is - available from http://hostap.epitest.fi/. + Firmware image downloading needs a user space tool, prism2_srec. + It is available from http://hostap.epitest.fi/. + +config HOSTAP_FIRMWARE_NVRAM + bool "Support for non-volatile firmware download" + depends on HOSTAP_FIRMWARE + ---help--- + Allow Host AP driver to write firmware images to the non-volatile + card memory, i.e. flash memory that survives power cycling. + Enable this option if you want to be able to change card firmware + permanently. + + Firmware image downloading needs a user space tool, prism2_srec. + It is available from http://hostap.epitest.fi/. config HOSTAP_PLX tristate "Host AP driver for Prism2/2.5/3 in PLX9052 PCI adaptors" diff --git a/drivers/net/wireless/hostap/hostap_config.h b/drivers/net/wireless/hostap/hostap_config.h index 7ed3425d08c1..c090a5aebb58 100644 --- a/drivers/net/wireless/hostap/hostap_config.h +++ b/drivers/net/wireless/hostap/hostap_config.h @@ -21,15 +21,10 @@ #define PRISM2_DOWNLOAD_SUPPORT #endif -#ifdef PRISM2_DOWNLOAD_SUPPORT -/* Allow writing firmware images into flash, i.e., to non-volatile storage. - * Before you enable this option, you should make absolutely sure that you are - * using prism2_srec utility that comes with THIS version of the driver! - * In addition, please note that it is possible to kill your card with - * non-volatile download if you are using incorrect image. This feature has not - * been fully tested, so please be careful with it. */ -/* #define PRISM2_NON_VOLATILE_DOWNLOAD */ -#endif /* PRISM2_DOWNLOAD_SUPPORT */ +/* Allow kernel configuration to enable non-volatile download support. */ +#ifdef CONFIG_HOSTAP_FIRMWARE_NVRAM +#define PRISM2_NON_VOLATILE_DOWNLOAD +#endif /* Save low-level I/O for debugging. This should not be enabled in normal use. */ From d6a13a24b76236ade7fd70081ba41a51e8215578 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 12 Jan 2006 15:00:58 -0500 Subject: [PATCH 05/76] [PATCH] drivers/net/wireless: correct reported ssid lengths ESSIDs can technically include NULL characters. Drivers should not be adjusting the length of the ESSID before reporting it in their SIOCGIWESSID handlers. Breaks stuff like wpa_supplicant. Note that ipw drivers, which seem to currently be the "most correct", don't have this problem. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/airo.c | 2 +- drivers/net/wireless/atmel.c | 4 ++-- drivers/net/wireless/prism54/isl_ioctl.c | 2 +- drivers/net/wireless/ray_cs.c | 2 +- drivers/net/wireless/wavelan_cs.c | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index ee866fd6957d..65057348838b 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -5783,7 +5783,7 @@ static int airo_get_essid(struct net_device *dev, /* If none, we may want to get the one that was set */ /* Push it out ! */ - dwrq->length = status_rid.SSIDlen + 1; + dwrq->length = status_rid.SSIDlen; dwrq->flags = 1; /* active */ return 0; diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index f0ccfef66445..98a76f10a0f7 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -1718,11 +1718,11 @@ static int atmel_get_essid(struct net_device *dev, if (priv->new_SSID_size != 0) { memcpy(extra, priv->new_SSID, priv->new_SSID_size); extra[priv->new_SSID_size] = '\0'; - dwrq->length = priv->new_SSID_size + 1; + dwrq->length = priv->new_SSID_size; } else { memcpy(extra, priv->SSID, priv->SSID_size); extra[priv->SSID_size] = '\0'; - dwrq->length = priv->SSID_size + 1; + dwrq->length = priv->SSID_size; } dwrq->flags = !priv->connect_to_any_BSS; /* active */ diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c index 135a156db25d..c5cd61c7f927 100644 --- a/drivers/net/wireless/prism54/isl_ioctl.c +++ b/drivers/net/wireless/prism54/isl_ioctl.c @@ -748,7 +748,7 @@ prism54_get_essid(struct net_device *ndev, struct iw_request_info *info, if (essid->length) { dwrq->flags = 1; /* set ESSID to ON for Wireless Extensions */ /* if it is to big, trunk it */ - dwrq->length = min(IW_ESSID_MAX_SIZE, essid->length + 1); + dwrq->length = min(IW_ESSID_MAX_SIZE, essid->length); } else { dwrq->flags = 0; dwrq->length = 0; diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 319180ca7e71..7880d8c31aad 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -1256,7 +1256,7 @@ static int ray_get_essid(struct net_device *dev, extra[IW_ESSID_MAX_SIZE] = '\0'; /* Push it out ! */ - dwrq->length = strlen(extra) + 1; + dwrq->length = strlen(extra); dwrq->flags = 1; /* active */ return 0; diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index 7e2039f52c49..cf373625fc70 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c @@ -2280,7 +2280,7 @@ static int wavelan_get_essid(struct net_device *dev, extra[IW_ESSID_MAX_SIZE] = '\0'; /* Set the length */ - wrqu->data.length = strlen(extra) + 1; + wrqu->data.length = strlen(extra); return 0; } From 8aec938389d8409d5d036131c0d16c8b6748703f Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sat, 14 Jan 2006 16:20:53 +0100 Subject: [PATCH 06/76] [PATCH] ipw2100: remove code for WIRELESS_EXT < 18 WIRELESS_EXT < 18 will never be true in the kernel. Signed-off-by: Adrian Bunk Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2100.c | 434 --------------------------------- 1 file changed, 434 deletions(-) diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index 7518384f34d9..8bf02763b5c7 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -5735,70 +5735,6 @@ static struct net_device_stats *ipw2100_stats(struct net_device *dev) return &priv->ieee->stats; } -#if WIRELESS_EXT < 18 -/* Support for wpa_supplicant before WE-18, deprecated. */ - -/* following definitions must match definitions in driver_ipw.c */ - -#define IPW2100_IOCTL_WPA_SUPPLICANT SIOCIWFIRSTPRIV+30 - -#define IPW2100_CMD_SET_WPA_PARAM 1 -#define IPW2100_CMD_SET_WPA_IE 2 -#define IPW2100_CMD_SET_ENCRYPTION 3 -#define IPW2100_CMD_MLME 4 - -#define IPW2100_PARAM_WPA_ENABLED 1 -#define IPW2100_PARAM_TKIP_COUNTERMEASURES 2 -#define IPW2100_PARAM_DROP_UNENCRYPTED 3 -#define IPW2100_PARAM_PRIVACY_INVOKED 4 -#define IPW2100_PARAM_AUTH_ALGS 5 -#define IPW2100_PARAM_IEEE_802_1X 6 - -#define IPW2100_MLME_STA_DEAUTH 1 -#define IPW2100_MLME_STA_DISASSOC 2 - -#define IPW2100_CRYPT_ERR_UNKNOWN_ALG 2 -#define IPW2100_CRYPT_ERR_UNKNOWN_ADDR 3 -#define IPW2100_CRYPT_ERR_CRYPT_INIT_FAILED 4 -#define IPW2100_CRYPT_ERR_KEY_SET_FAILED 5 -#define IPW2100_CRYPT_ERR_TX_KEY_SET_FAILED 6 -#define IPW2100_CRYPT_ERR_CARD_CONF_FAILED 7 - -#define IPW2100_CRYPT_ALG_NAME_LEN 16 - -struct ipw2100_param { - u32 cmd; - u8 sta_addr[ETH_ALEN]; - union { - struct { - u8 name; - u32 value; - } wpa_param; - struct { - u32 len; - u8 reserved[32]; - u8 data[0]; - } wpa_ie; - struct { - u32 command; - u32 reason_code; - } mlme; - struct { - u8 alg[IPW2100_CRYPT_ALG_NAME_LEN]; - u8 set_tx; - u32 err; - u8 idx; - u8 seq[8]; /* sequence counter (set: RX, get: TX) */ - u16 key_len; - u8 key[0]; - } crypt; - - } u; -}; - -/* end of driver_ipw.c code */ -#endif /* WIRELESS_EXT < 18 */ - static int ipw2100_wpa_enable(struct ipw2100_priv *priv, int value) { /* This is called when wpa_supplicant loads and closes the driver @@ -5807,11 +5743,6 @@ static int ipw2100_wpa_enable(struct ipw2100_priv *priv, int value) return 0; } -#if WIRELESS_EXT < 18 -#define IW_AUTH_ALG_OPEN_SYSTEM 0x1 -#define IW_AUTH_ALG_SHARED_KEY 0x2 -#endif - static int ipw2100_wpa_set_auth_algs(struct ipw2100_priv *priv, int value) { @@ -5855,360 +5786,6 @@ void ipw2100_wpa_assoc_frame(struct ipw2100_priv *priv, ipw2100_set_wpa_ie(priv, &frame, 0); } -#if WIRELESS_EXT < 18 -static int ipw2100_wpa_set_param(struct net_device *dev, u8 name, u32 value) -{ - struct ipw2100_priv *priv = ieee80211_priv(dev); - struct ieee80211_crypt_data *crypt; - unsigned long flags; - int ret = 0; - - switch (name) { - case IPW2100_PARAM_WPA_ENABLED: - ret = ipw2100_wpa_enable(priv, value); - break; - - case IPW2100_PARAM_TKIP_COUNTERMEASURES: - crypt = priv->ieee->crypt[priv->ieee->tx_keyidx]; - if (!crypt || !crypt->ops->set_flags || !crypt->ops->get_flags) - break; - - flags = crypt->ops->get_flags(crypt->priv); - - if (value) - flags |= IEEE80211_CRYPTO_TKIP_COUNTERMEASURES; - else - flags &= ~IEEE80211_CRYPTO_TKIP_COUNTERMEASURES; - - crypt->ops->set_flags(flags, crypt->priv); - - break; - - case IPW2100_PARAM_DROP_UNENCRYPTED:{ - /* See IW_AUTH_DROP_UNENCRYPTED handling for details */ - struct ieee80211_security sec = { - .flags = SEC_ENABLED, - .enabled = value, - }; - priv->ieee->drop_unencrypted = value; - /* We only change SEC_LEVEL for open mode. Others - * are set by ipw_wpa_set_encryption. - */ - if (!value) { - sec.flags |= SEC_LEVEL; - sec.level = SEC_LEVEL_0; - } else { - sec.flags |= SEC_LEVEL; - sec.level = SEC_LEVEL_1; - } - if (priv->ieee->set_security) - priv->ieee->set_security(priv->ieee->dev, &sec); - break; - } - - case IPW2100_PARAM_PRIVACY_INVOKED: - priv->ieee->privacy_invoked = value; - break; - - case IPW2100_PARAM_AUTH_ALGS: - ret = ipw2100_wpa_set_auth_algs(priv, value); - break; - - case IPW2100_PARAM_IEEE_802_1X: - priv->ieee->ieee802_1x = value; - break; - - default: - printk(KERN_ERR DRV_NAME ": %s: Unknown WPA param: %d\n", - dev->name, name); - ret = -EOPNOTSUPP; - } - - return ret; -} - -static int ipw2100_wpa_mlme(struct net_device *dev, int command, int reason) -{ - - struct ipw2100_priv *priv = ieee80211_priv(dev); - int ret = 0; - - switch (command) { - case IPW2100_MLME_STA_DEAUTH: - // silently ignore - break; - - case IPW2100_MLME_STA_DISASSOC: - ipw2100_disassociate_bssid(priv); - break; - - default: - printk(KERN_ERR DRV_NAME ": %s: Unknown MLME request: %d\n", - dev->name, command); - ret = -EOPNOTSUPP; - } - - return ret; -} - -static int ipw2100_wpa_set_wpa_ie(struct net_device *dev, - struct ipw2100_param *param, int plen) -{ - - struct ipw2100_priv *priv = ieee80211_priv(dev); - struct ieee80211_device *ieee = priv->ieee; - u8 *buf; - - if (!ieee->wpa_enabled) - return -EOPNOTSUPP; - - if (param->u.wpa_ie.len > MAX_WPA_IE_LEN || - (param->u.wpa_ie.len && param->u.wpa_ie.data == NULL)) - return -EINVAL; - - if (param->u.wpa_ie.len) { - buf = kmalloc(param->u.wpa_ie.len, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - memcpy(buf, param->u.wpa_ie.data, param->u.wpa_ie.len); - - kfree(ieee->wpa_ie); - ieee->wpa_ie = buf; - ieee->wpa_ie_len = param->u.wpa_ie.len; - - } else { - kfree(ieee->wpa_ie); - ieee->wpa_ie = NULL; - ieee->wpa_ie_len = 0; - } - - ipw2100_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len); - - return 0; -} - -/* implementation borrowed from hostap driver */ - -static int ipw2100_wpa_set_encryption(struct net_device *dev, - struct ipw2100_param *param, - int param_len) -{ - int ret = 0; - struct ipw2100_priv *priv = ieee80211_priv(dev); - struct ieee80211_device *ieee = priv->ieee; - struct ieee80211_crypto_ops *ops; - struct ieee80211_crypt_data **crypt; - - struct ieee80211_security sec = { - .flags = 0, - }; - - param->u.crypt.err = 0; - param->u.crypt.alg[IPW2100_CRYPT_ALG_NAME_LEN - 1] = '\0'; - - if (param_len != - (int)((char *)param->u.crypt.key - (char *)param) + - param->u.crypt.key_len) { - IPW_DEBUG_INFO("Len mismatch %d, %d\n", param_len, - param->u.crypt.key_len); - return -EINVAL; - } - if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && - param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && - param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { - if (param->u.crypt.idx >= WEP_KEYS) - return -EINVAL; - crypt = &ieee->crypt[param->u.crypt.idx]; - } else { - return -EINVAL; - } - - sec.flags |= SEC_ENABLED | SEC_ENCRYPT; - if (strcmp(param->u.crypt.alg, "none") == 0) { - if (crypt) { - sec.enabled = 0; - sec.encrypt = 0; - sec.level = SEC_LEVEL_0; - sec.flags |= SEC_LEVEL; - ieee80211_crypt_delayed_deinit(ieee, crypt); - } - goto done; - } - sec.enabled = 1; - sec.encrypt = 1; - - ops = ieee80211_get_crypto_ops(param->u.crypt.alg); - if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0) { - request_module("ieee80211_crypt_wep"); - ops = ieee80211_get_crypto_ops(param->u.crypt.alg); - } else if (ops == NULL && strcmp(param->u.crypt.alg, "TKIP") == 0) { - request_module("ieee80211_crypt_tkip"); - ops = ieee80211_get_crypto_ops(param->u.crypt.alg); - } else if (ops == NULL && strcmp(param->u.crypt.alg, "CCMP") == 0) { - request_module("ieee80211_crypt_ccmp"); - ops = ieee80211_get_crypto_ops(param->u.crypt.alg); - } - if (ops == NULL) { - IPW_DEBUG_INFO("%s: unknown crypto alg '%s'\n", - dev->name, param->u.crypt.alg); - param->u.crypt.err = IPW2100_CRYPT_ERR_UNKNOWN_ALG; - ret = -EINVAL; - goto done; - } - - if (*crypt == NULL || (*crypt)->ops != ops) { - struct ieee80211_crypt_data *new_crypt; - - ieee80211_crypt_delayed_deinit(ieee, crypt); - - new_crypt = kzalloc(sizeof(struct ieee80211_crypt_data), GFP_KERNEL); - if (new_crypt == NULL) { - ret = -ENOMEM; - goto done; - } - new_crypt->ops = ops; - if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) - new_crypt->priv = - new_crypt->ops->init(param->u.crypt.idx); - - if (new_crypt->priv == NULL) { - kfree(new_crypt); - param->u.crypt.err = - IPW2100_CRYPT_ERR_CRYPT_INIT_FAILED; - ret = -EINVAL; - goto done; - } - - *crypt = new_crypt; - } - - if (param->u.crypt.key_len > 0 && (*crypt)->ops->set_key && - (*crypt)->ops->set_key(param->u.crypt.key, - param->u.crypt.key_len, param->u.crypt.seq, - (*crypt)->priv) < 0) { - IPW_DEBUG_INFO("%s: key setting failed\n", dev->name); - param->u.crypt.err = IPW2100_CRYPT_ERR_KEY_SET_FAILED; - ret = -EINVAL; - goto done; - } - - if (param->u.crypt.set_tx) { - ieee->tx_keyidx = param->u.crypt.idx; - sec.active_key = param->u.crypt.idx; - sec.flags |= SEC_ACTIVE_KEY; - } - - if (ops->name != NULL) { - - if (strcmp(ops->name, "WEP") == 0) { - memcpy(sec.keys[param->u.crypt.idx], - param->u.crypt.key, param->u.crypt.key_len); - sec.key_sizes[param->u.crypt.idx] = - param->u.crypt.key_len; - sec.flags |= (1 << param->u.crypt.idx); - sec.flags |= SEC_LEVEL; - sec.level = SEC_LEVEL_1; - } else if (strcmp(ops->name, "TKIP") == 0) { - sec.flags |= SEC_LEVEL; - sec.level = SEC_LEVEL_2; - } else if (strcmp(ops->name, "CCMP") == 0) { - sec.flags |= SEC_LEVEL; - sec.level = SEC_LEVEL_3; - } - } - done: - if (ieee->set_security) - ieee->set_security(ieee->dev, &sec); - - /* Do not reset port if card is in Managed mode since resetting will - * generate new IEEE 802.11 authentication which may end up in looping - * with IEEE 802.1X. If your hardware requires a reset after WEP - * configuration (for example... Prism2), implement the reset_port in - * the callbacks structures used to initialize the 802.11 stack. */ - if (ieee->reset_on_keychange && - ieee->iw_mode != IW_MODE_INFRA && - ieee->reset_port && ieee->reset_port(dev)) { - IPW_DEBUG_INFO("%s: reset_port failed\n", dev->name); - param->u.crypt.err = IPW2100_CRYPT_ERR_CARD_CONF_FAILED; - return -EINVAL; - } - - return ret; -} - -static int ipw2100_wpa_supplicant(struct net_device *dev, struct iw_point *p) -{ - - struct ipw2100_param *param; - int ret = 0; - - IPW_DEBUG_IOCTL("wpa_supplicant: len=%d\n", p->length); - - if (p->length < sizeof(struct ipw2100_param) || !p->pointer) - return -EINVAL; - - param = (struct ipw2100_param *)kmalloc(p->length, GFP_KERNEL); - if (param == NULL) - return -ENOMEM; - - if (copy_from_user(param, p->pointer, p->length)) { - kfree(param); - return -EFAULT; - } - - switch (param->cmd) { - - case IPW2100_CMD_SET_WPA_PARAM: - ret = ipw2100_wpa_set_param(dev, param->u.wpa_param.name, - param->u.wpa_param.value); - break; - - case IPW2100_CMD_SET_WPA_IE: - ret = ipw2100_wpa_set_wpa_ie(dev, param, p->length); - break; - - case IPW2100_CMD_SET_ENCRYPTION: - ret = ipw2100_wpa_set_encryption(dev, param, p->length); - break; - - case IPW2100_CMD_MLME: - ret = ipw2100_wpa_mlme(dev, param->u.mlme.command, - param->u.mlme.reason_code); - break; - - default: - printk(KERN_ERR DRV_NAME - ": %s: Unknown WPA supplicant request: %d\n", dev->name, - param->cmd); - ret = -EOPNOTSUPP; - - } - - if (ret == 0 && copy_to_user(p->pointer, param, p->length)) - ret = -EFAULT; - - kfree(param); - return ret; -} - -static int ipw2100_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct iwreq *wrq = (struct iwreq *)rq; - int ret = -1; - switch (cmd) { - case IPW2100_IOCTL_WPA_SUPPLICANT: - ret = ipw2100_wpa_supplicant(dev, &wrq->u.data); - return ret; - - default: - return -EOPNOTSUPP; - } - - return -EOPNOTSUPP; -} -#endif /* WIRELESS_EXT < 18 */ - static void ipw_ethtool_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { @@ -6337,9 +5914,6 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev, dev->open = ipw2100_open; dev->stop = ipw2100_close; dev->init = ipw2100_net_init; -#if WIRELESS_EXT < 18 - dev->do_ioctl = ipw2100_ioctl; -#endif dev->get_stats = ipw2100_stats; dev->ethtool_ops = &ipw2100_ethtool_ops; dev->tx_timeout = ipw2100_tx_timeout; @@ -7855,7 +7429,6 @@ static int ipw2100_wx_get_power(struct net_device *dev, return 0; } -#if WIRELESS_EXT > 17 /* * WE-18 WPA support */ @@ -8117,7 +7690,6 @@ static int ipw2100_wx_set_mlme(struct net_device *dev, } return 0; } -#endif /* WIRELESS_EXT > 17 */ /* * @@ -8350,11 +7922,7 @@ static iw_handler ipw2100_wx_handlers[] = { NULL, /* SIOCWIWTHRSPY */ ipw2100_wx_set_wap, /* SIOCSIWAP */ ipw2100_wx_get_wap, /* SIOCGIWAP */ -#if WIRELESS_EXT > 17 ipw2100_wx_set_mlme, /* SIOCSIWMLME */ -#else - NULL, /* -- hole -- */ -#endif NULL, /* SIOCGIWAPLIST -- deprecated */ ipw2100_wx_set_scan, /* SIOCSIWSCAN */ ipw2100_wx_get_scan, /* SIOCGIWSCAN */ @@ -8378,7 +7946,6 @@ static iw_handler ipw2100_wx_handlers[] = { ipw2100_wx_get_encode, /* SIOCGIWENCODE */ ipw2100_wx_set_power, /* SIOCSIWPOWER */ ipw2100_wx_get_power, /* SIOCGIWPOWER */ -#if WIRELESS_EXT > 17 NULL, /* -- hole -- */ NULL, /* -- hole -- */ ipw2100_wx_set_genie, /* SIOCSIWGENIE */ @@ -8388,7 +7955,6 @@ static iw_handler ipw2100_wx_handlers[] = { ipw2100_wx_set_encodeext, /* SIOCSIWENCODEEXT */ ipw2100_wx_get_encodeext, /* SIOCGIWENCODEEXT */ NULL, /* SIOCSIWPMKSA */ -#endif }; #define IPW2100_PRIV_SET_MONITOR SIOCIWFIRSTPRIV From 5fad5a2e1f34b333a801b749c4e143c2ac3e8a4f Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sat, 14 Jan 2006 03:09:34 +0100 Subject: [PATCH 07/76] [PATCH] hostap: don't #include C files in hostap_main.c This patch contains an attempt to properly build hostap.o without #include'ing C files. Signed-off-by: Adrian Bunk Signed-off-by: John W. Linville --- drivers/net/wireless/hostap/Makefile | 3 +- drivers/net/wireless/hostap/hostap.h | 37 ++++++++++++ drivers/net/wireless/hostap/hostap_80211.h | 3 + drivers/net/wireless/hostap/hostap_80211_rx.c | 11 ++++ drivers/net/wireless/hostap/hostap_80211_tx.c | 15 +++++ drivers/net/wireless/hostap/hostap_ap.c | 36 ++++++----- drivers/net/wireless/hostap/hostap_ap.h | 2 + drivers/net/wireless/hostap/hostap_common.h | 3 + drivers/net/wireless/hostap/hostap_info.c | 3 + drivers/net/wireless/hostap/hostap_ioctl.c | 12 ++-- drivers/net/wireless/hostap/hostap_main.c | 60 ++----------------- drivers/net/wireless/hostap/hostap_proc.c | 7 +++ drivers/net/wireless/hostap/hostap_wlan.h | 4 ++ include/net/ieee80211_crypt.h | 1 + 14 files changed, 120 insertions(+), 77 deletions(-) diff --git a/drivers/net/wireless/hostap/Makefile b/drivers/net/wireless/hostap/Makefile index 353ccb93134b..b8e41a702c00 100644 --- a/drivers/net/wireless/hostap/Makefile +++ b/drivers/net/wireless/hostap/Makefile @@ -1,4 +1,5 @@ -hostap-y := hostap_main.o +hostap-y := hostap_80211_rx.o hostap_80211_tx.o hostap_ap.o hostap_info.o \ + hostap_ioctl.o hostap_main.o hostap_proc.o obj-$(CONFIG_HOSTAP) += hostap.o obj-$(CONFIG_HOSTAP_CS) += hostap_cs.o diff --git a/drivers/net/wireless/hostap/hostap.h b/drivers/net/wireless/hostap/hostap.h index 5fac89b8ce3a..5e63765219fe 100644 --- a/drivers/net/wireless/hostap/hostap.h +++ b/drivers/net/wireless/hostap/hostap.h @@ -1,6 +1,15 @@ #ifndef HOSTAP_H #define HOSTAP_H +#include + +#include "hostap_wlan.h" +#include "hostap_ap.h" + +static const long freq_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, + 2447, 2452, 2457, 2462, 2467, 2472, 2484 }; +#define FREQ_COUNT (sizeof(freq_list) / sizeof(freq_list[0])) + /* hostap.c */ extern struct proc_dir_entry *hostap_proc; @@ -40,6 +49,26 @@ int prism2_update_comms_qual(struct net_device *dev); int prism2_sta_send_mgmt(local_info_t *local, u8 *dst, u16 stype, u8 *body, size_t bodylen); int prism2_sta_deauth(local_info_t *local, u16 reason); +int prism2_wds_add(local_info_t *local, u8 *remote_addr, + int rtnl_locked); +int prism2_wds_del(local_info_t *local, u8 *remote_addr, + int rtnl_locked, int do_not_remove); + + +/* hostap_ap.c */ + +int ap_control_add_mac(struct mac_restrictions *mac_restrictions, u8 *mac); +int ap_control_del_mac(struct mac_restrictions *mac_restrictions, u8 *mac); +void ap_control_flush_macs(struct mac_restrictions *mac_restrictions); +int ap_control_kick_mac(struct ap_data *ap, struct net_device *dev, u8 *mac); +void ap_control_kickall(struct ap_data *ap); +void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent, + struct ieee80211_crypt_data ***crypt); +int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[], + struct iw_quality qual[], int buf_size, + int aplist); +int prism2_ap_translate_scan(struct net_device *dev, char *buffer); +int prism2_hostapd(struct ap_data *ap, struct prism2_hostapd_param *param); /* hostap_proc.c */ @@ -54,4 +83,12 @@ void hostap_info_init(local_info_t *local); void hostap_info_process(local_info_t *local, struct sk_buff *skb); +/* hostap_ioctl.c */ + +extern const struct iw_handler_def hostap_iw_handler_def; +extern struct ethtool_ops prism2_ethtool_ops; + +int hostap_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); + + #endif /* HOSTAP_H */ diff --git a/drivers/net/wireless/hostap/hostap_80211.h b/drivers/net/wireless/hostap/hostap_80211.h index bf506f50d722..1fc72fe511e9 100644 --- a/drivers/net/wireless/hostap/hostap_80211.h +++ b/drivers/net/wireless/hostap/hostap_80211.h @@ -1,6 +1,9 @@ #ifndef HOSTAP_80211_H #define HOSTAP_80211_H +#include +#include + struct hostap_ieee80211_mgmt { u16 frame_control; u16 duration; diff --git a/drivers/net/wireless/hostap/hostap_80211_rx.c b/drivers/net/wireless/hostap/hostap_80211_rx.c index 4b13b76425c1..7e04dc94b3bc 100644 --- a/drivers/net/wireless/hostap/hostap_80211_rx.c +++ b/drivers/net/wireless/hostap/hostap_80211_rx.c @@ -1,7 +1,18 @@ #include +#include #include "hostap_80211.h" #include "hostap.h" +#include "hostap_ap.h" + +/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ +/* Ethernet-II snap header (RFC1042 for most EtherTypes) */ +static unsigned char rfc1042_header[] = +{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; +/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ +static unsigned char bridge_tunnel_header[] = +{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; +/* No encapsulation header if EtherType < 0x600 (=length) */ void hostap_dump_rx_80211(const char *name, struct sk_buff *skb, struct hostap_80211_rx_status *rx_stats) diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c index 9d24f8a38ac5..4a85e63906f1 100644 --- a/drivers/net/wireless/hostap/hostap_80211_tx.c +++ b/drivers/net/wireless/hostap/hostap_80211_tx.c @@ -1,3 +1,18 @@ +#include "hostap_80211.h" +#include "hostap_common.h" +#include "hostap_wlan.h" +#include "hostap.h" +#include "hostap_ap.h" + +/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ +/* Ethernet-II snap header (RFC1042 for most EtherTypes) */ +static unsigned char rfc1042_header[] = +{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; +/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ +static unsigned char bridge_tunnel_header[] = +{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; +/* No encapsulation header if EtherType < 0x600 (=length) */ + void hostap_dump_tx_80211(const char *name, struct sk_buff *skb) { struct ieee80211_hdr_4addr *hdr; diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c index 9da94ab7f05f..753a1de6664b 100644 --- a/drivers/net/wireless/hostap/hostap_ap.c +++ b/drivers/net/wireless/hostap/hostap_ap.c @@ -16,6 +16,14 @@ * (8802.11: 5.5) */ +#include +#include +#include + +#include "hostap_wlan.h" +#include "hostap.h" +#include "hostap_ap.h" + static int other_ap_policy[MAX_PARM_DEVICES] = { AP_OTHER_AP_SKIP_ALL, DEF_INTS }; module_param_array(other_ap_policy, int, NULL, 0444); @@ -360,8 +368,7 @@ static int ap_control_proc_read(char *page, char **start, off_t off, } -static int ap_control_add_mac(struct mac_restrictions *mac_restrictions, - u8 *mac) +int ap_control_add_mac(struct mac_restrictions *mac_restrictions, u8 *mac) { struct mac_entry *entry; @@ -380,8 +387,7 @@ static int ap_control_add_mac(struct mac_restrictions *mac_restrictions, } -static int ap_control_del_mac(struct mac_restrictions *mac_restrictions, - u8 *mac) +int ap_control_del_mac(struct mac_restrictions *mac_restrictions, u8 *mac) { struct list_head *ptr; struct mac_entry *entry; @@ -433,7 +439,7 @@ static int ap_control_mac_deny(struct mac_restrictions *mac_restrictions, } -static void ap_control_flush_macs(struct mac_restrictions *mac_restrictions) +void ap_control_flush_macs(struct mac_restrictions *mac_restrictions) { struct list_head *ptr, *n; struct mac_entry *entry; @@ -454,8 +460,7 @@ static void ap_control_flush_macs(struct mac_restrictions *mac_restrictions) } -static int ap_control_kick_mac(struct ap_data *ap, struct net_device *dev, - u8 *mac) +int ap_control_kick_mac(struct ap_data *ap, struct net_device *dev, u8 *mac) { struct sta_info *sta; u16 resp; @@ -486,7 +491,7 @@ static int ap_control_kick_mac(struct ap_data *ap, struct net_device *dev, #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ -static void ap_control_kickall(struct ap_data *ap) +void ap_control_kickall(struct ap_data *ap) { struct list_head *ptr, *n; struct sta_info *sta; @@ -2321,9 +2326,9 @@ static void schedule_packet_send(local_info_t *local, struct sta_info *sta) } -static int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[], - struct iw_quality qual[], int buf_size, - int aplist) +int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[], + struct iw_quality qual[], int buf_size, + int aplist) { struct ap_data *ap = local->ap; struct list_head *ptr; @@ -2363,7 +2368,7 @@ static int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[], /* Translate our list of Access Points & Stations to a card independant * format that the Wireless Tools will understand - Jean II */ -static int prism2_ap_translate_scan(struct net_device *dev, char *buffer) +int prism2_ap_translate_scan(struct net_device *dev, char *buffer) { struct hostap_interface *iface; local_info_t *local; @@ -2608,8 +2613,7 @@ static int prism2_hostapd_sta_clear_stats(struct ap_data *ap, } -static int prism2_hostapd(struct ap_data *ap, - struct prism2_hostapd_param *param) +int prism2_hostapd(struct ap_data *ap, struct prism2_hostapd_param *param) { switch (param->cmd) { case PRISM2_HOSTAPD_FLUSH: @@ -3207,8 +3211,8 @@ void hostap_update_rates(local_info_t *local) } -static void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent, - struct ieee80211_crypt_data ***crypt) +void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent, + struct ieee80211_crypt_data ***crypt) { struct sta_info *sta; diff --git a/drivers/net/wireless/hostap/hostap_ap.h b/drivers/net/wireless/hostap/hostap_ap.h index 6d00df69c2e3..2fa2452b6b07 100644 --- a/drivers/net/wireless/hostap/hostap_ap.h +++ b/drivers/net/wireless/hostap/hostap_ap.h @@ -1,6 +1,8 @@ #ifndef HOSTAP_AP_H #define HOSTAP_AP_H +#include "hostap_80211.h" + /* AP data structures for STAs */ /* maximum number of frames to buffer per STA */ diff --git a/drivers/net/wireless/hostap/hostap_common.h b/drivers/net/wireless/hostap/hostap_common.h index 6f4fa9dc308f..01624005d808 100644 --- a/drivers/net/wireless/hostap/hostap_common.h +++ b/drivers/net/wireless/hostap/hostap_common.h @@ -1,6 +1,9 @@ #ifndef HOSTAP_COMMON_H #define HOSTAP_COMMON_H +#include +#include + #define BIT(x) (1 << (x)) #define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] diff --git a/drivers/net/wireless/hostap/hostap_info.c b/drivers/net/wireless/hostap/hostap_info.c index 5aa998fdf1c4..50f72d831cf4 100644 --- a/drivers/net/wireless/hostap/hostap_info.c +++ b/drivers/net/wireless/hostap/hostap_info.c @@ -1,5 +1,8 @@ /* Host AP driver Info Frame processing (part of hostap.o module) */ +#include "hostap_wlan.h" +#include "hostap.h" +#include "hostap_ap.h" /* Called only as a tasklet (software IRQ) */ static void prism2_info_commtallies16(local_info_t *local, unsigned char *buf, diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c index 2617d70bcda9..f3e0ce1ee037 100644 --- a/drivers/net/wireless/hostap/hostap_ioctl.c +++ b/drivers/net/wireless/hostap/hostap_ioctl.c @@ -1,11 +1,13 @@ /* ioctl() (mostly Linux Wireless Extensions) routines for Host AP driver */ -#ifdef in_atomic -/* Get kernel_locked() for in_atomic() */ +#include #include -#endif #include +#include +#include "hostap_wlan.h" +#include "hostap.h" +#include "hostap_ap.h" static struct iw_statistics *hostap_get_wireless_stats(struct net_device *dev) { @@ -3910,7 +3912,7 @@ static void prism2_get_drvinfo(struct net_device *dev, local->sta_fw_ver & 0xff); } -static struct ethtool_ops prism2_ethtool_ops = { +struct ethtool_ops prism2_ethtool_ops = { .get_drvinfo = prism2_get_drvinfo }; @@ -3985,7 +3987,7 @@ static const iw_handler prism2_private_handler[] = (iw_handler) prism2_ioctl_priv_readmif, /* 3 */ }; -static const struct iw_handler_def hostap_iw_handler_def = +const struct iw_handler_def hostap_iw_handler_def = { .num_standard = sizeof(prism2_handler) / sizeof(iw_handler), .num_private = sizeof(prism2_private_handler) / sizeof(iw_handler), diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c index 3d2ea61033be..8dd4c4446a64 100644 --- a/drivers/net/wireless/hostap/hostap_main.c +++ b/drivers/net/wireless/hostap/hostap_main.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -47,57 +48,6 @@ MODULE_VERSION(PRISM2_VERSION); #define PRISM2_MAX_MTU (PRISM2_MAX_FRAME_SIZE - (6 /* LLC */ + 8 /* WEP */)) -/* hostap.c */ -static int prism2_wds_add(local_info_t *local, u8 *remote_addr, - int rtnl_locked); -static int prism2_wds_del(local_info_t *local, u8 *remote_addr, - int rtnl_locked, int do_not_remove); - -/* hostap_ap.c */ -static int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[], - struct iw_quality qual[], int buf_size, - int aplist); -static int prism2_ap_translate_scan(struct net_device *dev, char *buffer); -static int prism2_hostapd(struct ap_data *ap, - struct prism2_hostapd_param *param); -static void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent, - struct ieee80211_crypt_data ***crypt); -static void ap_control_kickall(struct ap_data *ap); -#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT -static int ap_control_add_mac(struct mac_restrictions *mac_restrictions, - u8 *mac); -static int ap_control_del_mac(struct mac_restrictions *mac_restrictions, - u8 *mac); -static void ap_control_flush_macs(struct mac_restrictions *mac_restrictions); -static int ap_control_kick_mac(struct ap_data *ap, struct net_device *dev, - u8 *mac); -#endif /* !PRISM2_NO_KERNEL_IEEE80211_MGMT */ - - -static const long freq_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, - 2447, 2452, 2457, 2462, 2467, 2472, 2484 }; -#define FREQ_COUNT (sizeof(freq_list) / sizeof(freq_list[0])) - - -/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ -/* Ethernet-II snap header (RFC1042 for most EtherTypes) */ -static unsigned char rfc1042_header[] = -{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; -/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ -static unsigned char bridge_tunnel_header[] = -{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; -/* No encapsulation header if EtherType < 0x600 (=length) */ - - -/* FIX: these could be compiled separately and linked together to hostap.o */ -#include "hostap_ap.c" -#include "hostap_info.c" -#include "hostap_ioctl.c" -#include "hostap_proc.c" -#include "hostap_80211_rx.c" -#include "hostap_80211_tx.c" - - struct net_device * hostap_add_interface(struct local_info *local, int type, int rtnl_locked, const char *prefix, @@ -196,8 +146,8 @@ static inline int prism2_wds_special_addr(u8 *addr) } -static int prism2_wds_add(local_info_t *local, u8 *remote_addr, - int rtnl_locked) +int prism2_wds_add(local_info_t *local, u8 *remote_addr, + int rtnl_locked) { struct net_device *dev; struct list_head *ptr; @@ -258,8 +208,8 @@ static int prism2_wds_add(local_info_t *local, u8 *remote_addr, } -static int prism2_wds_del(local_info_t *local, u8 *remote_addr, - int rtnl_locked, int do_not_remove) +int prism2_wds_del(local_info_t *local, u8 *remote_addr, + int rtnl_locked, int do_not_remove) { unsigned long flags; struct list_head *ptr; diff --git a/drivers/net/wireless/hostap/hostap_proc.c b/drivers/net/wireless/hostap/hostap_proc.c index a0a4cbd4937a..d1d8ce022e63 100644 --- a/drivers/net/wireless/hostap/hostap_proc.c +++ b/drivers/net/wireless/hostap/hostap_proc.c @@ -1,5 +1,12 @@ /* /proc routines for Host AP driver */ +#include +#include +#include + +#include "hostap_wlan.h" +#include "hostap.h" + #define PROC_LIMIT (PAGE_SIZE - 80) diff --git a/drivers/net/wireless/hostap/hostap_wlan.h b/drivers/net/wireless/hostap/hostap_wlan.h index cfd801559492..87a54aa6f4dd 100644 --- a/drivers/net/wireless/hostap/hostap_wlan.h +++ b/drivers/net/wireless/hostap/hostap_wlan.h @@ -1,6 +1,10 @@ #ifndef HOSTAP_WLAN_H #define HOSTAP_WLAN_H +#include +#include +#include + #include "hostap_config.h" #include "hostap_common.h" diff --git a/include/net/ieee80211_crypt.h b/include/net/ieee80211_crypt.h index 03b766afdc39..cd82c3e998e4 100644 --- a/include/net/ieee80211_crypt.h +++ b/include/net/ieee80211_crypt.h @@ -25,6 +25,7 @@ #include #include +#include #include enum { From b60d6975e80ac69e4b797173857eeb5362e265a2 Mon Sep 17 00:00:00 2001 From: Dale Farnsworth Date: Mon, 16 Jan 2006 16:45:45 -0700 Subject: [PATCH 08/76] [PATCH] mv643xx_eth: Add Dale Farnsworth as a maintainer MAINTAINERS | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) Signed-off-by: Dale Farnsworth Signed-off-by: Jeff Garzik --- MAINTAINERS | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 6d1b048c62a1..ff16eac8cf5b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1696,11 +1696,13 @@ M: mtk-manpages@gmx.net W: ftp://ftp.kernel.org/pub/linux/docs/manpages S: Maintained -MARVELL MV64340 ETHERNET DRIVER +MARVELL MV643XX ETHERNET DRIVER +P: Dale Farnsworth +M: dale@farnsworth.org P: Manish Lachwani -L: linux-mips@linux-mips.org +M: mlachwani@mvista.com L: netdev@vger.kernel.org -S: Supported +S: Odd Fixes for 2.4; Maintained for 2.6. MATROX FRAMEBUFFER DRIVER P: Petr Vandrovec From 78a5e534758349fd3effc90ce1152b55368f52ee Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Mon, 16 Jan 2006 16:47:00 -0700 Subject: [PATCH 09/76] [PATCH] mv643xx_eth: 2.6.16 needs ip.h and in.h Signed-off-by: Olaf Hering Signed-off-by: Dale Farnsworth mv643xx_eth.c | 2 ++ 1 file changed, 2 insertions(+) Signed-off-by: Jeff Garzik --- drivers/net/mv643xx_eth.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 22c3a37bba5a..a6152db82e9c 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -35,6 +35,8 @@ #include #include #include +#include +#include #include #include From cb415d30048f0c1f80fd2f5340a982e8c9617d0d Mon Sep 17 00:00:00 2001 From: Paolo Galtieri Date: Mon, 16 Jan 2006 16:48:02 -0700 Subject: [PATCH 10/76] [PATCH] mv643xx_eth: Fix dma_map/dma_unmap relations If you do a dma_map_single you must do dma_unmap_single and if you do a dma_map_page you must do a dma_unmap_page. Signed-off-by: Paolo Galtieri Signed-off-by: Dale Farnsworth mv643xx_eth.c | 51 +++++++++++++++++++++------------------------------ 1 file changed, 21 insertions(+), 30 deletions(-) Signed-off-by: Jeff Garzik --- drivers/net/mv643xx_eth.c | 51 +++++++++++++++------------------------ 1 file changed, 20 insertions(+), 31 deletions(-) diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index a6152db82e9c..fe53fa0e3aed 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -353,27 +353,19 @@ static int mv643xx_eth_free_tx_queue(struct net_device *dev, stats->tx_errors++; } - /* - * If return_info is different than 0, release the skb. - * The case where return_info is not 0 is only in case - * when transmitted a scatter/gather packet, where only - * last skb releases the whole chain. - */ - if (pkt_info.return_info) { - if (skb_shinfo(pkt_info.return_info)->nr_frags) - dma_unmap_page(NULL, pkt_info.buf_ptr, - pkt_info.byte_cnt, - DMA_TO_DEVICE); - else - dma_unmap_single(NULL, pkt_info.buf_ptr, - pkt_info.byte_cnt, - DMA_TO_DEVICE); + if (pkt_info.cmd_sts & ETH_TX_FIRST_DESC) + dma_unmap_single(NULL, pkt_info.buf_ptr, + pkt_info.byte_cnt, + DMA_TO_DEVICE); + else + dma_unmap_page(NULL, pkt_info.buf_ptr, + pkt_info.byte_cnt, + DMA_TO_DEVICE); + if (pkt_info.return_info) { dev_kfree_skb_irq(pkt_info.return_info); released = 0; - } else - dma_unmap_page(NULL, pkt_info.buf_ptr, - pkt_info.byte_cnt, DMA_TO_DEVICE); + } } spin_unlock(&mp->lock); @@ -1024,20 +1016,17 @@ static void mv643xx_tx(struct net_device *dev) struct pkt_info pkt_info; while (eth_tx_return_desc(mp, &pkt_info) == ETH_OK) { - if (pkt_info.return_info) { - if (skb_shinfo(pkt_info.return_info)->nr_frags) - dma_unmap_page(NULL, pkt_info.buf_ptr, - pkt_info.byte_cnt, - DMA_TO_DEVICE); - else - dma_unmap_single(NULL, pkt_info.buf_ptr, - pkt_info.byte_cnt, - DMA_TO_DEVICE); - - dev_kfree_skb_irq(pkt_info.return_info); - } else + if (pkt_info.cmd_sts & ETH_TX_FIRST_DESC) + dma_unmap_single(NULL, pkt_info.buf_ptr, + pkt_info.byte_cnt, + DMA_TO_DEVICE); + else dma_unmap_page(NULL, pkt_info.buf_ptr, - pkt_info.byte_cnt, DMA_TO_DEVICE); + pkt_info.byte_cnt, + DMA_TO_DEVICE); + + if (pkt_info.return_info) + dev_kfree_skb_irq(pkt_info.return_info); } if (netif_queue_stopped(dev) && From 4eaa3cb35b22cccc53846ce2820e244b1fb04f0b Mon Sep 17 00:00:00 2001 From: Paolo Galtieri Date: Mon, 16 Jan 2006 16:48:58 -0700 Subject: [PATCH 11/76] [PATCH] mv643xx_eth: Fix a NULL pointer dereference Fix a NULL pointer dereference. Fill in the buf_ptr and byte_cnt fields of pkt_info in eth_tx_return_desc(). Signed-off-by: Paolo Galtieri Signed-off-by: Dale Farnsworth mv643xx_eth.c | 51 +++++++++++++++++++++------------------------------ 1 file changed, 21 insertions(+), 30 deletions(-) Signed-off-by: Jeff Garzik --- drivers/net/mv643xx_eth.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index fe53fa0e3aed..88a59d9715ac 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -2660,6 +2660,8 @@ static ETH_FUNC_RET_STATUS eth_tx_return_desc(struct mv643xx_private *mp, /* Pass the packet information to the caller */ p_pkt_info->cmd_sts = command_status; p_pkt_info->return_info = mp->tx_skb[tx_desc_used]; + p_pkt_info->buf_ptr = p_tx_desc_used->buf_ptr; + p_pkt_info->byte_cnt = p_tx_desc_used->byte_cnt; mp->tx_skb[tx_desc_used] = NULL; /* Update the next descriptor to release. */ From 16e0301831767ee1b8e5e022cc08e76f9f8a8938 Mon Sep 17 00:00:00 2001 From: Dale Farnsworth Date: Mon, 16 Jan 2006 16:50:02 -0700 Subject: [PATCH 12/76] [PATCH] mv643xx_eth: Add multicast support This code is adapted from code in a ppc-specific version of the driver. Signed-off-by: Dale Farnsworth mv643xx_eth.c | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 197 insertions(+), 4 deletions(-) Signed-off-by: Jeff Garzik --- drivers/net/mv643xx_eth.c | 201 +++++++++++++++++++++++++++++++++++++- 1 file changed, 197 insertions(+), 4 deletions(-) diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 88a59d9715ac..f100ca7d3ee2 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -80,6 +80,7 @@ static int eth_port_link_is_up(unsigned int eth_port_num); static void eth_port_uc_addr_get(struct net_device *dev, unsigned char *MacAddr); +static void eth_port_set_multicast_list(struct net_device *); static int mv643xx_eth_real_open(struct net_device *); static int mv643xx_eth_real_stop(struct net_device *); static int mv643xx_eth_change_mtu(struct net_device *, int); @@ -269,6 +270,8 @@ static void mv643xx_eth_set_rx_mode(struct net_device *dev) mp->port_config &= ~(u32) MV643XX_ETH_UNICAST_PROMISCUOUS_MODE; mv_write(MV643XX_ETH_PORT_CONFIG_REG(mp->port_num), mp->port_config); + + eth_port_set_multicast_list(dev); } /* @@ -2044,6 +2047,196 @@ static int eth_port_uc_addr(unsigned int eth_port_num, unsigned char uc_nibble, return 1; } +/* + * The entries in each table are indexed by a hash of a packet's MAC + * address. One bit in each entry determines whether the packet is + * accepted. There are 4 entries (each 8 bits wide) in each register + * of the table. The bits in each entry are defined as follows: + * 0 Accept=1, Drop=0 + * 3-1 Queue (ETH_Q0=0) + * 7-4 Reserved = 0; + */ +static void eth_port_set_filter_table_entry(int table, unsigned char entry) +{ + unsigned int table_reg; + unsigned int tbl_offset; + unsigned int reg_offset; + + tbl_offset = (entry / 4) * 4; /* Register offset of DA table entry */ + reg_offset = entry % 4; /* Entry offset within the register */ + + /* Set "accepts frame bit" at specified table entry */ + table_reg = mv_read(table + tbl_offset); + table_reg |= 0x01 << (8 * reg_offset); + mv_write(table + tbl_offset, table_reg); +} + +/* + * eth_port_mc_addr - Multicast address settings. + * + * The MV device supports multicast using two tables: + * 1) Special Multicast Table for MAC addresses of the form + * 0x01-00-5E-00-00-XX (where XX is between 0x00 and 0x_FF). + * The MAC DA[7:0] bits are used as a pointer to the Special Multicast + * Table entries in the DA-Filter table. + * 2) Other Multicast Table for multicast of another type. A CRC-8bit + * is used as an index to the Other Multicast Table entries in the + * DA-Filter table. This function calculates the CRC-8bit value. + * In either case, eth_port_set_filter_table_entry() is then called + * to set to set the actual table entry. + */ +static void eth_port_mc_addr(unsigned int eth_port_num, unsigned char *p_addr) +{ + unsigned int mac_h; + unsigned int mac_l; + unsigned char crc_result = 0; + int table; + int mac_array[48]; + int crc[8]; + int i; + + if ((p_addr[0] == 0x01) && (p_addr[1] == 0x00) && + (p_addr[2] == 0x5E) && (p_addr[3] == 0x00) && (p_addr[4] == 0x00)) { + table = MV643XX_ETH_DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE + (eth_port_num); + eth_port_set_filter_table_entry(table, p_addr[5]); + return; + } + + /* Calculate CRC-8 out of the given address */ + mac_h = (p_addr[0] << 8) | (p_addr[1]); + mac_l = (p_addr[2] << 24) | (p_addr[3] << 16) | + (p_addr[4] << 8) | (p_addr[5] << 0); + + for (i = 0; i < 32; i++) + mac_array[i] = (mac_l >> i) & 0x1; + for (i = 32; i < 48; i++) + mac_array[i] = (mac_h >> (i - 32)) & 0x1; + + crc[0] = mac_array[45] ^ mac_array[43] ^ mac_array[40] ^ mac_array[39] ^ + mac_array[35] ^ mac_array[34] ^ mac_array[31] ^ mac_array[30] ^ + mac_array[28] ^ mac_array[23] ^ mac_array[21] ^ mac_array[19] ^ + mac_array[18] ^ mac_array[16] ^ mac_array[14] ^ mac_array[12] ^ + mac_array[8] ^ mac_array[7] ^ mac_array[6] ^ mac_array[0]; + + crc[1] = mac_array[46] ^ mac_array[45] ^ mac_array[44] ^ mac_array[43] ^ + mac_array[41] ^ mac_array[39] ^ mac_array[36] ^ mac_array[34] ^ + mac_array[32] ^ mac_array[30] ^ mac_array[29] ^ mac_array[28] ^ + mac_array[24] ^ mac_array[23] ^ mac_array[22] ^ mac_array[21] ^ + mac_array[20] ^ mac_array[18] ^ mac_array[17] ^ mac_array[16] ^ + mac_array[15] ^ mac_array[14] ^ mac_array[13] ^ mac_array[12] ^ + mac_array[9] ^ mac_array[6] ^ mac_array[1] ^ mac_array[0]; + + crc[2] = mac_array[47] ^ mac_array[46] ^ mac_array[44] ^ mac_array[43] ^ + mac_array[42] ^ mac_array[39] ^ mac_array[37] ^ mac_array[34] ^ + mac_array[33] ^ mac_array[29] ^ mac_array[28] ^ mac_array[25] ^ + mac_array[24] ^ mac_array[22] ^ mac_array[17] ^ mac_array[15] ^ + mac_array[13] ^ mac_array[12] ^ mac_array[10] ^ mac_array[8] ^ + mac_array[6] ^ mac_array[2] ^ mac_array[1] ^ mac_array[0]; + + crc[3] = mac_array[47] ^ mac_array[45] ^ mac_array[44] ^ mac_array[43] ^ + mac_array[40] ^ mac_array[38] ^ mac_array[35] ^ mac_array[34] ^ + mac_array[30] ^ mac_array[29] ^ mac_array[26] ^ mac_array[25] ^ + mac_array[23] ^ mac_array[18] ^ mac_array[16] ^ mac_array[14] ^ + mac_array[13] ^ mac_array[11] ^ mac_array[9] ^ mac_array[7] ^ + mac_array[3] ^ mac_array[2] ^ mac_array[1]; + + crc[4] = mac_array[46] ^ mac_array[45] ^ mac_array[44] ^ mac_array[41] ^ + mac_array[39] ^ mac_array[36] ^ mac_array[35] ^ mac_array[31] ^ + mac_array[30] ^ mac_array[27] ^ mac_array[26] ^ mac_array[24] ^ + mac_array[19] ^ mac_array[17] ^ mac_array[15] ^ mac_array[14] ^ + mac_array[12] ^ mac_array[10] ^ mac_array[8] ^ mac_array[4] ^ + mac_array[3] ^ mac_array[2]; + + crc[5] = mac_array[47] ^ mac_array[46] ^ mac_array[45] ^ mac_array[42] ^ + mac_array[40] ^ mac_array[37] ^ mac_array[36] ^ mac_array[32] ^ + mac_array[31] ^ mac_array[28] ^ mac_array[27] ^ mac_array[25] ^ + mac_array[20] ^ mac_array[18] ^ mac_array[16] ^ mac_array[15] ^ + mac_array[13] ^ mac_array[11] ^ mac_array[9] ^ mac_array[5] ^ + mac_array[4] ^ mac_array[3]; + + crc[6] = mac_array[47] ^ mac_array[46] ^ mac_array[43] ^ mac_array[41] ^ + mac_array[38] ^ mac_array[37] ^ mac_array[33] ^ mac_array[32] ^ + mac_array[29] ^ mac_array[28] ^ mac_array[26] ^ mac_array[21] ^ + mac_array[19] ^ mac_array[17] ^ mac_array[16] ^ mac_array[14] ^ + mac_array[12] ^ mac_array[10] ^ mac_array[6] ^ mac_array[5] ^ + mac_array[4]; + + crc[7] = mac_array[47] ^ mac_array[44] ^ mac_array[42] ^ mac_array[39] ^ + mac_array[38] ^ mac_array[34] ^ mac_array[33] ^ mac_array[30] ^ + mac_array[29] ^ mac_array[27] ^ mac_array[22] ^ mac_array[20] ^ + mac_array[18] ^ mac_array[17] ^ mac_array[15] ^ mac_array[13] ^ + mac_array[11] ^ mac_array[7] ^ mac_array[6] ^ mac_array[5]; + + for (i = 0; i < 8; i++) + crc_result = crc_result | (crc[i] << i); + + table = MV643XX_ETH_DA_FILTER_OTHER_MULTICAST_TABLE_BASE(eth_port_num); + eth_port_set_filter_table_entry(table, crc_result); +} + +/* + * Set the entire multicast list based on dev->mc_list. + */ +static void eth_port_set_multicast_list(struct net_device *dev) +{ + + struct dev_mc_list *mc_list; + int i; + int table_index; + struct mv643xx_private *mp = netdev_priv(dev); + unsigned int eth_port_num = mp->port_num; + + /* If the device is in promiscuous mode or in all multicast mode, + * we will fully populate both multicast tables with accept. + * This is guaranteed to yield a match on all multicast addresses... + */ + if ((dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI)) { + for (table_index = 0; table_index <= 0xFC; table_index += 4) { + /* Set all entries in DA filter special multicast + * table (Ex_dFSMT) + * Set for ETH_Q0 for now + * Bits + * 0 Accept=1, Drop=0 + * 3-1 Queue ETH_Q0=0 + * 7-4 Reserved = 0; + */ + mv_write(MV643XX_ETH_DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE(eth_port_num) + table_index, 0x01010101); + + /* Set all entries in DA filter other multicast + * table (Ex_dFOMT) + * Set for ETH_Q0 for now + * Bits + * 0 Accept=1, Drop=0 + * 3-1 Queue ETH_Q0=0 + * 7-4 Reserved = 0; + */ + mv_write(MV643XX_ETH_DA_FILTER_OTHER_MULTICAST_TABLE_BASE(eth_port_num) + table_index, 0x01010101); + } + return; + } + + /* We will clear out multicast tables every time we get the list. + * Then add the entire new list... + */ + for (table_index = 0; table_index <= 0xFC; table_index += 4) { + /* Clear DA filter special multicast table (Ex_dFSMT) */ + mv_write(MV643XX_ETH_DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE + (eth_port_num) + table_index, 0); + + /* Clear DA filter other multicast table (Ex_dFOMT) */ + mv_write(MV643XX_ETH_DA_FILTER_OTHER_MULTICAST_TABLE_BASE + (eth_port_num) + table_index, 0); + } + + /* Get pointer to net_device multicast list and add each one... */ + for (i = 0, mc_list = dev->mc_list; + (i < 256) && (mc_list != NULL) && (i < dev->mc_count); + i++, mc_list = mc_list->next) + if (mc_list->dmi_addrlen == 6) + eth_port_mc_addr(eth_port_num, mc_list->dmi_addr); +} + /* * eth_port_init_mac_tables - Clear all entrance in the UC, SMC and OMC tables * @@ -2071,11 +2264,11 @@ static void eth_port_init_mac_tables(unsigned int eth_port_num) for (table_index = 0; table_index <= 0xFC; table_index += 4) { /* Clear DA filter special multicast table (Ex_dFSMT) */ - mv_write((MV643XX_ETH_DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE - (eth_port_num) + table_index), 0); + mv_write(MV643XX_ETH_DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE + (eth_port_num) + table_index, 0); /* Clear DA filter other multicast table (Ex_dFOMT) */ - mv_write((MV643XX_ETH_DA_FILTER_OTHER_MULTICAST_TABLE_BASE - (eth_port_num) + table_index), 0); + mv_write(MV643XX_ETH_DA_FILTER_OTHER_MULTICAST_TABLE_BASE + (eth_port_num) + table_index, 0); } } From b44cd572623cb6a931a947d9108595517fd945f8 Mon Sep 17 00:00:00 2001 From: Dale Farnsworth Date: Mon, 16 Jan 2006 16:51:22 -0700 Subject: [PATCH 13/76] [PATCH] mv643xx_eth: Receive buffers require 8 byte alignment The Marvell mv643xx ethernet hardware requires that DMA buffers be aligned to 8-byte boundaries. This patch satisfies this requirement. Buffers allocated by dev_alloc_skb() only have 4-byte alignment when slab debugging is enabled. Also, document that the 2-byte offset to align the IP packets on receive is a hardware feature and is not tied to NET_IP_ALIGN. Signed-off-by: Dale Farnsworth mv643xx_eth.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) Signed-off-by: Jeff Garzik --- drivers/net/mv643xx_eth.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index f100ca7d3ee2..4afb954092a6 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -57,7 +57,9 @@ /* Constants */ #define VLAN_HLEN 4 #define FCS_LEN 4 -#define WRAP NET_IP_ALIGN + ETH_HLEN + VLAN_HLEN + FCS_LEN +#define DMA_ALIGN 8 /* hw requires 8-byte alignment */ +#define HW_IP_ALIGN 2 /* hw aligns IP header */ +#define WRAP HW_IP_ALIGN + ETH_HLEN + VLAN_HLEN + FCS_LEN #define RX_SKB_SIZE ((dev->mtu + WRAP + 7) & ~0x7) #define INT_CAUSE_UNMASK_ALL 0x0007ffff @@ -173,15 +175,19 @@ static void mv643xx_eth_rx_task(void *data) struct mv643xx_private *mp = netdev_priv(dev); struct pkt_info pkt_info; struct sk_buff *skb; + int unaligned; if (test_and_set_bit(0, &mp->rx_task_busy)) panic("%s: Error in test_set_bit / clear_bit", dev->name); while (mp->rx_ring_skbs < (mp->rx_ring_size - 5)) { - skb = dev_alloc_skb(RX_SKB_SIZE); + skb = dev_alloc_skb(RX_SKB_SIZE + DMA_ALIGN); if (!skb) break; mp->rx_ring_skbs++; + unaligned = (u32)skb->data & (DMA_ALIGN - 1); + if (unaligned) + skb_reserve(skb, DMA_ALIGN - unaligned); pkt_info.cmd_sts = ETH_RX_ENABLE_INTERRUPT; pkt_info.byte_cnt = RX_SKB_SIZE; pkt_info.buf_ptr = dma_map_single(NULL, skb->data, RX_SKB_SIZE, @@ -192,7 +198,7 @@ static void mv643xx_eth_rx_task(void *data) "%s: Error allocating RX Ring\n", dev->name); break; } - skb_reserve(skb, 2); + skb_reserve(skb, HW_IP_ALIGN); } clear_bit(0, &mp->rx_task_busy); /* From f7ea333765438232ac346a2f23cfec3e2012758f Mon Sep 17 00:00:00 2001 From: Paul Janzen Date: Mon, 16 Jan 2006 16:52:13 -0700 Subject: [PATCH 14/76] [PATCH] mv643xx_eth: Fix handling of small, unaligned fragments Fix handling of small, unaligned fragments. It also solves a potential deadlock if skb_linearize() returns -ENOMEM. Signed-off-by: Paul Janzen Signed-off-by: Dale Farnsworth mv643xx_eth.c | 54 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 23 deletions(-) Signed-off-by: Jeff Garzik --- drivers/net/mv643xx_eth.c | 54 ++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 4afb954092a6..e01b03c7615e 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -1093,6 +1093,25 @@ static int mv643xx_poll(struct net_device *dev, int *budget) } #endif +/* Hardware can't handle unaligned fragments smaller than 9 bytes. + * This helper function detects that case. + */ + +static inline unsigned int has_tiny_unaligned_frags(struct sk_buff *skb) +{ + unsigned int frag; + skb_frag_t *fragp; + + for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) { + fragp = &skb_shinfo(skb)->frags[frag]; + if (fragp->size <= 8 && fragp->page_offset & 0x7) + return 1; + + } + return 0; +} + + /* * mv643xx_eth_start_xmit * @@ -1136,12 +1155,19 @@ static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev) return 1; } +#ifdef MV643XX_CHECKSUM_OFFLOAD_TX + if (has_tiny_unaligned_frags(skb)) { + if ((skb_linearize(skb, GFP_ATOMIC) != 0)) { + stats->tx_dropped++; + printk(KERN_DEBUG "%s: failed to linearize tiny " + "unaligned fragment\n", dev->name); + return 1; + } + } + spin_lock_irqsave(&mp->lock, flags); - /* Update packet info data structure -- DMA owned, first last */ -#ifdef MV643XX_CHECKSUM_OFFLOAD_TX if (!skb_shinfo(skb)->nr_frags) { -linear: if (skb->ip_summed != CHECKSUM_HW) { /* Errata BTS #50, IHL must be 5 if no HW checksum */ pkt_info.cmd_sts = ETH_TX_ENABLE_INTERRUPT | @@ -1183,26 +1209,6 @@ linear: } else { unsigned int frag; - /* Since hardware can't handle unaligned fragments smaller - * than 9 bytes, if we find any, we linearize the skb - * and start again. When I've seen it, it's always been - * the first frag (probably near the end of the page), - * but we check all frags to be safe. - */ - for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) { - skb_frag_t *fragp; - - fragp = &skb_shinfo(skb)->frags[frag]; - if (fragp->size <= 8 && fragp->page_offset & 0x7) { - skb_linearize(skb, GFP_ATOMIC); - printk(KERN_DEBUG "%s: unaligned tiny fragment" - "%d of %d, fixed\n", - dev->name, frag, - skb_shinfo(skb)->nr_frags); - goto linear; - } - } - /* first frag which is skb header */ pkt_info.byte_cnt = skb_headlen(skb); pkt_info.buf_ptr = dma_map_single(NULL, skb->data, @@ -1288,6 +1294,8 @@ linear: } } #else + spin_lock_irqsave(&mp->lock, flags); + pkt_info.cmd_sts = ETH_TX_ENABLE_INTERRUPT | ETH_TX_FIRST_DESC | ETH_TX_LAST_DESC; pkt_info.l4i_chk = 0; From dd09b1de08b28ccfb130ca97d617dc3283165d22 Mon Sep 17 00:00:00 2001 From: Dale Farnsworth Date: Mon, 16 Jan 2006 16:53:15 -0700 Subject: [PATCH 15/76] [PATCH] mv643xx_eth: iounmap the correct SRAM buffer Signed-off-by: Dale Farnsworth mv643xx_eth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) Signed-off-by: Jeff Garzik --- drivers/net/mv643xx_eth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index e01b03c7615e..f632323fbf06 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -877,7 +877,7 @@ static int mv643xx_eth_real_open(struct net_device *dev) printk(KERN_ERR "%s: Freeing previously allocated TX queues...", dev->name); if (mp->rx_sram_size) - iounmap(mp->p_rx_desc_area); + iounmap(mp->p_tx_desc_area); else dma_free_coherent(NULL, mp->tx_desc_area_size, mp->p_tx_desc_area, mp->tx_desc_dma); From 8f5187035ad475c90ca865318daa09ba43bc3e68 Mon Sep 17 00:00:00 2001 From: Dale Farnsworth Date: Mon, 16 Jan 2006 16:56:30 -0700 Subject: [PATCH 16/76] [PATCH] mv643xx_eth: Hold spinlocks only where needed This driver has historically held a spin_lock during the entire open and stop functions and while receiving multiple packets. This is unecessarily long and holds locks during calls that may sleep. This patch reduces the size of windows where locks are held. Signed-off-by: Dale Farnsworth mv643xx_eth.c | 172 ++++++++++++++++++++++++++++++---------------------------- 1 file changed, 91 insertions(+), 81 deletions(-) Signed-off-by: Jeff Garzik --- drivers/net/mv643xx_eth.c | 174 ++++++++++++++++++++------------------ 1 file changed, 92 insertions(+), 82 deletions(-) diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index f632323fbf06..f6d4ea175e11 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -129,15 +129,8 @@ static inline void mv_write(int offset, u32 data) */ static int mv643xx_eth_change_mtu(struct net_device *dev, int new_mtu) { - struct mv643xx_private *mp = netdev_priv(dev); - unsigned long flags; - - spin_lock_irqsave(&mp->lock, flags); - - if ((new_mtu > 9500) || (new_mtu < 64)) { - spin_unlock_irqrestore(&mp->lock, flags); + if ((new_mtu > 9500) || (new_mtu < 64)) return -EINVAL; - } dev->mtu = new_mtu; /* @@ -157,7 +150,6 @@ static int mv643xx_eth_change_mtu(struct net_device *dev, int new_mtu) dev->name); } - spin_unlock_irqrestore(&mp->lock, flags); return 0; } @@ -353,8 +345,6 @@ static int mv643xx_eth_free_tx_queue(struct net_device *dev, if (!(eth_int_cause_ext & (BIT0 | BIT8))) return released; - spin_lock(&mp->lock); - /* Check only queue 0 */ while (eth_tx_return_desc(mp, &pkt_info) == ETH_OK) { if (pkt_info.cmd_sts & BIT0) { @@ -377,8 +367,6 @@ static int mv643xx_eth_free_tx_queue(struct net_device *dev, } } - spin_unlock(&mp->lock); - return released; } @@ -518,6 +506,8 @@ static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id, mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), 0); mv_write(MV643XX_ETH_INTERRUPT_EXTEND_MASK_REG (port_num), 0); + /* ensure previous writes have taken effect */ + mv_read(MV643XX_ETH_INTERRUPT_EXTEND_MASK_REG(port_num)); __netif_rx_schedule(dev); } #else @@ -533,6 +523,9 @@ static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id, /* Unmask all interrupts on ethernet port */ mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), INT_CAUSE_MASK_ALL); + /* wait for previous write to take effect */ + mv_read(MV643XX_ETH_INTERRUPT_MASK_REG(port_num)); + queue_task(&mp->rx_task, &tq_immediate); mark_bh(IMMEDIATE_BH); #else @@ -657,34 +650,20 @@ static int mv643xx_eth_open(struct net_device *dev) unsigned int port_num = mp->port_num; int err; - spin_lock_irq(&mp->lock); - err = request_irq(dev->irq, mv643xx_eth_int_handler, SA_SHIRQ | SA_SAMPLE_RANDOM, dev->name, dev); - if (err) { printk(KERN_ERR "Can not assign IRQ number to MV643XX_eth%d\n", port_num); - err = -EAGAIN; - goto out; + return -EAGAIN; } if (mv643xx_eth_real_open(dev)) { printk("%s: Error opening interface\n", dev->name); + free_irq(dev->irq, dev); err = -EBUSY; - goto out_free; } - spin_unlock_irq(&mp->lock); - - return 0; - -out_free: - free_irq(dev->irq, dev); - -out: - spin_unlock_irq(&mp->lock); - return err; } @@ -790,18 +769,6 @@ static int mv643xx_eth_real_open(struct net_device *dev) /* Stop RX Queues */ mv_write(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num), 0x0000ff00); - /* Clear the ethernet port interrupts */ - mv_write(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num), 0); - mv_write(MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), 0); - - /* Unmask RX buffer and TX end interrupt */ - mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), - INT_CAUSE_UNMASK_ALL); - - /* Unmask phy and link status changes interrupts */ - mv_write(MV643XX_ETH_INTERRUPT_EXTEND_MASK_REG(port_num), - INT_CAUSE_UNMASK_ALL_EXT); - /* Set the MAC Address */ memcpy(mp->port_mac_addr, dev->dev_addr, 6); @@ -903,8 +870,17 @@ static int mv643xx_eth_real_open(struct net_device *dev) mp->tx_int_coal = eth_port_set_tx_coal(port_num, 133000000, MV643XX_TX_COAL); - netif_start_queue(dev); + /* Clear any pending ethernet port interrupts */ + mv_write(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num), 0); + mv_write(MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), 0); + /* Unmask phy and link status changes interrupts */ + mv_write(MV643XX_ETH_INTERRUPT_EXTEND_MASK_REG(port_num), + INT_CAUSE_UNMASK_ALL_EXT); + + /* Unmask RX buffer and TX end interrupt */ + mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), + INT_CAUSE_UNMASK_ALL); return 0; } @@ -983,37 +959,38 @@ static int mv643xx_eth_real_stop(struct net_device *dev) struct mv643xx_private *mp = netdev_priv(dev); unsigned int port_num = mp->port_num; - netif_carrier_off(dev); - netif_stop_queue(dev); - - mv643xx_eth_free_tx_rings(dev); - mv643xx_eth_free_rx_rings(dev); - - eth_port_reset(mp->port_num); - - /* Disable ethernet port interrupts */ - mv_write(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num), 0); - mv_write(MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), 0); - /* Mask RX buffer and TX end interrupt */ mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), 0); /* Mask phy and link status changes interrupts */ mv_write(MV643XX_ETH_INTERRUPT_EXTEND_MASK_REG(port_num), 0); + /* ensure previous writes have taken effect */ + mv_read(MV643XX_ETH_INTERRUPT_MASK_REG(port_num)); + +#ifdef MV643XX_NAPI + netif_poll_disable(dev); +#endif + netif_carrier_off(dev); + netif_stop_queue(dev); + + eth_port_reset(mp->port_num); + + mv643xx_eth_free_tx_rings(dev); + mv643xx_eth_free_rx_rings(dev); + +#ifdef MV643XX_NAPI + netif_poll_enable(dev); +#endif + return 0; } static int mv643xx_eth_stop(struct net_device *dev) { - struct mv643xx_private *mp = netdev_priv(dev); - - spin_lock_irq(&mp->lock); - mv643xx_eth_real_stop(dev); free_irq(dev->irq, dev); - spin_unlock_irq(&mp->lock); return 0; } @@ -1053,14 +1030,11 @@ static int mv643xx_poll(struct net_device *dev, int *budget) struct mv643xx_private *mp = netdev_priv(dev); int done = 1, orig_budget, work_done; unsigned int port_num = mp->port_num; - unsigned long flags; #ifdef MV643XX_TX_FAST_REFILL if (++mp->tx_clean_threshold > 5) { - spin_lock_irqsave(&mp->lock, flags); mv643xx_tx(dev); mp->tx_clean_threshold = 0; - spin_unlock_irqrestore(&mp->lock, flags); } #endif @@ -1078,15 +1052,13 @@ static int mv643xx_poll(struct net_device *dev, int *budget) } if (done) { - spin_lock_irqsave(&mp->lock, flags); - __netif_rx_complete(dev); + netif_rx_complete(dev); mv_write(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num), 0); mv_write(MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), 0); mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), INT_CAUSE_UNMASK_ALL); mv_write(MV643XX_ETH_INTERRUPT_EXTEND_MASK_REG(port_num), INT_CAUSE_UNMASK_ALL_EXT); - spin_unlock_irqrestore(&mp->lock, flags); } return done ? 0 : 1; @@ -2687,6 +2659,7 @@ static ETH_FUNC_RET_STATUS eth_port_send(struct mv643xx_private *mp, struct eth_tx_desc *current_descriptor; struct eth_tx_desc *first_descriptor; u32 command; + unsigned long flags; /* Do not process Tx ring in case of Tx ring resource error */ if (mp->tx_resource_err) @@ -2703,6 +2676,8 @@ static ETH_FUNC_RET_STATUS eth_port_send(struct mv643xx_private *mp, return ETH_ERROR; } + spin_lock_irqsave(&mp->lock, flags); + mp->tx_ring_skbs++; BUG_ON(mp->tx_ring_skbs > mp->tx_ring_size); @@ -2752,11 +2727,15 @@ static ETH_FUNC_RET_STATUS eth_port_send(struct mv643xx_private *mp, mp->tx_resource_err = 1; mp->tx_curr_desc_q = tx_first_desc; + spin_unlock_irqrestore(&mp->lock, flags); + return ETH_QUEUE_LAST_RESOURCE; } mp->tx_curr_desc_q = tx_next_desc; + spin_unlock_irqrestore(&mp->lock, flags); + return ETH_OK; } #else @@ -2767,11 +2746,14 @@ static ETH_FUNC_RET_STATUS eth_port_send(struct mv643xx_private *mp, int tx_desc_used; struct eth_tx_desc *current_descriptor; unsigned int command_status; + unsigned long flags; /* Do not process Tx ring in case of Tx ring resource error */ if (mp->tx_resource_err) return ETH_QUEUE_FULL; + spin_lock_irqsave(&mp->lock, flags); + mp->tx_ring_skbs++; BUG_ON(mp->tx_ring_skbs > mp->tx_ring_size); @@ -2802,9 +2784,12 @@ static ETH_FUNC_RET_STATUS eth_port_send(struct mv643xx_private *mp, /* Check for ring index overlap in the Tx desc ring */ if (tx_desc_curr == tx_desc_used) { mp->tx_resource_err = 1; + + spin_unlock_irqrestore(&mp->lock, flags); return ETH_QUEUE_LAST_RESOURCE; } + spin_unlock_irqrestore(&mp->lock, flags); return ETH_OK; } #endif @@ -2827,23 +2812,27 @@ static ETH_FUNC_RET_STATUS eth_port_send(struct mv643xx_private *mp, * Tx ring 'first' and 'used' indexes are updated. * * RETURN: - * ETH_ERROR in case the routine can not access Tx desc ring. - * ETH_RETRY in case there is transmission in process. - * ETH_END_OF_JOB if the routine has nothing to release. - * ETH_OK otherwise. + * ETH_OK on success + * ETH_ERROR otherwise. * */ static ETH_FUNC_RET_STATUS eth_tx_return_desc(struct mv643xx_private *mp, struct pkt_info *p_pkt_info) { int tx_desc_used; -#ifdef MV643XX_CHECKSUM_OFFLOAD_TX - int tx_busy_desc = mp->tx_first_desc_q; -#else - int tx_busy_desc = mp->tx_curr_desc_q; -#endif + int tx_busy_desc; struct eth_tx_desc *p_tx_desc_used; unsigned int command_status; + unsigned long flags; + int err = ETH_OK; + + spin_lock_irqsave(&mp->lock, flags); + +#ifdef MV643XX_CHECKSUM_OFFLOAD_TX + tx_busy_desc = mp->tx_first_desc_q; +#else + tx_busy_desc = mp->tx_curr_desc_q; +#endif /* Get the Tx Desc ring indexes */ tx_desc_used = mp->tx_used_desc_q; @@ -2851,18 +2840,24 @@ static ETH_FUNC_RET_STATUS eth_tx_return_desc(struct mv643xx_private *mp, p_tx_desc_used = &mp->p_tx_desc_area[tx_desc_used]; /* Sanity check */ - if (p_tx_desc_used == NULL) - return ETH_ERROR; + if (p_tx_desc_used == NULL) { + err = ETH_ERROR; + goto out; + } /* Stop release. About to overlap the current available Tx descriptor */ - if (tx_desc_used == tx_busy_desc && !mp->tx_resource_err) - return ETH_END_OF_JOB; + if (tx_desc_used == tx_busy_desc && !mp->tx_resource_err) { + err = ETH_ERROR; + goto out; + } command_status = p_tx_desc_used->cmd_sts; /* Still transmitting... */ - if (command_status & (ETH_BUFFER_OWNED_BY_DMA)) - return ETH_RETRY; + if (command_status & (ETH_BUFFER_OWNED_BY_DMA)) { + err = ETH_ERROR; + goto out; + } /* Pass the packet information to the caller */ p_pkt_info->cmd_sts = command_status; @@ -2880,7 +2875,10 @@ static ETH_FUNC_RET_STATUS eth_tx_return_desc(struct mv643xx_private *mp, BUG_ON(mp->tx_ring_skbs == 0); mp->tx_ring_skbs--; - return ETH_OK; +out: + spin_unlock_irqrestore(&mp->lock, flags); + + return err; } /* @@ -2912,11 +2910,14 @@ static ETH_FUNC_RET_STATUS eth_port_receive(struct mv643xx_private *mp, int rx_next_curr_desc, rx_curr_desc, rx_used_desc; volatile struct eth_rx_desc *p_rx_desc; unsigned int command_status; + unsigned long flags; /* Do not process Rx ring in case of Rx ring resource error */ if (mp->rx_resource_err) return ETH_QUEUE_FULL; + spin_lock_irqsave(&mp->lock, flags); + /* Get the Rx Desc ring 'curr and 'used' indexes */ rx_curr_desc = mp->rx_curr_desc_q; rx_used_desc = mp->rx_used_desc_q; @@ -2928,8 +2929,10 @@ static ETH_FUNC_RET_STATUS eth_port_receive(struct mv643xx_private *mp, rmb(); /* Nothing to receive... */ - if (command_status & (ETH_BUFFER_OWNED_BY_DMA)) + if (command_status & (ETH_BUFFER_OWNED_BY_DMA)) { + spin_unlock_irqrestore(&mp->lock, flags); return ETH_END_OF_JOB; + } p_pkt_info->byte_cnt = (p_rx_desc->byte_cnt) - RX_BUF_OFFSET; p_pkt_info->cmd_sts = command_status; @@ -2949,6 +2952,8 @@ static ETH_FUNC_RET_STATUS eth_port_receive(struct mv643xx_private *mp, if (rx_next_curr_desc == rx_used_desc) mp->rx_resource_err = 1; + spin_unlock_irqrestore(&mp->lock, flags); + return ETH_OK; } @@ -2977,6 +2982,9 @@ static ETH_FUNC_RET_STATUS eth_rx_return_buff(struct mv643xx_private *mp, { int used_rx_desc; /* Where to return Rx resource */ volatile struct eth_rx_desc *p_used_rx_desc; + unsigned long flags; + + spin_lock_irqsave(&mp->lock, flags); /* Get 'used' Rx descriptor */ used_rx_desc = mp->rx_used_desc_q; @@ -3000,6 +3008,8 @@ static ETH_FUNC_RET_STATUS eth_rx_return_buff(struct mv643xx_private *mp, /* Any Rx return cancels the Rx resource error status */ mp->rx_resource_err = 0; + spin_unlock_irqrestore(&mp->lock, flags); + return ETH_OK; } From 63890576a3bfd5c6aea86fb72236682480865bc0 Mon Sep 17 00:00:00 2001 From: Wolfram Joost Date: Mon, 16 Jan 2006 16:57:41 -0700 Subject: [PATCH 17/76] [PATCH] mv643xx_eth: Request HW checksum generation only for IPv4 This patch removes the NETIF_F_HW_CSUM flag to be able to use other protocols than IPv4. Hardware checksums for IPv4 should continue to work because NETIF_F_IP_CSUM is still set. The sanity-check has been enhanced to check the used protocol and to not access skb->iph for non-ipv4-packets. Signed-off-by: Wolfram Joost Signed-off-by: Dale Farnsworth mv643xx_eth.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) Signed-off-by: Jeff Garzik --- drivers/net/mv643xx_eth.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index f6d4ea175e11..615b3622ea67 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -1148,7 +1148,6 @@ static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev) 5 << ETH_TX_IHL_SHIFT; pkt_info.l4i_chk = 0; } else { - pkt_info.cmd_sts = ETH_TX_ENABLE_INTERRUPT | ETH_TX_FIRST_DESC | ETH_TX_LAST_DESC | @@ -1156,14 +1155,16 @@ static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev) ETH_GEN_IP_V_4_CHECKSUM | skb->nh.iph->ihl << ETH_TX_IHL_SHIFT; /* CPU already calculated pseudo header checksum. */ - if (skb->nh.iph->protocol == IPPROTO_UDP) { + if ((skb->protocol == ETH_P_IP) && + (skb->nh.iph->protocol == IPPROTO_UDP) ) { pkt_info.cmd_sts |= ETH_UDP_FRAME; pkt_info.l4i_chk = skb->h.uh->check; - } else if (skb->nh.iph->protocol == IPPROTO_TCP) + } else if ((skb->protocol == ETH_P_IP) && + (skb->nh.iph->protocol == IPPROTO_TCP)) pkt_info.l4i_chk = skb->h.th->check; else { printk(KERN_ERR - "%s: chksum proto != TCP or UDP\n", + "%s: chksum proto != IPv4 TCP or UDP\n", dev->name); spin_unlock_irqrestore(&mp->lock, flags); return 1; @@ -1199,14 +1200,16 @@ static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev) ETH_GEN_IP_V_4_CHECKSUM | skb->nh.iph->ihl << ETH_TX_IHL_SHIFT; /* CPU already calculated pseudo header checksum. */ - if (skb->nh.iph->protocol == IPPROTO_UDP) { + if ((skb->protocol == ETH_P_IP) && + (skb->nh.iph->protocol == IPPROTO_UDP)) { pkt_info.cmd_sts |= ETH_UDP_FRAME; pkt_info.l4i_chk = skb->h.uh->check; - } else if (skb->nh.iph->protocol == IPPROTO_TCP) + } else if ((skb->protocol == ETH_P_IP) && + (skb->nh.iph->protocol == IPPROTO_TCP)) pkt_info.l4i_chk = skb->h.th->check; else { printk(KERN_ERR - "%s: chksum proto != TCP or UDP\n", + "%s: chksum proto != IPv4 TCP or UDP\n", dev->name); spin_unlock_irqrestore(&mp->lock, flags); return 1; @@ -1421,7 +1424,7 @@ static int mv643xx_eth_probe(struct platform_device *pdev) * Zero copy can only work if we use Discovery II memory. Else, we will * have to map the buffers to ISA memory which is only 16 MB */ - dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_HW_CSUM; + dev->features = NETIF_F_SG | NETIF_F_IP_CSUM; #endif #endif From 4476e0e4c7e6a2c22288391b853b6e071622f079 Mon Sep 17 00:00:00 2001 From: Dale Farnsworth Date: Mon, 16 Jan 2006 16:58:24 -0700 Subject: [PATCH 18/76] [PATCH] mv643xx_eth: Fix transmit skb accounting Signed-off-by: Dale Farnsworth mv643xx_eth.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) Signed-off-by: Jeff Garzik --- drivers/net/mv643xx_eth.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 615b3622ea67..5de06d714ab0 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -889,14 +889,17 @@ static void mv643xx_eth_free_tx_rings(struct net_device *dev) struct mv643xx_private *mp = netdev_priv(dev); unsigned int port_num = mp->port_num; unsigned int curr; + struct sk_buff *skb; /* Stop Tx Queues */ mv_write(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num), 0x0000ff00); /* Free outstanding skb's on TX rings */ for (curr = 0; mp->tx_ring_skbs && curr < mp->tx_ring_size; curr++) { - if (mp->tx_skb[curr]) { - dev_kfree_skb(mp->tx_skb[curr]); + skb = mp->tx_skb[curr]; + if (skb) { + mp->tx_ring_skbs -= skb_shinfo(skb)->nr_frags; + dev_kfree_skb(skb); mp->tx_ring_skbs--; } } From ab4384a6588925607f734e195f49e34a80f31e84 Mon Sep 17 00:00:00 2001 From: Dale Farnsworth Date: Mon, 16 Jan 2006 16:59:21 -0700 Subject: [PATCH 19/76] [PATCH] mv643xx_eth: Merge open and stop helper functions Move code from helper functions mv643xx_eth_real_open and mv643xx_eth_real_stop as they are no longer needed. Signed-off-by Dale Farnsworth mv643xx_eth.c | 109 +++++++++++++++++++++++----------------------------------- 1 file changed, 45 insertions(+), 64 deletions(-) Signed-off-by: Jeff Garzik --- drivers/net/mv643xx_eth.c | 109 ++++++++++++++++---------------------- 1 file changed, 45 insertions(+), 64 deletions(-) diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 5de06d714ab0..6118ea799a65 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -83,8 +83,8 @@ static int eth_port_link_is_up(unsigned int eth_port_num); static void eth_port_uc_addr_get(struct net_device *dev, unsigned char *MacAddr); static void eth_port_set_multicast_list(struct net_device *); -static int mv643xx_eth_real_open(struct net_device *); -static int mv643xx_eth_real_stop(struct net_device *); +static int mv643xx_eth_open(struct net_device *); +static int mv643xx_eth_stop(struct net_device *); static int mv643xx_eth_change_mtu(struct net_device *, int); static struct net_device_stats *mv643xx_eth_get_stats(struct net_device *); static void eth_port_init_mac_tables(unsigned int eth_port_num); @@ -140,11 +140,8 @@ static int mv643xx_eth_change_mtu(struct net_device *dev, int new_mtu) * to memory is full, which might fail the open function. */ if (netif_running(dev)) { - if (mv643xx_eth_real_stop(dev)) - printk(KERN_ERR - "%s: Fatal error on stopping device\n", - dev->name); - if (mv643xx_eth_real_open(dev)) + mv643xx_eth_stop(dev); + if (mv643xx_eth_open(dev)) printk(KERN_ERR "%s: Fatal error on opening device\n", dev->name); @@ -631,42 +628,6 @@ static unsigned int eth_port_set_tx_coal(unsigned int eth_port_num, return coal; } -/* - * mv643xx_eth_open - * - * This function is called when openning the network device. The function - * should initialize all the hardware, initialize cyclic Rx/Tx - * descriptors chain and buffers and allocate an IRQ to the network - * device. - * - * Input : a pointer to the network device structure - * - * Output : zero of success , nonzero if fails. - */ - -static int mv643xx_eth_open(struct net_device *dev) -{ - struct mv643xx_private *mp = netdev_priv(dev); - unsigned int port_num = mp->port_num; - int err; - - err = request_irq(dev->irq, mv643xx_eth_int_handler, - SA_SHIRQ | SA_SAMPLE_RANDOM, dev->name, dev); - if (err) { - printk(KERN_ERR "Can not assign IRQ number to MV643XX_eth%d\n", - port_num); - return -EAGAIN; - } - - if (mv643xx_eth_real_open(dev)) { - printk("%s: Error opening interface\n", dev->name); - free_irq(dev->irq, dev); - err = -EBUSY; - } - - return err; -} - /* * ether_init_rx_desc_ring - Curve a Rx chain desc list and buffer in memory. * @@ -759,12 +720,33 @@ static void ether_init_tx_desc_ring(struct mv643xx_private *mp) mp->port_tx_queue_command |= 1; } -/* Helper function for mv643xx_eth_open */ -static int mv643xx_eth_real_open(struct net_device *dev) +/* + * mv643xx_eth_open + * + * This function is called when openning the network device. The function + * should initialize all the hardware, initialize cyclic Rx/Tx + * descriptors chain and buffers and allocate an IRQ to the network + * device. + * + * Input : a pointer to the network device structure + * + * Output : zero of success , nonzero if fails. + */ + +static int mv643xx_eth_open(struct net_device *dev) { struct mv643xx_private *mp = netdev_priv(dev); unsigned int port_num = mp->port_num; unsigned int size; + int err; + + err = request_irq(dev->irq, mv643xx_eth_int_handler, + SA_SHIRQ | SA_SAMPLE_RANDOM, dev->name, dev); + if (err) { + printk(KERN_ERR "Can not assign IRQ number to MV643XX_eth%d\n", + port_num); + return -EAGAIN; + } /* Stop RX Queues */ mv_write(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num), 0x0000ff00); @@ -788,14 +770,15 @@ static int mv643xx_eth_real_open(struct net_device *dev) GFP_KERNEL); if (!mp->rx_skb) { printk(KERN_ERR "%s: Cannot allocate Rx skb ring\n", dev->name); - return -ENOMEM; + err = -ENOMEM; + goto out_free_irq; } mp->tx_skb = kmalloc(sizeof(*mp->tx_skb) * mp->tx_ring_size, GFP_KERNEL); if (!mp->tx_skb) { printk(KERN_ERR "%s: Cannot allocate Tx skb ring\n", dev->name); - kfree(mp->rx_skb); - return -ENOMEM; + err = -ENOMEM; + goto out_free_rx_skb; } /* Allocate TX ring */ @@ -815,9 +798,8 @@ static int mv643xx_eth_real_open(struct net_device *dev) if (!mp->p_tx_desc_area) { printk(KERN_ERR "%s: Cannot allocate Tx Ring (size %d bytes)\n", dev->name, size); - kfree(mp->rx_skb); - kfree(mp->tx_skb); - return -ENOMEM; + err = -ENOMEM; + goto out_free_tx_skb; } BUG_ON((u32) mp->p_tx_desc_area & 0xf); /* check 16-byte alignment */ memset((void *)mp->p_tx_desc_area, 0, mp->tx_desc_area_size); @@ -848,9 +830,8 @@ static int mv643xx_eth_real_open(struct net_device *dev) else dma_free_coherent(NULL, mp->tx_desc_area_size, mp->p_tx_desc_area, mp->tx_desc_dma); - kfree(mp->rx_skb); - kfree(mp->tx_skb); - return -ENOMEM; + err = -ENOMEM; + goto out_free_tx_skb; } memset((void *)mp->p_rx_desc_area, 0, size); @@ -882,6 +863,15 @@ static int mv643xx_eth_real_open(struct net_device *dev) mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), INT_CAUSE_UNMASK_ALL); return 0; + +out_free_tx_skb: + kfree(mp->tx_skb); +out_free_rx_skb: + kfree(mp->rx_skb); +out_free_irq: + free_irq(dev->irq, dev); + + return err; } static void mv643xx_eth_free_tx_rings(struct net_device *dev) @@ -955,9 +945,7 @@ static void mv643xx_eth_free_rx_rings(struct net_device *dev) * Output : zero if success , nonzero if fails */ -/* Helper function for mv643xx_eth_stop */ - -static int mv643xx_eth_real_stop(struct net_device *dev) +static int mv643xx_eth_stop(struct net_device *dev) { struct mv643xx_private *mp = netdev_priv(dev); unsigned int port_num = mp->port_num; @@ -986,13 +974,6 @@ static int mv643xx_eth_real_stop(struct net_device *dev) netif_poll_enable(dev); #endif - return 0; -} - -static int mv643xx_eth_stop(struct net_device *dev) -{ - mv643xx_eth_real_stop(dev); - free_irq(dev->irq, dev); return 0; From c2e5b352fcefb644959a0c8b1bb2e297f0d4ac3d Mon Sep 17 00:00:00 2001 From: Dale Farnsworth Date: Mon, 16 Jan 2006 17:00:24 -0700 Subject: [PATCH 20/76] [PATCH] mv643xx_eth: Remove needless mask of extended intr register All interrupts controlled by the extended mask register are also masked by a bit in the main mask register, so there is no need to directly manipulate the extended mask register. Signed-off-by: Dale Farnsworth mv643xx_eth.c | 81 ++++++++++++++++++---------------------------------------- 1 file changed, 26 insertions(+), 55 deletions(-) Signed-off-by: Jeff Garzik --- drivers/net/mv643xx_eth.c | 81 +++++++++++++-------------------------- 1 file changed, 26 insertions(+), 55 deletions(-) diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 6118ea799a65..40ae36b20c9d 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -62,10 +62,10 @@ #define WRAP HW_IP_ALIGN + ETH_HLEN + VLAN_HLEN + FCS_LEN #define RX_SKB_SIZE ((dev->mtu + WRAP + 7) & ~0x7) -#define INT_CAUSE_UNMASK_ALL 0x0007ffff -#define INT_CAUSE_UNMASK_ALL_EXT 0x0011ffff -#define INT_CAUSE_MASK_ALL 0x00000000 -#define INT_CAUSE_MASK_ALL_EXT 0x00000000 +#define INT_UNMASK_ALL 0x0007ffff +#define INT_UNMASK_ALL_EXT 0x0011ffff +#define INT_MASK_ALL 0x00000000 +#define INT_MASK_ALL_EXT 0x00000000 #define INT_CAUSE_CHECK_BITS INT_CAUSE_UNMASK_ALL #define INT_CAUSE_CHECK_BITS_EXT INT_CAUSE_UNMASK_ALL_EXT @@ -205,7 +205,7 @@ static void mv643xx_eth_rx_task(void *data) else { /* Return interrupts */ mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(mp->port_num), - INT_CAUSE_UNMASK_ALL); + INT_UNMASK_ALL); } #endif } @@ -470,12 +470,12 @@ static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id, /* Read interrupt cause registers */ eth_int_cause = mv_read(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num)) & - INT_CAUSE_UNMASK_ALL; + INT_UNMASK_ALL; if (eth_int_cause & BIT1) eth_int_cause_ext = mv_read( MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num)) & - INT_CAUSE_UNMASK_ALL_EXT; + INT_UNMASK_ALL_EXT; #ifdef MV643XX_NAPI if (!(eth_int_cause & 0x0007fffd)) { @@ -500,11 +500,10 @@ static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id, } else { if (netif_rx_schedule_prep(dev)) { /* Mask all the interrupts */ - mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), 0); - mv_write(MV643XX_ETH_INTERRUPT_EXTEND_MASK_REG - (port_num), 0); - /* ensure previous writes have taken effect */ - mv_read(MV643XX_ETH_INTERRUPT_EXTEND_MASK_REG(port_num)); + mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), + INT_MASK_ALL); + /* wait for previous write to complete */ + mv_read(MV643XX_ETH_INTERRUPT_MASK_REG(port_num)); __netif_rx_schedule(dev); } #else @@ -517,9 +516,9 @@ static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id, * with skb's. */ #ifdef MV643XX_RX_QUEUE_FILL_ON_TASK - /* Unmask all interrupts on ethernet port */ + /* Mask all interrupts on ethernet port */ mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), - INT_CAUSE_MASK_ALL); + INT_MASK_ALL); /* wait for previous write to take effect */ mv_read(MV643XX_ETH_INTERRUPT_MASK_REG(port_num)); @@ -857,11 +856,10 @@ static int mv643xx_eth_open(struct net_device *dev) /* Unmask phy and link status changes interrupts */ mv_write(MV643XX_ETH_INTERRUPT_EXTEND_MASK_REG(port_num), - INT_CAUSE_UNMASK_ALL_EXT); + INT_UNMASK_ALL_EXT); /* Unmask RX buffer and TX end interrupt */ - mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), - INT_CAUSE_UNMASK_ALL); + mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), INT_UNMASK_ALL); return 0; out_free_tx_skb: @@ -950,13 +948,9 @@ static int mv643xx_eth_stop(struct net_device *dev) struct mv643xx_private *mp = netdev_priv(dev); unsigned int port_num = mp->port_num; - /* Mask RX buffer and TX end interrupt */ - mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), 0); - - /* Mask phy and link status changes interrupts */ - mv_write(MV643XX_ETH_INTERRUPT_EXTEND_MASK_REG(port_num), 0); - - /* ensure previous writes have taken effect */ + /* Mask all interrupts on ethernet port */ + mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), INT_MASK_ALL); + /* wait for previous write to complete */ mv_read(MV643XX_ETH_INTERRUPT_MASK_REG(port_num)); #ifdef MV643XX_NAPI @@ -1040,9 +1034,7 @@ static int mv643xx_poll(struct net_device *dev, int *budget) mv_write(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num), 0); mv_write(MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), 0); mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), - INT_CAUSE_UNMASK_ALL); - mv_write(MV643XX_ETH_INTERRUPT_EXTEND_MASK_REG(port_num), - INT_CAUSE_UNMASK_ALL_EXT); + INT_UNMASK_ALL); } return done ? 0 : 1; @@ -1307,39 +1299,18 @@ static struct net_device_stats *mv643xx_eth_get_stats(struct net_device *dev) } #ifdef CONFIG_NET_POLL_CONTROLLER -static inline void mv643xx_enable_irq(struct mv643xx_private *mp) -{ - int port_num = mp->port_num; - unsigned long flags; - - spin_lock_irqsave(&mp->lock, flags); - mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), - INT_CAUSE_UNMASK_ALL); - mv_write(MV643XX_ETH_INTERRUPT_EXTEND_MASK_REG(port_num), - INT_CAUSE_UNMASK_ALL_EXT); - spin_unlock_irqrestore(&mp->lock, flags); -} - -static inline void mv643xx_disable_irq(struct mv643xx_private *mp) -{ - int port_num = mp->port_num; - unsigned long flags; - - spin_lock_irqsave(&mp->lock, flags); - mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), - INT_CAUSE_MASK_ALL); - mv_write(MV643XX_ETH_INTERRUPT_EXTEND_MASK_REG(port_num), - INT_CAUSE_MASK_ALL_EXT); - spin_unlock_irqrestore(&mp->lock, flags); -} - static void mv643xx_netpoll(struct net_device *netdev) { struct mv643xx_private *mp = netdev_priv(netdev); + int port_num = mp->port_num; + + mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), INT_MASK_ALL); + /* wait for previous write to complete */ + mv_read(MV643XX_ETH_INTERRUPT_MASK_REG(port_num)); - mv643xx_disable_irq(mp); mv643xx_eth_int_handler(netdev->irq, netdev, NULL); - mv643xx_enable_irq(mp); + + mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), INT_UNMASK_ALL); } #endif From 0d3ea1666f1894a874681fe33e2cb7fee41a0c73 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 12 Jan 2006 17:16:41 -0500 Subject: [PATCH 21/76] [PATCH] spidernet: check if firmware was loaded correctly Uploading the device firmware may fail if wrong input data was provided by the user. This checks for the condition. From: Jens Osterkamp Signed-off-by: Jens Osterkamp Signed-off-by: Arnd Bergmann Signed-off-by: Jeff Garzik --- drivers/net/spider_net.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 0d765f1733b5..2154469678b7 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -1836,7 +1836,7 @@ spider_net_setup_phy(struct spider_net_card *card) * spider_net_download_firmware loads the firmware opened by * spider_net_init_firmware into the adapter. */ -static void +static int spider_net_download_firmware(struct spider_net_card *card, const struct firmware *firmware) { @@ -1857,8 +1857,13 @@ spider_net_download_firmware(struct spider_net_card *card, } } + if (spider_net_read_reg(card, SPIDER_NET_GSINIT)) + return -EIO; + spider_net_write_reg(card, SPIDER_NET_GSINIT, SPIDER_NET_RUN_SEQ_VALUE); + + return 0; } /** @@ -1909,9 +1914,8 @@ spider_net_init_firmware(struct spider_net_card *card) goto out; } - spider_net_download_firmware(card, firmware); - - err = 0; + if (!spider_net_download_firmware(card, firmware)) + err = 0; out: release_firmware(firmware); From 030d6753f8b6251927330431a7e5f0ac86bc6da9 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 12 Jan 2006 17:16:42 -0500 Subject: [PATCH 22/76] [PATCH] spidernet: read firmware from the OF device tree request_firmware() is sometimes problematic, especially in initramfs, reading the firmware from Open Firmware is much preferrable. We still try to get the firmware from the file system first, in order to support old SLOF releases and to allow updates of the spidernet firmware without reflashing the system. From: Jens Osterkamp Signed-off-by: Jens Osterkamp Signed-off-by: Arnd Bergmann Signed-off-by: Jeff Garzik --- drivers/net/spider_net.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 2154469678b7..94e238f6ed31 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -1895,16 +1895,27 @@ spider_net_download_firmware(struct spider_net_card *card, static int spider_net_init_firmware(struct spider_net_card *card) { - const struct firmware *firmware; + struct firmware *firmware; + struct device_node *dn; + u8 *fw_prop; int err = -EIO; - if (request_firmware(&firmware, + if (request_firmware((const struct firmware **)&firmware, SPIDER_NET_FIRMWARE_NAME, &card->pdev->dev) < 0) { if (netif_msg_probe(card)) pr_err("Couldn't read in sequencer data file %s.\n", SPIDER_NET_FIRMWARE_NAME); - firmware = NULL; - goto out; + + dn = pci_device_to_OF_node(card->pdev); + if (!dn) + goto out; + + fw_prop = (u8 *)get_property(dn, "firmware", NULL); + if (!fw_prop) + goto out; + + memcpy(firmware->data, fw_prop, 6 * SPIDER_NET_FIRMWARE_LEN * sizeof(u32)); + firmware->size = 6 * SPIDER_NET_FIRMWARE_LEN * sizeof(u32); } if (firmware->size != 6 * SPIDER_NET_FIRMWARE_LEN * sizeof(u32)) { From 8e0a613bf61ccaab376877d7c2ed50315b8ca6d7 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 12 Jan 2006 17:16:43 -0500 Subject: [PATCH 23/76] [PATCH] spidernet: fix HW structures for 64 bit dma_addr_t The driver incorrectly used dma_addr_t to describe HW structures and consequently broke when that type was changed in 2.6.15-rc. This changed spidernet to use u32 for 32 bit HW defined structure elements. From: Jens Osterkamp Signed-off-by: Jens Osterkamp Signed-off-by: Arnd Bergmann Signed-off-by: Jeff Garzik --- drivers/net/spider_net.c | 13 ++++++++----- drivers/net/spider_net.h | 4 ++-- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 94e238f6ed31..86969191c3f7 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -480,6 +480,7 @@ static int spider_net_prepare_rx_descr(struct spider_net_card *card, struct spider_net_descr *descr) { + dma_addr_t buf; int error = 0; int offset; int bufsize; @@ -510,10 +511,11 @@ spider_net_prepare_rx_descr(struct spider_net_card *card, if (offset) skb_reserve(descr->skb, SPIDER_NET_RXBUF_ALIGN - offset); /* io-mmu-map the skb */ - descr->buf_addr = pci_map_single(card->pdev, descr->skb->data, + buf = pci_map_single(card->pdev, descr->skb->data, SPIDER_NET_MAX_MTU, PCI_DMA_BIDIRECTIONAL); - if (descr->buf_addr == DMA_ERROR_CODE) { + descr->buf_addr = buf; + if (buf == DMA_ERROR_CODE) { dev_kfree_skb_any(descr->skb); if (netif_msg_rx_err(card)) pr_err("Could not iommu-map rx buffer\n"); @@ -914,15 +916,16 @@ spider_net_prepare_tx_descr(struct spider_net_card *card, struct spider_net_descr *descr, struct sk_buff *skb) { - descr->buf_addr = pci_map_single(card->pdev, skb->data, - skb->len, PCI_DMA_BIDIRECTIONAL); - if (descr->buf_addr == DMA_ERROR_CODE) { + dma_addr_t buf = pci_map_single(card->pdev, skb->data, + skb->len, PCI_DMA_BIDIRECTIONAL); + if (buf == DMA_ERROR_CODE) { if (netif_msg_tx_err(card)) pr_err("could not iommu-map packet (%p, %i). " "Dropping packet\n", skb->data, skb->len); return -ENOMEM; } + descr->buf_addr = buf; descr->buf_size = skb->len; descr->skb = skb; descr->data_status = 0; diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h index 22b2f2347351..98f11ecf48fc 100644 --- a/drivers/net/spider_net.h +++ b/drivers/net/spider_net.h @@ -373,9 +373,9 @@ enum spider_net_descr_status { struct spider_net_descr { /* as defined by the hardware */ - dma_addr_t buf_addr; + u32 buf_addr; u32 buf_size; - dma_addr_t next_descr_addr; + u32 next_descr_addr; u32 dmac_cmd_status; u32 result_size; u32 valid_size; /* all zeroes for tx */ From 11f1a52b87eaf830bd03d4e01d563437c30f7728 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 12 Jan 2006 17:16:44 -0500 Subject: [PATCH 24/76] [PATCH] spidernet: performance optimizations Performance optimizations, changes in these areas: - RX and TX checksum offload - correct maximum MTU - don't use TX interrupts anymore, use a timer instead - remove some superfluous barriers - improve RX RAM full handling From: Utz Bacher Signed-off-by: Jens Osterkamp Signed-off-by: Arnd Bergmann Signed-off-by: Jeff Garzik --- drivers/net/spider_net.c | 511 +++++++++++++++---------------- drivers/net/spider_net.h | 71 +++-- drivers/net/spider_net_ethtool.c | 19 ++ 3 files changed, 314 insertions(+), 287 deletions(-) diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 86969191c3f7..e2ad9aef0109 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -22,7 +22,6 @@ */ #include - #include #include #include @@ -43,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -108,42 +108,6 @@ spider_net_write_reg(struct spider_net_card *card, u32 reg, u32 value) writel(value, card->regs + reg); } -/** - * spider_net_write_reg_sync - writes to an SMMIO register of a card - * @card: device structure - * @reg: register to write to - * @value: value to write into the specified SMMIO register - * - * Unlike spider_net_write_reg, this will also make sure the - * data arrives on the card by reading the reg again. - */ -static void -spider_net_write_reg_sync(struct spider_net_card *card, u32 reg, u32 value) -{ - value = cpu_to_le32(value); - writel(value, card->regs + reg); - (void)readl(card->regs + reg); -} - -/** - * spider_net_rx_irq_off - switch off rx irq on this spider card - * @card: device structure - * - * switches off rx irq by masking them out in the GHIINTnMSK register - */ -static void -spider_net_rx_irq_off(struct spider_net_card *card) -{ - u32 regvalue; - unsigned long flags; - - spin_lock_irqsave(&card->intmask_lock, flags); - regvalue = spider_net_read_reg(card, SPIDER_NET_GHIINT0MSK); - regvalue &= ~SPIDER_NET_RXINT; - spider_net_write_reg_sync(card, SPIDER_NET_GHIINT0MSK, regvalue); - spin_unlock_irqrestore(&card->intmask_lock, flags); -} - /** spider_net_write_phy - write to phy register * @netdev: adapter to be written to * @mii_id: id of MII @@ -198,6 +162,21 @@ spider_net_read_phy(struct net_device *netdev, int mii_id, int reg) return readvalue; } +/** + * spider_net_rx_irq_off - switch off rx irq on this spider card + * @card: device structure + * + * switches off rx irq by masking them out in the GHIINTnMSK register + */ +static void +spider_net_rx_irq_off(struct spider_net_card *card) +{ + u32 regvalue; + + regvalue = SPIDER_NET_INT0_MASK_VALUE & (~SPIDER_NET_RXINT); + spider_net_write_reg(card, SPIDER_NET_GHIINT0MSK, regvalue); +} + /** * spider_net_rx_irq_on - switch on rx irq on this spider card * @card: device structure @@ -208,51 +187,9 @@ static void spider_net_rx_irq_on(struct spider_net_card *card) { u32 regvalue; - unsigned long flags; - spin_lock_irqsave(&card->intmask_lock, flags); - regvalue = spider_net_read_reg(card, SPIDER_NET_GHIINT0MSK); - regvalue |= SPIDER_NET_RXINT; - spider_net_write_reg_sync(card, SPIDER_NET_GHIINT0MSK, regvalue); - spin_unlock_irqrestore(&card->intmask_lock, flags); -} - -/** - * spider_net_tx_irq_off - switch off tx irq on this spider card - * @card: device structure - * - * switches off tx irq by masking them out in the GHIINTnMSK register - */ -static void -spider_net_tx_irq_off(struct spider_net_card *card) -{ - u32 regvalue; - unsigned long flags; - - spin_lock_irqsave(&card->intmask_lock, flags); - regvalue = spider_net_read_reg(card, SPIDER_NET_GHIINT0MSK); - regvalue &= ~SPIDER_NET_TXINT; - spider_net_write_reg_sync(card, SPIDER_NET_GHIINT0MSK, regvalue); - spin_unlock_irqrestore(&card->intmask_lock, flags); -} - -/** - * spider_net_tx_irq_on - switch on tx irq on this spider card - * @card: device structure - * - * switches on tx irq by enabling them in the GHIINTnMSK register - */ -static void -spider_net_tx_irq_on(struct spider_net_card *card) -{ - u32 regvalue; - unsigned long flags; - - spin_lock_irqsave(&card->intmask_lock, flags); - regvalue = spider_net_read_reg(card, SPIDER_NET_GHIINT0MSK); - regvalue |= SPIDER_NET_TXINT; - spider_net_write_reg_sync(card, SPIDER_NET_GHIINT0MSK, regvalue); - spin_unlock_irqrestore(&card->intmask_lock, flags); + regvalue = SPIDER_NET_INT0_MASK_VALUE | SPIDER_NET_RXINT; + spider_net_write_reg(card, SPIDER_NET_GHIINT0MSK, regvalue); } /** @@ -326,9 +263,8 @@ static enum spider_net_descr_status spider_net_get_descr_status(struct spider_net_descr *descr) { u32 cmd_status; - rmb(); + cmd_status = descr->dmac_cmd_status; - rmb(); cmd_status >>= SPIDER_NET_DESCR_IND_PROC_SHIFT; /* no need to mask out any bits, as cmd_status is 32 bits wide only * (and unsigned) */ @@ -349,7 +285,6 @@ spider_net_set_descr_status(struct spider_net_descr *descr, { u32 cmd_status; /* read the status */ - mb(); cmd_status = descr->dmac_cmd_status; /* clean the upper 4 bits */ cmd_status &= SPIDER_NET_DESCR_IND_PROC_MASKO; @@ -357,7 +292,6 @@ spider_net_set_descr_status(struct spider_net_descr *descr, cmd_status |= ((u32)status)<dmac_cmd_status = cmd_status; - wmb(); } /** @@ -398,8 +332,9 @@ spider_net_init_chain(struct spider_net_card *card, { int i; struct spider_net_descr *descr; + dma_addr_t buf; - spin_lock_init(&card->chain_lock); + atomic_set(&card->rx_chain_refill,0); descr = start_descr; memset(descr, 0, sizeof(*descr) * no); @@ -408,14 +343,14 @@ spider_net_init_chain(struct spider_net_card *card, for (i=0; ibus_addr = - pci_map_single(card->pdev, descr, - SPIDER_NET_DESCR_SIZE, - PCI_DMA_BIDIRECTIONAL); + buf = pci_map_single(card->pdev, descr, + SPIDER_NET_DESCR_SIZE, + PCI_DMA_BIDIRECTIONAL); - if (descr->bus_addr == DMA_ERROR_CODE) + if (buf == DMA_ERROR_CODE) goto iommu_error; + descr->bus_addr = buf; descr->next = descr + 1; descr->prev = descr - 1; @@ -439,7 +374,8 @@ iommu_error: for (i=0; i < no; i++, descr++) if (descr->bus_addr) pci_unmap_single(card->pdev, descr->bus_addr, - SPIDER_NET_DESCR_SIZE, PCI_DMA_BIDIRECTIONAL); + SPIDER_NET_DESCR_SIZE, + PCI_DMA_BIDIRECTIONAL); return -ENOMEM; } @@ -459,7 +395,7 @@ spider_net_free_rx_chain_contents(struct spider_net_card *card) if (descr->skb) { dev_kfree_skb(descr->skb); pci_unmap_single(card->pdev, descr->buf_addr, - SPIDER_NET_MAX_MTU, + SPIDER_NET_MAX_FRAME, PCI_DMA_BIDIRECTIONAL); } descr = descr->next; @@ -486,7 +422,7 @@ spider_net_prepare_rx_descr(struct spider_net_card *card, int bufsize; /* we need to round up the buffer size to a multiple of 128 */ - bufsize = (SPIDER_NET_MAX_MTU + SPIDER_NET_RXBUF_ALIGN - 1) & + bufsize = (SPIDER_NET_MAX_FRAME + SPIDER_NET_RXBUF_ALIGN - 1) & (~(SPIDER_NET_RXBUF_ALIGN - 1)); /* and we need to have it 128 byte aligned, therefore we allocate a @@ -494,10 +430,8 @@ spider_net_prepare_rx_descr(struct spider_net_card *card, /* allocate an skb */ descr->skb = dev_alloc_skb(bufsize + SPIDER_NET_RXBUF_ALIGN - 1); if (!descr->skb) { - if (net_ratelimit()) - if (netif_msg_rx_err(card)) - pr_err("Not enough memory to allocate " - "rx buffer\n"); + if (netif_msg_rx_err(card) && net_ratelimit()) + pr_err("Not enough memory to allocate rx buffer\n"); return -ENOMEM; } descr->buf_size = bufsize; @@ -512,12 +446,11 @@ spider_net_prepare_rx_descr(struct spider_net_card *card, skb_reserve(descr->skb, SPIDER_NET_RXBUF_ALIGN - offset); /* io-mmu-map the skb */ buf = pci_map_single(card->pdev, descr->skb->data, - SPIDER_NET_MAX_MTU, - PCI_DMA_BIDIRECTIONAL); + SPIDER_NET_MAX_FRAME, PCI_DMA_BIDIRECTIONAL); descr->buf_addr = buf; if (buf == DMA_ERROR_CODE) { dev_kfree_skb_any(descr->skb); - if (netif_msg_rx_err(card)) + if (netif_msg_rx_err(card) && net_ratelimit()) pr_err("Could not iommu-map rx buffer\n"); spider_net_set_descr_status(descr, SPIDER_NET_DESCR_NOT_IN_USE); } else { @@ -528,10 +461,10 @@ spider_net_prepare_rx_descr(struct spider_net_card *card, } /** - * spider_net_enable_rxctails - sets RX dmac chain tail addresses + * spider_net_enable_rxchtails - sets RX dmac chain tail addresses * @card: card structure * - * spider_net_enable_rxctails sets the RX DMAC chain tail adresses in the + * spider_net_enable_rxchtails sets the RX DMAC chain tail adresses in the * chip by writing to the appropriate register. DMA is enabled in * spider_net_enable_rxdmac. */ @@ -553,6 +486,7 @@ spider_net_enable_rxchtails(struct spider_net_card *card) static void spider_net_enable_rxdmac(struct spider_net_card *card) { + wmb(); spider_net_write_reg(card, SPIDER_NET_GDADMACCNTR, SPIDER_NET_DMA_RX_VALUE); } @@ -561,32 +495,28 @@ spider_net_enable_rxdmac(struct spider_net_card *card) * spider_net_refill_rx_chain - refills descriptors/skbs in the rx chains * @card: card structure * - * refills descriptors in all chains (last used chain first): allocates skbs - * and iommu-maps them. + * refills descriptors in the rx chain: allocates skbs and iommu-maps them. */ static void spider_net_refill_rx_chain(struct spider_net_card *card) { struct spider_net_descr_chain *chain; - int count = 0; - unsigned long flags; chain = &card->rx_chain; - spin_lock_irqsave(&card->chain_lock, flags); - while (spider_net_get_descr_status(chain->head) == - SPIDER_NET_DESCR_NOT_IN_USE) { - if (spider_net_prepare_rx_descr(card, chain->head)) - break; - count++; - chain->head = chain->head->next; - } - spin_unlock_irqrestore(&card->chain_lock, flags); + /* one context doing the refill (and a second context seeing that + * and omitting it) is ok. If called by NAPI, we'll be called again + * as spider_net_decode_one_descr is called several times. If some + * interrupt calls us, the NAPI is about to clean up anyway. */ + if (atomic_inc_return(&card->rx_chain_refill) == 1) + while (spider_net_get_descr_status(chain->head) == + SPIDER_NET_DESCR_NOT_IN_USE) { + if (spider_net_prepare_rx_descr(card, chain->head)) + break; + chain->head = chain->head->next; + } - /* could be optimized, only do that, if we know the DMA processing - * has terminated */ - if (count) - spider_net_enable_rxdmac(card); + atomic_dec(&card->rx_chain_refill); } /** @@ -615,6 +545,7 @@ spider_net_alloc_rx_skbs(struct spider_net_card *card) /* this will allocate the rest of the rx buffers; if not, it's * business as usual later on */ spider_net_refill_rx_chain(card); + spider_net_enable_rxdmac(card); return 0; error: @@ -651,24 +582,30 @@ spider_net_release_tx_descr(struct spider_net_card *card, * @card: adapter structure * @brutal: if set, don't care about whether descriptor seems to be in use * - * releases the tx descriptors that spider has finished with (if non-brutal) - * or simply release tx descriptors (if brutal) + * returns 0 if the tx ring is empty, otherwise 1. + * + * spider_net_release_tx_chain releases the tx descriptors that spider has + * finished with (if non-brutal) or simply release tx descriptors (if brutal). + * If some other context is calling this function, we return 1 so that we're + * scheduled again (if we were scheduled) and will not loose initiative. */ -static void +static int spider_net_release_tx_chain(struct spider_net_card *card, int brutal) { struct spider_net_descr_chain *tx_chain = &card->tx_chain; enum spider_net_descr_status status; - spider_net_tx_irq_off(card); + if (atomic_inc_return(&card->tx_chain_release) != 1) { + atomic_dec(&card->tx_chain_release); + return 1; + } - /* no lock for chain needed, if this is only executed once at a time */ -again: for (;;) { status = spider_net_get_descr_status(tx_chain->tail); switch (status) { case SPIDER_NET_DESCR_CARDOWNED: - if (!brutal) goto out; + if (!brutal) + goto out; /* fallthrough, if we release the descriptors * brutally (then we don't care about * SPIDER_NET_DESCR_CARDOWNED) */ @@ -695,25 +632,30 @@ again: tx_chain->tail = tx_chain->tail->next; } out: + atomic_dec(&card->tx_chain_release); + netif_wake_queue(card->netdev); - if (!brutal) { - /* switch on tx irqs (while we are still in the interrupt - * handler, so we don't get an interrupt), check again - * for done descriptors. This results in fewer interrupts */ - spider_net_tx_irq_on(card); - status = spider_net_get_descr_status(tx_chain->tail); - switch (status) { - case SPIDER_NET_DESCR_RESPONSE_ERROR: - case SPIDER_NET_DESCR_PROTECTION_ERROR: - case SPIDER_NET_DESCR_FORCE_END: - case SPIDER_NET_DESCR_COMPLETE: - goto again; - default: - break; - } - } + if (status == SPIDER_NET_DESCR_CARDOWNED) + return 1; + return 0; +} +/** + * spider_net_cleanup_tx_ring - cleans up the TX ring + * @card: card structure + * + * spider_net_cleanup_tx_ring is called by the tx_timer (as we don't use + * interrupts to cleanup our TX ring) and returns sent packets to the stack + * by freeing them + */ +static void +spider_net_cleanup_tx_ring(struct spider_net_card *card) +{ + if ( (spider_net_release_tx_chain(card, 0)) && + (card->netdev->flags & IFF_UP) ) { + mod_timer(&card->tx_timer, jiffies + SPIDER_NET_TX_TIMER); + } } /** @@ -728,16 +670,22 @@ out: static u8 spider_net_get_multicast_hash(struct net_device *netdev, __u8 *addr) { - /* FIXME: an addr of 01:00:5e:00:00:01 must result in 0xa9, - * ff:ff:ff:ff:ff:ff must result in 0xfd */ u32 crc; u8 hash; + char addr_for_crc[ETH_ALEN] = { 0, }; + int i, bit; - crc = crc32_be(~0, addr, netdev->addr_len); + for (i = 0; i < ETH_ALEN * 8; i++) { + bit = (addr[i / 8] >> (i % 8)) & 1; + addr_for_crc[ETH_ALEN - 1 - i / 8] += bit << (7 - (i % 8)); + } + + crc = crc32_be(~0, addr_for_crc, netdev->addr_len); hash = (crc >> 27); hash <<= 3; hash |= crc & 7; + hash &= 0xff; return hash; } @@ -823,9 +771,11 @@ spider_net_stop(struct net_device *netdev) { struct spider_net_card *card = netdev_priv(netdev); + tasklet_kill(&card->rxram_full_tl); netif_poll_disable(netdev); netif_carrier_off(netdev); netif_stop_queue(netdev); + del_timer_sync(&card->tx_timer); /* disable/mask all interrupts */ spider_net_write_reg(card, SPIDER_NET_GHIINT0MSK, 0); @@ -874,13 +824,15 @@ spider_net_get_next_tx_descr(struct spider_net_card *card) * @skb: packet to consider * * fills out the command and status field of the descriptor structure, - * depending on hardware checksum settings. This function assumes a wmb() - * has executed before. + * depending on hardware checksum settings. */ static void spider_net_set_txdescr_cmdstat(struct spider_net_descr *descr, struct sk_buff *skb) { + /* make sure the other fields in the descriptor are written */ + wmb(); + if (skb->ip_summed != CHECKSUM_HW) { descr->dmac_cmd_status = SPIDER_NET_DMAC_CMDSTAT_NOCS; return; @@ -889,14 +841,13 @@ spider_net_set_txdescr_cmdstat(struct spider_net_descr *descr, /* is packet ip? * if yes: tcp? udp? */ if (skb->protocol == htons(ETH_P_IP)) { - if (skb->nh.iph->protocol == IPPROTO_TCP) { + if (skb->nh.iph->protocol == IPPROTO_TCP) descr->dmac_cmd_status = SPIDER_NET_DMAC_CMDSTAT_TCPCS; - } else if (skb->nh.iph->protocol == IPPROTO_UDP) { + else if (skb->nh.iph->protocol == IPPROTO_UDP) descr->dmac_cmd_status = SPIDER_NET_DMAC_CMDSTAT_UDPCS; - } else { /* the stack should checksum non-tcp and non-udp - packets on his own: NETIF_F_IP_CSUM */ + else /* the stack should checksum non-tcp and non-udp + packets on his own: NETIF_F_IP_CSUM */ descr->dmac_cmd_status = SPIDER_NET_DMAC_CMDSTAT_NOCS; - } } } @@ -916,10 +867,12 @@ spider_net_prepare_tx_descr(struct spider_net_card *card, struct spider_net_descr *descr, struct sk_buff *skb) { - dma_addr_t buf = pci_map_single(card->pdev, skb->data, - skb->len, PCI_DMA_BIDIRECTIONAL); + dma_addr_t buf; + + buf = pci_map_single(card->pdev, skb->data, + skb->len, PCI_DMA_BIDIRECTIONAL); if (buf == DMA_ERROR_CODE) { - if (netif_msg_tx_err(card)) + if (netif_msg_tx_err(card) && net_ratelimit()) pr_err("could not iommu-map packet (%p, %i). " "Dropping packet\n", skb->data, skb->len); return -ENOMEM; @@ -930,10 +883,6 @@ spider_net_prepare_tx_descr(struct spider_net_card *card, descr->skb = skb; descr->data_status = 0; - /* make sure the above values are in memory before we change the - * status */ - wmb(); - spider_net_set_txdescr_cmdstat(descr,skb); return 0; @@ -975,17 +924,12 @@ spider_net_xmit(struct sk_buff *skb, struct net_device *netdev) struct spider_net_descr *descr; int result; + spider_net_release_tx_chain(card, 0); + descr = spider_net_get_next_tx_descr(card); - if (!descr) { - netif_stop_queue(netdev); - - descr = spider_net_get_next_tx_descr(card); - if (!descr) - goto error; - else - netif_start_queue(netdev); - } + if (!descr) + goto error; result = spider_net_prepare_tx_descr(card, descr, skb); if (result) @@ -993,19 +937,25 @@ spider_net_xmit(struct sk_buff *skb, struct net_device *netdev) card->tx_chain.head = card->tx_chain.head->next; - /* make sure the status from spider_net_prepare_tx_descr is in - * memory before we check out the previous descriptor */ - wmb(); - if (spider_net_get_descr_status(descr->prev) != - SPIDER_NET_DESCR_CARDOWNED) - spider_net_kick_tx_dma(card, descr); + SPIDER_NET_DESCR_CARDOWNED) { + /* make sure the current descriptor is in memory. Then + * kicking it on again makes sense, if the previous is not + * card-owned anymore. Check the previous descriptor twice + * to omit an mb() in heavy traffic cases */ + mb(); + if (spider_net_get_descr_status(descr->prev) != + SPIDER_NET_DESCR_CARDOWNED) + spider_net_kick_tx_dma(card, descr); + } + + mod_timer(&card->tx_timer, jiffies + SPIDER_NET_TX_TIMER); return NETDEV_TX_OK; error: card->netdev_stats.tx_dropped++; - return NETDEV_TX_LOCKED; + return NETDEV_TX_BUSY; } /** @@ -1030,6 +980,7 @@ spider_net_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) * spider_net_pass_skb_up - takes an skb from a descriptor and passes it on * @descr: descriptor to process * @card: card structure + * @napi: whether caller is in NAPI context * * returns 1 on success, 0 if no packet was passed to the stack * @@ -1038,7 +989,7 @@ spider_net_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) */ static int spider_net_pass_skb_up(struct spider_net_descr *descr, - struct spider_net_card *card) + struct spider_net_card *card, int napi) { struct sk_buff *skb; struct net_device *netdev; @@ -1049,22 +1000,20 @@ spider_net_pass_skb_up(struct spider_net_descr *descr, netdev = card->netdev; - /* check for errors in the data_error flag */ - if ((data_error & SPIDER_NET_DATA_ERROR_MASK) && - netif_msg_rx_err(card)) - pr_err("error in received descriptor found, " - "data_status=x%08x, data_error=x%08x\n", - data_status, data_error); - - /* prepare skb, unmap descriptor */ - skb = descr->skb; - pci_unmap_single(card->pdev, descr->buf_addr, SPIDER_NET_MAX_MTU, + /* unmap descriptor */ + pci_unmap_single(card->pdev, descr->buf_addr, SPIDER_NET_MAX_FRAME, PCI_DMA_BIDIRECTIONAL); /* the cases we'll throw away the packet immediately */ - if (data_error & SPIDER_NET_DESTROY_RX_FLAGS) + if (data_error & SPIDER_NET_DESTROY_RX_FLAGS) { + if (netif_msg_rx_err(card)) + pr_err("error in received descriptor found, " + "data_status=x%08x, data_error=x%08x\n", + data_status, data_error); return 0; + } + skb = descr->skb; skb->dev = netdev; skb_put(skb, descr->valid_size); @@ -1076,14 +1025,14 @@ spider_net_pass_skb_up(struct spider_net_descr *descr, /* checksum offload */ if (card->options.rx_csum) { - if ( (data_status & SPIDER_NET_DATA_STATUS_CHK_MASK) && - (!(data_error & SPIDER_NET_DATA_ERROR_CHK_MASK)) ) + if ( ( (data_status & SPIDER_NET_DATA_STATUS_CKSUM_MASK) == + SPIDER_NET_DATA_STATUS_CKSUM_MASK) && + !(data_error & SPIDER_NET_DATA_ERR_CKSUM_MASK)) skb->ip_summed = CHECKSUM_UNNECESSARY; else skb->ip_summed = CHECKSUM_NONE; - } else { + } else skb->ip_summed = CHECKSUM_NONE; - } if (data_status & SPIDER_NET_VLAN_PACKET) { /* further enhancements: HW-accel VLAN @@ -1092,7 +1041,10 @@ spider_net_pass_skb_up(struct spider_net_descr *descr, } /* pass skb up to stack */ - netif_receive_skb(skb); + if (napi) + netif_receive_skb(skb); + else + netif_rx_ni(skb); /* update netdevice statistics */ card->netdev_stats.rx_packets++; @@ -1102,16 +1054,18 @@ spider_net_pass_skb_up(struct spider_net_descr *descr, } /** - * spider_net_decode_descr - processes an rx descriptor + * spider_net_decode_one_descr - processes an rx descriptor * @card: card structure + * @napi: whether caller is in NAPI context * * returns 1 if a packet has been sent to the stack, otherwise 0 * * processes an rx descriptor by iommu-unmapping the data buffer and passing - * the packet up to the stack + * the packet up to the stack. This function is called in softirq + * context, e.g. either bottom half from interrupt or NAPI polling context */ static int -spider_net_decode_one_descr(struct spider_net_card *card) +spider_net_decode_one_descr(struct spider_net_card *card, int napi) { enum spider_net_descr_status status; struct spider_net_descr *descr; @@ -1125,17 +1079,19 @@ spider_net_decode_one_descr(struct spider_net_card *card) if (status == SPIDER_NET_DESCR_CARDOWNED) { /* nothing in the descriptor yet */ - return 0; + result=0; + goto out; } if (status == SPIDER_NET_DESCR_NOT_IN_USE) { - /* not initialized yet, I bet chain->tail == chain->head - * and the ring is empty */ + /* not initialized yet, the ring must be empty */ spider_net_refill_rx_chain(card); - return 0; + spider_net_enable_rxdmac(card); + result=0; + goto out; } - /* descriptor definitively used -- move on head */ + /* descriptor definitively used -- move on tail */ chain->tail = descr->next; result = 0; @@ -1146,6 +1102,9 @@ spider_net_decode_one_descr(struct spider_net_card *card) pr_err("%s: dropping RX descriptor with state %d\n", card->netdev->name, status); card->netdev_stats.rx_dropped++; + pci_unmap_single(card->pdev, descr->buf_addr, + SPIDER_NET_MAX_FRAME, PCI_DMA_BIDIRECTIONAL); + dev_kfree_skb_irq(descr->skb); goto refill; } @@ -1158,12 +1117,13 @@ spider_net_decode_one_descr(struct spider_net_card *card) } /* ok, we've got a packet in descr */ - result = spider_net_pass_skb_up(descr, card); + result = spider_net_pass_skb_up(descr, card, napi); refill: spider_net_set_descr_status(descr, SPIDER_NET_DESCR_NOT_IN_USE); /* change the descriptor state: */ - spider_net_refill_rx_chain(card); - + if (!napi) + spider_net_refill_rx_chain(card); +out: return result; } @@ -1189,7 +1149,7 @@ spider_net_poll(struct net_device *netdev, int *budget) packets_to_do = min(*budget, netdev->quota); while (packets_to_do) { - if (spider_net_decode_one_descr(card)) { + if (spider_net_decode_one_descr(card, 1)) { packets_done++; packets_to_do--; } else { @@ -1201,6 +1161,7 @@ spider_net_poll(struct net_device *netdev, int *budget) netdev->quota -= packets_done; *budget -= packets_done; + spider_net_refill_rx_chain(card); /* if all packets are in the stack, enable interrupts and return 0 */ /* if not, return 1 */ @@ -1344,6 +1305,24 @@ spider_net_enable_txdmac(struct spider_net_card *card) card->tx_chain.tail->bus_addr); } +/** + * spider_net_handle_rxram_full - cleans up RX ring upon RX RAM full interrupt + * @card: card structure + * + * spider_net_handle_rxram_full empties the RX ring so that spider can put + * more packets in it and empty its RX RAM. This is called in bottom half + * context + */ +static void +spider_net_handle_rxram_full(struct spider_net_card *card) +{ + while (spider_net_decode_one_descr(card, 0)) + ; + spider_net_enable_rxchtails(card); + spider_net_enable_rxdmac(card); + netif_rx_schedule(card->netdev); +} + /** * spider_net_handle_error_irq - handles errors raised by an interrupt * @card: card structure @@ -1452,17 +1431,21 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg) switch (i) { case SPIDER_NET_GTMFLLINT: - if (netif_msg_intr(card)) + if (netif_msg_intr(card) && net_ratelimit()) pr_err("Spider TX RAM full\n"); show_error = 0; break; + case SPIDER_NET_GRFDFLLINT: /* fallthrough */ + case SPIDER_NET_GRFCFLLINT: /* fallthrough */ + case SPIDER_NET_GRFBFLLINT: /* fallthrough */ + case SPIDER_NET_GRFAFLLINT: /* fallthrough */ case SPIDER_NET_GRMFLLINT: - if (netif_msg_intr(card)) + if (netif_msg_intr(card) && net_ratelimit()) pr_err("Spider RX RAM full, incoming packets " - "might be discarded !\n"); - netif_rx_schedule(card->netdev); - spider_net_enable_rxchtails(card); - spider_net_enable_rxdmac(card); + "might be discarded!\n"); + spider_net_rx_irq_off(card); + tasklet_schedule(&card->rxram_full_tl); + show_error = 0; break; /* case SPIDER_NET_GTMSHTINT: problem, print a message */ @@ -1470,10 +1453,6 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg) /* allrighty. tx from previous descr ok */ show_error = 0; break; - /* case SPIDER_NET_GRFDFLLINT: print a message down there */ - /* case SPIDER_NET_GRFCFLLINT: print a message down there */ - /* case SPIDER_NET_GRFBFLLINT: print a message down there */ - /* case SPIDER_NET_GRFAFLLINT: print a message down there */ /* chain end */ case SPIDER_NET_GDDDCEINT: /* fallthrough */ @@ -1485,6 +1464,7 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg) "restarting DMAC %c.\n", 'D'+i-SPIDER_NET_GDDDCEINT); spider_net_refill_rx_chain(card); + spider_net_enable_rxdmac(card); show_error = 0; break; @@ -1495,6 +1475,7 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg) case SPIDER_NET_GDAINVDINT: /* could happen when rx chain is full */ spider_net_refill_rx_chain(card); + spider_net_enable_rxdmac(card); show_error = 0; break; @@ -1583,17 +1564,13 @@ spider_net_interrupt(int irq, void *ptr, struct pt_regs *regs) if (!status_reg) return IRQ_NONE; - if (status_reg & SPIDER_NET_TXINT) - spider_net_release_tx_chain(card, 0); - if (status_reg & SPIDER_NET_RXINT ) { spider_net_rx_irq_off(card); netif_rx_schedule(netdev); } - /* we do this after rx and tx processing, as we want the tx chain - * processed to see, whether we should restart tx dma processing */ - spider_net_handle_error_irq(card, status_reg); + if (status_reg & SPIDER_NET_ERRINT ) + spider_net_handle_error_irq(card, status_reg); /* clear interrupt sources */ spider_net_write_reg(card, SPIDER_NET_GHIINT0STS, status_reg); @@ -1834,26 +1811,27 @@ spider_net_setup_phy(struct spider_net_card *card) /** * spider_net_download_firmware - loads firmware into the adapter * @card: card structure - * @firmware: firmware pointer + * @firmware_ptr: pointer to firmware data * - * spider_net_download_firmware loads the firmware opened by - * spider_net_init_firmware into the adapter. + * spider_net_download_firmware loads the firmware data into the + * adapter. It assumes the length etc. to be allright. */ static int spider_net_download_firmware(struct spider_net_card *card, - const struct firmware *firmware) + u8 *firmware_ptr) { int sequencer, i; - u32 *fw_ptr = (u32 *)firmware->data; + u32 *fw_ptr = (u32 *)firmware_ptr; /* stop sequencers */ spider_net_write_reg(card, SPIDER_NET_GSINIT, SPIDER_NET_STOP_SEQ_VALUE); - for (sequencer = 0; sequencer < 6; sequencer++) { + for (sequencer = 0; sequencer < SPIDER_NET_FIRMWARE_SEQS; + sequencer++) { spider_net_write_reg(card, SPIDER_NET_GSnPRGADR + sequencer * 8, 0); - for (i = 0; i < SPIDER_NET_FIRMWARE_LEN; i++) { + for (i = 0; i < SPIDER_NET_FIRMWARE_SEQWORDS; i++) { spider_net_write_reg(card, SPIDER_NET_GSnPRGDAT + sequencer * 8, *fw_ptr); fw_ptr++; @@ -1898,41 +1876,53 @@ spider_net_download_firmware(struct spider_net_card *card, static int spider_net_init_firmware(struct spider_net_card *card) { - struct firmware *firmware; + struct firmware *firmware = NULL; struct device_node *dn; - u8 *fw_prop; - int err = -EIO; + u8 *fw_prop = NULL; + int err = -ENOENT; + int fw_size; if (request_firmware((const struct firmware **)&firmware, - SPIDER_NET_FIRMWARE_NAME, &card->pdev->dev) < 0) { - if (netif_msg_probe(card)) - pr_err("Couldn't read in sequencer data file %s.\n", - SPIDER_NET_FIRMWARE_NAME); + SPIDER_NET_FIRMWARE_NAME, &card->pdev->dev) == 0) { + if ( (firmware->size != SPIDER_NET_FIRMWARE_LEN) && + netif_msg_probe(card) ) { + pr_err("Incorrect size of spidernet firmware in " \ + "filesystem. Looking in host firmware...\n"); + goto try_host_fw; + } + err = spider_net_download_firmware(card, firmware->data); - dn = pci_device_to_OF_node(card->pdev); - if (!dn) - goto out; + release_firmware(firmware); + if (err) + goto try_host_fw; - fw_prop = (u8 *)get_property(dn, "firmware", NULL); - if (!fw_prop) - goto out; - - memcpy(firmware->data, fw_prop, 6 * SPIDER_NET_FIRMWARE_LEN * sizeof(u32)); - firmware->size = 6 * SPIDER_NET_FIRMWARE_LEN * sizeof(u32); + goto done; } - if (firmware->size != 6 * SPIDER_NET_FIRMWARE_LEN * sizeof(u32)) { - if (netif_msg_probe(card)) - pr_err("Invalid size of sequencer data file %s.\n", - SPIDER_NET_FIRMWARE_NAME); - goto out; +try_host_fw: + dn = pci_device_to_OF_node(card->pdev); + if (!dn) + goto out_err; + + fw_prop = (u8 *)get_property(dn, "firmware", &fw_size); + if (!fw_prop) + goto out_err; + + if ( (fw_size != SPIDER_NET_FIRMWARE_LEN) && + netif_msg_probe(card) ) { + pr_err("Incorrect size of spidernet firmware in " \ + "host firmware\n"); + goto done; } - if (!spider_net_download_firmware(card, firmware)) - err = 0; -out: - release_firmware(firmware); + err = spider_net_download_firmware(card, fw_prop); +done: + return err; +out_err: + if (netif_msg_probe(card)) + pr_err("Couldn't find spidernet firmware in filesystem " \ + "or host firmware\n"); return err; } @@ -1952,10 +1942,11 @@ spider_net_workaround_rxramfull(struct spider_net_card *card) SPIDER_NET_CKRCTRL_RUN_VALUE); /* empty sequencer data */ - for (sequencer = 0; sequencer < 6; sequencer++) { + for (sequencer = 0; sequencer < SPIDER_NET_FIRMWARE_SEQS; + sequencer++) { spider_net_write_reg(card, SPIDER_NET_GSnPRGDAT + sequencer * 8, 0x0); - for (i = 0; i < SPIDER_NET_FIRMWARE_LEN; i++) { + for (i = 0; i < SPIDER_NET_FIRMWARE_SEQWORDS; i++) { spider_net_write_reg(card, SPIDER_NET_GSnPRGDAT + sequencer * 8, 0x0); } @@ -2079,7 +2070,15 @@ spider_net_setup_netdev(struct spider_net_card *card) SET_NETDEV_DEV(netdev, &card->pdev->dev); pci_set_drvdata(card->pdev, netdev); - spin_lock_init(&card->intmask_lock); + + atomic_set(&card->tx_chain_release,0); + card->rxram_full_tl.data = (unsigned long) card; + card->rxram_full_tl.func = + (void (*)(unsigned long)) spider_net_handle_rxram_full; + init_timer(&card->tx_timer); + card->tx_timer.function = + (void (*)(unsigned long)) spider_net_cleanup_tx_ring; + card->tx_timer.data = (unsigned long) card; netdev->irq = card->pdev->irq; card->options.rx_csum = SPIDER_NET_RX_CSUM_DEFAULT; diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h index 98f11ecf48fc..5922b529a048 100644 --- a/drivers/net/spider_net.h +++ b/drivers/net/spider_net.h @@ -33,25 +33,32 @@ extern struct ethtool_ops spider_net_ethtool_ops; extern char spider_net_driver_name[]; -#define SPIDER_NET_MAX_MTU 2308 +#define SPIDER_NET_MAX_FRAME 2312 +#define SPIDER_NET_MAX_MTU 2294 #define SPIDER_NET_MIN_MTU 64 #define SPIDER_NET_RXBUF_ALIGN 128 -#define SPIDER_NET_RX_DESCRIPTORS_DEFAULT 64 +#define SPIDER_NET_RX_DESCRIPTORS_DEFAULT 256 #define SPIDER_NET_RX_DESCRIPTORS_MIN 16 -#define SPIDER_NET_RX_DESCRIPTORS_MAX 256 +#define SPIDER_NET_RX_DESCRIPTORS_MAX 512 -#define SPIDER_NET_TX_DESCRIPTORS_DEFAULT 64 +#define SPIDER_NET_TX_DESCRIPTORS_DEFAULT 256 #define SPIDER_NET_TX_DESCRIPTORS_MIN 16 -#define SPIDER_NET_TX_DESCRIPTORS_MAX 256 +#define SPIDER_NET_TX_DESCRIPTORS_MAX 512 + +#define SPIDER_NET_TX_TIMER 20 #define SPIDER_NET_RX_CSUM_DEFAULT 1 -#define SPIDER_NET_WATCHDOG_TIMEOUT 5*HZ -#define SPIDER_NET_NAPI_WEIGHT 64 +#define SPIDER_NET_WATCHDOG_TIMEOUT 50*HZ +#define SPIDER_NET_NAPI_WEIGHT 64 -#define SPIDER_NET_FIRMWARE_LEN 1024 +#define SPIDER_NET_FIRMWARE_SEQS 6 +#define SPIDER_NET_FIRMWARE_SEQWORDS 1024 +#define SPIDER_NET_FIRMWARE_LEN (SPIDER_NET_FIRMWARE_SEQS * \ + SPIDER_NET_FIRMWARE_SEQWORDS * \ + sizeof(u32)) #define SPIDER_NET_FIRMWARE_NAME "spider_fw.bin" /** spider_net SMMIO registers */ @@ -142,14 +149,12 @@ extern char spider_net_driver_name[]; /** SCONFIG registers */ #define SPIDER_NET_SCONFIG_IOACTE 0x00002810 -/** hardcoded register values */ -#define SPIDER_NET_INT0_MASK_VALUE 0x3f7fe3ff -#define SPIDER_NET_INT1_MASK_VALUE 0xffffffff +/** interrupt mask registers */ +#define SPIDER_NET_INT0_MASK_VALUE 0x3f7fe2c7 +#define SPIDER_NET_INT1_MASK_VALUE 0xffff7ff7 /* no MAC aborts -> auto retransmission */ -#define SPIDER_NET_INT2_MASK_VALUE 0xfffffff1 +#define SPIDER_NET_INT2_MASK_VALUE 0xffef7ff1 -/* clear counter when interrupt sources are cleared -#define SPIDER_NET_FRAMENUM_VALUE 0x0001f001 */ /* we rely on flagged descriptor interrupts */ #define SPIDER_NET_FRAMENUM_VALUE 0x00000000 /* set this first, then the FRAMENUM_VALUE */ @@ -168,7 +173,7 @@ extern char spider_net_driver_name[]; #if 0 #define SPIDER_NET_WOL_VALUE 0x00000000 #endif -#define SPIDER_NET_IPSECINIT_VALUE 0x00f000f8 +#define SPIDER_NET_IPSECINIT_VALUE 0x6f716f71 /* pause frames: automatic, no upper retransmission count */ /* outside loopback mode: ETOMOD signal dont matter, not connected */ @@ -318,6 +323,10 @@ enum spider_net_int2_status { #define SPIDER_NET_RXINT ( (1 << SPIDER_NET_GDAFDCINT) | \ (1 << SPIDER_NET_GRMFLLINT) ) +#define SPIDER_NET_ERRINT ( 0xffffffff & \ + (~SPIDER_NET_TXINT) & \ + (~SPIDER_NET_RXINT) ) + #define SPIDER_NET_GPREXEC 0x80000000 #define SPIDER_NET_GPRDAT_MASK 0x0000ffff @@ -358,9 +367,6 @@ enum spider_net_int2_status { /* descr ready, descr is in middle of chain, get interrupt on completion */ #define SPIDER_NET_DMAC_RX_CARDOWNED 0xa0800000 -/* multicast is no problem */ -#define SPIDER_NET_DATA_ERROR_MASK 0xffffbfff - enum spider_net_descr_status { SPIDER_NET_DESCR_COMPLETE = 0x00, /* used in rx and tx */ SPIDER_NET_DESCR_RESPONSE_ERROR = 0x01, /* used in rx and tx */ @@ -384,7 +390,7 @@ struct spider_net_descr { /* used in the driver */ struct sk_buff *skb; - dma_addr_t bus_addr; + u32 bus_addr; struct spider_net_descr *next; struct spider_net_descr *prev; } __attribute__((aligned(32))); @@ -396,21 +402,21 @@ struct spider_net_descr_chain { }; /* descriptor data_status bits */ -#define SPIDER_NET_RXIPCHK 29 -#define SPIDER_NET_TCPUDPIPCHK 28 -#define SPIDER_NET_DATA_STATUS_CHK_MASK (1 << SPIDER_NET_RXIPCHK | \ - 1 << SPIDER_NET_TCPUDPIPCHK) - +#define SPIDER_NET_RX_IPCHK 29 +#define SPIDER_NET_RX_TCPCHK 28 #define SPIDER_NET_VLAN_PACKET 21 +#define SPIDER_NET_DATA_STATUS_CKSUM_MASK ( (1 << SPIDER_NET_RX_IPCHK) | \ + (1 << SPIDER_NET_RX_TCPCHK) ) /* descriptor data_error bits */ -#define SPIDER_NET_RXIPCHKERR 27 -#define SPIDER_NET_RXTCPCHKERR 26 -#define SPIDER_NET_DATA_ERROR_CHK_MASK (1 << SPIDER_NET_RXIPCHKERR | \ - 1 << SPIDER_NET_RXTCPCHKERR) +#define SPIDER_NET_RX_IPCHKERR 27 +#define SPIDER_NET_RX_RXTCPCHKERR 28 -/* the cases we don't pass the packet to the stack */ -#define SPIDER_NET_DESTROY_RX_FLAGS 0x70138000 +#define SPIDER_NET_DATA_ERR_CKSUM_MASK (1 << SPIDER_NET_RX_IPCHKERR) + +/* the cases we don't pass the packet to the stack. + * 701b8000 would be correct, but every packets gets that flag */ +#define SPIDER_NET_DESTROY_RX_FLAGS 0x700b8000 #define SPIDER_NET_DESCR_SIZE 32 @@ -445,13 +451,16 @@ struct spider_net_card { struct spider_net_descr_chain tx_chain; struct spider_net_descr_chain rx_chain; - spinlock_t chain_lock; + atomic_t rx_chain_refill; + atomic_t tx_chain_release; struct net_device_stats netdev_stats; struct spider_net_options options; spinlock_t intmask_lock; + struct tasklet_struct rxram_full_tl; + struct timer_list tx_timer; struct work_struct tx_timeout_task; atomic_t tx_timeout_task_counter; diff --git a/drivers/net/spider_net_ethtool.c b/drivers/net/spider_net_ethtool.c index d42e60ba74ce..a5bb0b7633af 100644 --- a/drivers/net/spider_net_ethtool.c +++ b/drivers/net/spider_net_ethtool.c @@ -113,6 +113,23 @@ spider_net_ethtool_set_rx_csum(struct net_device *netdev, u32 n) return 0; } +static uint32_t +spider_net_ethtool_get_tx_csum(struct net_device *netdev) +{ + return (netdev->features & NETIF_F_HW_CSUM) != 0; +} + +static int +spider_net_ethtool_set_tx_csum(struct net_device *netdev, uint32_t data) +{ + if (data) + netdev->features |= NETIF_F_HW_CSUM; + else + netdev->features &= ~NETIF_F_HW_CSUM; + + return 0; +} + struct ethtool_ops spider_net_ethtool_ops = { .get_settings = spider_net_ethtool_get_settings, .get_drvinfo = spider_net_ethtool_get_drvinfo, @@ -122,5 +139,7 @@ struct ethtool_ops spider_net_ethtool_ops = { .nway_reset = spider_net_ethtool_nway_reset, .get_rx_csum = spider_net_ethtool_get_rx_csum, .set_rx_csum = spider_net_ethtool_set_rx_csum, + .get_tx_csum = spider_net_ethtool_get_tx_csum, + .set_tx_csum = spider_net_ethtool_set_tx_csum, }; From 7c5c220e254b2cdcf7083dcaf445820b899f7e8b Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 12 Jan 2006 17:16:45 -0500 Subject: [PATCH 25/76] [PATCH] spidernet: fix missing include This is now required to avoid drivers/net/spider_net.c:844: error: 'IPPROTO_TCP' undeclared Signed-off-by: Arnd Bergmann Signed-off-by: Jeff Garzik --- drivers/net/spider_net.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index e2ad9aef0109..1f5975a61e1f 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include From 4ee9c02007249cf9c66e368b5d433c6956e05586 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 12 Jan 2006 16:50:18 -0800 Subject: [PATCH 26/76] [PATCH] e1000: Fix jumbo frame performance Partition PBA for Jumbo frames based on MTU size. Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 438a931fd55d..4b44bcd0f958 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -43,7 +43,7 @@ static char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver"; #else #define DRIVERNAPI "-NAPI" #endif -#define DRV_VERSION "6.1.16-k2"DRIVERNAPI +#define DRV_VERSION "6.3.9-k2"DRIVERNAPI char e1000_driver_version[] = DRV_VERSION; static char e1000_copyright[] = "Copyright (c) 1999-2005 Intel Corporation."; @@ -449,7 +449,7 @@ e1000_reset(struct e1000_adapter *adapter) } if((adapter->hw.mac_type != e1000_82573) && - (adapter->rx_buffer_len > E1000_RXBUFFER_8192)) { + (adapter->netdev->mtu > E1000_RXBUFFER_8192)) { pba -= 8; /* allocate more FIFO for Tx */ /* send an XOFF when there is enough space in the * Rx FIFO to hold one extra full size Rx packet From 9a3056da0d7fde1e19e806824c41857b239954ed Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 12 Jan 2006 16:50:23 -0800 Subject: [PATCH 27/76] [PATCH] e1000: Fix TSO Fixed the TSO workaround for 82571/2 controllers. Fixed TSO issue where a non-tso packet in a linear SKB which followed a TSO packet would get written back prematurely. Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_main.c | 37 +++++++++++++++++----------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 4b44bcd0f958..4945a41e3aea 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -2688,11 +2688,23 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) * overrun the FIFO, adjust the max buffer len if mss * drops. */ if(mss) { + uint8_t hdr_len; max_per_txd = min(mss << 2, max_per_txd); max_txd_pwr = fls(max_per_txd) - 1; + + /* TSO Workaround for 82571/2 Controllers -- if skb->data + * points to just header, pull a few bytes of payload from + * frags into skb->data */ + hdr_len = ((skb->h.raw - skb->data) + (skb->h.th->doff << 2)); + if (skb->data_len && (hdr_len == (skb->len - skb->data_len)) && + (adapter->hw.mac_type == e1000_82571 || + adapter->hw.mac_type == e1000_82572)) { + len = skb->len - skb->data_len; + } } if((mss) || (skb->ip_summed == CHECKSUM_HW)) + /* reserve a descriptor for the offload context */ count++; count++; #else @@ -2726,26 +2738,13 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) if(adapter->pcix_82544) count += nr_frags; -#ifdef NETIF_F_TSO - /* TSO Workaround for 82571/2 Controllers -- if skb->data - * points to just header, pull a few bytes of payload from - * frags into skb->data */ - if (skb_shinfo(skb)->tso_size) { - uint8_t hdr_len; - hdr_len = ((skb->h.raw - skb->data) + (skb->h.th->doff << 2)); - if (skb->data_len && (hdr_len < (skb->len - skb->data_len)) && - (adapter->hw.mac_type == e1000_82571 || - adapter->hw.mac_type == e1000_82572)) { - unsigned int pull_size; - pull_size = min((unsigned int)4, skb->data_len); - if (!__pskb_pull_tail(skb, pull_size)) { - printk(KERN_ERR "__pskb_pull_tail failed.\n"); - dev_kfree_skb_any(skb); - return -EFAULT; - } + unsigned int pull_size; + pull_size = min((unsigned int)4, skb->data_len); + if (!__pskb_pull_tail(skb, pull_size)) { + printk(KERN_ERR "__pskb_pull_tail failed.\n"); + dev_kfree_skb_any(skb); + return -EFAULT; } - } -#endif if(adapter->hw.tx_pkt_filtering && (adapter->hw.mac_type == e1000_82573) ) e1000_transfer_dhcp_info(adapter, skb); From 545c67c0a3550545fe50d28c874b0664bc5dc882 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 12 Jan 2006 16:50:25 -0800 Subject: [PATCH 28/76] [PATCH] e1000: General Fixes These fixes update the TX and RX ring structures. Prepare driver for up-coming fixes. Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000.h | 8 ++++++-- drivers/net/e1000/e1000_main.c | 14 +++++++++----- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index e02e9ba2e18b..c87187d3e595 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -191,7 +191,6 @@ struct e1000_tx_ring { spinlock_t tx_lock; uint16_t tdh; uint16_t tdt; - uint64_t pkt; boolean_t last_tx_tso; @@ -216,9 +215,14 @@ struct e1000_rx_ring { struct e1000_ps_page *ps_page; struct e1000_ps_page_dma *ps_page_dma; + struct sk_buff *rx_skb_top; + struct sk_buff *rx_skb_prev; + + /* cpu for rx queue */ + int cpu; + uint16_t rdh; uint16_t rdt; - uint64_t pkt; }; #define E1000_DESC_UNUSED(R) \ diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 4945a41e3aea..22c8286a4849 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -2204,7 +2204,7 @@ static void e1000_watchdog_task(struct e1000_adapter *adapter) { struct net_device *netdev = adapter->netdev; - struct e1000_tx_ring *txdr = &adapter->tx_ring[0]; + struct e1000_tx_ring *txdr = adapter->tx_ring; uint32_t link; e1000_check_for_link(&adapter->hw); @@ -2314,6 +2314,7 @@ e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, { #ifdef NETIF_F_TSO struct e1000_context_desc *context_desc; + struct e1000_buffer *buffer_info; unsigned int i; uint32_t cmd_length = 0; uint16_t ipcse = 0, tucse, mss; @@ -2363,6 +2364,7 @@ e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, i = tx_ring->next_to_use; context_desc = E1000_CONTEXT_DESC(*tx_ring, i); + buffer_info = &tx_ring->buffer_info[i]; context_desc->lower_setup.ip_fields.ipcss = ipcss; context_desc->lower_setup.ip_fields.ipcso = ipcso; @@ -2374,6 +2376,8 @@ e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, context_desc->tcp_seg_setup.fields.hdr_len = hdr_len; context_desc->cmd_and_length = cpu_to_le32(cmd_length); + buffer_info->time_stamp = jiffies; + if (++i == tx_ring->count) i = 0; tx_ring->next_to_use = i; @@ -2389,6 +2393,7 @@ e1000_tx_csum(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, struct sk_buff *skb) { struct e1000_context_desc *context_desc; + struct e1000_buffer *buffer_info; unsigned int i; uint8_t css; @@ -2396,6 +2401,7 @@ e1000_tx_csum(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, css = skb->h.raw - skb->data; i = tx_ring->next_to_use; + buffer_info = &tx_ring->buffer_info[i]; context_desc = E1000_CONTEXT_DESC(*tx_ring, i); context_desc->upper_setup.tcp_fields.tucss = css; @@ -2404,6 +2410,8 @@ e1000_tx_csum(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, context_desc->tcp_seg_setup.data = 0; context_desc->cmd_and_length = cpu_to_le32(E1000_TXD_CMD_DEXT); + buffer_info->time_stamp = jiffies; + if (unlikely(++i == tx_ring->count)) i = 0; tx_ring->next_to_use = i; @@ -3255,8 +3263,6 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter, if(unlikely(++i == tx_ring->count)) i = 0; } - tx_ring->pkt++; - eop = tx_ring->buffer_info[i].next_to_watch; eop_desc = E1000_TX_DESC(*tx_ring, eop); } @@ -3461,7 +3467,6 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter, } #endif /* CONFIG_E1000_NAPI */ netdev->last_rx = jiffies; - rx_ring->pkt++; next_desc: rx_desc->status = 0; @@ -3592,7 +3597,6 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, } #endif /* CONFIG_E1000_NAPI */ netdev->last_rx = jiffies; - rx_ring->pkt++; next_desc: rx_desc->wb.middle.status_error &= ~0xFF; From 571281972e2ca590ef160dcd6669b9f724b64283 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 12 Jan 2006 16:50:28 -0800 Subject: [PATCH 29/76] [PATCH] e1000: Fix SoL/IDER link and loopback Fix so that if a SoL/IDER session is active, do not allow operations which require a PHY reset and instead log a message. Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_ethtool.c | 128 +++++++++++------------------- drivers/net/e1000/e1000_main.c | 16 ++-- drivers/net/e1000/e1000_param.c | 6 ++ 3 files changed, 65 insertions(+), 85 deletions(-) diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index c88f1a3c1b1d..c929277dc276 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -183,7 +183,15 @@ e1000_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; - if(ecmd->autoneg == AUTONEG_ENABLE) { + /* When SoL/IDER sessions are active, autoneg/speed/duplex + * cannot be changed */ + if (e1000_check_phy_reset_block(hw)) { + DPRINTK(DRV, ERR, "Cannot change link characteristics " + "when SoL/IDER is active.\n"); + return -EINVAL; + } + + if (ecmd->autoneg == AUTONEG_ENABLE) { hw->autoneg = 1; if(hw->media_type == e1000_media_type_fiber) hw->autoneg_advertised = ADVERTISED_1000baseT_Full | @@ -562,29 +570,10 @@ e1000_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo) { struct e1000_adapter *adapter = netdev_priv(netdev); - char firmware_version[32]; - uint16_t eeprom_data; strncpy(drvinfo->driver, e1000_driver_name, 32); strncpy(drvinfo->version, e1000_driver_version, 32); - - /* EEPROM image version # is reported as firware version # for - * 8257{1|2|3} controllers */ - e1000_read_eeprom(&adapter->hw, 5, 1, &eeprom_data); - switch (adapter->hw.mac_type) { - case e1000_82571: - case e1000_82572: - case e1000_82573: - sprintf(firmware_version, "%d.%d-%d", - (eeprom_data & 0xF000) >> 12, - (eeprom_data & 0x0FF0) >> 4, - eeprom_data & 0x000F); - break; - default: - sprintf(firmware_version, "n/a"); - } - - strncpy(drvinfo->fw_version, firmware_version, 32); + strncpy(drvinfo->fw_version, "N/A", 32); strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32); drvinfo->n_stats = E1000_STATS_LEN; drvinfo->testinfo_len = E1000_TEST_LEN; @@ -990,10 +979,8 @@ e1000_free_desc_rings(struct e1000_adapter *adapter) kfree(txdr->buffer_info); txdr->buffer_info = NULL; - kfree(rxdr->buffer_info); rxdr->buffer_info = NULL; - return; } @@ -1328,32 +1315,21 @@ static int e1000_setup_loopback_test(struct e1000_adapter *adapter) { uint32_t rctl; - struct e1000_hw *hw = &adapter->hw; - if (hw->media_type == e1000_media_type_fiber || - hw->media_type == e1000_media_type_internal_serdes) { - switch (hw->mac_type) { - case e1000_82545: - case e1000_82546: - case e1000_82545_rev_3: - case e1000_82546_rev_3: + if(adapter->hw.media_type == e1000_media_type_fiber || + adapter->hw.media_type == e1000_media_type_internal_serdes) { + if(adapter->hw.mac_type == e1000_82545 || + adapter->hw.mac_type == e1000_82546 || + adapter->hw.mac_type == e1000_82545_rev_3 || + adapter->hw.mac_type == e1000_82546_rev_3) return e1000_set_phy_loopback(adapter); - break; - case e1000_82571: - case e1000_82572: -#define E1000_SERDES_LB_ON 0x410 - e1000_set_phy_loopback(adapter); - E1000_WRITE_REG(hw, SCTL, E1000_SERDES_LB_ON); - msec_delay(10); - return 0; - break; - default: - rctl = E1000_READ_REG(hw, RCTL); + else { + rctl = E1000_READ_REG(&adapter->hw, RCTL); rctl |= E1000_RCTL_LBM_TCVR; - E1000_WRITE_REG(hw, RCTL, rctl); + E1000_WRITE_REG(&adapter->hw, RCTL, rctl); return 0; } - } else if (hw->media_type == e1000_media_type_copper) + } else if(adapter->hw.media_type == e1000_media_type_copper) return e1000_set_phy_loopback(adapter); return 7; @@ -1364,36 +1340,25 @@ e1000_loopback_cleanup(struct e1000_adapter *adapter) { uint32_t rctl; uint16_t phy_reg; - struct e1000_hw *hw = &adapter->hw; rctl = E1000_READ_REG(&adapter->hw, RCTL); rctl &= ~(E1000_RCTL_LBM_TCVR | E1000_RCTL_LBM_MAC); E1000_WRITE_REG(&adapter->hw, RCTL, rctl); - switch (hw->mac_type) { - case e1000_82571: - case e1000_82572: - if (hw->media_type == e1000_media_type_fiber || - hw->media_type == e1000_media_type_internal_serdes){ -#define E1000_SERDES_LB_OFF 0x400 - E1000_WRITE_REG(hw, SCTL, E1000_SERDES_LB_OFF); - msec_delay(10); - break; - } - /* fall thru for Cu adapters */ - case e1000_82545: - case e1000_82546: - case e1000_82545_rev_3: - case e1000_82546_rev_3: - default: - hw->autoneg = TRUE; - e1000_read_phy_reg(hw, PHY_CTRL, &phy_reg); - if (phy_reg & MII_CR_LOOPBACK) { + if(adapter->hw.media_type == e1000_media_type_copper || + ((adapter->hw.media_type == e1000_media_type_fiber || + adapter->hw.media_type == e1000_media_type_internal_serdes) && + (adapter->hw.mac_type == e1000_82545 || + adapter->hw.mac_type == e1000_82546 || + adapter->hw.mac_type == e1000_82545_rev_3 || + adapter->hw.mac_type == e1000_82546_rev_3))) { + adapter->hw.autoneg = TRUE; + e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &phy_reg); + if(phy_reg & MII_CR_LOOPBACK) { phy_reg &= ~MII_CR_LOOPBACK; - e1000_write_phy_reg(hw, PHY_CTRL, phy_reg); - e1000_phy_reset(hw); + e1000_write_phy_reg(&adapter->hw, PHY_CTRL, phy_reg); + e1000_phy_reset(&adapter->hw); } - break; } } @@ -1488,14 +1453,25 @@ e1000_run_loopback_test(struct e1000_adapter *adapter) static int e1000_loopback_test(struct e1000_adapter *adapter, uint64_t *data) { - if((*data = e1000_setup_desc_rings(adapter))) goto err_loopback; - if((*data = e1000_setup_loopback_test(adapter))) - goto err_loopback_setup; + /* PHY loopback cannot be performed if SoL/IDER + * sessions are active */ + if (e1000_check_phy_reset_block(&adapter->hw)) { + DPRINTK(DRV, ERR, "Cannot do PHY loopback test " + "when SoL/IDER is active.\n"); + *data = 0; + goto out; + } + + if ((*data = e1000_setup_desc_rings(adapter))) + goto out; + if ((*data = e1000_setup_loopback_test(adapter))) + goto err_loopback; *data = e1000_run_loopback_test(adapter); e1000_loopback_cleanup(adapter); -err_loopback_setup: - e1000_free_desc_rings(adapter); + err_loopback: + e1000_free_desc_rings(adapter); +out: return *data; } @@ -1722,14 +1698,6 @@ e1000_phys_id(struct net_device *netdev, uint32_t data) msleep_interruptible(data * 1000); del_timer_sync(&adapter->blink_timer); } - else if(adapter->hw.mac_type < e1000_82573) { - E1000_WRITE_REG(&adapter->hw, LEDCTL, (E1000_LEDCTL_LED2_BLINK_RATE | - E1000_LEDCTL_LED0_BLINK | E1000_LEDCTL_LED2_BLINK | - (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED2_MODE_SHIFT) | - (E1000_LEDCTL_MODE_LINK_ACTIVITY << E1000_LEDCTL_LED0_MODE_SHIFT) | - (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED1_MODE_SHIFT))); - msleep_interruptible(data * 1000); - } else { E1000_WRITE_REG(&adapter->hw, LEDCTL, (E1000_LEDCTL_LED2_BLINK_RATE | E1000_LEDCTL_LED1_BLINK | E1000_LEDCTL_LED2_BLINK | diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 22c8286a4849..66cf1748ba9b 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -378,6 +378,8 @@ void e1000_down(struct e1000_adapter *adapter) { struct net_device *netdev = adapter->netdev; + boolean_t mng_mode_enabled = (adapter->hw.mac_type >= e1000_82571) && + e1000_check_mng_mode(&adapter->hw); e1000_irq_disable(adapter); #ifdef CONFIG_E1000_MQ @@ -405,12 +407,16 @@ e1000_down(struct e1000_adapter *adapter) e1000_clean_all_tx_rings(adapter); e1000_clean_all_rx_rings(adapter); - /* If WoL is not enabled and management mode is not IAMT - * Power down the PHY so no link is implied when interface is down */ - if(!adapter->wol && adapter->hw.mac_type >= e1000_82540 && + /* Power down the PHY so no link is implied when interface is down * + * The PHY cannot be powered down if any of the following is TRUE * + * (a) WoL is enabled + * (b) AMT is active + * (c) SoL/IDER session is active */ + if (!adapter->wol && adapter->hw.mac_type >= e1000_82540 && adapter->hw.media_type == e1000_media_type_copper && - !e1000_check_mng_mode(&adapter->hw) && - !(E1000_READ_REG(&adapter->hw, MANC) & E1000_MANC_SMBUS_EN)) { + !(E1000_READ_REG(&adapter->hw, MANC) & E1000_MANC_SMBUS_EN) && + !mng_mode_enabled && + !e1000_check_phy_reset_block(&adapter->hw)) { uint16_t mii_reg; e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &mii_reg); mii_reg |= MII_CR_POWER_DOWN; diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c index ccbbe5ad8e0f..852841f12fb9 100644 --- a/drivers/net/e1000/e1000_param.c +++ b/drivers/net/e1000/e1000_param.c @@ -584,6 +584,12 @@ e1000_check_copper_options(struct e1000_adapter *adapter) .p = dplx_list }} }; + if (e1000_check_phy_reset_block(&adapter->hw)) { + DPRINTK(PROBE, INFO, + "Link active due to SoL/IDER Session. " + "Speed/Duplex/AutoNeg parameter ignored.\n"); + return; + } if (num_Duplex > bd) { dplx = Duplex[bd]; e1000_validate_option(&dplx, &opt, adapter); From b55ccb356167ed2d2d40b9dc0fe05bbe1a3d6f39 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 12 Jan 2006 16:50:30 -0800 Subject: [PATCH 30/76] [PATCH] e1000: Fix ASF/AMT for 8257{1|2|3} controllers The 82573 controller required different logic than 82571|2 controllers. Corrected the reset logic for 8257{1|2|3} controllers. Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_hw.c | 2 + drivers/net/e1000/e1000_main.c | 175 ++++++++++++++++++++------------- 2 files changed, 107 insertions(+), 70 deletions(-) diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index 136fc031e4ad..f853e1064ac0 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -2982,6 +2982,8 @@ e1000_phy_hw_reset(struct e1000_hw *hw) if (hw->mac_type < e1000_82571) msec_delay(10); + else + udelay(100); E1000_WRITE_REG(hw, CTRL, ctrl); E1000_WRITE_FLUSH(hw); diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 66cf1748ba9b..5b4287163e01 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -319,7 +319,75 @@ e1000_update_mng_vlan(struct e1000_adapter *adapter) } } } - + +/** + * e1000_release_hw_control - release control of the h/w to f/w + * @adapter: address of board private structure + * + * e1000_release_hw_control resets {CTRL_EXT|FWSM}:DRV_LOAD bit. + * For ASF and Pass Through versions of f/w this means that the + * driver is no longer loaded. For AMT version (only with 82573) i + * of the f/w this means that the netowrk i/f is closed. + * + **/ + +static inline void +e1000_release_hw_control(struct e1000_adapter *adapter) +{ + uint32_t ctrl_ext; + uint32_t swsm; + + /* Let firmware taken over control of h/w */ + switch (adapter->hw.mac_type) { + case e1000_82571: + case e1000_82572: + ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT); + E1000_WRITE_REG(&adapter->hw, CTRL_EXT, + ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD); + break; + case e1000_82573: + swsm = E1000_READ_REG(&adapter->hw, SWSM); + E1000_WRITE_REG(&adapter->hw, SWSM, + swsm & ~E1000_SWSM_DRV_LOAD); + default: + break; + } +} + +/** + * e1000_get_hw_control - get control of the h/w from f/w + * @adapter: address of board private structure + * + * e1000_get_hw_control sets {CTRL_EXT|FWSM}:DRV_LOAD bit. + * For ASF and Pass Through versions of f/w this means that + * the driver is loaded. For AMT version (only with 82573) + * of the f/w this means that the netowrk i/f is open. + * + **/ + +static inline void +e1000_get_hw_control(struct e1000_adapter *adapter) +{ + uint32_t ctrl_ext; + uint32_t swsm; + /* Let firmware know the driver has taken over */ + switch (adapter->hw.mac_type) { + case e1000_82571: + case e1000_82572: + ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT); + E1000_WRITE_REG(&adapter->hw, CTRL_EXT, + ctrl_ext | E1000_CTRL_EXT_DRV_LOAD); + break; + case e1000_82573: + swsm = E1000_READ_REG(&adapter->hw, SWSM); + E1000_WRITE_REG(&adapter->hw, SWSM, + swsm | E1000_SWSM_DRV_LOAD); + break; + default: + break; + } +} + int e1000_up(struct e1000_adapter *adapter) { @@ -523,8 +591,6 @@ e1000_probe(struct pci_dev *pdev, struct net_device *netdev; struct e1000_adapter *adapter; unsigned long mmio_start, mmio_len; - uint32_t ctrl_ext; - uint32_t swsm; static int cards_found = 0; int i, err, pci_using_dac; @@ -736,22 +802,13 @@ e1000_probe(struct pci_dev *pdev, /* reset the hardware with the new settings */ e1000_reset(adapter); - /* Let firmware know the driver has taken over */ - switch(adapter->hw.mac_type) { - case e1000_82571: - case e1000_82572: - ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT); - E1000_WRITE_REG(&adapter->hw, CTRL_EXT, - ctrl_ext | E1000_CTRL_EXT_DRV_LOAD); - break; - case e1000_82573: - swsm = E1000_READ_REG(&adapter->hw, SWSM); - E1000_WRITE_REG(&adapter->hw, SWSM, - swsm | E1000_SWSM_DRV_LOAD); - break; - default: - break; - } + /* If the controller is 82573 and f/w is AMT, do not set + * DRV_LOAD until the interface is up. For all other cases, + * let the f/w know that the h/w is now under the control + * of the driver. */ + if (adapter->hw.mac_type != e1000_82573 || + !e1000_check_mng_mode(&adapter->hw)) + e1000_get_hw_control(adapter); strcpy(netdev->name, "eth%d"); if((err = register_netdev(netdev))) @@ -788,8 +845,7 @@ e1000_remove(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); struct e1000_adapter *adapter = netdev_priv(netdev); - uint32_t ctrl_ext; - uint32_t manc, swsm; + uint32_t manc; #ifdef CONFIG_E1000_NAPI int i; #endif @@ -805,22 +861,9 @@ e1000_remove(struct pci_dev *pdev) } } - switch(adapter->hw.mac_type) { - case e1000_82571: - case e1000_82572: - ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT); - E1000_WRITE_REG(&adapter->hw, CTRL_EXT, - ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD); - break; - case e1000_82573: - swsm = E1000_READ_REG(&adapter->hw, SWSM); - E1000_WRITE_REG(&adapter->hw, SWSM, - swsm & ~E1000_SWSM_DRV_LOAD); - break; - - default: - break; - } + /* Release control of h/w to f/w. If f/w is AMT enabled, this + * would have already happened in close and is redundant. */ + e1000_release_hw_control(adapter); unregister_netdev(netdev); #ifdef CONFIG_E1000_NAPI @@ -1077,6 +1120,12 @@ e1000_open(struct net_device *netdev) e1000_update_mng_vlan(adapter); } + /* If AMT is enabled, let the firmware know that the network + * interface is now open */ + if (adapter->hw.mac_type == e1000_82573 && + e1000_check_mng_mode(&adapter->hw)) + e1000_get_hw_control(adapter); + return E1000_SUCCESS; err_up: @@ -1115,6 +1164,13 @@ e1000_close(struct net_device *netdev) E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT)) { e1000_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id); } + + /* If AMT is enabled, let the firmware know that the network + * interface is now closed */ + if (adapter->hw.mac_type == e1000_82573 && + e1000_check_mng_mode(&adapter->hw)) + e1000_release_hw_control(adapter); + return 0; } @@ -4182,7 +4238,7 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state) { struct net_device *netdev = pci_get_drvdata(pdev); struct e1000_adapter *adapter = netdev_priv(netdev); - uint32_t ctrl, ctrl_ext, rctl, manc, status, swsm; + uint32_t ctrl, ctrl_ext, rctl, manc, status; uint32_t wufc = adapter->wol; netif_device_detach(netdev); @@ -4251,21 +4307,9 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state) } } - switch(adapter->hw.mac_type) { - case e1000_82571: - case e1000_82572: - ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT); - E1000_WRITE_REG(&adapter->hw, CTRL_EXT, - ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD); - break; - case e1000_82573: - swsm = E1000_READ_REG(&adapter->hw, SWSM); - E1000_WRITE_REG(&adapter->hw, SWSM, - swsm & ~E1000_SWSM_DRV_LOAD); - break; - default: - break; - } + /* Release control of h/w to f/w. If f/w is AMT enabled, this + * would have already happened in close and is redundant. */ + e1000_release_hw_control(adapter); pci_disable_device(pdev); pci_set_power_state(pdev, pci_choose_state(pdev, state)); @@ -4278,8 +4322,7 @@ e1000_resume(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); struct e1000_adapter *adapter = netdev_priv(netdev); - uint32_t manc, ret_val, swsm; - uint32_t ctrl_ext; + uint32_t manc, ret_val; pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); @@ -4304,21 +4347,13 @@ e1000_resume(struct pci_dev *pdev) E1000_WRITE_REG(&adapter->hw, MANC, manc); } - switch(adapter->hw.mac_type) { - case e1000_82571: - case e1000_82572: - ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT); - E1000_WRITE_REG(&adapter->hw, CTRL_EXT, - ctrl_ext | E1000_CTRL_EXT_DRV_LOAD); - break; - case e1000_82573: - swsm = E1000_READ_REG(&adapter->hw, SWSM); - E1000_WRITE_REG(&adapter->hw, SWSM, - swsm | E1000_SWSM_DRV_LOAD); - break; - default: - break; - } + /* If the controller is 82573 and f/w is AMT, do not set + * DRV_LOAD until the interface is up. For all other cases, + * let the f/w know that the h/w is now under the control + * of the driver. */ + if (adapter->hw.mac_type != e1000_82573 || + !e1000_check_mng_mode(&adapter->hw)) + e1000_get_hw_control(adapter); return 0; } From 7892f59c5ea86115450293441ca10654168e00da Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 12 Jan 2006 16:50:32 -0800 Subject: [PATCH 31/76] [PATCH] e1000: Fix PHY config for 82573 controller Added a delay to allow PHY configuration to complete before accessing NVM. Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_hw.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index f853e1064ac0..45fa386d212e 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -6722,6 +6722,12 @@ e1000_get_phy_cfg_done(struct e1000_hw *hw) break; } + /* PHY configuration from NVM just starts after EECD_AUTO_RD sets to high. + * Need to wait for PHY configuration completion before accessing NVM + * and PHY. */ + if (hw->mac_type == e1000_82573) + msec_delay(25); + return E1000_SUCCESS; } From 6b7660cd4df23ee92ddc0ba4b4ec31e3adee7bc9 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 12 Jan 2006 16:50:35 -0800 Subject: [PATCH 32/76] [PATCH] Fix e1000 stats Updated the e1000_stats structure and removed mpx for rx_errors and rx_dropped. Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000.h | 2 ++ drivers/net/e1000/e1000_ethtool.c | 2 ++ drivers/net/e1000/e1000_main.c | 8 ++++---- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index c87187d3e595..4dd1326dd04f 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -275,6 +275,7 @@ struct e1000_adapter { uint64_t gotcl_old; uint64_t tpt_old; uint64_t colc_old; + uint32_t tx_timeout_count; uint32_t tx_fifo_head; uint32_t tx_head_addr; uint32_t tx_fifo_size; @@ -307,6 +308,7 @@ struct e1000_adapter { uint64_t hw_csum_err; uint64_t hw_csum_good; uint64_t rx_hdr_split; + uint32_t alloc_rx_buff_failed; uint32_t rx_int_delay; uint32_t rx_abs_int_delay; boolean_t rx_csum; diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index c929277dc276..791110d4bbaa 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -80,6 +80,7 @@ static const struct e1000_stats e1000_gstrings_stats[] = { { "tx_deferred_ok", E1000_STAT(stats.dc) }, { "tx_single_coll_ok", E1000_STAT(stats.scc) }, { "tx_multi_coll_ok", E1000_STAT(stats.mcc) }, + { "tx_timeout_count", E1000_STAT(tx_timeout_count) }, { "rx_long_length_errors", E1000_STAT(stats.roc) }, { "rx_short_length_errors", E1000_STAT(stats.ruc) }, { "rx_align_errors", E1000_STAT(stats.algnerrc) }, @@ -93,6 +94,7 @@ static const struct e1000_stats e1000_gstrings_stats[] = { { "rx_csum_offload_good", E1000_STAT(hw_csum_good) }, { "rx_csum_offload_errors", E1000_STAT(hw_csum_err) }, { "rx_header_split", E1000_STAT(rx_hdr_split) }, + { "alloc_rx_buff_failed", E1000_STAT(alloc_rx_buff_failed) }, }; #define E1000_STATS_LEN \ sizeof(e1000_gstrings_stats) / sizeof(struct e1000_stats) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 5b4287163e01..5f848b3a3a4d 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -2902,6 +2902,7 @@ e1000_tx_timeout_task(struct net_device *netdev) { struct e1000_adapter *adapter = netdev_priv(netdev); + adapter->tx_timeout_count++; e1000_down(adapter); e1000_up(adapter); } @@ -2919,7 +2920,7 @@ e1000_get_stats(struct net_device *netdev) { struct e1000_adapter *adapter = netdev_priv(netdev); - e1000_update_stats(adapter); + /* only return the current stats */ return &adapter->net_stats; } @@ -3106,12 +3107,11 @@ e1000_update_stats(struct e1000_adapter *adapter) adapter->net_stats.rx_errors = adapter->stats.rxerrc + adapter->stats.crcerrs + adapter->stats.algnerrc + - adapter->stats.rlec + adapter->stats.mpc + - adapter->stats.cexterr; + adapter->stats.rlec + adapter->stats.cexterr; + adapter->net_stats.rx_dropped = 0; adapter->net_stats.rx_length_errors = adapter->stats.rlec; adapter->net_stats.rx_crc_errors = adapter->stats.crcerrs; adapter->net_stats.rx_frame_errors = adapter->stats.algnerrc; - adapter->net_stats.rx_fifo_errors = adapter->stats.mpc; adapter->net_stats.rx_missed_errors = adapter->stats.mpc; /* Tx Errors */ From d8c2bd3d3aa49e18ffebb999979b976f04280284 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 12 Jan 2006 16:50:37 -0800 Subject: [PATCH 33/76] [PATCH] e1000: Fix LED functionality for 82573 Fixed adapter identification issue. Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_ethtool.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index 791110d4bbaa..54ae8805e79f 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -1699,13 +1699,21 @@ e1000_phys_id(struct net_device *netdev, uint32_t data) mod_timer(&adapter->blink_timer, jiffies); msleep_interruptible(data * 1000); del_timer_sync(&adapter->blink_timer); - } - else { - E1000_WRITE_REG(&adapter->hw, LEDCTL, (E1000_LEDCTL_LED2_BLINK_RATE | - E1000_LEDCTL_LED1_BLINK | E1000_LEDCTL_LED2_BLINK | - (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED2_MODE_SHIFT) | - (E1000_LEDCTL_MODE_LINK_ACTIVITY << E1000_LEDCTL_LED1_MODE_SHIFT) | - (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED0_MODE_SHIFT))); + } else if (adapter->hw.mac_type < e1000_82573) { + E1000_WRITE_REG(&adapter->hw, LEDCTL, + (E1000_LEDCTL_LED2_BLINK_RATE | + E1000_LEDCTL_LED0_BLINK | E1000_LEDCTL_LED2_BLINK | + (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED2_MODE_SHIFT) | + (E1000_LEDCTL_MODE_LINK_ACTIVITY << E1000_LEDCTL_LED0_MODE_SHIFT) | + (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED1_MODE_SHIFT))); + msleep_interruptible(data * 1000); + } else { + E1000_WRITE_REG(&adapter->hw, LEDCTL, + (E1000_LEDCTL_LED2_BLINK_RATE | + E1000_LEDCTL_LED1_BLINK | E1000_LEDCTL_LED2_BLINK | + (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED2_MODE_SHIFT) | + (E1000_LEDCTL_MODE_LINK_ACTIVITY << E1000_LEDCTL_LED1_MODE_SHIFT) | + (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED0_MODE_SHIFT))); msleep_interruptible(data * 1000); } From f56799ea39a85a6f3760a134aa0e6d1c17eea369 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 12 Jan 2006 16:50:39 -0800 Subject: [PATCH 34/76] [PATCH] e1000: Fix adapter structure and prepare for multique fix Fix adapter structure to handle multiple queues and prepping the driver for full multiple queue support, some changes are ifdef'd our unless you define CONFIG_E1000_MQ. Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000.h | 5 +- drivers/net/e1000/e1000_ethtool.c | 8 ++-- drivers/net/e1000/e1000_hw.h | 1 + drivers/net/e1000/e1000_main.c | 76 ++++++++++++++++++------------- drivers/net/e1000/e1000_param.c | 4 +- 5 files changed, 55 insertions(+), 39 deletions(-) diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index 4dd1326dd04f..5940f7a223bc 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -268,6 +268,7 @@ struct e1000_adapter { #ifdef CONFIG_E1000_MQ struct e1000_tx_ring **cpu_tx_ring; /* per-cpu */ #endif + unsigned long tx_queue_len; uint32_t txd_cmd; uint32_t tx_int_delay; uint32_t tx_abs_int_delay; @@ -303,7 +304,8 @@ struct e1000_adapter { struct call_async_data_struct rx_sched_call_data; int cpu_for_queue[4]; #endif - int num_queues; + int num_tx_queues; + int num_rx_queues; uint64_t hw_csum_err; uint64_t hw_csum_good; @@ -336,6 +338,7 @@ struct e1000_adapter { struct e1000_rx_ring test_rx_ring; + u32 *config_space; int msg_enable; #ifdef CONFIG_PCI_MSI boolean_t have_msi; diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index 54ae8805e79f..fa9a4659369a 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -614,8 +614,8 @@ e1000_set_ringparam(struct net_device *netdev, struct e1000_rx_ring *rxdr, *rx_old, *rx_new; int i, err, tx_ring_size, rx_ring_size; - tx_ring_size = sizeof(struct e1000_tx_ring) * adapter->num_queues; - rx_ring_size = sizeof(struct e1000_rx_ring) * adapter->num_queues; + tx_ring_size = sizeof(struct e1000_tx_ring) * adapter->num_tx_queues; + rx_ring_size = sizeof(struct e1000_rx_ring) * adapter->num_rx_queues; if (netif_running(adapter->netdev)) e1000_down(adapter); @@ -654,10 +654,10 @@ e1000_set_ringparam(struct net_device *netdev, E1000_MAX_TXD : E1000_MAX_82544_TXD)); E1000_ROUNDUP(txdr->count, REQ_TX_DESCRIPTOR_MULTIPLE); - for (i = 0; i < adapter->num_queues; i++) { + for (i = 0; i < adapter->num_tx_queues; i++) txdr[i].count = txdr->count; + for (i = 0; i < adapter->num_rx_queues; i++) rxdr[i].count = rxdr->count; - } if(netif_running(adapter->netdev)) { /* Try to get new resources before deleting old */ diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h index 7caa35748cea..1ddfd56fc5df 100644 --- a/drivers/net/e1000/e1000_hw.h +++ b/drivers/net/e1000/e1000_hw.h @@ -1497,6 +1497,7 @@ struct e1000_hw { #define E1000_CTRL_EXT_EE_RST 0x00002000 /* Reinitialize from EEPROM */ #define E1000_CTRL_EXT_IPS 0x00004000 /* Invert Power State */ #define E1000_CTRL_EXT_SPD_BYPS 0x00008000 /* Speed Select Bypass */ +#define E1000_CTRL_EXT_RO_DIS 0x00020000 /* Relaxed Ordering disable */ #define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000 #define E1000_CTRL_EXT_LINK_MODE_GMII 0x00000000 #define E1000_CTRL_EXT_LINK_MODE_TBI 0x00C00000 diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 5f848b3a3a4d..540c8561fc24 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -411,8 +411,9 @@ e1000_up(struct e1000_adapter *adapter) e1000_configure_tx(adapter); e1000_setup_rctl(adapter); e1000_configure_rx(adapter); - for (i = 0; i < adapter->num_queues; i++) + for (i = 0; i < adapter->num_rx_queues; i++) { adapter->alloc_rx_buf(adapter, &adapter->rx_ring[i]); + } #ifdef CONFIG_PCI_MSI if(adapter->hw.mac_type > e1000_82547_rev_2) { @@ -867,7 +868,7 @@ e1000_remove(struct pci_dev *pdev) unregister_netdev(netdev); #ifdef CONFIG_E1000_NAPI - for (i = 0; i < adapter->num_queues; i++) + for (i = 0; i < adapter->num_rx_queues; i++) __dev_put(&adapter->polling_netdev[i]); #endif @@ -972,15 +973,25 @@ e1000_sw_init(struct e1000_adapter *adapter) switch (hw->mac_type) { case e1000_82571: case e1000_82572: - adapter->num_queues = 2; + /* These controllers support 2 tx queues, but with a single + * qdisc implementation, multiple tx queues aren't quite as + * interesting. If we can find a logical way of mapping + * flows to a queue, then perhaps we can up the num_tx_queue + * count back to its default. Until then, we run the risk of + * terrible performance due to SACK overload. */ + adapter->num_tx_queues = 1; + adapter->num_rx_queues = 2; break; default: - adapter->num_queues = 1; + adapter->num_tx_queues = 1; + adapter->num_rx_queues = 1; break; } - adapter->num_queues = min(adapter->num_queues, num_online_cpus()); + adapter->num_rx_queues = min(adapter->num_rx_queues, num_online_cpus()); + adapter->num_tx_queues = min(adapter->num_tx_queues, num_online_cpus()); #else - adapter->num_queues = 1; + adapter->num_tx_queues = 1; + adapter->num_rx_queues = 1; #endif if (e1000_alloc_queues(adapter)) { @@ -989,7 +1000,7 @@ e1000_sw_init(struct e1000_adapter *adapter) } #ifdef CONFIG_E1000_NAPI - for (i = 0; i < adapter->num_queues; i++) { + for (i = 0; i < adapter->num_rx_queues; i++) { adapter->polling_netdev[i].priv = adapter; adapter->polling_netdev[i].poll = &e1000_clean; adapter->polling_netdev[i].weight = 64; @@ -1022,13 +1033,13 @@ e1000_alloc_queues(struct e1000_adapter *adapter) { int size; - size = sizeof(struct e1000_tx_ring) * adapter->num_queues; + size = sizeof(struct e1000_tx_ring) * adapter->num_tx_queues; adapter->tx_ring = kmalloc(size, GFP_KERNEL); if (!adapter->tx_ring) return -ENOMEM; memset(adapter->tx_ring, 0, size); - size = sizeof(struct e1000_rx_ring) * adapter->num_queues; + size = sizeof(struct e1000_rx_ring) * adapter->num_rx_queues; adapter->rx_ring = kmalloc(size, GFP_KERNEL); if (!adapter->rx_ring) { kfree(adapter->tx_ring); @@ -1037,7 +1048,7 @@ e1000_alloc_queues(struct e1000_adapter *adapter) memset(adapter->rx_ring, 0, size); #ifdef CONFIG_E1000_NAPI - size = sizeof(struct net_device) * adapter->num_queues; + size = sizeof(struct net_device) * adapter->num_rx_queues; adapter->polling_netdev = kmalloc(size, GFP_KERNEL); if (!adapter->polling_netdev) { kfree(adapter->tx_ring); @@ -1066,12 +1077,12 @@ e1000_setup_queue_mapping(struct e1000_adapter *adapter) lock_cpu_hotplug(); i = 0; for_each_online_cpu(cpu) { - *per_cpu_ptr(adapter->cpu_tx_ring, cpu) = &adapter->tx_ring[i % adapter->num_queues]; + *per_cpu_ptr(adapter->cpu_tx_ring, cpu) = &adapter->tx_ring[i % adapter->num_tx_queues]; /* This is incomplete because we'd like to assign separate * physical cpus to these netdev polling structures and * avoid saturating a subset of cpus. */ - if (i < adapter->num_queues) { + if (i < adapter->num_rx_queues) { *per_cpu_ptr(adapter->cpu_netdev, cpu) = &adapter->polling_netdev[i]; adapter->cpu_for_queue[i] = cpu; } else @@ -1291,7 +1302,7 @@ e1000_setup_all_tx_resources(struct e1000_adapter *adapter) { int i, err = 0; - for (i = 0; i < adapter->num_queues; i++) { + for (i = 0; i < adapter->num_tx_queues; i++) { err = e1000_setup_tx_resources(adapter, &adapter->tx_ring[i]); if (err) { DPRINTK(PROBE, ERR, @@ -1319,7 +1330,7 @@ e1000_configure_tx(struct e1000_adapter *adapter) /* Setup the HW Tx Head and Tail descriptor pointers */ - switch (adapter->num_queues) { + switch (adapter->num_tx_queues) { case 2: tdba = adapter->tx_ring[1].dma; tdlen = adapter->tx_ring[1].count * @@ -1537,7 +1548,7 @@ e1000_setup_all_rx_resources(struct e1000_adapter *adapter) { int i, err = 0; - for (i = 0; i < adapter->num_queues; i++) { + for (i = 0; i < adapter->num_rx_queues; i++) { err = e1000_setup_rx_resources(adapter, &adapter->rx_ring[i]); if (err) { DPRINTK(PROBE, ERR, @@ -1709,7 +1720,7 @@ e1000_configure_rx(struct e1000_adapter *adapter) /* Setup the HW Rx Head and Tail Descriptor Pointers and * the Base and Length of the Rx Descriptor Ring */ - switch (adapter->num_queues) { + switch (adapter->num_rx_queues) { #ifdef CONFIG_E1000_MQ case 2: rdba = adapter->rx_ring[1].dma; @@ -1736,7 +1747,7 @@ e1000_configure_rx(struct e1000_adapter *adapter) } #ifdef CONFIG_E1000_MQ - if (adapter->num_queues > 1) { + if (adapter->num_rx_queues > 1) { uint32_t random[10]; get_random_bytes(&random[0], 40); @@ -1746,7 +1757,7 @@ e1000_configure_rx(struct e1000_adapter *adapter) E1000_WRITE_REG(hw, RSSIM, 0); } - switch (adapter->num_queues) { + switch (adapter->num_rx_queues) { case 2: default: reta = 0x00800080; @@ -1838,7 +1849,7 @@ e1000_free_all_tx_resources(struct e1000_adapter *adapter) { int i; - for (i = 0; i < adapter->num_queues; i++) + for (i = 0; i < adapter->num_tx_queues; i++) e1000_free_tx_resources(adapter, &adapter->tx_ring[i]); } @@ -1905,7 +1916,7 @@ e1000_clean_all_tx_rings(struct e1000_adapter *adapter) { int i; - for (i = 0; i < adapter->num_queues; i++) + for (i = 0; i < adapter->num_tx_queues; i++) e1000_clean_tx_ring(adapter, &adapter->tx_ring[i]); } @@ -1949,7 +1960,7 @@ e1000_free_all_rx_resources(struct e1000_adapter *adapter) { int i; - for (i = 0; i < adapter->num_queues; i++) + for (i = 0; i < adapter->num_rx_queues; i++) e1000_free_rx_resources(adapter, &adapter->rx_ring[i]); } @@ -2025,7 +2036,7 @@ e1000_clean_all_rx_rings(struct e1000_adapter *adapter) { int i; - for (i = 0; i < adapter->num_queues; i++) + for (i = 0; i < adapter->num_rx_queues; i++) e1000_clean_rx_ring(adapter, &adapter->rx_ring[i]); } @@ -2325,7 +2336,10 @@ e1000_watchdog_task(struct e1000_adapter *adapter) e1000_update_adaptive(&adapter->hw); - if (adapter->num_queues == 1 && !netif_carrier_ok(netdev)) { +#ifdef CONFIG_E1000_MQ + txdr = *per_cpu_ptr(adapter->cpu_tx_ring, smp_processor_id()); +#endif + if (!netif_carrier_ok(netdev)) { if (E1000_DESC_UNUSED(txdr) + 1 < txdr->count) { /* We've lost link, so the controller stops DMA, * but we've got queued Tx work that's never going @@ -3197,14 +3211,12 @@ e1000_intr(int irq, void *data, struct pt_regs *regs) E1000_WRITE_FLUSH(hw); #ifdef CONFIG_E1000_MQ if (atomic_read(&adapter->rx_sched_call_data.count) == 0) { - cpu_set(adapter->cpu_for_queue[0], - adapter->rx_sched_call_data.cpumask); - for (i = 1; i < adapter->num_queues; i++) { - cpu_set(adapter->cpu_for_queue[i], - adapter->rx_sched_call_data.cpumask); - atomic_inc(&adapter->irq_sem); - } - atomic_set(&adapter->rx_sched_call_data.count, i); + /* We must setup the cpumask once count == 0 since + * each cpu bit is cleared when the work is done. */ + adapter->rx_sched_call_data.cpumask = adapter->cpumask; + atomic_add(adapter->num_rx_queues - 1, &adapter->irq_sem); + atomic_set(&adapter->rx_sched_call_data.count, + adapter->num_rx_queues); smp_call_async_mask(&adapter->rx_sched_call_data); } else { printk("call_data.count == %u\n", atomic_read(&adapter->rx_sched_call_data.count)); @@ -3267,7 +3279,7 @@ e1000_clean(struct net_device *poll_dev, int *budget) while (poll_dev != &adapter->polling_netdev[i]) { i++; - if (unlikely(i == adapter->num_queues)) + if (unlikely(i == adapter->num_rx_queues)) BUG(); } diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c index 852841f12fb9..b0be7d69af34 100644 --- a/drivers/net/e1000/e1000_param.c +++ b/drivers/net/e1000/e1000_param.c @@ -320,7 +320,7 @@ e1000_check_options(struct e1000_adapter *adapter) } else { tx_ring->count = opt.def; } - for (i = 0; i < adapter->num_queues; i++) + for (i = 0; i < adapter->num_tx_queues; i++) tx_ring[i].count = tx_ring->count; } { /* Receive Descriptor Count */ @@ -346,7 +346,7 @@ e1000_check_options(struct e1000_adapter *adapter) } else { rx_ring->count = opt.def; } - for (i = 0; i < adapter->num_queues; i++) + for (i = 0; i < adapter->num_rx_queues; i++) rx_ring[i].count = rx_ring->count; } { /* Checksum Offload Enable/Disable */ From 7bfa48162d4924e8cc7fb8eccc8c8f66cc111eb4 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 12 Jan 2006 16:50:41 -0800 Subject: [PATCH 35/76] [PATCH] e1000: Fix mulitple queues Fixed stats when using multiple queues. When multiple queues are enabled, log a message in syslog. Fixed memory allocation for multiple queues. Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000.h | 26 ++++++++++--- drivers/net/e1000/e1000_ethtool.c | 65 +++++++++++++++++++++++++++---- drivers/net/e1000/e1000_main.c | 47 +++++++++++++++++++--- 3 files changed, 120 insertions(+), 18 deletions(-) diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index 5940f7a223bc..0a084e915dd6 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -72,10 +72,6 @@ #include #include #include -#ifdef CONFIG_E1000_MQ -#include -#include -#endif #define BAR_0 0 #define BAR_1 1 @@ -87,6 +83,10 @@ struct e1000_adapter; #include "e1000_hw.h" +#ifdef CONFIG_E1000_MQ +#include +#include +#endif #ifdef DBG #define E1000_DBG(args...) printk(KERN_DEBUG "e1000: " args) @@ -169,6 +169,13 @@ struct e1000_buffer { uint16_t next_to_watch; }; +#ifdef CONFIG_E1000_MQ +struct e1000_queue_stats { + uint64_t packets; + uint64_t bytes; +}; +#endif + struct e1000_ps_page { struct page *ps_page[PS_PAGE_BUFFERS]; }; struct e1000_ps_page_dma { uint64_t ps_page_dma[PS_PAGE_BUFFERS]; }; @@ -194,6 +201,9 @@ struct e1000_tx_ring { boolean_t last_tx_tso; +#ifdef CONFIG_E1000_MQ + struct e1000_queue_stats tx_stats; +#endif }; struct e1000_rx_ring { @@ -223,6 +233,9 @@ struct e1000_rx_ring { uint16_t rdh; uint16_t rdt; +#ifdef CONFIG_E1000_MQ + struct e1000_queue_stats rx_stats; +#endif }; #define E1000_DESC_UNUSED(R) \ @@ -255,6 +268,9 @@ struct e1000_adapter { uint16_t link_speed; uint16_t link_duplex; spinlock_t stats_lock; +#ifdef CONFIG_E1000_NAPI + spinlock_t tx_queue_lock; +#endif atomic_t irq_sem; struct work_struct tx_timeout_task; struct work_struct watchdog_task; @@ -302,7 +318,7 @@ struct e1000_adapter { #ifdef CONFIG_E1000_MQ struct net_device **cpu_netdev; /* per-cpu */ struct call_async_data_struct rx_sched_call_data; - int cpu_for_queue[4]; + cpumask_t cpumask; #endif int num_tx_queues; int num_rx_queues; diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index fa9a4659369a..ffdf76b725bc 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -96,8 +96,18 @@ static const struct e1000_stats e1000_gstrings_stats[] = { { "rx_header_split", E1000_STAT(rx_hdr_split) }, { "alloc_rx_buff_failed", E1000_STAT(alloc_rx_buff_failed) }, }; -#define E1000_STATS_LEN \ + +#ifdef CONFIG_E1000_MQ +#define E1000_QUEUE_STATS_LEN \ + (((struct e1000_adapter *)netdev->priv)->num_tx_queues + \ + ((struct e1000_adapter *)netdev->priv)->num_rx_queues) \ + * (sizeof(struct e1000_queue_stats) / sizeof(uint64_t)) +#else +#define E1000_QUEUE_STATS_LEN 0 +#endif +#define E1000_GLOBAL_STATS_LEN \ sizeof(e1000_gstrings_stats) / sizeof(struct e1000_stats) +#define E1000_STATS_LEN (E1000_GLOBAL_STATS_LEN + E1000_QUEUE_STATS_LEN) static const char e1000_gstrings_test[][ETH_GSTRING_LEN] = { "Register test (offline)", "Eeprom test (offline)", "Interrupt test (offline)", "Loopback test (offline)", @@ -1746,19 +1756,43 @@ e1000_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats, uint64_t *data) { struct e1000_adapter *adapter = netdev_priv(netdev); +#ifdef CONFIG_E1000_MQ + uint64_t *queue_stat; + int stat_count = sizeof(struct e1000_queue_stats) / sizeof(uint64_t); + int j, k; +#endif int i; e1000_update_stats(adapter); - for(i = 0; i < E1000_STATS_LEN; i++) { - char *p = (char *)adapter+e1000_gstrings_stats[i].stat_offset; - data[i] = (e1000_gstrings_stats[i].sizeof_stat == + for (i = 0; i < E1000_GLOBAL_STATS_LEN; i++) { + char *p = (char *)adapter+e1000_gstrings_stats[i].stat_offset; + data[i] = (e1000_gstrings_stats[i].sizeof_stat == sizeof(uint64_t)) ? *(uint64_t *)p : *(uint32_t *)p; } +#ifdef CONFIG_E1000_MQ + for (j = 0; j < adapter->num_tx_queues; j++) { + queue_stat = (uint64_t *)&adapter->tx_ring[j].tx_stats; + for (k = 0; k < stat_count; k++) + data[i + k] = queue_stat[k]; + i += k; + } + for (j = 0; j < adapter->num_rx_queues; j++) { + queue_stat = (uint64_t *)&adapter->rx_ring[j].rx_stats; + for (k = 0; k < stat_count; k++) + data[i + k] = queue_stat[k]; + i += k; + } +#endif +/* BUG_ON(i != E1000_STATS_LEN); */ } static void e1000_get_strings(struct net_device *netdev, uint32_t stringset, uint8_t *data) { +#ifdef CONFIG_E1000_MQ + struct e1000_adapter *adapter = netdev_priv(netdev); +#endif + uint8_t *p = data; int i; switch(stringset) { @@ -1767,11 +1801,26 @@ e1000_get_strings(struct net_device *netdev, uint32_t stringset, uint8_t *data) E1000_TEST_LEN*ETH_GSTRING_LEN); break; case ETH_SS_STATS: - for (i=0; i < E1000_STATS_LEN; i++) { - memcpy(data + i * ETH_GSTRING_LEN, - e1000_gstrings_stats[i].stat_string, - ETH_GSTRING_LEN); + for (i = 0; i < E1000_GLOBAL_STATS_LEN; i++) { + memcpy(p, e1000_gstrings_stats[i].stat_string, + ETH_GSTRING_LEN); + p += ETH_GSTRING_LEN; } +#ifdef CONFIG_E1000_MQ + for (i = 0; i < adapter->num_tx_queues; i++) { + sprintf(p, "tx_queue_%u_packets", i); + p += ETH_GSTRING_LEN; + sprintf(p, "tx_queue_%u_bytes", i); + p += ETH_GSTRING_LEN; + } + for (i = 0; i < adapter->num_rx_queues; i++) { + sprintf(p, "rx_queue_%u_packets", i); + p += ETH_GSTRING_LEN; + sprintf(p, "rx_queue_%u_bytes", i); + p += ETH_GSTRING_LEN; + } +#endif +/* BUG_ON(p - data != E1000_STATS_LEN * ETH_GSTRING_LEN); */ break; } } diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 540c8561fc24..4016264a7919 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -433,6 +433,12 @@ e1000_up(struct e1000_adapter *adapter) return err; } +#ifdef CONFIG_E1000_MQ + e1000_setup_queue_mapping(adapter); +#endif + + adapter->tx_queue_len = netdev->tx_queue_len; + mod_timer(&adapter->watchdog_timer, jiffies); #ifdef CONFIG_E1000_NAPI @@ -467,6 +473,7 @@ e1000_down(struct e1000_adapter *adapter) #ifdef CONFIG_E1000_NAPI netif_poll_disable(netdev); #endif + netdev->tx_queue_len = adapter->tx_queue_len; adapter->link_speed = 0; adapter->link_duplex = 0; netif_carrier_off(netdev); @@ -989,6 +996,15 @@ e1000_sw_init(struct e1000_adapter *adapter) } adapter->num_rx_queues = min(adapter->num_rx_queues, num_online_cpus()); adapter->num_tx_queues = min(adapter->num_tx_queues, num_online_cpus()); + DPRINTK(DRV, INFO, "Multiqueue Enabled: Rx Queue count = %u %s\n", + adapter->num_rx_queues, + ((adapter->num_rx_queues == 1) + ? ((num_online_cpus() > 1) + ? "(due to unsupported feature in current adapter)" + : "(due to unsupported system configuration)") + : "")); + DPRINTK(DRV, INFO, "Multiqueue Enabled: Tx Queue count = %u\n", + adapter->num_tx_queues); #else adapter->num_tx_queues = 1; adapter->num_rx_queues = 1; @@ -1007,10 +1023,7 @@ e1000_sw_init(struct e1000_adapter *adapter) dev_hold(&adapter->polling_netdev[i]); set_bit(__LINK_STATE_START, &adapter->polling_netdev[i].state); } -#endif - -#ifdef CONFIG_E1000_MQ - e1000_setup_queue_mapping(adapter); + spin_lock_init(&adapter->tx_queue_lock); #endif atomic_set(&adapter->irq_sem, 1); @@ -1058,6 +1071,14 @@ e1000_alloc_queues(struct e1000_adapter *adapter) memset(adapter->polling_netdev, 0, size); #endif +#ifdef CONFIG_E1000_MQ + adapter->rx_sched_call_data.func = e1000_rx_schedule; + adapter->rx_sched_call_data.info = adapter->netdev; + + adapter->cpu_netdev = alloc_percpu(struct net_device *); + adapter->cpu_tx_ring = alloc_percpu(struct e1000_tx_ring *); +#endif + return E1000_SUCCESS; } @@ -1084,7 +1105,8 @@ e1000_setup_queue_mapping(struct e1000_adapter *adapter) */ if (i < adapter->num_rx_queues) { *per_cpu_ptr(adapter->cpu_netdev, cpu) = &adapter->polling_netdev[i]; - adapter->cpu_for_queue[i] = cpu; + adapter->rx_ring[i].cpu = cpu; + cpu_set(cpu, adapter->cpumask); } else *per_cpu_ptr(adapter->cpu_netdev, cpu) = NULL; @@ -3337,6 +3359,10 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter, if(unlikely(++i == tx_ring->count)) i = 0; } +#ifdef CONFIG_E1000_MQ + tx_ring->tx_stats.packets++; +#endif + eop = tx_ring->buffer_info[i].next_to_watch; eop_desc = E1000_TX_DESC(*tx_ring, eop); } @@ -3365,6 +3391,7 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter, eop = tx_ring->buffer_info[i].next_to_watch; eop_desc = E1000_TX_DESC(*tx_ring, eop); DPRINTK(DRV, ERR, "Detected Tx Unit Hang\n" + " Tx Queue <%lu>\n" " TDH <%x>\n" " TDT <%x>\n" " next_to_use <%x>\n" @@ -3375,6 +3402,8 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter, " next_to_watch <%x>\n" " jiffies <%lx>\n" " next_to_watch.status <%x>\n", + (unsigned long)((tx_ring - adapter->tx_ring) / + sizeof(struct e1000_tx_ring)), readl(adapter->hw.hw_addr + tx_ring->tdh), readl(adapter->hw.hw_addr + tx_ring->tdt), tx_ring->next_to_use, @@ -3541,6 +3570,10 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter, } #endif /* CONFIG_E1000_NAPI */ netdev->last_rx = jiffies; +#ifdef CONFIG_E1000_MQ + rx_ring->rx_stats.packets++; + rx_ring->rx_stats.bytes += length; +#endif next_desc: rx_desc->status = 0; @@ -3671,6 +3704,10 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, } #endif /* CONFIG_E1000_NAPI */ netdev->last_rx = jiffies; +#ifdef CONFIG_E1000_MQ + rx_ring->rx_stats.packets++; + rx_ring->rx_stats.bytes += length; +#endif next_desc: rx_desc->wb.middle.status_error &= ~0xFF; From 492731632cce0a7c8817376e1316f0af093830c4 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 12 Jan 2006 16:50:44 -0800 Subject: [PATCH 36/76] [PATCH] e1000: Fix loopback logic Fixed the loopback logic to work for the PCI express adapters. Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_ethtool.c | 72 ++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 25 deletions(-) diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index ffdf76b725bc..ceb9cd059b90 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -1326,22 +1326,33 @@ e1000_set_phy_loopback(struct e1000_adapter *adapter) static int e1000_setup_loopback_test(struct e1000_adapter *adapter) { + struct e1000_hw *hw = &adapter->hw; uint32_t rctl; - if(adapter->hw.media_type == e1000_media_type_fiber || - adapter->hw.media_type == e1000_media_type_internal_serdes) { - if(adapter->hw.mac_type == e1000_82545 || - adapter->hw.mac_type == e1000_82546 || - adapter->hw.mac_type == e1000_82545_rev_3 || - adapter->hw.mac_type == e1000_82546_rev_3) + if (hw->media_type == e1000_media_type_fiber || + hw->media_type == e1000_media_type_internal_serdes) { + switch (hw->mac_type) { + case e1000_82545: + case e1000_82546: + case e1000_82545_rev_3: + case e1000_82546_rev_3: return e1000_set_phy_loopback(adapter); - else { - rctl = E1000_READ_REG(&adapter->hw, RCTL); + break; + case e1000_82571: + case e1000_82572: +#define E1000_SERDES_LB_ON 0x410 + e1000_set_phy_loopback(adapter); + E1000_WRITE_REG(hw, SCTL, E1000_SERDES_LB_ON); + msec_delay(10); + return 0; + break; + default: + rctl = E1000_READ_REG(hw, RCTL); rctl |= E1000_RCTL_LBM_TCVR; - E1000_WRITE_REG(&adapter->hw, RCTL, rctl); + E1000_WRITE_REG(hw, RCTL, rctl); return 0; } - } else if(adapter->hw.media_type == e1000_media_type_copper) + } else if (hw->media_type == e1000_media_type_copper) return e1000_set_phy_loopback(adapter); return 7; @@ -1350,27 +1361,38 @@ e1000_setup_loopback_test(struct e1000_adapter *adapter) static void e1000_loopback_cleanup(struct e1000_adapter *adapter) { + struct e1000_hw *hw = &adapter->hw; uint32_t rctl; uint16_t phy_reg; - rctl = E1000_READ_REG(&adapter->hw, RCTL); + rctl = E1000_READ_REG(hw, RCTL); rctl &= ~(E1000_RCTL_LBM_TCVR | E1000_RCTL_LBM_MAC); - E1000_WRITE_REG(&adapter->hw, RCTL, rctl); + E1000_WRITE_REG(hw, RCTL, rctl); - if(adapter->hw.media_type == e1000_media_type_copper || - ((adapter->hw.media_type == e1000_media_type_fiber || - adapter->hw.media_type == e1000_media_type_internal_serdes) && - (adapter->hw.mac_type == e1000_82545 || - adapter->hw.mac_type == e1000_82546 || - adapter->hw.mac_type == e1000_82545_rev_3 || - adapter->hw.mac_type == e1000_82546_rev_3))) { - adapter->hw.autoneg = TRUE; - e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &phy_reg); - if(phy_reg & MII_CR_LOOPBACK) { - phy_reg &= ~MII_CR_LOOPBACK; - e1000_write_phy_reg(&adapter->hw, PHY_CTRL, phy_reg); - e1000_phy_reset(&adapter->hw); + switch (hw->mac_type) { + case e1000_82571: + case e1000_82572: + if (hw->media_type == e1000_media_type_fiber || + hw->media_type == e1000_media_type_internal_serdes) { +#define E1000_SERDES_LB_OFF 0x400 + E1000_WRITE_REG(hw, SCTL, E1000_SERDES_LB_OFF); + msec_delay(10); + break; } + /* Fall Through */ + case e1000_82545: + case e1000_82546: + case e1000_82545_rev_3: + case e1000_82546_rev_3: + default: + hw->autoneg = TRUE; + e1000_read_phy_reg(hw, PHY_CTRL, &phy_reg); + if (phy_reg & MII_CR_LOOPBACK) { + phy_reg &= ~MII_CR_LOOPBACK; + e1000_write_phy_reg(hw, PHY_CTRL, phy_reg); + e1000_phy_reset(hw); + } + break; } } From 526f99572e9f18f42c8da2c9adafbe64482c0737 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 12 Jan 2006 16:50:46 -0800 Subject: [PATCH 37/76] [PATCH] e1000: Fix PHY reset when blocked Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_hw.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index 45fa386d212e..bb9d00e0dc14 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -838,6 +838,11 @@ e1000_setup_link(struct e1000_hw *hw) DEBUGFUNC("e1000_setup_link"); + /* In the case of the phy reset being blocked, we already have a link. + * We do not have to set it up again. */ + if (e1000_check_phy_reset_block(hw)) + return E1000_SUCCESS; + /* Read and store word 0x0F of the EEPROM. This word contains bits * that determine the hardware's default PAUSE (flow control) mode, * a bit that determines whether the HW defaults to enabling or From 4d351858e41145fa236730b7749e3aed18edef43 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 12 Jan 2006 16:50:48 -0800 Subject: [PATCH 38/76] [PATCH] e1000: Fix EEPROM read logic Fixed read_eeprom logic to test use_eerd instead of testing for 82573 controllers. Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_hw.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index bb9d00e0dc14..19a0b2a6ada1 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -3888,14 +3888,16 @@ e1000_read_eeprom(struct e1000_hw *hw, return -E1000_ERR_EEPROM; } - /* FLASH reads without acquiring the semaphore are safe in 82573-based - * controllers. - */ - if ((e1000_is_onboard_nvm_eeprom(hw) == TRUE) || - (hw->mac_type != e1000_82573)) { - /* Prepare the EEPROM for reading */ - if(e1000_acquire_eeprom(hw) != E1000_SUCCESS) - return -E1000_ERR_EEPROM; + /* FLASH reads without acquiring the semaphore are safe */ + if (e1000_is_onboard_nvm_eeprom(hw) == TRUE && + hw->eeprom.use_eerd == FALSE) { + switch (hw->mac_type) { + default: + /* Prepare the EEPROM for reading */ + if (e1000_acquire_eeprom(hw) != E1000_SUCCESS) + return -E1000_ERR_EEPROM; + break; + } } if(eeprom->use_eerd == TRUE) { From f11b7f8535fab0f9196a7387e93dca5deaa5fff2 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 12 Jan 2006 16:50:51 -0800 Subject: [PATCH 39/76] [PATCH] e1000: Fix flow control water marks Fixed flow control water marks based on PBA size. Store flow control state in original_fc in addition to fc. Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_main.c | 21 +++++++-------------- drivers/net/e1000/e1000_param.c | 2 +- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 4016264a7919..cefc7cc092a7 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -504,10 +504,8 @@ e1000_down(struct e1000_adapter *adapter) void e1000_reset(struct e1000_adapter *adapter) { - struct net_device *netdev = adapter->netdev; uint32_t pba, manc; uint16_t fc_high_water_mark = E1000_FC_HIGH_DIFF; - uint16_t fc_low_water_mark = E1000_FC_LOW_DIFF; /* Repartition Pba for greater than 9k mtu * To take effect CTRL.RST is required. @@ -531,15 +529,8 @@ e1000_reset(struct e1000_adapter *adapter) } if((adapter->hw.mac_type != e1000_82573) && - (adapter->netdev->mtu > E1000_RXBUFFER_8192)) { + (adapter->netdev->mtu > E1000_RXBUFFER_8192)) pba -= 8; /* allocate more FIFO for Tx */ - /* send an XOFF when there is enough space in the - * Rx FIFO to hold one extra full size Rx packet - */ - fc_high_water_mark = netdev->mtu + ENET_HEADER_SIZE + - ETHERNET_FCS_SIZE + 1; - fc_low_water_mark = fc_high_water_mark + 8; - } if(adapter->hw.mac_type == e1000_82547) { @@ -553,10 +544,12 @@ e1000_reset(struct e1000_adapter *adapter) E1000_WRITE_REG(&adapter->hw, PBA, pba); /* flow control settings */ - adapter->hw.fc_high_water = (pba << E1000_PBA_BYTES_SHIFT) - - fc_high_water_mark; - adapter->hw.fc_low_water = (pba << E1000_PBA_BYTES_SHIFT) - - fc_low_water_mark; + /* Set the FC high water mark to 90% of the FIFO size. + * Required to clear last 3 LSB */ + fc_high_water_mark = ((pba * 9216)/10) & 0xFFF8; + + adapter->hw.fc_high_water = fc_high_water_mark; + adapter->hw.fc_low_water = fc_high_water_mark - 8; adapter->hw.fc_pause_time = E1000_FC_PAUSE_TIME; adapter->hw.fc_send_xon = 1; adapter->hw.fc = adapter->hw.original_fc; diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c index b0be7d69af34..133a76b71b9c 100644 --- a/drivers/net/e1000/e1000_param.c +++ b/drivers/net/e1000/e1000_param.c @@ -388,7 +388,7 @@ e1000_check_options(struct e1000_adapter *adapter) e1000_validate_option(&fc, &opt, adapter); adapter->hw.fc = adapter->hw.original_fc = fc; } else { - adapter->hw.fc = opt.def; + adapter->hw.fc = adapter->hw.original_fc = opt.def; } } { /* Transmit Interrupt Delay */ From 66a2b0a30fcc37876d3639ea375a9d24649b53bf Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 12 Jan 2006 16:50:53 -0800 Subject: [PATCH 40/76] [PATCH] e1000: Fix TX queue length based on link speed 10/100 speeds seem to have some problems reporting false tx timeouts especially at half duplex. Fixed by using a timeout factor to attempt to mitigate the false timeouts. Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000.h | 1 + drivers/net/e1000/e1000_main.c | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index 0a084e915dd6..d95a5f88181c 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -296,6 +296,7 @@ struct e1000_adapter { uint32_t tx_fifo_head; uint32_t tx_head_addr; uint32_t tx_fifo_size; + uint8_t tx_timeout_factor; atomic_t tx_fifo_stall; boolean_t pcix_82544; boolean_t detect_tx_hung; diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index cefc7cc092a7..cf4fc5117032 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -2319,6 +2319,21 @@ e1000_watchdog_task(struct e1000_adapter *adapter) adapter->link_duplex == FULL_DUPLEX ? "Full Duplex" : "Half Duplex"); + /* tweak tx_queue_len according to speed/duplex */ + netdev->tx_queue_len = adapter->tx_queue_len; + adapter->tx_timeout_factor = 1; + if (adapter->link_duplex == HALF_DUPLEX) { + switch (adapter->link_speed) { + case SPEED_10: + netdev->tx_queue_len = 10; + adapter->tx_timeout_factor = 8; + break; + case SPEED_100: + netdev->tx_queue_len = 100; + break; + } + } + netif_carrier_on(netdev); netif_wake_queue(netdev); mod_timer(&adapter->phy_info_timer, jiffies + 2 * HZ); From 997f5cbdded3d8282dc56b741d332e51014ea64b Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 12 Jan 2006 16:50:55 -0800 Subject: [PATCH 41/76] [PATCH] e1000: Fix Desc. Rings and Jumbo Frames This patch contains two fixes. The first fix is to the tx and rx descriptor rings clean up process. The second fix is to jumbo frames, which cleans up the code logic and removes most of the fifo related limitations on jumbo frames. This is because the driver code now supports splitting a packet across multiple descriptors. Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_main.c | 108 +++++++++++++++++++-------------- 1 file changed, 61 insertions(+), 47 deletions(-) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index cf4fc5117032..41f44a3ded9a 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -1542,6 +1542,8 @@ setup_rx_desc_die: rxdr->next_to_clean = 0; rxdr->next_to_use = 0; + rxdr->rx_skb_top = NULL; + rxdr->rx_skb_prev = NULL; return 0; } @@ -2010,19 +2012,30 @@ e1000_clean_rx_ring(struct e1000_adapter *adapter, dev_kfree_skb(buffer_info->skb); buffer_info->skb = NULL; - - for(j = 0; j < adapter->rx_ps_pages; j++) { - if(!ps_page->ps_page[j]) break; - pci_unmap_single(pdev, - ps_page_dma->ps_page_dma[j], - PAGE_SIZE, PCI_DMA_FROMDEVICE); - ps_page_dma->ps_page_dma[j] = 0; - put_page(ps_page->ps_page[j]); - ps_page->ps_page[j] = NULL; - } + } + ps_page = &rx_ring->ps_page[i]; + ps_page_dma = &rx_ring->ps_page_dma[i]; + for (j = 0; j < adapter->rx_ps_pages; j++) { + if (!ps_page->ps_page[j]) break; + pci_unmap_page(pdev, + ps_page_dma->ps_page_dma[j], + PAGE_SIZE, PCI_DMA_FROMDEVICE); + ps_page_dma->ps_page_dma[j] = 0; + put_page(ps_page->ps_page[j]); + ps_page->ps_page[j] = NULL; } } + /* there also may be some cached data in our adapter */ + if (rx_ring->rx_skb_top) { + dev_kfree_skb(rx_ring->rx_skb_top); + + /* rx_skb_prev will be wiped out by rx_skb_top */ + rx_ring->rx_skb_top = NULL; + rx_ring->rx_skb_prev = NULL; + } + + size = sizeof(struct e1000_buffer) * rx_ring->count; memset(rx_ring->buffer_info, 0, size); size = sizeof(struct e1000_ps_page) * rx_ring->count; @@ -2985,50 +2998,51 @@ e1000_change_mtu(struct net_device *netdev, int new_mtu) if((max_frame < MINIMUM_ETHERNET_FRAME_SIZE) || (max_frame > MAX_JUMBO_FRAME_SIZE)) { DPRINTK(PROBE, ERR, "Invalid MTU setting\n"); - return -EINVAL; - } - -#define MAX_STD_JUMBO_FRAME_SIZE 9234 - /* might want this to be bigger enum check... */ - /* 82571 controllers limit jumbo frame size to 10500 bytes */ - if ((adapter->hw.mac_type == e1000_82571 || - adapter->hw.mac_type == e1000_82572) && - max_frame > MAX_STD_JUMBO_FRAME_SIZE) { - DPRINTK(PROBE, ERR, "MTU > 9216 bytes not supported " - "on 82571 and 82572 controllers.\n"); return -EINVAL; } - if(adapter->hw.mac_type == e1000_82573 && - max_frame > MAXIMUM_ETHERNET_FRAME_SIZE) { - DPRINTK(PROBE, ERR, "Jumbo Frames not supported " - "on 82573\n"); - return -EINVAL; - } - - if(adapter->hw.mac_type > e1000_82547_rev_2) { - adapter->rx_buffer_len = max_frame; - E1000_ROUNDUP(adapter->rx_buffer_len, 1024); - } else { - if(unlikely((adapter->hw.mac_type < e1000_82543) && - (max_frame > MAXIMUM_ETHERNET_FRAME_SIZE))) { - DPRINTK(PROBE, ERR, "Jumbo Frames not supported " - "on 82542\n"); + /* Adapter-specific max frame size limits. */ + switch (adapter->hw.mac_type) { + case e1000_82542_rev2_0: + case e1000_82542_rev2_1: + case e1000_82573: + if (max_frame > MAXIMUM_ETHERNET_FRAME_SIZE) { + DPRINTK(PROBE, ERR, "Jumbo Frames not supported.\n"); return -EINVAL; - - } else { - if(max_frame <= E1000_RXBUFFER_2048) { - adapter->rx_buffer_len = E1000_RXBUFFER_2048; - } else if(max_frame <= E1000_RXBUFFER_4096) { - adapter->rx_buffer_len = E1000_RXBUFFER_4096; - } else if(max_frame <= E1000_RXBUFFER_8192) { - adapter->rx_buffer_len = E1000_RXBUFFER_8192; - } else if(max_frame <= E1000_RXBUFFER_16384) { - adapter->rx_buffer_len = E1000_RXBUFFER_16384; - } } + break; + case e1000_82571: + case e1000_82572: +#define MAX_STD_JUMBO_FRAME_SIZE 9234 + if (max_frame > MAX_STD_JUMBO_FRAME_SIZE) { + DPRINTK(PROBE, ERR, "MTU > 9216 not supported.\n"); + return -EINVAL; + } + break; + default: + /* Capable of supporting up to MAX_JUMBO_FRAME_SIZE limit. */ + break; } + /* since the driver code now supports splitting a packet across + * multiple descriptors, most of the fifo related limitations on + * jumbo frame traffic have gone away. + * simply use 2k descriptors for everything. + * + * NOTE: dev_alloc_skb reserves 16 bytes, and typically NET_IP_ALIGN + * means we reserve 2 more, this pushes us to allocate from the next + * larger slab size + * i.e. RXBUFFER_2048 --> size-4096 slab */ + + /* recent hardware supports 1KB granularity */ + if (adapter->hw.mac_type > e1000_82547_rev_2) { + adapter->rx_buffer_len = + ((max_frame < E1000_RXBUFFER_2048) ? + max_frame : E1000_RXBUFFER_2048); + E1000_ROUNDUP(adapter->rx_buffer_len, 1024); + } else + adapter->rx_buffer_len = E1000_RXBUFFER_2048; + netdev->mtu = new_mtu; if(netif_running(netdev)) { From 392137fa9b966cf03f020f9a9a2619099b996266 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 12 Jan 2006 16:50:57 -0800 Subject: [PATCH 42/76] [PATCH] e1000: Fix TX timeout logic Fixed the TX timeout logic to use "end of packet" rather than "next to clean". Updated message log. Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_main.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 41f44a3ded9a..d2e77ee103bb 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -3403,15 +3403,13 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter, /* Detect a transmit hang in hardware, this serializes the * check with the clearing of time_stamp and movement of i */ adapter->detect_tx_hung = FALSE; - if (tx_ring->buffer_info[i].dma && - time_after(jiffies, tx_ring->buffer_info[i].time_stamp + HZ) + if (tx_ring->buffer_info[eop].dma && + time_after(jiffies, tx_ring->buffer_info[eop].time_stamp + + adapter->tx_timeout_factor * HZ) && !(E1000_READ_REG(&adapter->hw, STATUS) & - E1000_STATUS_TXOFF)) { + E1000_STATUS_TXOFF)) { /* detected Tx unit hang */ - i = tx_ring->next_to_clean; - eop = tx_ring->buffer_info[i].next_to_watch; - eop_desc = E1000_TX_DESC(*tx_ring, eop); DPRINTK(DRV, ERR, "Detected Tx Unit Hang\n" " Tx Queue <%lu>\n" " TDH <%x>\n" @@ -3419,7 +3417,6 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter, " next_to_use <%x>\n" " next_to_clean <%x>\n" "buffer_info[next_to_clean]\n" - " dma <%llx>\n" " time_stamp <%lx>\n" " next_to_watch <%x>\n" " jiffies <%lx>\n" @@ -3429,9 +3426,8 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter, readl(adapter->hw.hw_addr + tx_ring->tdh), readl(adapter->hw.hw_addr + tx_ring->tdt), tx_ring->next_to_use, - i, - (unsigned long long)tx_ring->buffer_info[i].dma, - tx_ring->buffer_info[i].time_stamp, + tx_ring->next_to_clean, + tx_ring->buffer_info[eop].time_stamp, eop, jiffies, eop_desc->upper.fields.status); From f5645110aa2ed2dcc3e0373821474506ed4dc512 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 12 Jan 2006 16:51:01 -0800 Subject: [PATCH 43/76] [PATCH] e1000: Fix desc. clean up These were two separate community submitted patches. Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_ethtool.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index ceb9cd059b90..ad9ca2ac25fa 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -980,11 +980,11 @@ e1000_free_desc_rings(struct e1000_adapter *adapter) } } - if(txdr->desc) { + if (txdr->desc) { pci_free_consistent(pdev, txdr->size, txdr->desc, txdr->dma); txdr->desc = NULL; } - if(rxdr->desc) { + if (rxdr->desc) { pci_free_consistent(pdev, rxdr->size, rxdr->desc, rxdr->dma); rxdr->desc = NULL; } @@ -993,6 +993,7 @@ e1000_free_desc_rings(struct e1000_adapter *adapter) txdr->buffer_info = NULL; kfree(rxdr->buffer_info); rxdr->buffer_info = NULL; + return; } From 47028635d17c7b9c7ffc67499be5fed579bdfe72 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 12 Jan 2006 16:51:03 -0800 Subject: [PATCH 44/76] [PATCH] e1000: Fix bit 22 (TXDCTL) for 82571 & 82572 controllers Removed duplicate code, TXDCTL and TXDCTL_COUNT_DESC are the same bit and there is no need to set it twice. Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_hw.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index 19a0b2a6ada1..f79d2a06ee7f 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -735,7 +735,6 @@ e1000_init_hw(struct e1000_hw *hw) break; case e1000_82571: case e1000_82572: - ctrl |= (1 << 22); case e1000_82573: ctrl |= E1000_TXDCTL_COUNT_DESC; break; From 0fadb0597d240d4ed279042cab632d567510a1a3 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 12 Jan 2006 16:51:05 -0800 Subject: [PATCH 45/76] [PATCH] e1000: Fix collision distance Fixed the collision distance for 82543 controllers and newer. Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_hw.c | 9 +++++++-- drivers/net/e1000/e1000_hw.h | 5 ++++- drivers/net/e1000/e1000_main.c | 28 ++++++++++++++++++---------- 3 files changed, 29 insertions(+), 13 deletions(-) diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index f79d2a06ee7f..ac227c7847ff 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -1933,14 +1933,19 @@ e1000_phy_force_speed_duplex(struct e1000_hw *hw) void e1000_config_collision_dist(struct e1000_hw *hw) { - uint32_t tctl; + uint32_t tctl, coll_dist; DEBUGFUNC("e1000_config_collision_dist"); + if (hw->mac_type < e1000_82543) + coll_dist = E1000_COLLISION_DISTANCE_82542; + else + coll_dist = E1000_COLLISION_DISTANCE; + tctl = E1000_READ_REG(hw, TCTL); tctl &= ~E1000_TCTL_COLD; - tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT; + tctl |= coll_dist << E1000_COLD_SHIFT; E1000_WRITE_REG(hw, TCTL, tctl); E1000_WRITE_FLUSH(hw); diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h index 1ddfd56fc5df..600570ff254b 100644 --- a/drivers/net/e1000/e1000_hw.h +++ b/drivers/net/e1000/e1000_hw.h @@ -2078,7 +2078,10 @@ struct e1000_host_command_info { /* Collision related configuration parameters */ #define E1000_COLLISION_THRESHOLD 15 #define E1000_CT_SHIFT 4 -#define E1000_COLLISION_DISTANCE 64 +/* Collision distance is a 0-based value that applies to + * half-duplex-capable hardware only. */ +#define E1000_COLLISION_DISTANCE 63 +#define E1000_COLLISION_DISTANCE_82542 64 #define E1000_FDX_COLLISION_DISTANCE E1000_COLLISION_DISTANCE #define E1000_HDX_COLLISION_DISTANCE E1000_COLLISION_DISTANCE #define E1000_COLD_SHIFT 12 diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index d2e77ee103bb..36b04d42252f 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -1342,6 +1342,7 @@ e1000_configure_tx(struct e1000_adapter *adapter) uint64_t tdba; struct e1000_hw *hw = &adapter->hw; uint32_t tdlen, tctl, tipg, tarc; + uint32_t ipgr1, ipgr2; /* Setup the HW Tx Head and Tail descriptor pointers */ @@ -1375,22 +1376,26 @@ e1000_configure_tx(struct e1000_adapter *adapter) /* Set the default values for the Tx Inter Packet Gap timer */ + if (hw->media_type == e1000_media_type_fiber || + hw->media_type == e1000_media_type_internal_serdes) + tipg = DEFAULT_82543_TIPG_IPGT_FIBER; + else + tipg = DEFAULT_82543_TIPG_IPGT_COPPER; + switch (hw->mac_type) { case e1000_82542_rev2_0: case e1000_82542_rev2_1: tipg = DEFAULT_82542_TIPG_IPGT; - tipg |= DEFAULT_82542_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT; - tipg |= DEFAULT_82542_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT; + ipgr1 = DEFAULT_82542_TIPG_IPGR1; + ipgr2 = DEFAULT_82542_TIPG_IPGR2; break; default: - if (hw->media_type == e1000_media_type_fiber || - hw->media_type == e1000_media_type_internal_serdes) - tipg = DEFAULT_82543_TIPG_IPGT_FIBER; - else - tipg = DEFAULT_82543_TIPG_IPGT_COPPER; - tipg |= DEFAULT_82543_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT; - tipg |= DEFAULT_82543_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT; + ipgr1 = DEFAULT_82543_TIPG_IPGR1; + ipgr2 = DEFAULT_82543_TIPG_IPGR2; + break; } + tipg |= ipgr1 << E1000_TIPG_IPGR1_SHIFT; + tipg |= ipgr2 << E1000_TIPG_IPGR2_SHIFT; E1000_WRITE_REG(hw, TIPG, tipg); /* Set the Tx Interrupt Delay register */ @@ -1600,7 +1605,10 @@ e1000_setup_rctl(struct e1000_adapter *adapter) E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF | (adapter->hw.mc_filter_type << E1000_RCTL_MO_SHIFT); - if(adapter->hw.tbi_compatibility_on == 1) + if (adapter->hw.mac_type > e1000_82543) + rctl |= E1000_RCTL_SECRC; + + if (adapter->hw.tbi_compatibility_on == 1) rctl |= E1000_RCTL_SBP; else rctl &= ~E1000_RCTL_SBP; From d74bbd3bbfd70470446e0d8153f91967d53c0798 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 12 Jan 2006 16:51:07 -0800 Subject: [PATCH 46/76] [PATCH] e1000: Fix __pskb_pull_tail Fixed by moving code to correct location (for 82572 and 82571 controllers). Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_main.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 36b04d42252f..dd3d3232c94e 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -2834,6 +2834,13 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) if (skb->data_len && (hdr_len == (skb->len - skb->data_len)) && (adapter->hw.mac_type == e1000_82571 || adapter->hw.mac_type == e1000_82572)) { + unsigned int pull_size; + pull_size = min((unsigned int)4, skb->data_len); + if (!__pskb_pull_tail(skb, pull_size)) { + printk(KERN_ERR "__pskb_pull_tail failed.\n"); + dev_kfree_skb_any(skb); + return -EFAULT; + } len = skb->len - skb->data_len; } } @@ -2873,14 +2880,6 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) if(adapter->pcix_82544) count += nr_frags; - unsigned int pull_size; - pull_size = min((unsigned int)4, skb->data_len); - if (!__pskb_pull_tail(skb, pull_size)) { - printk(KERN_ERR "__pskb_pull_tail failed.\n"); - dev_kfree_skb_any(skb); - return -EFAULT; - } - if(adapter->hw.tx_pkt_filtering && (adapter->hw.mac_type == e1000_82573) ) e1000_transfer_dhcp_info(adapter, skb); From ff14701350eef6df9b7fc0ae118e1689e141a54c Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 12 Jan 2006 16:51:10 -0800 Subject: [PATCH 47/76] [PATCH] e1000: Fix VLAN support Fixed VLAN support by switching control over to the firmware. Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_main.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index dd3d3232c94e..8190eb00d54f 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -4245,8 +4245,12 @@ e1000_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid) if((adapter->hw.mng_cookie.status & E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT) && - (vid == adapter->mng_vlan_id)) + (vid == adapter->mng_vlan_id)) { + /* release control to f/w */ + e1000_release_hw_control(adapter); return; + } + /* remove VID from filter table */ index = (vid >> 5) & 0x7F; vfta = E1000_READ_REG_ARRAY(&adapter->hw, VFTA, index); From ce7393b93502f52e2ef7259e9e9bc3b1a1fd6799 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 12 Jan 2006 16:51:12 -0800 Subject: [PATCH 48/76] [PATCH] e1000: Fixed frame size logic Simplified the logic used to assign the frame_size. Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_ethtool.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index ad9ca2ac25fa..8363d8d86318 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -1401,7 +1401,7 @@ static void e1000_create_lbtest_frame(struct sk_buff *skb, unsigned int frame_size) { memset(skb->data, 0xFF, frame_size); - frame_size = (frame_size % 2) ? (frame_size - 1) : frame_size; + frame_size &= ~1; memset(&skb->data[frame_size / 2], 0xAA, frame_size / 2 - 1); memset(&skb->data[frame_size / 2 + 10], 0xBE, 1); memset(&skb->data[frame_size / 2 + 12], 0xAF, 1); @@ -1410,7 +1410,7 @@ e1000_create_lbtest_frame(struct sk_buff *skb, unsigned int frame_size) static int e1000_check_lbtest_frame(struct sk_buff *skb, unsigned int frame_size) { - frame_size = (frame_size % 2) ? (frame_size - 1) : frame_size; + frame_size &= ~1; if(*(skb->data + 3) == 0xFF) { if((*(skb->data + frame_size / 2 + 10) == 0xBE) && (*(skb->data + frame_size / 2 + 12) == 0xAF)) { From e8da8be146e6043fb4b60a222be0014a0fb46d24 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 12 Jan 2006 16:51:14 -0800 Subject: [PATCH 49/76] [PATCH] e1000: Fix Netpoll issue Fixed an issue netpoll would error out during communication, generating the following error: --netdump[14973]: Got toomany timeouts in handshaking, ... Even after a kernel panic, netpoll requires two way communication to successfully transfer the crash log to the remote server. Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 8190eb00d54f..6d7f9c9df085 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -4449,6 +4449,9 @@ e1000_netpoll(struct net_device *netdev) disable_irq(adapter->pdev->irq); e1000_intr(adapter->pdev->irq, netdev, NULL); e1000_clean_tx_irq(adapter, adapter->tx_ring); +#ifndef CONFIG_E1000_NAPI + adapter->clean_rx(adapter, adapter->rx_ring); +#endif enable_irq(adapter->pdev->irq); } #endif From 1e613fd9d64aba9945ddb3b7f1107127ee8a9835 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 12 Jan 2006 16:51:16 -0800 Subject: [PATCH 50/76] [PATCH] e1000: Added interrupt auto mask support Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_main.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 6d7f9c9df085..53f87fe511c5 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -1736,10 +1736,15 @@ e1000_configure_rx(struct e1000_adapter *adapter) } if (hw->mac_type >= e1000_82571) { - /* Reset delay timers after every interrupt */ ctrl_ext = E1000_READ_REG(hw, CTRL_EXT); + /* Reset delay timers after every interrupt */ ctrl_ext |= E1000_CTRL_EXT_CANC; +#ifdef CONFIG_E1000_NAPI + /* Auto-Mask interrupts upon ICR read. */ + ctrl_ext |= E1000_CTRL_EXT_IAME; +#endif E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext); + E1000_WRITE_REG(hw, IAM, ~0); E1000_WRITE_FLUSH(hw); } @@ -3244,12 +3249,24 @@ e1000_intr(int irq, void *data, struct pt_regs *regs) struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; uint32_t icr = E1000_READ_REG(hw, ICR); -#if defined(CONFIG_E1000_NAPI) && defined(CONFIG_E1000_MQ) || !defined(CONFIG_E1000_NAPI) +#ifndef CONFIG_E1000_NAPI int i; +#else + /* Interrupt Auto-Mask...upon reading ICR, + * interrupts are masked. No need for the + * IMC write, but it does mean we should + * account for it ASAP. */ + if (likely(hw->mac_type >= e1000_82571)) + atomic_inc(&adapter->irq_sem); #endif - if(unlikely(!icr)) + if (unlikely(!icr)) { +#ifdef CONFIG_E1000_NAPI + if (hw->mac_type >= e1000_82571) + e1000_irq_enable(adapter); +#endif return IRQ_NONE; /* Not our interrupt */ + } if(unlikely(icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC))) { hw->get_link_status = 1; @@ -3257,9 +3274,11 @@ e1000_intr(int irq, void *data, struct pt_regs *regs) } #ifdef CONFIG_E1000_NAPI - atomic_inc(&adapter->irq_sem); - E1000_WRITE_REG(hw, IMC, ~0); - E1000_WRITE_FLUSH(hw); + if (unlikely(hw->mac_type < e1000_82571)) { + atomic_inc(&adapter->irq_sem); + E1000_WRITE_REG(hw, IMC, ~0); + E1000_WRITE_FLUSH(hw); + } #ifdef CONFIG_E1000_MQ if (atomic_read(&adapter->rx_sched_call_data.count) == 0) { /* We must setup the cpumask once count == 0 since From 72d64a436724da72f876c85a73895a622da6a673 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 12 Jan 2006 16:51:19 -0800 Subject: [PATCH 51/76] [PATCH] e1000: Added cleaned_count to RX buffer allocation Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000.h | 9 +++-- drivers/net/e1000/e1000_main.c | 68 +++++++++++++++++++++++----------- 2 files changed, 51 insertions(+), 26 deletions(-) diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index d95a5f88181c..27c77306193b 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -304,14 +304,15 @@ struct e1000_adapter { /* RX */ #ifdef CONFIG_E1000_NAPI boolean_t (*clean_rx) (struct e1000_adapter *adapter, - struct e1000_rx_ring *rx_ring, - int *work_done, int work_to_do); + struct e1000_rx_ring *rx_ring, + int *work_done, int work_to_do); #else boolean_t (*clean_rx) (struct e1000_adapter *adapter, - struct e1000_rx_ring *rx_ring); + struct e1000_rx_ring *rx_ring); #endif void (*alloc_rx_buf) (struct e1000_adapter *adapter, - struct e1000_rx_ring *rx_ring); + struct e1000_rx_ring *rx_ring, + int cleaned_count); struct e1000_rx_ring *rx_ring; /* One per active queue */ #ifdef CONFIG_E1000_NAPI struct net_device *polling_netdev; /* One per active queue */ diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 53f87fe511c5..72a80099f4ae 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -171,9 +171,11 @@ static boolean_t e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, struct e1000_rx_ring *rx_ring); #endif static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter, - struct e1000_rx_ring *rx_ring); + struct e1000_rx_ring *rx_ring, + int cleaned_count); static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter, - struct e1000_rx_ring *rx_ring); + struct e1000_rx_ring *rx_ring, + int cleaned_count); static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd); static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd); @@ -411,8 +413,12 @@ e1000_up(struct e1000_adapter *adapter) e1000_configure_tx(adapter); e1000_setup_rctl(adapter); e1000_configure_rx(adapter); + /* call E1000_DESC_UNUSED which always leaves + * at least 1 descriptor unused to make sure + * next_to_use != next_to_clean */ for (i = 0; i < adapter->num_rx_queues; i++) { - adapter->alloc_rx_buf(adapter, &adapter->rx_ring[i]); + struct e1000_rx_ring *ring = &adapter->rx_ring[i]; + adapter->alloc_rx_buf(adapter, ring, E1000_DESC_UNUSED(ring)); } #ifdef CONFIG_PCI_MSI @@ -2119,7 +2125,9 @@ e1000_leave_82542_rst(struct e1000_adapter *adapter) if(netif_running(netdev)) { e1000_configure_rx(adapter); - e1000_alloc_rx_buffers(adapter, &adapter->rx_ring[0]); + /* No need to loop, because 82542 supports only 1 queue */ + struct e1000_rx_ring *ring = &adapter->rx_ring[0]; + adapter->alloc_rx_buf(adapter, ring, E1000_DESC_UNUSED(ring)); } } @@ -3539,6 +3547,7 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter, uint8_t last_byte; unsigned int i; boolean_t cleaned = FALSE; + int cleaned_count = 0; i = rx_ring->next_to_clean; rx_desc = E1000_RX_DESC(*rx_ring, i); @@ -3550,11 +3559,10 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter, break; (*work_done)++; #endif - cleaned = TRUE; - pci_unmap_single(pdev, - buffer_info->dma, - buffer_info->length, + cleaned = TRUE; + cleaned_count++; + pci_unmap_single(pdev, buffer_info->dma, buffer_info->length, PCI_DMA_FROMDEVICE); skb = buffer_info->skb; @@ -3573,8 +3581,7 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter, if(TBI_ACCEPT(&adapter->hw, rx_desc->status, rx_desc->errors, length, last_byte)) { spin_lock_irqsave(&adapter->stats_lock, flags); - e1000_tbi_adjust_stats(&adapter->hw, - &adapter->stats, + e1000_tbi_adjust_stats(&adapter->hw, &adapter->stats, length, skb->data); spin_unlock_irqrestore(&adapter->stats_lock, flags); @@ -3589,8 +3596,7 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter, skb_put(skb, length - ETHERNET_FCS_SIZE); /* Receive Checksum Offload */ - e1000_rx_checksum(adapter, - (uint32_t)(rx_desc->status) | + e1000_rx_checksum(adapter, (uint32_t)(rx_desc->status) | ((uint32_t)(rx_desc->errors) << 24), rx_desc->csum, skb); skb->protocol = eth_type_trans(skb, netdev); @@ -3621,13 +3627,19 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter, next_desc: rx_desc->status = 0; - buffer_info->skb = NULL; - if(unlikely(++i == rx_ring->count)) i = 0; - rx_desc = E1000_RX_DESC(*rx_ring, i); + /* return some buffers to hardware, one at a time is too slow */ + if (unlikely(cleaned_count >= E1000_RX_BUFFER_WRITE)) { + adapter->alloc_rx_buf(adapter, rx_ring, cleaned_count); + cleaned_count = 0; + } + } rx_ring->next_to_clean = i; - adapter->alloc_rx_buf(adapter, rx_ring); + + cleaned_count = E1000_DESC_UNUSED(rx_ring); + if (cleaned_count) + adapter->alloc_rx_buf(adapter, rx_ring, cleaned_count); return cleaned; } @@ -3656,6 +3668,7 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, struct sk_buff *skb; unsigned int i, j; uint32_t length, staterr; + int cleaned_count = 0; boolean_t cleaned = FALSE; i = rx_ring->next_to_clean; @@ -3672,6 +3685,7 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, (*work_done)++; #endif cleaned = TRUE; + cleaned_count++; pci_unmap_single(pdev, buffer_info->dma, buffer_info->length, PCI_DMA_FROMDEVICE); @@ -3756,13 +3770,20 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, next_desc: rx_desc->wb.middle.status_error &= ~0xFF; buffer_info->skb = NULL; - if(unlikely(++i == rx_ring->count)) i = 0; - rx_desc = E1000_RX_DESC_PS(*rx_ring, i); + /* return some buffers to hardware, one at a time is too slow */ + if (unlikely(cleaned_count >= E1000_RX_BUFFER_WRITE)) { + adapter->alloc_rx_buf(adapter, rx_ring, cleaned_count); + cleaned_count = 0; + } + staterr = le32_to_cpu(rx_desc->wb.middle.status_error); } rx_ring->next_to_clean = i; - adapter->alloc_rx_buf(adapter, rx_ring); + + cleaned_count = E1000_DESC_UNUSED(rx_ring); + if (cleaned_count) + adapter->alloc_rx_buf(adapter, rx_ring, cleaned_count); return cleaned; } @@ -3774,7 +3795,8 @@ next_desc: static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter, - struct e1000_rx_ring *rx_ring) + struct e1000_rx_ring *rx_ring, + int cleaned_count) { struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; @@ -3792,6 +3814,7 @@ e1000_alloc_rx_buffers(struct e1000_adapter *adapter, if(unlikely(!skb)) { /* Better luck next round */ + adapter->alloc_rx_buff_failed++; break; } @@ -3876,7 +3899,8 @@ e1000_alloc_rx_buffers(struct e1000_adapter *adapter, static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter, - struct e1000_rx_ring *rx_ring) + struct e1000_rx_ring *rx_ring, + int cleaned_count) { struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; @@ -3892,7 +3916,7 @@ e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter, ps_page = &rx_ring->ps_page[i]; ps_page_dma = &rx_ring->ps_page_dma[i]; - while(!buffer_info->skb) { + while (cleaned_count--) { rx_desc = E1000_RX_DESC_PS(*rx_ring, i); for(j = 0; j < PS_PAGE_BUFFERS; j++) { From b7ee49db8b4b21dad3284d5507e7ea2946031f6e Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 12 Jan 2006 16:51:21 -0800 Subject: [PATCH 52/76] [PATCH] e1000: Added hardware support for PCI express, 82546GB, and 82571 Fiber Added 82571 fiber to WOL fix for dual port adapters. Added support for 82546GB (Quad Copper). Added PCIe typedef for x2, igp cable length 115, and extended TX CTRL registers. Added parity error detection and PCIe CTRL registers. Added EEPROM config registers. Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_ethtool.c | 2 ++ drivers/net/e1000/e1000_hw.c | 12 ++++++++++++ drivers/net/e1000/e1000_hw.h | 19 +++++++++++++++++++ drivers/net/e1000/e1000_main.c | 5 +++-- 4 files changed, 36 insertions(+), 2 deletions(-) diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index 8363d8d86318..0f9c86057a58 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -1628,6 +1628,7 @@ e1000_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) case E1000_DEV_ID_82546EB_FIBER: case E1000_DEV_ID_82546GB_FIBER: + case E1000_DEV_ID_82571EB_FIBER: /* Wake events only supported on port A for dual fiber */ if(E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1) { wol->supported = 0; @@ -1671,6 +1672,7 @@ e1000_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) case E1000_DEV_ID_82546EB_FIBER: case E1000_DEV_ID_82546GB_FIBER: + case E1000_DEV_ID_82571EB_FIBER: /* Wake events only supported on port A for dual fiber */ if(E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1) return wol->wolopts ? -EOPNOTSUPP : 0; diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index ac227c7847ff..2437d362ff63 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -318,6 +318,8 @@ e1000_set_mac_type(struct e1000_hw *hw) case E1000_DEV_ID_82546GB_FIBER: case E1000_DEV_ID_82546GB_SERDES: case E1000_DEV_ID_82546GB_PCIE: + case E1000_DEV_ID_82546GB_QUAD_COPPER: + case E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3: hw->mac_type = e1000_82546_rev_3; break; case E1000_DEV_ID_82541EI: @@ -639,6 +641,7 @@ e1000_init_hw(struct e1000_hw *hw) uint16_t cmd_mmrbc; uint16_t stat_mmrbc; uint32_t mta_size; + uint32_t ctrl_ext; DEBUGFUNC("e1000_init_hw"); @@ -774,6 +777,15 @@ e1000_init_hw(struct e1000_hw *hw) */ e1000_clear_hw_cntrs(hw); + if (hw->device_id == E1000_DEV_ID_82546GB_QUAD_COPPER || + hw->device_id == E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3) { + ctrl_ext = E1000_READ_REG(hw, CTRL_EXT); + /* Relaxed ordering must be disabled to avoid a parity + * error crash in a PCI slot. */ + ctrl_ext |= E1000_CTRL_EXT_RO_DIS; + E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext); + } + return ret_val; } diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h index 600570ff254b..0b8f6f2b774b 100644 --- a/drivers/net/e1000/e1000_hw.h +++ b/drivers/net/e1000/e1000_hw.h @@ -439,6 +439,7 @@ int32_t e1000_check_phy_reset_block(struct e1000_hw *hw); #define E1000_DEV_ID_82546GB_FIBER 0x107A #define E1000_DEV_ID_82546GB_SERDES 0x107B #define E1000_DEV_ID_82546GB_PCIE 0x108A +#define E1000_DEV_ID_82546GB_QUAD_COPPER 0x1099 #define E1000_DEV_ID_82547EI 0x1019 #define E1000_DEV_ID_82571EB_COPPER 0x105E #define E1000_DEV_ID_82571EB_FIBER 0x105F @@ -449,6 +450,7 @@ int32_t e1000_check_phy_reset_block(struct e1000_hw *hw); #define E1000_DEV_ID_82573E 0x108B #define E1000_DEV_ID_82573E_IAMT 0x108C #define E1000_DEV_ID_82573L 0x109A +#define E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3 0x10B5 #define NODE_ADDRESS_SIZE 6 @@ -1955,6 +1957,23 @@ struct e1000_host_command_info { #define E1000_MDALIGN 4096 +/* PCI-Ex registers */ + +/* PCI-Ex Control Register */ +#define E1000_GCR_RXD_NO_SNOOP 0x00000001 +#define E1000_GCR_RXDSCW_NO_SNOOP 0x00000002 +#define E1000_GCR_RXDSCR_NO_SNOOP 0x00000004 +#define E1000_GCR_TXD_NO_SNOOP 0x00000008 +#define E1000_GCR_TXDSCW_NO_SNOOP 0x00000010 +#define E1000_GCR_TXDSCR_NO_SNOOP 0x00000020 + +#define PCI_EX_NO_SNOOP_ALL (E1000_GCR_RXD_NO_SNOOP | \ + E1000_GCR_RXDSCW_NO_SNOOP | \ + E1000_GCR_RXDSCR_NO_SNOOP | \ + E1000_GCR TXD_NO_SNOOP | \ + E1000_GCR_TXDSCW_NO_SNOOP | \ + E1000_GCR_TXDSCR_NO_SNOOP) + #define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000 /* Function Active and Power State to MNG */ #define E1000_FACTPS_FUNC0_POWER_STATE_MASK 0x00000003 diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 72a80099f4ae..ca4e5e9255d2 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -97,7 +97,9 @@ static struct pci_device_id e1000_pci_tbl[] = { INTEL_E1000_ETHERNET_DEVICE(0x108A), INTEL_E1000_ETHERNET_DEVICE(0x108B), INTEL_E1000_ETHERNET_DEVICE(0x108C), + INTEL_E1000_ETHERNET_DEVICE(0x1099), INTEL_E1000_ETHERNET_DEVICE(0x109A), + INTEL_E1000_ETHERNET_DEVICE(0x10B5), /* required last entry */ {0,} }; @@ -791,8 +793,7 @@ e1000_probe(struct pci_dev *pdev, case e1000_82546: case e1000_82546_rev_3: case e1000_82571: - if((E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_FUNC_1) - && (adapter->hw.media_type == e1000_media_type_copper)) { + if(E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_FUNC_1){ e1000_read_eeprom(&adapter->hw, EEPROM_INIT_CONTROL3_PORT_B, 1, &eeprom_data); break; From a2917e22dcaa53e8ad2d8dc3bcfa55a4b04e6d0f Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 12 Jan 2006 16:51:23 -0800 Subject: [PATCH 53/76] [PATCH] e1000: Added firmware version reporting for 8257{1|2|3} controllers The EEPROM image version is reported as a firmware version for these controllers. Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_ethtool.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index 0f9c86057a58..d252297e4db0 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -582,10 +582,29 @@ e1000_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo) { struct e1000_adapter *adapter = netdev_priv(netdev); + char firmware_version[32]; + uint16_t eeprom_data; strncpy(drvinfo->driver, e1000_driver_name, 32); strncpy(drvinfo->version, e1000_driver_version, 32); - strncpy(drvinfo->fw_version, "N/A", 32); + + /* EEPROM image version # is reported as firmware version # for + * 8257{1|2|3} controllers */ + e1000_read_eeprom(&adapter->hw, 5, 1, &eeprom_data); + switch (adapter->hw.mac_type) { + case e1000_82571: + case e1000_82572: + case e1000_82573: + sprintf(firmware_version, "%d.%d-%d", + (eeprom_data & 0xF000) >> 12, + (eeprom_data & 0x0FF0) >> 4, + eeprom_data & 0x000F); + break; + default: + sprintf(firmware_version, "N/A"); + } + + strncpy(drvinfo->fw_version, firmware_version, 32); strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32); drvinfo->n_stats = E1000_STATS_LEN; drvinfo->testinfo_len = E1000_TEST_LEN; From fb3d47d4c4cd79eeddd0ee1b470e157840dccf21 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 12 Jan 2006 16:51:25 -0800 Subject: [PATCH 54/76] [PATCH] e1000: Added PCIe bus information This is two patches, the first is adding additional bus information for the 8257{1|2|3} controllers. The second patch was orginally a community patch to print bus type/speed/width, and enhanced by us. Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_main.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index ca4e5e9255d2..75cd6dfbaa37 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -807,6 +807,26 @@ e1000_probe(struct pci_dev *pdev, if(eeprom_data & eeprom_apme_mask) adapter->wol |= E1000_WUFC_MAG; + /* print bus type/speed/width info */ + { + struct e1000_hw *hw = &adapter->hw; + DPRINTK(PROBE, INFO, "(PCI%s:%s:%s) ", + ((hw->bus_type == e1000_bus_type_pcix) ? "-X" : + (hw->bus_type == e1000_bus_type_pci_express ? " Express":"")), + ((hw->bus_speed == e1000_bus_speed_2500) ? "2.5Gb/s" : + (hw->bus_speed == e1000_bus_speed_133) ? "133MHz" : + (hw->bus_speed == e1000_bus_speed_120) ? "120MHz" : + (hw->bus_speed == e1000_bus_speed_100) ? "100MHz" : + (hw->bus_speed == e1000_bus_speed_66) ? "66MHz" : "33MHz"), + ((hw->bus_width == e1000_bus_width_64) ? "64-bit" : + (hw->bus_width == e1000_bus_width_pciex_4) ? "Width x4" : + (hw->bus_width == e1000_bus_width_pciex_1) ? "Width x1" : + "32-bit")); + } + + for (i = 0; i < 6; i++) + printk("%2.2x%c", netdev->dev_addr[i], i == 5 ? '\n' : ':'); + /* reset the hardware with the new settings */ e1000_reset(adapter); From 240b1710f56b359685bc698e2a1473a2f3f2b8d7 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 12 Jan 2006 16:51:28 -0800 Subject: [PATCH 55/76] [PATCH] e1000: Added variable to handle return values for pci_enable_* functions This was to fix compilation warnings. Also added log messages when pci_enable_* functions return with an error. Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_main.c | 44 +++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 75cd6dfbaa37..8207db44b705 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -4382,6 +4382,7 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state) struct e1000_adapter *adapter = netdev_priv(netdev); uint32_t ctrl, ctrl_ext, rctl, manc, status; uint32_t wufc = adapter->wol; + int retval = 0; netif_device_detach(netdev); @@ -4427,13 +4428,21 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state) E1000_WRITE_REG(&adapter->hw, WUC, E1000_WUC_PME_EN); E1000_WRITE_REG(&adapter->hw, WUFC, wufc); - pci_enable_wake(pdev, 3, 1); - pci_enable_wake(pdev, 4, 1); /* 4 == D3 cold */ + retval = pci_enable_wake(pdev, PCI_D3hot, 1); + if (retval) + DPRINTK(PROBE, ERR, "Error enabling D3 wake\n"); + retval = pci_enable_wake(pdev, PCI_D3cold, 1); + if (retval) + DPRINTK(PROBE, ERR, "Error enabling D3 cold wake\n"); } else { E1000_WRITE_REG(&adapter->hw, WUC, 0); E1000_WRITE_REG(&adapter->hw, WUFC, 0); - pci_enable_wake(pdev, 3, 0); - pci_enable_wake(pdev, 4, 0); /* 4 == D3 cold */ + retval = pci_enable_wake(pdev, PCI_D3hot, 0); + if (retval) + DPRINTK(PROBE, ERR, "Error enabling D3 wake\n"); + retval = pci_enable_wake(pdev, PCI_D3cold, 0); /* 4 == D3 cold */ + if (retval) + DPRINTK(PROBE, ERR, "Error enabling D3 cold wake\n"); } pci_save_state(pdev); @@ -4444,8 +4453,12 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state) if(manc & E1000_MANC_SMBUS_EN) { manc |= E1000_MANC_ARP_EN; E1000_WRITE_REG(&adapter->hw, MANC, manc); - pci_enable_wake(pdev, 3, 1); - pci_enable_wake(pdev, 4, 1); /* 4 == D3 cold */ + retval = pci_enable_wake(pdev, PCI_D3hot, 1); + if (retval) + DPRINTK(PROBE, ERR, "Error enabling D3 wake\n"); + retval = pci_enable_wake(pdev, PCI_D3cold, 1); + if (retval) + DPRINTK(PROBE, ERR, "Error enabling D3 cold wake\n"); } } @@ -4454,7 +4467,10 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state) e1000_release_hw_control(adapter); pci_disable_device(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); + + retval = pci_set_power_state(pdev, pci_choose_state(pdev, state)); + if (retval) + DPRINTK(PROBE, ERR, "Error in setting power state\n"); return 0; } @@ -4464,15 +4480,21 @@ e1000_resume(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); struct e1000_adapter *adapter = netdev_priv(netdev); + int retval; uint32_t manc, ret_val; - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); + retval = pci_set_power_state(pdev, PCI_D0); + if (retval) + DPRINTK(PROBE, ERR, "Error in setting power state\n"); ret_val = pci_enable_device(pdev); pci_set_master(pdev); - pci_enable_wake(pdev, PCI_D3hot, 0); - pci_enable_wake(pdev, PCI_D3cold, 0); + retval = pci_enable_wake(pdev, PCI_D3hot, 0); + if (retval) + DPRINTK(PROBE, ERR, "Error enabling D3 wake\n"); + retval = pci_enable_wake(pdev, PCI_D3cold, 0); + if (retval) + DPRINTK(PROBE, ERR, "Error enabling D3 cold wake\n"); e1000_reset(adapter); E1000_WRITE_REG(&adapter->hw, WUS, ~0); From a292ca6efbc1f259ddfb9c902367f2588e0e8b0f Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 12 Jan 2006 16:51:30 -0800 Subject: [PATCH 56/76] [PATCH] e1000: Added copy break code Improves small packet performance with large amounts of reassembly being done in the stack. Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_main.c | 59 +++++++++++++++++++++++++++------- 1 file changed, 47 insertions(+), 12 deletions(-) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 8207db44b705..bef4d9d6f2d5 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -420,7 +420,8 @@ e1000_up(struct e1000_adapter *adapter) * next_to_use != next_to_clean */ for (i = 0; i < adapter->num_rx_queues; i++) { struct e1000_rx_ring *ring = &adapter->rx_ring[i]; - adapter->alloc_rx_buf(adapter, ring, E1000_DESC_UNUSED(ring)); + adapter->alloc_rx_buf(adapter, ring, + E1000_DESC_UNUSED(ring)); } #ifdef CONFIG_PCI_MSI @@ -3567,23 +3568,26 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter, uint32_t length; uint8_t last_byte; unsigned int i; - boolean_t cleaned = FALSE; int cleaned_count = 0; + boolean_t cleaned = FALSE, multi_descriptor = FALSE; i = rx_ring->next_to_clean; rx_desc = E1000_RX_DESC(*rx_ring, i); while(rx_desc->status & E1000_RXD_STAT_DD) { buffer_info = &rx_ring->buffer_info[i]; + u8 status; #ifdef CONFIG_E1000_NAPI if(*work_done >= work_to_do) break; (*work_done)++; #endif - + status = rx_desc->status; cleaned = TRUE; cleaned_count++; - pci_unmap_single(pdev, buffer_info->dma, buffer_info->length, + pci_unmap_single(pdev, + buffer_info->dma, + buffer_info->length, PCI_DMA_FROMDEVICE); skb = buffer_info->skb; @@ -3602,7 +3606,8 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter, if(TBI_ACCEPT(&adapter->hw, rx_desc->status, rx_desc->errors, length, last_byte)) { spin_lock_irqsave(&adapter->stats_lock, flags); - e1000_tbi_adjust_stats(&adapter->hw, &adapter->stats, + e1000_tbi_adjust_stats(&adapter->hw, + &adapter->stats, length, skb->data); spin_unlock_irqrestore(&adapter->stats_lock, flags); @@ -3613,17 +3618,40 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter, } } - /* Good Receive */ - skb_put(skb, length - ETHERNET_FCS_SIZE); + /* code added for copybreak, this should improve + * performance for small packets with large amounts + * of reassembly being done in the stack */ +#define E1000_CB_LENGTH 256 + if ((length < E1000_CB_LENGTH) && + !rx_ring->rx_skb_top && + /* or maybe (status & E1000_RXD_STAT_EOP) && */ + !multi_descriptor) { + struct sk_buff *new_skb = + dev_alloc_skb(length + NET_IP_ALIGN); + if (new_skb) { + skb_reserve(new_skb, NET_IP_ALIGN); + new_skb->dev = netdev; + memcpy(new_skb->data - NET_IP_ALIGN, + skb->data - NET_IP_ALIGN, + length + NET_IP_ALIGN); + /* save the skb in buffer_info as good */ + buffer_info->skb = skb; + skb = new_skb; + skb_put(skb, length); + } + } + + /* end copybreak code */ /* Receive Checksum Offload */ - e1000_rx_checksum(adapter, (uint32_t)(rx_desc->status) | + e1000_rx_checksum(adapter, + (uint32_t)(status) | ((uint32_t)(rx_desc->errors) << 24), rx_desc->csum, skb); skb->protocol = eth_type_trans(skb, netdev); #ifdef CONFIG_E1000_NAPI if(unlikely(adapter->vlgrp && - (rx_desc->status & E1000_RXD_STAT_VP))) { + (status & E1000_RXD_STAT_VP))) { vlan_hwaccel_receive_skb(skb, adapter->vlgrp, le16_to_cpu(rx_desc->special) & E1000_RXD_SPC_VLAN_MASK); @@ -3817,7 +3845,7 @@ next_desc: static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter, struct e1000_rx_ring *rx_ring, - int cleaned_count) + int cleaned_count) { struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; @@ -3830,8 +3858,14 @@ e1000_alloc_rx_buffers(struct e1000_adapter *adapter, i = rx_ring->next_to_use; buffer_info = &rx_ring->buffer_info[i]; - while(!buffer_info->skb) { - skb = dev_alloc_skb(bufsz); + while (cleaned_count--) { + if (!(skb = buffer_info->skb)) + skb = dev_alloc_skb(bufsz); + else { + skb_trim(skb, 0); + goto map_skb; + } + if(unlikely(!skb)) { /* Better luck next round */ @@ -3872,6 +3906,7 @@ e1000_alloc_rx_buffers(struct e1000_adapter *adapter, buffer_info->skb = skb; buffer_info->length = adapter->rx_buffer_len; +map_skb: buffer_info->dma = pci_map_single(pdev, skb->data, adapter->rx_buffer_len, From 8241e35e0c6ae7531fe270de34608edfdc2ea483 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 12 Jan 2006 16:51:34 -0800 Subject: [PATCH 57/76] [PATCH] e1000: Cleaned up code and removed hard coded numbers Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_main.c | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index bef4d9d6f2d5..e246b5e0f21a 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -1920,12 +1920,10 @@ e1000_unmap_and_free_tx_resource(struct e1000_adapter *adapter, buffer_info->dma, buffer_info->length, PCI_DMA_TODEVICE); - buffer_info->dma = 0; } - if(buffer_info->skb) { + if (buffer_info->skb) dev_kfree_skb_any(buffer_info->skb); - buffer_info->skb = NULL; - } + memset(buffer_info, 0, sizeof(struct e1000_buffer)); } /** @@ -2044,8 +2042,6 @@ e1000_clean_rx_ring(struct e1000_adapter *adapter, for(i = 0; i < rx_ring->count; i++) { buffer_info = &rx_ring->buffer_info[i]; if(buffer_info->skb) { - ps_page = &rx_ring->ps_page[i]; - ps_page_dma = &rx_ring->ps_page_dma[i]; pci_unmap_single(pdev, buffer_info->dma, buffer_info->length, @@ -2543,11 +2539,11 @@ e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, if (++i == tx_ring->count) i = 0; tx_ring->next_to_use = i; - return 1; + return TRUE; } #endif - return 0; + return FALSE; } static inline boolean_t @@ -3383,7 +3379,19 @@ e1000_clean(struct net_device *poll_dev, int *budget) BUG(); } - tx_cleaned = e1000_clean_tx_irq(adapter, &adapter->tx_ring[i]); + if (likely(adapter->num_tx_queues == 1)) { + /* e1000_clean is called per-cpu. This lock protects + * tx_ring[0] from being cleaned by multiple cpus + * simultaneously. A failure obtaining the lock means + * tx_ring[0] is currently being cleaned anyway. */ + if (spin_trylock(&adapter->tx_queue_lock)) { + tx_cleaned = e1000_clean_tx_irq(adapter, + &adapter->tx_ring[0]); + spin_unlock(&adapter->tx_queue_lock); + } + } else + tx_cleaned = e1000_clean_tx_irq(adapter, &adapter->tx_ring[i]); + adapter->clean_rx(adapter, &adapter->rx_ring[i], &work_done, work_to_do); @@ -3428,11 +3436,11 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter, buffer_info = &tx_ring->buffer_info[i]; cleaned = (i == eop); +#ifdef CONFIG_E1000_MQ + tx_ring->tx_stats.bytes += buffer_info->length; +#endif e1000_unmap_and_free_tx_resource(adapter, buffer_info); - - tx_desc->buffer_addr = 0; - tx_desc->lower.data = 0; - tx_desc->upper.data = 0; + memset(tx_desc, 0, sizeof(struct e1000_tx_desc)); if(unlikely(++i == tx_ring->count)) i = 0; } From 38bd3b2629702894ca3528358ffc447bbacc9442 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 12 Jan 2006 16:51:37 -0800 Subject: [PATCH 58/76] [PATCH] e1000: Removed unused variables and initialized variables Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_main.c | 2 +- drivers/net/e1000/e1000_param.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index e246b5e0f21a..d0a5d1656c5f 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -3364,7 +3364,7 @@ e1000_clean(struct net_device *poll_dev, int *budget) { struct e1000_adapter *adapter; int work_to_do = min(*budget, poll_dev->quota); - int tx_cleaned, i = 0, work_done = 0; + int tx_cleaned = 0, i = 0, work_done = 0; /* Must NOT use netdev_priv macro here. */ adapter = poll_dev->priv; diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c index 133a76b71b9c..0a7918c62557 100644 --- a/drivers/net/e1000/e1000_param.c +++ b/drivers/net/e1000/e1000_param.c @@ -177,7 +177,7 @@ E1000_PARAM(RxAbsIntDelay, "Receive Absolute Interrupt Delay"); * * Valid Range: 100-100000 (0=off, 1=dynamic) * - * Default Value: 1 + * Default Value: 8000 */ E1000_PARAM(InterruptThrottleRate, "Interrupt Throttling Rate"); From 2610c733023850be2db9fef9c81f851a64bb9f67 Mon Sep 17 00:00:00 2001 From: Javier Achirica Date: Tue, 17 Jan 2006 08:01:01 -0500 Subject: [PATCH 59/76] airo: Off-by-one channel fix --- drivers/net/wireless/airo.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 65057348838b..a4c7ae94614d 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -5668,13 +5668,13 @@ static int airo_set_freq(struct net_device *dev, int channel = fwrq->m; /* We should do a better check than that, * based on the card capability !!! */ - if((channel < 1) || (channel > 16)) { + if((channel < 1) || (channel > 14)) { printk(KERN_DEBUG "%s: New channel value of %d is invalid!\n", dev->name, fwrq->m); rc = -EINVAL; } else { readConfigRid(local, 1); /* Yes ! We can set it !!! */ - local->config.channelSet = (u16)(channel - 1); + local->config.channelSet = (u16) channel; set_bit (FLAG_COMMIT, &local->flags); } } @@ -5692,6 +5692,7 @@ static int airo_get_freq(struct net_device *dev, { struct airo_info *local = dev->priv; StatusRid status_rid; /* Card status info */ + int ch; readConfigRid(local, 1); if ((local->config.opmode & 0xFF) == MODE_STA_ESS) @@ -5699,16 +5700,14 @@ static int airo_get_freq(struct net_device *dev, else readStatusRid(local, &status_rid, 1); -#ifdef WEXT_USECHANNELS - fwrq->m = ((int)status_rid.channel) + 1; - fwrq->e = 0; -#else - { - int f = (int)status_rid.channel; - fwrq->m = frequency_list[f] * 100000; + ch = (int)status_rid.channel; + if((ch > 0) && (ch < 15)) { + fwrq->m = frequency_list[ch - 1] * 100000; fwrq->e = 1; + } else { + fwrq->m = ch; + fwrq->e = 0; } -#endif return 0; } From 24180333206519e6b0c4633eab81e773b4527cac Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Tue, 17 Jan 2006 15:01:06 -0800 Subject: [PATCH 60/76] [PATCH] e100: Fix TX hang and RMCP Ping issue (due to a microcode loading issue) e100: Fix TX hang and RMCP Ping issue (due to a microcode loading issue) Set the end of list bit to cause the hardware's transmit state machine to work correctly and not prevent management (BMC) traffic. Signed-off-by: Jesse Brandeburg Signed-off-by: Jeff Kirsher Signed-off-by: John Ronciak Signed-off-by: Jeff Garzik --- drivers/net/e100.c | 44 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 4726722a0635..67b99353acfe 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -160,7 +160,7 @@ #define DRV_NAME "e100" #define DRV_EXT "-NAPI" -#define DRV_VERSION "3.4.14-k4"DRV_EXT +#define DRV_VERSION "3.5.10-k2"DRV_EXT #define DRV_DESCRIPTION "Intel(R) PRO/100 Network Driver" #define DRV_COPYRIGHT "Copyright(c) 1999-2005 Intel Corporation" #define PFX DRV_NAME ": " @@ -1170,7 +1170,7 @@ static void e100_configure(struct nic *nic, struct cb *cb, struct sk_buff *skb) 0x00000000, 0x00000000, 0x00000000, 0x00000000, \ } -static void e100_load_ucode(struct nic *nic, struct cb *cb, struct sk_buff *skb) +static void e100_setup_ucode(struct nic *nic, struct cb *cb, struct sk_buff *skb) { /* *INDENT-OFF* */ static struct { @@ -1284,12 +1284,46 @@ static void e100_load_ucode(struct nic *nic, struct cb *cb, struct sk_buff *skb) for (i = 0; i < UCODE_SIZE; i++) cb->u.ucode[i] = cpu_to_le32(ucode[i]); - cb->command = cpu_to_le16(cb_ucode); + cb->command = cpu_to_le16(cb_ucode | cb_el); return; } noloaducode: - cb->command = cpu_to_le16(cb_nop); + cb->command = cpu_to_le16(cb_nop | cb_el); +} + +static inline int e100_exec_cb_wait(struct nic *nic, struct sk_buff *skb, + void (*cb_prepare)(struct nic *, struct cb *, struct sk_buff *)) +{ + int err = 0, counter = 50; + struct cb *cb = nic->cb_to_clean; + + if ((err = e100_exec_cb(nic, NULL, e100_setup_ucode))) + DPRINTK(PROBE,ERR, "ucode cmd failed with error %d\n", err); + + /* must restart cuc */ + nic->cuc_cmd = cuc_start; + + /* wait for completion */ + e100_write_flush(nic); + udelay(10); + + /* wait for possibly (ouch) 500ms */ + while (!(cb->status & cpu_to_le16(cb_complete))) { + msleep(10); + if (!--counter) break; + } + + /* ack any interupts, something could have been set */ + writeb(~0, &nic->csr->scb.stat_ack); + + /* if the command failed, or is not OK, notify and return */ + if (!counter || !(cb->status & cpu_to_le16(cb_ok))) { + DPRINTK(PROBE,ERR, "ucode load failed\n"); + err = -EPERM; + } + + return err; } static void e100_setup_iaaddr(struct nic *nic, struct cb *cb, @@ -1388,7 +1422,7 @@ static int e100_hw_init(struct nic *nic) return err; if((err = e100_exec_cmd(nic, ruc_load_base, 0))) return err; - if((err = e100_exec_cb(nic, NULL, e100_load_ucode))) + if ((err = e100_exec_cb_wait(nic, NULL, e100_setup_ucode))) return err; if((err = e100_exec_cb(nic, NULL, e100_configure))) return err; From 3435dbcec199740d3100e0a2f316e795286b5424 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Tue, 17 Jan 2006 15:01:08 -0800 Subject: [PATCH 61/76] [PATCH] e100: Handle the return values from pci_* functions e100: Handle the return values from pci_* functions This is to resolve warnings during compile time. Signed-off-by: Jesse Brandeburg Signed-off-by: Jeff Kirsher Signed-off-by: John Ronciak Signed-off-by: Jeff Garzik --- drivers/net/e100.c | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 67b99353acfe..394fb019c4f4 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -2665,7 +2665,9 @@ static int __devinit e100_probe(struct pci_dev *pdev, nic->flags |= wol_magic; /* ack any pending wake events, disable PME */ - pci_enable_wake(pdev, 0, 0); + err = pci_enable_wake(pdev, 0, 0); + if (err) + DPRINTK(PROBE, ERR, "Error clearing wake event\n"); strcpy(netdev->name, "eth%d"); if((err = register_netdev(netdev))) { @@ -2716,6 +2718,7 @@ static int e100_suspend(struct pci_dev *pdev, pm_message_t state) { struct net_device *netdev = pci_get_drvdata(pdev); struct nic *nic = netdev_priv(netdev); + int retval; if(netif_running(netdev)) e100_down(nic); @@ -2723,9 +2726,14 @@ static int e100_suspend(struct pci_dev *pdev, pm_message_t state) netif_device_detach(netdev); pci_save_state(pdev); - pci_enable_wake(pdev, pci_choose_state(pdev, state), nic->flags & (wol_magic | e100_asf(nic))); + retval = pci_enable_wake(pdev, pci_choose_state(pdev, state), + nic->flags & (wol_magic | e100_asf(nic))); + if (retval) + DPRINTK(PROBE,ERR, "Error enabling wake\n"); pci_disable_device(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); + retval = pci_set_power_state(pdev, pci_choose_state(pdev, state)); + if (retval) + DPRINTK(PROBE,ERR, "Error %d setting power state\n", retval); return 0; } @@ -2734,11 +2742,16 @@ static int e100_resume(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); struct nic *nic = netdev_priv(netdev); + int retval; - pci_set_power_state(pdev, PCI_D0); + retval = pci_set_power_state(pdev, PCI_D0); + if (retval) + DPRINTK(PROBE,ERR, "Error waking adapter\n"); pci_restore_state(pdev); /* ack any pending wake events, disable PME */ - pci_enable_wake(pdev, 0, 0); + retval = pci_enable_wake(pdev, 0, 0); + if (retval) + DPRINTK(PROBE,ERR, "Error clearing wake events\n"); if(e100_hw_init(nic)) DPRINTK(HW, ERR, "e100_hw_init failed\n"); @@ -2755,12 +2768,15 @@ static void e100_shutdown(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); struct nic *nic = netdev_priv(netdev); + int retval; #ifdef CONFIG_PM - pci_enable_wake(pdev, 0, nic->flags & (wol_magic | e100_asf(nic))); + retval = pci_enable_wake(pdev, 0, nic->flags & (wol_magic | e100_asf(nic))); #else - pci_enable_wake(pdev, 0, nic->flags & (wol_magic)); + retval = pci_enable_wake(pdev, 0, nic->flags & (wol_magic)); #endif + if (retval) + DPRINTK(PROBE,ERR, "Error enabling wake\n"); } From 0547993820378ef8140b0470b604737bf1fa6c85 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Tue, 17 Jan 2006 15:01:10 -0800 Subject: [PATCH 62/76] [PATCH] e100: e100 whitespace fixes e100: e100 whitespace fixes These are whitespace only fixes. Signed-off-by: Jesse Brandeburg Signed-off-by: Jeff Kirsher Signed-off-by: John Ronciak Signed-off-by: Jeff Garzik --- drivers/net/e100.c | 74 +++++++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 394fb019c4f4..bf1fd2b98bf8 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -1,25 +1,25 @@ /******************************************************************************* - + Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2 of the License, or (at your option) + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., 59 + this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - + The full GNU General Public License is included in this distribution in the file called LICENSE. - + Contact Information: Linux NICS Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 @@ -320,7 +320,7 @@ enum cuc_dump { cuc_dump_complete = 0x0000A005, cuc_dump_reset_complete = 0x0000A007, }; - + enum port { software_reset = 0x0000, selftest = 0x0001, @@ -715,10 +715,10 @@ static u16 e100_eeprom_read(struct nic *nic, u16 *addr_len, u16 addr) ctrl = (cmd_addr_data & (1 << i)) ? eecs | eedi : eecs; writeb(ctrl, &nic->csr->eeprom_ctrl_lo); e100_write_flush(nic); udelay(4); - + writeb(ctrl | eesk, &nic->csr->eeprom_ctrl_lo); e100_write_flush(nic); udelay(4); - + /* Eeprom drives a dummy zero to EEDO after receiving * complete address. Use this to adjust addr_len. */ ctrl = readb(&nic->csr->eeprom_ctrl_lo); @@ -726,7 +726,7 @@ static u16 e100_eeprom_read(struct nic *nic, u16 *addr_len, u16 addr) *addr_len -= (i - 16); i = 17; } - + data = (data << 1) | (ctrl & eedo ? 1 : 0); } @@ -1213,13 +1213,13 @@ static void e100_setup_ucode(struct nic *nic, struct cb *cb, struct sk_buff *skb * driver can change the algorithm. * * INTDELAY - This loads the dead-man timer with its inital value. -* When this timer expires the interrupt is asserted, and the +* When this timer expires the interrupt is asserted, and the * timer is reset each time a new packet is received. (see * BUNDLEMAX below to set the limit on number of chained packets) * The current default is 0x600 or 1536. Experiments show that * the value should probably stay within the 0x200 - 0x1000. * -* BUNDLEMAX - +* BUNDLEMAX - * This sets the maximum number of frames that will be bundled. In * some situations, such as the TCP windowing algorithm, it may be * better to limit the growth of the bundle size than let it go as @@ -1229,7 +1229,7 @@ static void e100_setup_ucode(struct nic *nic, struct cb *cb, struct sk_buff *skb * an interrupt for every frame received. If you do not want to put * a limit on the bundle size, set this value to xFFFF. * -* BUNDLESMALL - +* BUNDLESMALL - * This contains a bit-mask describing the minimum size frame that * will be bundled. The default masks the lower 7 bits, which means * that any frame less than 128 bytes in length will not be bundled, @@ -1244,7 +1244,7 @@ static void e100_setup_ucode(struct nic *nic, struct cb *cb, struct sk_buff *skb * * The current default is 0xFF80, which masks out the lower 7 bits. * This means that any frame which is x7F (127) bytes or smaller -* will cause an immediate interrupt. Because this value must be a +* will cause an immediate interrupt. Because this value must be a * bit mask, there are only a few valid values that can be used. To * turn this feature off, the driver can write the value xFFFF to the * lower word of this instruction (in the same way that the other @@ -1253,7 +1253,7 @@ static void e100_setup_ucode(struct nic *nic, struct cb *cb, struct sk_buff *skb * standard Ethernet frames are <= 2047 bytes in length. *************************************************************************/ -/* if you wish to disable the ucode functionality, while maintaining the +/* if you wish to disable the ucode functionality, while maintaining the * workarounds it provides, set the following defines to: * BUNDLESMALL 0 * BUNDLEMAX 1 @@ -1300,7 +1300,7 @@ static inline int e100_exec_cb_wait(struct nic *nic, struct sk_buff *skb, if ((err = e100_exec_cb(nic, NULL, e100_setup_ucode))) DPRINTK(PROBE,ERR, "ucode cmd failed with error %d\n", err); - + /* must restart cuc */ nic->cuc_cmd = cuc_start; @@ -1313,7 +1313,7 @@ static inline int e100_exec_cb_wait(struct nic *nic, struct sk_buff *skb, msleep(10); if (!--counter) break; } - + /* ack any interupts, something could have been set */ writeb(~0, &nic->csr->scb.stat_ack); @@ -1322,7 +1322,7 @@ static inline int e100_exec_cb_wait(struct nic *nic, struct sk_buff *skb, DPRINTK(PROBE,ERR, "ucode load failed\n"); err = -EPERM; } - + return err; } @@ -1391,13 +1391,13 @@ static int e100_phy_init(struct nic *nic) mdio_write(netdev, nic->mii.phy_id, MII_NSC_CONG, cong); } - if((nic->mac >= mac_82550_D102) || ((nic->flags & ich) && + if((nic->mac >= mac_82550_D102) || ((nic->flags & ich) && (mdio_read(netdev, nic->mii.phy_id, MII_TPISTATUS) & 0x8000))) { /* enable/disable MDI/MDI-X auto-switching. MDI/MDI-X auto-switching is disabled for 82551ER/QM chips */ if((nic->mac == mac_82551_E) || (nic->mac == mac_82551_F) || - (nic->mac == mac_82551_10) || (nic->mii.force_media) || - !(nic->eeprom[eeprom_cnfg_mdix] & eeprom_mdix_enabled)) + (nic->mac == mac_82551_10) || (nic->mii.force_media) || + !(nic->eeprom[eeprom_cnfg_mdix] & eeprom_mdix_enabled)) mdio_write(netdev, nic->mii.phy_id, MII_NCONFIG, 0); else mdio_write(netdev, nic->mii.phy_id, MII_NCONFIG, NCONFIG_AUTO_SWITCH); @@ -1527,7 +1527,7 @@ static void e100_update_stats(struct nic *nic) } } - + if(e100_exec_cmd(nic, cuc_dump_reset, 0)) DPRINTK(TX_ERR, DEBUG, "exec cuc_dump_reset failed\n"); } @@ -1576,10 +1576,10 @@ static void e100_watchdog(unsigned long data) mii_check_link(&nic->mii); /* Software generated interrupt to recover from (rare) Rx - * allocation failure. - * Unfortunately have to use a spinlock to not re-enable interrupts - * accidentally, due to hardware that shares a register between the - * interrupt mask bit and the SW Interrupt generation bit */ + * allocation failure. + * Unfortunately have to use a spinlock to not re-enable interrupts + * accidentally, due to hardware that shares a register between the + * interrupt mask bit and the SW Interrupt generation bit */ spin_lock_irq(&nic->cmd_lock); writeb(readb(&nic->csr->scb.cmd_hi) | irq_sw_gen,&nic->csr->scb.cmd_hi); spin_unlock_irq(&nic->cmd_lock); @@ -1864,7 +1864,7 @@ static void e100_rx_clean(struct nic *nic, unsigned int *work_done, struct rx *rx_to_start = NULL; /* are we already rnr? then pay attention!!! this ensures that - * the state machine progression never allows a start with a + * the state machine progression never allows a start with a * partially cleaned list, avoiding a race between hardware * and rx_to_clean when in NAPI mode */ if(RU_SUSPENDED == nic->ru_running) @@ -2100,7 +2100,7 @@ static void e100_tx_timeout(struct net_device *netdev) { struct nic *nic = netdev_priv(netdev); - /* Reset outside of interrupt context, to avoid request_irq + /* Reset outside of interrupt context, to avoid request_irq * in interrupt context */ schedule_work(&nic->tx_timeout_task); } @@ -2347,7 +2347,7 @@ static int e100_set_ringparam(struct net_device *netdev, struct param_range *rfds = &nic->params.rfds; struct param_range *cbs = &nic->params.cbs; - if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) + if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) return -EINVAL; if(netif_running(netdev)) @@ -2789,7 +2789,7 @@ static struct pci_driver e100_driver = { .suspend = e100_suspend, .resume = e100_resume, #endif - .shutdown = e100_shutdown, + .shutdown = e100_shutdown, }; static int __init e100_init_module(void) From 82788c7a47e50ee8d42e3be23afb23448d651c4c Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 17 Jan 2006 13:43:10 -0800 Subject: [PATCH 63/76] [PATCH] sky2: receive buffer alignment Need to make sure that sky2 receive buffers are 64 bit aligned. Also, don't need to start off with GFP_ATOMIC on initial setup. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index f5d697c0c031..996275245144 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -75,6 +75,7 @@ #define RX_LE_BYTES (RX_LE_SIZE*sizeof(struct sky2_rx_le)) #define RX_MAX_PENDING (RX_LE_SIZE/2 - 2) #define RX_DEF_PENDING RX_MAX_PENDING +#define RX_SKB_ALIGN 8 #define TX_RING_SIZE 512 #define TX_DEF_PENDING (TX_RING_SIZE - 1) @@ -904,16 +905,31 @@ static void sky2_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) } #endif +/* + * It appears the hardware has a bug in the FIFO logic that + * cause it to hang if the FIFO gets overrun and the receive buffer + * is not aligned. ALso alloc_skb() won't align properly if slab + * debugging is enabled. + */ +static inline struct sk_buff *sky2_alloc_skb(unsigned int size, gfp_t gfp_mask) +{ + struct sk_buff *skb; + + skb = alloc_skb(size + RX_SKB_ALIGN, gfp_mask); + if (likely(skb)) { + unsigned long p = (unsigned long) skb->data; + skb_reserve(skb, + ((p + RX_SKB_ALIGN - 1) & ~(RX_SKB_ALIGN - 1)) - p); + } + + return skb; +} + /* * Allocate and setup receiver buffer pool. * In case of 64 bit dma, there are 2X as many list elements * available as ring entries * and need to reserve one list element so we don't wrap around. - * - * It appears the hardware has a bug in the FIFO logic that - * cause it to hang if the FIFO gets overrun and the receive buffer - * is not aligned. This means we can't use skb_reserve to align - * the IP header. */ static int sky2_rx_start(struct sky2_port *sky2) { @@ -929,7 +945,7 @@ static int sky2_rx_start(struct sky2_port *sky2) for (i = 0; i < sky2->rx_pending; i++) { struct ring_info *re = sky2->rx_ring + i; - re->skb = dev_alloc_skb(sky2->rx_bufsize); + re->skb = sky2_alloc_skb(sky2->rx_bufsize, GFP_KERNEL); if (!re->skb) goto nomem; @@ -1713,7 +1729,7 @@ static struct sk_buff *sky2_receive(struct sky2_port *sky2, } else { struct sk_buff *nskb; - nskb = dev_alloc_skb(sky2->rx_bufsize); + nskb = sky2_alloc_skb(sky2->rx_bufsize, GFP_ATOMIC); if (!nskb) goto resubmit; From d1f3d4ddddc3c86e25ce2a41dc129cbe10e24991 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 17 Jan 2006 13:43:11 -0800 Subject: [PATCH 64/76] [PATCH] sky2: call pci_set_consistent_dma_mask Need to call pci_set_consistent_dma_mask in the case of 64 bit DMA. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 996275245144..9f4553315960 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -3054,13 +3054,17 @@ static int __devinit sky2_probe(struct pci_dev *pdev, goto err_out_free_regions; } - if (sizeof(dma_addr_t) > sizeof(u32)) { - err = pci_set_dma_mask(pdev, DMA_64BIT_MASK); - if (!err) - using_dac = 1; - } + if (sizeof(dma_addr_t) > sizeof(u32) && + !(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK))) { + using_dac = 1; + err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); + if (err < 0) { + printk(KERN_ERR PFX "%s unable to obtain 64 bit DMA " + "for consistent allocations\n", pci_name(pdev)); + goto err_out_free_regions; + } - if (!using_dac) { + } else { err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); if (err) { printk(KERN_ERR PFX "%s no usable DMA configuration\n", @@ -3068,6 +3072,7 @@ static int __devinit sky2_probe(struct pci_dev *pdev, goto err_out_free_regions; } } + #ifdef __BIG_ENDIAN /* byte swap descriptors in hardware */ { From e0c94455ce2a0e5734eeb236fb49a4613e20e7b0 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 17 Jan 2006 13:43:12 -0800 Subject: [PATCH 65/76] [PATCH] sky2: version 0.12 Version update. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 9f4553315960..f68ccfbffff3 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -57,7 +57,7 @@ #include "sky2.h" #define DRV_NAME "sky2" -#define DRV_VERSION "0.11" +#define DRV_VERSION "0.12" #define PFX DRV_NAME " " /* From 1c28f6ba600d05be2dc7ab0592e4d845f668a485 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 17 Jan 2006 13:43:13 -0800 Subject: [PATCH 66/76] [PATCH] sky2: fix ram buffer for Yukon FE rev 2 Fix problems with Yukon FE rev 2 chipset. Don't cut and paste bugs in from sk98lin driver. Change how the ram buffer is divided up, and make the math clearer. Also, set the thresholds where rx takes precedence. The threshold values are just guesses at this point, it might be worth tuning them later. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 52 ++++++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index f68ccfbffff3..178249a96e1c 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -625,13 +625,16 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port) } -static void sky2_ramset(struct sky2_hw *hw, u16 q, u32 start, size_t len) +/* Assign Ram Buffer allocation. + * start and end are in units of 4k bytes + * ram registers are in units of 64bit words + */ +static void sky2_ramset(struct sky2_hw *hw, u16 q, u8 startk, u8 endk) { - u32 end; + u32 start, end; - start /= 8; - len /= 8; - end = start + len - 1; + start = startk * 4096/8; + end = (endk * 4096/8) - 1; sky2_write8(hw, RB_ADDR(q, RB_CTRL), RB_RST_CLR); sky2_write32(hw, RB_ADDR(q, RB_START), start); @@ -640,14 +643,19 @@ static void sky2_ramset(struct sky2_hw *hw, u16 q, u32 start, size_t len) sky2_write32(hw, RB_ADDR(q, RB_RP), start); if (q == Q_R1 || q == Q_R2) { - u32 rxup, rxlo; + u32 space = (endk - startk) * 4096/8; + u32 tp = space - space/4; - rxlo = len/2; - rxup = rxlo + len/4; + /* On receive queue's set the thresholds + * give receiver priority when > 3/4 full + * send pause when down to 2K + */ + sky2_write32(hw, RB_ADDR(q, RB_RX_UTHP), tp); + sky2_write32(hw, RB_ADDR(q, RB_RX_LTHP), space/2); - /* Set thresholds on receive queue's */ - sky2_write32(hw, RB_ADDR(q, RB_RX_UTPP), rxup); - sky2_write32(hw, RB_ADDR(q, RB_RX_LTPP), rxlo); + tp = space - 2048/8; + sky2_write32(hw, RB_ADDR(q, RB_RX_UTPP), tp); + sky2_write32(hw, RB_ADDR(q, RB_RX_LTPP), space/4); } else { /* Enable store & forward on Tx queue's because * Tx FIFO is only 1K on Yukon @@ -1002,19 +1010,19 @@ static int sky2_up(struct net_device *dev) sky2_mac_init(hw, port); - /* Configure RAM buffers */ - if (hw->chip_id == CHIP_ID_YUKON_FE || - (hw->chip_id == CHIP_ID_YUKON_EC && hw->chip_rev == 2)) - ramsize = 4096; - else { - u8 e0 = sky2_read8(hw, B2_E_0); - ramsize = (e0 == 0) ? (128 * 1024) : (e0 * 4096); - } + /* Determine available ram buffer space (in 4K blocks). + * Note: not sure about the FE setting below yet + */ + if (hw->chip_id == CHIP_ID_YUKON_FE) + ramsize = 4; + else + ramsize = sky2_read8(hw, B2_E_0); + + /* Give transmitter one third (rounded up) */ + rxspace = ramsize - (ramsize + 2) / 3; - /* 2/3 for Rx */ - rxspace = (2 * ramsize) / 3; sky2_ramset(hw, rxqaddr[port], 0, rxspace); - sky2_ramset(hw, txqaddr[port], rxspace, ramsize - rxspace); + sky2_ramset(hw, txqaddr[port], rxspace, ramsize); /* Make sure SyncQ is disabled */ sky2_write8(hw, RB_ADDR(port == 0 ? Q_XS1 : Q_XS2, RB_CTRL), From 762c2de2e61ef5f3c866d00861e6b1509cd8eacf Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 17 Jan 2006 13:43:14 -0800 Subject: [PATCH 67/76] [PATCH] sky2: write barrier's Be more careful about memory barriers. The only place we really need them is before and after updating the chip's ring interface. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 178249a96e1c..1407ff2da41e 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -707,6 +707,7 @@ static inline struct sky2_tx_le *get_tx_le(struct sky2_port *sky2) static inline void sky2_put_idx(struct sky2_hw *hw, unsigned q, u16 idx, u16 *last, u16 size) { + wmb(); if (is_ec_a1(hw) && idx < *last) { u16 hwget = sky2_read16(hw, Y2_QADDR(q, PREF_UNIT_GET_IDX)); @@ -730,6 +731,7 @@ setnew: sky2_write16(hw, Y2_QADDR(q, PREF_UNIT_PUT_IDX), idx); } *last = idx; + mmiowb(); } @@ -1253,7 +1255,6 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); out_unlock: - mmiowb(); spin_unlock(&sky2->tx_lock); dev->trans_start = jiffies; @@ -1896,7 +1897,6 @@ static int sky2_poll(struct net_device *dev0, int *budget) exit_loop: sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ); - mmiowb(); sky2_tx_check(hw, 0, tx_done[0]); sky2_tx_check(hw, 1, tx_done[1]); @@ -1911,7 +1911,6 @@ exit_loop: netif_rx_complete(dev0); hw->intr_mask |= Y2_IS_STAT_BMU; sky2_write32(hw, B0_IMSK, hw->intr_mask); - mmiowb(); return 0; } else { *budget -= work_done; From dc4d5ea2218b80eb8cd323082f09c506ba75fb6f Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 17 Jan 2006 13:43:15 -0800 Subject: [PATCH 68/76] [PATCH] sky2: don't bother clearing status ring elements Don't need to zero out the status ring entries after processing. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 1407ff2da41e..3c5d00403e5e 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1825,7 +1825,6 @@ static int sky2_poll(struct net_device *dev0, int *budget) struct sk_buff *skb; u32 status; u16 length; - u8 op; le = hw->st_le + hw->st_idx; hw->st_idx = (hw->st_idx + 1) % STATUS_RING_SIZE; @@ -1839,10 +1838,8 @@ static int sky2_poll(struct net_device *dev0, int *budget) sky2 = netdev_priv(dev); status = le32_to_cpu(le->status); length = le16_to_cpu(le->length); - op = le->opcode & ~HW_OWNER; - le->opcode = 0; - switch (op) { + switch (le->opcode & ~HW_OWNER) { case OP_RXSTAT: skb = sky2_receive(sky2, length, status); if (!skb) @@ -1890,7 +1887,7 @@ static int sky2_poll(struct net_device *dev0, int *budget) default: if (net_ratelimit()) printk(KERN_WARNING PFX - "unknown status opcode 0x%x\n", op); + "unknown status opcode 0x%x\n", le->opcode); break; } } From a036119f977eeeae2089ddf5b4759de9ca5fbdb6 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 17 Jan 2006 13:43:16 -0800 Subject: [PATCH 69/76] [PATCH] sky2: optimize for 32 bit dma Small optimization, if dma addresses are 32 bits, then high bits are always zero. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 3c5d00403e5e..92ea915c1d4b 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -745,7 +745,7 @@ static inline struct sky2_rx_le *sky2_next_rx(struct sky2_port *sky2) /* Return high part of DMA address (could be 32 or 64 bit) */ static inline u32 high32(dma_addr_t a) { - return (a >> 16) >> 16; + return sizeof(a) > sizeof(u32) ? (a >> 16) >> 16 : 0; } /* Build description to hardware about buffer */ @@ -1225,7 +1225,7 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) mapping = pci_map_page(hw->pdev, frag->page, frag->page_offset, frag->size, PCI_DMA_TODEVICE); - addr64 = (mapping >> 16) >> 16; + addr64 = high32(mapping); if (addr64 != sky2->tx_addr64) { le = get_tx_le(sky2); le->tx.addr = cpu_to_le32(addr64); From 3be92a70237a1bd813e46d6683a55b508627013a Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 17 Jan 2006 13:43:17 -0800 Subject: [PATCH 70/76] [PATCH] sky2: ratelimit error messages Make sure and rate limit all the error messages that might occur. If a problem occurs then a few messages are enough. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 44 +++++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 92ea915c1d4b..9308b3bbb5cb 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -92,7 +92,7 @@ static const u32 default_msg = NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | NETIF_MSG_TIMER | NETIF_MSG_TX_ERR | NETIF_MSG_RX_ERR - | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN | NETIF_MSG_INTR; + | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN; static int debug = -1; /* defaults above */ module_param(debug, int, 0); @@ -1125,8 +1125,9 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) */ if (!netif_queue_stopped(dev)) { netif_stop_queue(dev); - printk(KERN_WARNING PFX "%s: ring full when queue awake!\n", - dev->name); + if (net_ratelimit()) + printk(KERN_WARNING PFX "%s: ring full when queue awake!\n", + dev->name); } spin_unlock(&sky2->tx_lock); @@ -1770,7 +1771,7 @@ oversize: error: ++sky2->net_stats.rx_errors; - if (netif_msg_rx_err(sky2)) + if (netif_msg_rx_err(sky2) && net_ratelimit()) printk(KERN_INFO PFX "%s: rx error, status 0x%x length %d\n", sky2->netdev->name, status, length); @@ -1920,35 +1921,42 @@ static void sky2_hw_error(struct sky2_hw *hw, unsigned port, u32 status) { struct net_device *dev = hw->dev[port]; - printk(KERN_INFO PFX "%s: hw error interrupt status 0x%x\n", - dev->name, status); + if (net_ratelimit()) + printk(KERN_INFO PFX "%s: hw error interrupt status 0x%x\n", + dev->name, status); if (status & Y2_IS_PAR_RD1) { - printk(KERN_ERR PFX "%s: ram data read parity error\n", - dev->name); + if (net_ratelimit()) + printk(KERN_ERR PFX "%s: ram data read parity error\n", + dev->name); /* Clear IRQ */ sky2_write16(hw, RAM_BUFFER(port, B3_RI_CTRL), RI_CLR_RD_PERR); } if (status & Y2_IS_PAR_WR1) { - printk(KERN_ERR PFX "%s: ram data write parity error\n", - dev->name); + if (net_ratelimit()) + printk(KERN_ERR PFX "%s: ram data write parity error\n", + dev->name); sky2_write16(hw, RAM_BUFFER(port, B3_RI_CTRL), RI_CLR_WR_PERR); } if (status & Y2_IS_PAR_MAC1) { - printk(KERN_ERR PFX "%s: MAC parity error\n", dev->name); + if (net_ratelimit()) + printk(KERN_ERR PFX "%s: MAC parity error\n", dev->name); sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_CLI_TX_PE); } if (status & Y2_IS_PAR_RX1) { - printk(KERN_ERR PFX "%s: RX parity error\n", dev->name); + if (net_ratelimit()) + printk(KERN_ERR PFX "%s: RX parity error\n", dev->name); sky2_write32(hw, Q_ADDR(rxqaddr[port], Q_CSR), BMU_CLR_IRQ_PAR); } if (status & Y2_IS_TCP_TXA1) { - printk(KERN_ERR PFX "%s: TCP segmentation error\n", dev->name); + if (net_ratelimit()) + printk(KERN_ERR PFX "%s: TCP segmentation error\n", + dev->name); sky2_write32(hw, Q_ADDR(txqaddr[port], Q_CSR), BMU_CLR_IRQ_TCP); } } @@ -1964,8 +1972,9 @@ static void sky2_hw_intr(struct sky2_hw *hw) u16 pci_err; pci_read_config_word(hw->pdev, PCI_STATUS, &pci_err); - printk(KERN_ERR PFX "%s: pci hw error (0x%x)\n", - pci_name(hw->pdev), pci_err); + if (net_ratelimit()) + printk(KERN_ERR PFX "%s: pci hw error (0x%x)\n", + pci_name(hw->pdev), pci_err); sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); pci_write_config_word(hw->pdev, PCI_STATUS, @@ -1979,8 +1988,9 @@ static void sky2_hw_intr(struct sky2_hw *hw) pci_read_config_dword(hw->pdev, PEX_UNC_ERR_STAT, &pex_err); - printk(KERN_ERR PFX "%s: pci express error (0x%x)\n", - pci_name(hw->pdev), pex_err); + if (net_ratelimit()) + printk(KERN_ERR PFX "%s: pci express error (0x%x)\n", + pci_name(hw->pdev), pex_err); /* clear the interrupt */ sky2_write32(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); From 6aad85d6730d47d4867f24eeda517766aa89f8d0 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 17 Jan 2006 13:43:18 -0800 Subject: [PATCH 71/76] [PATCH] sky2: use kzalloc Can use kzalloc here. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 9308b3bbb5cb..9dc4adb95a7c 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -3099,14 +3099,13 @@ static int __devinit sky2_probe(struct pci_dev *pdev, #endif err = -ENOMEM; - hw = kmalloc(sizeof(*hw), GFP_KERNEL); + hw = kzalloc(sizeof(*hw), GFP_KERNEL); if (!hw) { printk(KERN_ERR PFX "%s: cannot allocate hardware struct\n", pci_name(pdev)); goto err_out_free_regions; } - memset(hw, 0, sizeof(*hw)); hw->pdev = pdev; hw->regs = ioremap_nocache(pci_resource_start(pdev, 0), 0x4000); From 28bd181a8e4abf1126de56f0934ba7c910276475 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 17 Jan 2006 13:43:19 -0800 Subject: [PATCH 72/76] [PATCH] sky2: don't inline so much Don't need to inline quite so many routines, let the compiler decide Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 9dc4adb95a7c..f03bf79ca1f5 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -704,7 +704,7 @@ static inline struct sky2_tx_le *get_tx_le(struct sky2_port *sky2) * This is a workaround code taken from SysKonnect sk98lin driver * to deal with chip bug on Yukon EC rev 0 in the wraparound case. */ -static inline void sky2_put_idx(struct sky2_hw *hw, unsigned q, +static void sky2_put_idx(struct sky2_hw *hw, unsigned q, u16 idx, u16 *last, u16 size) { wmb(); @@ -749,7 +749,7 @@ static inline u32 high32(dma_addr_t a) } /* Build description to hardware about buffer */ -static inline void sky2_rx_add(struct sky2_port *sky2, dma_addr_t map) +static void sky2_rx_add(struct sky2_port *sky2, dma_addr_t map) { struct sky2_rx_le *le; u32 hi = high32(map); @@ -1080,7 +1080,7 @@ static inline int tx_avail(const struct sky2_port *sky2) } /* Estimate of number of transmit list elements required */ -static inline unsigned tx_le_req(const struct sk_buff *skb) +static unsigned tx_le_req(const struct sk_buff *skb) { unsigned count; @@ -1792,7 +1792,7 @@ error: */ #define TX_NO_STATUS 0xffff -static inline void sky2_tx_check(struct sky2_hw *hw, int port, u16 last) +static void sky2_tx_check(struct sky2_hw *hw, int port, u16 last) { if (last != TX_NO_STATUS) { struct net_device *dev = hw->dev[port]; @@ -2280,7 +2280,7 @@ static int sky2_reset(struct sky2_hw *hw) return 0; } -static inline u32 sky2_supported_modes(const struct sky2_hw *hw) +static u32 sky2_supported_modes(const struct sky2_hw *hw) { u32 modes; if (hw->copper) { @@ -3025,7 +3025,7 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, return dev; } -static inline void sky2_show_addr(struct net_device *dev) +static void __devinit sky2_show_addr(struct net_device *dev) { const struct sky2_port *sky2 = netdev_priv(dev); From 302d12522a36790858ce93b69ebf2220f9e5173a Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 17 Jan 2006 13:43:20 -0800 Subject: [PATCH 73/76] [PATCH] sky2: more conservative transmit locking Be more careful about transmit locking, this solves a possible race between tx_complete and transmit, that would cause a tx timeout. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 43 +++++++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index f03bf79ca1f5..0c7665e465db 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -889,13 +889,13 @@ static void sky2_vlan_rx_register(struct net_device *dev, struct vlan_group *grp struct sky2_hw *hw = sky2->hw; u16 port = sky2->port; - spin_lock(&sky2->tx_lock); + spin_lock_bh(&sky2->tx_lock); sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), RX_VLAN_STRIP_ON); sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_VLAN_TAG_ON); sky2->vlgrp = grp; - spin_unlock(&sky2->tx_lock); + spin_unlock_bh(&sky2->tx_lock); } static void sky2_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) @@ -904,14 +904,14 @@ static void sky2_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) struct sky2_hw *hw = sky2->hw; u16 port = sky2->port; - spin_lock(&sky2->tx_lock); + spin_lock_bh(&sky2->tx_lock); sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), RX_VLAN_STRIP_OFF); sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_VLAN_TAG_OFF); if (sky2->vlgrp) sky2->vlgrp->vlan_devices[vid] = NULL; - spin_unlock(&sky2->tx_lock); + spin_unlock_bh(&sky2->tx_lock); } #endif @@ -1116,6 +1116,10 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) u16 mss; u8 ctrl; + /* No BH disabling for tx_lock here. We are running in BH disabled + * context and TX reclaim runs via poll inside of a software + * interrupt, and no related locks in IRQ processing. + */ if (!spin_trylock(&sky2->tx_lock)) return NETDEV_TX_LOCKED; @@ -1308,17 +1312,17 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done) dev_kfree_skb_any(skb); } - spin_lock(&sky2->tx_lock); sky2->tx_cons = put; if (netif_queue_stopped(dev) && tx_avail(sky2) > MAX_SKB_TX_LE) netif_wake_queue(dev); - spin_unlock(&sky2->tx_lock); } /* Cleanup all untransmitted buffers, assume transmitter not running */ static void sky2_tx_clean(struct sky2_port *sky2) { + spin_lock_bh(&sky2->tx_lock); sky2_tx_complete(sky2, sky2->tx_prod); + spin_unlock_bh(&sky2->tx_lock); } /* Network shutdown */ @@ -1608,28 +1612,40 @@ out: local_irq_enable(); } + +/* Transmit timeout is only called if we are running, carries is up + * and tx queue is full (stopped). + */ static void sky2_tx_timeout(struct net_device *dev) { struct sky2_port *sky2 = netdev_priv(dev); struct sky2_hw *hw = sky2->hw; unsigned txq = txqaddr[sky2->port]; + u16 ridx; + + /* Maybe we just missed an status interrupt */ + spin_lock(&sky2->tx_lock); + ridx = sky2_read16(hw, + sky2->port == 0 ? STAT_TXA1_RIDX : STAT_TXA2_RIDX); + sky2_tx_complete(sky2, ridx); + spin_unlock(&sky2->tx_lock); + + if (!netif_queue_stopped(dev)) { + if (net_ratelimit()) + pr_info(PFX "transmit interrupt missed? recovered\n"); + return; + } if (netif_msg_timer(sky2)) printk(KERN_ERR PFX "%s: tx timeout\n", dev->name); - netif_stop_queue(dev); - sky2_write32(hw, Q_ADDR(txq, Q_CSR), BMU_STOP); - sky2_read32(hw, Q_ADDR(txq, Q_CSR)); - sky2_write32(hw, Y2_QADDR(txq, PREF_UNIT_CTRL), PREF_UNIT_RST_SET); sky2_tx_clean(sky2); sky2_qset(hw, txq); sky2_prefetch_init(hw, txq, sky2->tx_le_map, TX_RING_SIZE - 1); - - netif_wake_queue(dev); } @@ -1798,7 +1814,10 @@ static void sky2_tx_check(struct sky2_hw *hw, int port, u16 last) struct net_device *dev = hw->dev[port]; if (dev && netif_running(dev)) { struct sky2_port *sky2 = netdev_priv(dev); + + spin_lock(&sky2->tx_lock); sky2_tx_complete(sky2, last); + spin_unlock(&sky2->tx_lock); } } } From 0570cc08194630bd78aef7c2c2b4f6a3f02c2bba Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 17 Jan 2006 13:43:21 -0800 Subject: [PATCH 74/76] [PATCH] sky2: 0.13 version Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 0c7665e465db..f8b973a04b65 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -57,7 +57,7 @@ #include "sky2.h" #define DRV_NAME "sky2" -#define DRV_VERSION "0.12" +#define DRV_VERSION "0.13" #define PFX DRV_NAME " " /* From 22d4d77183f0af8b3b643544a5ae64ec6105d88b Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 17 Jan 2006 17:53:56 +0000 Subject: [PATCH 75/76] [PATCH] Fix warning with b44.c on 64bit boxes sizeof() return is not an int, so use max_t to get the types right. Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/net/b44.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 7aa49b974dc5..df9d6e80c4f2 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -2136,7 +2136,7 @@ static int __init b44_init(void) /* Setup paramaters for syncing RX/TX DMA descriptors */ dma_desc_align_mask = ~(dma_desc_align_size - 1); - dma_desc_sync_size = max(dma_desc_align_size, sizeof(struct dma_desc)); + dma_desc_sync_size = max_t(unsigned int, dma_desc_align_size, sizeof(struct dma_desc)); return pci_module_init(&b44_driver); } From 77783a78ded96a56e3a1a0c03bbe87c56896fe6e Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 5 Jan 2006 16:26:05 -0800 Subject: [PATCH 76/76] [PATCH] skge: fix dma mask setup. There are a couple of problems in the DMA setup code for skge. * In the 64 bit case, it doesn't set the consistent mask. * In the 32 bit case, the error check is backwards! It likely will only be visible as a bug on 64 bit platforms. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/skge.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/drivers/net/skge.c b/drivers/net/skge.c index b538e3038058..bf55a4cfb3d2 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -3243,12 +3243,22 @@ static int __devinit skge_probe(struct pci_dev *pdev, pci_set_master(pdev); - if (!(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK))) + if (sizeof(dma_addr_t) > sizeof(u32) && + !(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK))) { using_dac = 1; - else if (!(err = pci_set_dma_mask(pdev, DMA_32BIT_MASK))) { - printk(KERN_ERR PFX "%s no usable DMA configuration\n", - pci_name(pdev)); - goto err_out_free_regions; + err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); + if (err < 0) { + printk(KERN_ERR PFX "%s unable to obtain 64 bit DMA " + "for consistent allocations\n", pci_name(pdev)); + goto err_out_free_regions; + } + } else { + err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (err) { + printk(KERN_ERR PFX "%s no usable DMA configuration\n", + pci_name(pdev)); + goto err_out_free_regions; + } } #ifdef __BIG_ENDIAN