From bceb0f126f25184eaec3f3c8f00c92b0d899e5de Mon Sep 17 00:00:00 2001 From: Tilman Schmidt Date: Wed, 1 Jul 2009 11:20:57 +0000 Subject: gigaset: accept connection establishment messages in any order ISDN connection setup failed if the "connection active" and "B channel up" messages from the device arrived in a different order than expected. Modify the state machine to accept them in any order. Impact: bugfix Signed-off-by: Tilman Schmidt CC: stable Signed-off-by: David S. Miller --- drivers/isdn/gigaset/ev-layer.c | 44 +++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c index ec5169604a6..2d91049571a 100644 --- a/drivers/isdn/gigaset/ev-layer.c +++ b/drivers/isdn/gigaset/ev-layer.c @@ -294,32 +294,33 @@ struct reply_t gigaset_tab_cid[] = {RSP_OK, 604,604, -1, 605, 5, {ACT_CMD+AT_MSN}}, {RSP_OK, 605,605, -1, 606, 5, {ACT_CMD+AT_ISO}}, {RSP_NULL, 605,605, -1, 606, 5, {ACT_CMD+AT_ISO}}, - {RSP_OK, 606,606, -1, 607, 5, {0}, "+VLS=17\r"}, /* set "Endgeraetemodus" */ + {RSP_OK, 606,606, -1, 607, 5, {0}, "+VLS=17\r"}, {RSP_OK, 607,607, -1, 608,-1}, - //{RSP_ZSAU, 608,608,ZSAU_PROCEEDING, 608, 0, {ACT_ERROR}},//DELETE {RSP_ZSAU, 608,608,ZSAU_PROCEEDING, 609, 5, {ACT_CMD+AT_DIAL}}, {RSP_OK, 609,609, -1, 650, 0, {ACT_DIALING}}, - {RSP_ZVLS, 608,608, 17, -1,-1, {ACT_DEBUG}}, - {RSP_ZCTP, 609,609, -1, -1,-1, {ACT_DEBUG}}, - {RSP_ZCPN, 609,609, -1, -1,-1, {ACT_DEBUG}}, {RSP_ERROR, 601,609, -1, 0, 0, {ACT_ABORTDIAL}}, {EV_TIMEOUT, 601,609, -1, 0, 0, {ACT_ABORTDIAL}}, - /* dialing */ - {RSP_ZCTP, 650,650, -1, -1,-1, {ACT_DEBUG}}, - {RSP_ZCPN, 650,650, -1, -1,-1, {ACT_DEBUG}}, - {RSP_ZSAU, 650,650,ZSAU_CALL_DELIVERED, -1,-1, {ACT_DEBUG}}, /* some devices don't send this */ - - /* connection established */ - {RSP_ZSAU, 650,650,ZSAU_ACTIVE, 800,-1, {ACT_CONNECT}}, //FIXME -> DLE1 - {RSP_ZSAU, 750,750,ZSAU_ACTIVE, 800,-1, {ACT_CONNECT}}, //FIXME -> DLE1 - - {EV_BC_OPEN, 800,800, -1, 800,-1, {ACT_NOTIFY_BC_UP}}, //FIXME new constate + timeout + /* optional dialing responses */ + {EV_BC_OPEN, 650,650, -1, 651,-1}, + {RSP_ZVLS, 608,651, 17, -1,-1, {ACT_DEBUG}}, + {RSP_ZCTP, 609,651, -1, -1,-1, {ACT_DEBUG}}, + {RSP_ZCPN, 609,651, -1, -1,-1, {ACT_DEBUG}}, + {RSP_ZSAU, 650,651,ZSAU_CALL_DELIVERED, -1,-1, {ACT_DEBUG}}, + + /* connect */ + {RSP_ZSAU, 650,650,ZSAU_ACTIVE, 800,-1, {ACT_CONNECT}}, + {RSP_ZSAU, 651,651,ZSAU_ACTIVE, 800,-1, {ACT_CONNECT, + ACT_NOTIFY_BC_UP}}, + {RSP_ZSAU, 750,750,ZSAU_ACTIVE, 800,-1, {ACT_CONNECT}}, + {RSP_ZSAU, 751,751,ZSAU_ACTIVE, 800,-1, {ACT_CONNECT, + ACT_NOTIFY_BC_UP}}, + {EV_BC_OPEN, 800,800, -1, 800,-1, {ACT_NOTIFY_BC_UP}}, /* remote hangup */ - {RSP_ZSAU, 650,650,ZSAU_DISCONNECT_IND, 0, 0, {ACT_REMOTEREJECT}}, - {RSP_ZSAU, 750,750,ZSAU_DISCONNECT_IND, 0, 0, {ACT_REMOTEHUP}}, + {RSP_ZSAU, 650,651,ZSAU_DISCONNECT_IND, 0, 0, {ACT_REMOTEREJECT}}, + {RSP_ZSAU, 750,751,ZSAU_DISCONNECT_IND, 0, 0, {ACT_REMOTEHUP}}, {RSP_ZSAU, 800,800,ZSAU_DISCONNECT_IND, 0, 0, {ACT_REMOTEHUP}}, /* hangup */ @@ -358,7 +359,8 @@ struct reply_t gigaset_tab_cid[] = {RSP_ZSAU, 700,729,ZSAU_ACTIVE, 0, 0, {ACT_ABORTACCEPT}}, {RSP_ZSAU, 700,729,ZSAU_DISCONNECT_IND, 0, 0, {ACT_ABORTACCEPT}}, - {EV_TIMEOUT, 750,750, -1, 0, 0, {ACT_CONNTIMEOUT}}, + {EV_BC_OPEN, 750,750, -1, 751,-1}, + {EV_TIMEOUT, 750,751, -1, 0, 0, {ACT_CONNTIMEOUT}}, /* B channel closed (general case) */ {EV_BC_CLOSED, -1, -1, -1, -1,-1, {ACT_NOTIFY_BC_DOWN}}, //FIXME @@ -876,12 +878,6 @@ static void bchannel_down(struct bc_state *bcs) static void bchannel_up(struct bc_state *bcs) { - if (!(bcs->chstate & CHS_D_UP)) { - dev_notice(bcs->cs->dev, "%s: D channel not up\n", __func__); - bcs->chstate |= CHS_D_UP; - gigaset_i4l_channel_cmd(bcs, ISDN_STAT_DCONN); - } - if (bcs->chstate & CHS_B_UP) { dev_notice(bcs->cs->dev, "%s: B channel already up\n", __func__); -- cgit v1.2.3 From c56bd0c39ce31e694b6f32223c15bdd582263a3f Mon Sep 17 00:00:00 2001 From: Tilman Schmidt Date: Wed, 1 Jul 2009 11:20:57 +0000 Subject: gigaset: drop pointless check Drop a sanity check which doesn't serve any useful purpose anymore. Signed-off-by: Tilman Schmidt Signed-off-by: David S. Miller --- drivers/isdn/gigaset/isocdata.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/isdn/gigaset/isocdata.c b/drivers/isdn/gigaset/isocdata.c index db3a1e4cd48..bed38fcc432 100644 --- a/drivers/isdn/gigaset/isocdata.c +++ b/drivers/isdn/gigaset/isocdata.c @@ -174,12 +174,6 @@ int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size) pr_err("invalid size %d\n", size); return -EINVAL; } - src = iwb->read; - if (unlikely(limit >= BAS_OUTBUFSIZE + BAS_OUTBUFPAD || - (read < src && limit >= src))) { - pr_err("isoc write buffer frame reservation violated\n"); - return -EFAULT; - } #endif if (read < write) { -- cgit v1.2.3 From 98e31bb00983a5b6d638a31e4ff77e5ca1ccf93e Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Wed, 1 Jul 2009 11:41:42 +0000 Subject: netxen: fix the version code macro Correct firmware encoding is 8 bit major, 8 bit minor and 16 bit subversion. Flash has sizes rightly set, but original driver submission messed it leaving 16 bit major and 8 bit subversion. Also fix a infinite loop when cut-thru file firmware is invalid. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic.h | 13 ++++++++++++- drivers/net/netxen/netxen_nic_init.c | 25 ++++++++++++++----------- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 970cedeb5f3..26afcb5658d 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -60,7 +60,18 @@ #define _NETXEN_NIC_LINUX_SUBVERSION 30 #define NETXEN_NIC_LINUX_VERSIONID "4.0.30" -#define NETXEN_VERSION_CODE(a, b, c) (((a) << 16) + ((b) << 8) + (c)) +#define NETXEN_VERSION_CODE(a, b, c) (((a) << 24) + ((b) << 16) + (c)) +#define _major(v) (((v) >> 24) & 0xff) +#define _minor(v) (((v) >> 16) & 0xff) +#define _build(v) ((v) & 0xffff) + +/* version in image has weird encoding: + * 7:0 - major + * 15:8 - minor + * 31:16 - build (little endian) + */ +#define NETXEN_DECODE_VERSION(v) \ + NETXEN_VERSION_CODE(((v) & 0xff), (((v) >> 8) & 0xff), ((v) >> 16)) #define NETXEN_NUM_FLASH_SECTORS (64) #define NETXEN_FLASH_SECTOR_SIZE (64 * 1024) diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 055bb61d6e7..7bdcbc67342 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -756,7 +756,7 @@ static int netxen_validate_firmware(struct netxen_adapter *adapter, const char *fwname) { __le32 val; - u32 major, minor, build, ver, min_ver, bios; + u32 ver, min_ver, bios; struct pci_dev *pdev = adapter->pdev; const struct firmware *fw = adapter->fw; @@ -768,21 +768,18 @@ netxen_validate_firmware(struct netxen_adapter *adapter, const char *fwname) return -EINVAL; val = cpu_to_le32(*(u32 *)&fw->data[NX_FW_VERSION_OFFSET]); - major = (__force u32)val & 0xff; - minor = ((__force u32)val >> 8) & 0xff; - build = (__force u32)val >> 16; if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) min_ver = NETXEN_VERSION_CODE(4, 0, 216); else min_ver = NETXEN_VERSION_CODE(3, 4, 216); - ver = NETXEN_VERSION_CODE(major, minor, build); + ver = NETXEN_DECODE_VERSION(val); - if ((major > _NETXEN_NIC_LINUX_MAJOR) || (ver < min_ver)) { + if ((_major(ver) > _NETXEN_NIC_LINUX_MAJOR) || (ver < min_ver)) { dev_err(&pdev->dev, "%s: firmware version %d.%d.%d unsupported\n", - fwname, major, minor, build); + fwname, _major(ver), _minor(ver), _build(ver)); return -EINVAL; } @@ -798,11 +795,12 @@ netxen_validate_firmware(struct netxen_adapter *adapter, const char *fwname) if (netxen_rom_fast_read(adapter, NX_FW_VERSION_OFFSET, (int *)&val)) return -EIO; - major = (__force u32)val & 0xff; - minor = ((__force u32)val >> 8) & 0xff; - build = (__force u32)val >> 16; - if (NETXEN_VERSION_CODE(major, minor, build) > ver) + val = NETXEN_DECODE_VERSION(val); + if (val > ver) { + dev_info(&pdev->dev, "%s: firmware is older than flash\n", + fwname); return -EINVAL; + } NXWR32(adapter, NETXEN_CAM_RAM(0x1fc), NETXEN_BDINFO_MAGIC); return 0; @@ -830,6 +828,8 @@ request_mn: netxen_rom_fast_read(adapter, NX_FW_VERSION_OFFSET, (int *)&flashed_ver); + flashed_ver = NETXEN_DECODE_VERSION(flashed_ver); + if (flashed_ver >= NETXEN_VERSION_CODE(4, 0, 220)) { capability = NXRD32(adapter, NX_PEG_TUNE_CAPABILITY); if (capability & NX_PEG_TUNE_MN_PRESENT) { @@ -838,6 +838,9 @@ request_mn: } } + adapter->fw = NULL; + goto done; + request_fw: rc = request_firmware(&adapter->fw, fw_name[fw_type], &pdev->dev); if (rc != 0) { -- cgit v1.2.3 From 67c38fc61af930fa03b042932b6b14fbf8126222 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Wed, 1 Jul 2009 11:41:43 +0000 Subject: netxen: avoid frequent firmware reset Restrict firmware reset to following cases - o chip rev is NX2031 (firmare doesn't support heartbit). o firmware is dead. o previous attempt to init firmware had failed. o we have got newer file firmware. This speeds up module load tremendously (by upto 8 sec), also avoids downtime for NCSI (management) pass-thru traffic. Signed-off-by: Dhananjay Phadke Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic.h | 4 +- drivers/net/netxen/netxen_nic_hdr.h | 1 + drivers/net/netxen/netxen_nic_init.c | 86 ++++++++++++++++++++++++++++++++---- drivers/net/netxen/netxen_nic_main.c | 4 ++ 4 files changed, 86 insertions(+), 9 deletions(-) diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 26afcb5658d..e1cdba752e0 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -625,6 +625,7 @@ struct netxen_new_user_info { #define NX_P2_MN_ROMIMAGE 0 #define NX_P3_CT_ROMIMAGE 1 #define NX_P3_MN_ROMIMAGE 2 +#define NX_FLASH_ROMIMAGE 3 #define NETXEN_USER_START_OLD NETXEN_PXE_START /* for backward compatibility */ @@ -1254,7 +1255,7 @@ struct netxen_adapter { u32 resv3; u8 has_link_events; - u8 resv1; + u8 fw_type; u16 tx_context_id; u16 mtu; u16 is_up; @@ -1398,6 +1399,7 @@ void netxen_free_adapter_offload(struct netxen_adapter *adapter); int netxen_initialize_adapter_offload(struct netxen_adapter *adapter); int netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val); int netxen_load_firmware(struct netxen_adapter *adapter); +int netxen_need_fw_reset(struct netxen_adapter *adapter); void netxen_request_firmware(struct netxen_adapter *adapter); void netxen_release_firmware(struct netxen_adapter *adapter); int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose); diff --git a/drivers/net/netxen/netxen_nic_hdr.h b/drivers/net/netxen/netxen_nic_hdr.h index 3cc047844af..82410367564 100644 --- a/drivers/net/netxen/netxen_nic_hdr.h +++ b/drivers/net/netxen/netxen_nic_hdr.h @@ -853,6 +853,7 @@ enum { #define NX_PEG_TUNE_CAPABILITY (NETXEN_CAM_RAM(0x02c)) #define NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL (0x14) +#define NETXEN_PEG_ALIVE_COUNTER (NETXEN_CAM_RAM(0xb0)) #define ISR_MSI_INT_TRIGGER(FUNC) (NETXEN_PCIX_PS_REG(PCIX_MSI_F(FUNC))) #define ISR_LEGACY_INT_TRIGGERED(VAL) (((VAL) & 0x300) == 0x200) diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 7bdcbc67342..b899bd51fcd 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -683,12 +683,85 @@ int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose) return 0; } +int +netxen_need_fw_reset(struct netxen_adapter *adapter) +{ + u32 count, old_count; + u32 val, version, major, minor, build; + int i, timeout; + u8 fw_type; + + /* NX2031 firmware doesn't support heartbit */ + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) + return 1; + + /* last attempt had failed */ + if (NXRD32(adapter, CRB_CMDPEG_STATE) == PHAN_INITIALIZE_FAILED) + return 1; + + old_count = count = NXRD32(adapter, NETXEN_PEG_ALIVE_COUNTER); + + for (i = 0; i < 10; i++) { + + timeout = msleep_interruptible(200); + if (timeout) { + NXWR32(adapter, CRB_CMDPEG_STATE, + PHAN_INITIALIZE_FAILED); + return -EINTR; + } + + count = NXRD32(adapter, NETXEN_PEG_ALIVE_COUNTER); + if (count != old_count) + break; + } + + /* firmware is dead */ + if (count == old_count) + return 1; + + /* check if we have got newer or different file firmware */ + if (adapter->fw) { + + const struct firmware *fw = adapter->fw; + + val = cpu_to_le32(*(u32 *)&fw->data[NX_FW_VERSION_OFFSET]); + version = NETXEN_DECODE_VERSION(val); + + major = NXRD32(adapter, NETXEN_FW_VERSION_MAJOR); + minor = NXRD32(adapter, NETXEN_FW_VERSION_MINOR); + build = NXRD32(adapter, NETXEN_FW_VERSION_SUB); + + if (version > NETXEN_VERSION_CODE(major, minor, build)) + return 1; + + if (version == NETXEN_VERSION_CODE(major, minor, build)) { + + val = NXRD32(adapter, NETXEN_MIU_MN_CONTROL); + fw_type = (val & 0x4) ? + NX_P3_CT_ROMIMAGE : NX_P3_MN_ROMIMAGE; + + if (adapter->fw_type != fw_type) + return 1; + } + } + + return 0; +} + +static char *fw_name[] = { + "nxromimg.bin", "nx3fwct.bin", "nx3fwmn.bin", "flash", +}; + int netxen_load_firmware(struct netxen_adapter *adapter) { u64 *ptr64; u32 i, flashaddr, size; const struct firmware *fw = adapter->fw; + struct pci_dev *pdev = adapter->pdev; + + dev_info(&pdev->dev, "loading firmware from %s\n", + fw_name[adapter->fw_type]); if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) NXWR32(adapter, NETXEN_ROMUSB_GLB_CAS_RST, 1); @@ -806,12 +879,10 @@ netxen_validate_firmware(struct netxen_adapter *adapter, const char *fwname) return 0; } -static char *fw_name[] = { "nxromimg.bin", "nx3fwct.bin", "nx3fwmn.bin" }; - void netxen_request_firmware(struct netxen_adapter *adapter) { u32 capability, flashed_ver; - int fw_type; + u8 fw_type; struct pci_dev *pdev = adapter->pdev; int rc = 0; @@ -838,6 +909,7 @@ request_mn: } } + fw_type = NX_FLASH_ROMIMAGE; adapter->fw = NULL; goto done; @@ -849,6 +921,7 @@ request_fw: goto request_mn; } + fw_type = NX_FLASH_ROMIMAGE; adapter->fw = NULL; goto done; } @@ -862,16 +935,13 @@ request_fw: goto request_mn; } + fw_type = NX_FLASH_ROMIMAGE; adapter->fw = NULL; goto done; } done: - if (adapter->fw) - dev_info(&pdev->dev, "loading firmware from file %s\n", - fw_name[fw_type]); - else - dev_info(&pdev->dev, "loading firmware from flash\n"); + adapter->fw_type = fw_type; } diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 2919a2d12bf..27539ddf94c 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -718,6 +718,10 @@ netxen_start_firmware(struct netxen_adapter *adapter, int request_fw) if (request_fw) netxen_request_firmware(adapter); + err = netxen_need_fw_reset(adapter); + if (err <= 0) + return err; + if (first_boot != 0x55555555) { NXWR32(adapter, CRB_CMDPEG_STATE, 0); netxen_pinit_from_rom(adapter, 0); -- cgit v1.2.3 From 42caa074042e22f873c408a0d13be657b16192f1 Mon Sep 17 00:00:00 2001 From: Wade Farnsworth Date: Wed, 1 Jul 2009 13:00:34 +0000 Subject: phylib: fixes for PHY_RESUMING state changes The PHY_HALTED state disables phydev->link, but the link will not be updated upon entering PHY_RESUMING. Add a call to phy_read_status() to update the link before entering PHY_RUNNING. If the link is not up at this point, enter the PHY_NOLINK state instead. Also, when transitioning from PHY_RESUMING to PHY_RUNNING, calls to netif_carrier_on() and phydev->adjust_link() are missing. Add the calls similar to the other transitions to PHY_RUNNING. Signed-off-by: Wade Farnsworth Acked-by: Andy Fleming Signed-off-by: David S. Miller --- drivers/net/phy/phy.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 61755cbd978..eda94fcd406 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -928,13 +928,32 @@ static void phy_state_machine(struct work_struct *work) * Otherwise, it's 0, and we're * still waiting for AN */ if (err > 0) { - phydev->state = PHY_RUNNING; + err = phy_read_status(phydev); + if (err) + break; + + if (phydev->link) { + phydev->state = PHY_RUNNING; + netif_carrier_on(phydev->attached_dev); + } else + phydev->state = PHY_NOLINK; + phydev->adjust_link(phydev->attached_dev); } else { phydev->state = PHY_AN; phydev->link_timeout = PHY_AN_TIMEOUT; } - } else - phydev->state = PHY_RUNNING; + } else { + err = phy_read_status(phydev); + if (err) + break; + + if (phydev->link) { + phydev->state = PHY_RUNNING; + netif_carrier_on(phydev->attached_dev); + } else + phydev->state = PHY_NOLINK; + phydev->adjust_link(phydev->attached_dev); + } break; } -- cgit v1.2.3 From 887b5ea3683ce04966e35fa2e5fe215bedcde73c Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Wed, 1 Jul 2009 13:38:26 +0000 Subject: if_ether: add define for 1588 aka Timesync This patch adds ETH_P_1588 protocol ID define. Signed-off-by: Alexander Duyck Signed-off-by: David S. Miller --- include/linux/if_ether.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h index ae3a1871413..70fdba2bbf7 100644 --- a/include/linux/if_ether.h +++ b/include/linux/if_ether.h @@ -78,6 +78,7 @@ #define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */ #define ETH_P_AOE 0x88A2 /* ATA over Ethernet */ #define ETH_P_TIPC 0x88CA /* TIPC */ +#define ETH_P_1588 0x88F7 /* IEEE 1588 Timesync */ #define ETH_P_FCOE 0x8906 /* Fibre Channel over Ethernet */ #define ETH_P_FIP 0x8914 /* FCoE Initialization Protocol */ #define ETH_P_EDSA 0xDADA /* Ethertype DSA [ NOT AN OFFICIALLY REGISTERED ID ] */ -- cgit v1.2.3 From 15da4b1612d608a47e095439b3dd1d77ffe20e0c Mon Sep 17 00:00:00 2001 From: Abhishek Kulkarni Date: Wed, 1 Jul 2009 08:50:54 +0000 Subject: net/9p: Fix crash due to bad mount parameters. It is not safe to use match_int without checking the token type returned by match_token (especially when the token type returned is Opt_err and args is empty). Fix it. Signed-off-by: Abhishek Kulkarni Signed-off-by: David S. Miller --- net/9p/trans_fd.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c index a2a1814c7a8..8c2588e4edc 100644 --- a/net/9p/trans_fd.c +++ b/net/9p/trans_fd.c @@ -735,12 +735,14 @@ static int parse_opts(char *params, struct p9_fd_opts *opts) if (!*p) continue; token = match_token(p, tokens, args); - r = match_int(&args[0], &option); - if (r < 0) { - P9_DPRINTK(P9_DEBUG_ERROR, - "integer field, but no integer?\n"); - ret = r; - continue; + if (token != Opt_err) { + r = match_int(&args[0], &option); + if (r < 0) { + P9_DPRINTK(P9_DEBUG_ERROR, + "integer field, but no integer?\n"); + ret = r; + continue; + } } switch (token) { case Opt_port: -- cgit v1.2.3 From c615c9f3f3cea60279b1bb38e8ef27bd575ecd0c Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Thu, 2 Jul 2009 16:57:23 +0000 Subject: xfrm4: fix the ports decode of sctp protocol The SCTP pushed the skb data above the sctp chunk header, so the check of pskb_may_pull(skb, xprth + 4 - skb->data) in _decode_session4() will never return 0 because xprth + 4 - skb->data < 0, the ports decode of sctp will always fail. Signed-off-by: Wei Yongjun Acked-by: Herbert Xu Signed-off-by: David S. Miller --- net/ipv4/xfrm4_policy.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index 60d918c96a4..0071ee6f441 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c @@ -136,7 +136,8 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse) case IPPROTO_TCP: case IPPROTO_SCTP: case IPPROTO_DCCP: - if (pskb_may_pull(skb, xprth + 4 - skb->data)) { + if (xprth + 4 < skb->data || + pskb_may_pull(skb, xprth + 4 - skb->data)) { __be16 *ports = (__be16 *)xprth; fl->fl_ip_sport = ports[!!reverse]; -- cgit v1.2.3 From 59cae0092e4da753b5a2adb32933e0d1b223bcc5 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Thu, 2 Jul 2009 16:59:49 +0000 Subject: xfrm6: fix the proto and ports decode of sctp protocol The SCTP pushed the skb above the sctp chunk header, so the check of pskb_may_pull(skb, nh + offset + 1 - skb->data) in _decode_session6() will never return 0 and the ports decode of sctp will always fail. (nh + offset + 1 - skb->data < 0) Signed-off-by: Wei Yongjun Acked-by: Herbert Xu Signed-off-by: David S. Miller --- net/ipv6/xfrm6_policy.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index b4b16a43f27..3a3c677bc0f 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c @@ -157,7 +157,8 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse) ipv6_addr_copy(&fl->fl6_dst, reverse ? &hdr->saddr : &hdr->daddr); ipv6_addr_copy(&fl->fl6_src, reverse ? &hdr->daddr : &hdr->saddr); - while (pskb_may_pull(skb, nh + offset + 1 - skb->data)) { + while (nh + offset + 1 < skb->data || + pskb_may_pull(skb, nh + offset + 1 - skb->data)) { nh = skb_network_header(skb); exthdr = (struct ipv6_opt_hdr *)(nh + offset); @@ -177,7 +178,8 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse) case IPPROTO_TCP: case IPPROTO_SCTP: case IPPROTO_DCCP: - if (!onlyproto && pskb_may_pull(skb, nh + offset + 4 - skb->data)) { + if (!onlyproto && (nh + offset + 4 < skb->data || + pskb_may_pull(skb, nh + offset + 4 - skb->data))) { __be16 *ports = (__be16 *)exthdr; fl->fl_ip_sport = ports[!!reverse]; -- cgit v1.2.3 From a1ed05263b74921742b454ef52c30b609ec6940f Mon Sep 17 00:00:00 2001 From: Brian Haley Date: Thu, 2 Jul 2009 07:10:52 +0000 Subject: IPv6: preferred lifetime of address not getting updated There's a bug in addrconf_prefix_rcv() where it won't update the preferred lifetime of an IPv6 address if the current valid lifetime of the address is less than 2 hours (the minimum value in the RA). For example, If I send a router advertisement with a prefix that has valid lifetime = preferred lifetime = 2 hours we'll build this address: 3: eth0: mtu 1500 qlen 1000 inet6 2001:1890:1109:a20:217:8ff:fe7d:4718/64 scope global dynamic valid_lft 7175sec preferred_lft 7175sec If I then send the same prefix with valid lifetime = preferred lifetime = 0 it will be ignored since the minimum valid lifetime is 2 hours: 3: eth0: mtu 1500 qlen 1000 inet6 2001:1890:1109:a20:217:8ff:fe7d:4718/64 scope global dynamic valid_lft 7161sec preferred_lft 7161sec But according to RFC 4862 we should always reset the preferred lifetime even if the valid lifetime is invalid, which would cause the address to immediately get deprecated. So with this patch we'd see this: 5: eth0: mtu 1500 qlen 1000 inet6 2001:1890:1109:a20:21f:29ff:fe5a:ef04/64 scope global deprecated dynamic valid_lft 7163sec preferred_lft 0sec The comment winds-up being 5x the size of the code to fix the problem. Update the preferred lifetime of IPv6 addresses derived from a prefix info option in a router advertisement even if the valid lifetime in the option is invalid, as specified in RFC 4862 Section 5.5.3e. Fixes an issue where an address will not immediately become deprecated. Reported by Jens Rosenboom. Signed-off-by: Brian Haley Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 3883b4036a7..43b3c9f89c1 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -1916,8 +1916,32 @@ ok: update_lft = 1; else if (stored_lft <= MIN_VALID_LIFETIME) { /* valid_lft <= stored_lft is always true */ - /* XXX: IPsec */ - update_lft = 0; + /* + * RFC 4862 Section 5.5.3e: + * "Note that the preferred lifetime of + * the corresponding address is always + * reset to the Preferred Lifetime in + * the received Prefix Information + * option, regardless of whether the + * valid lifetime is also reset or + * ignored." + * + * So if the preferred lifetime in + * this advertisement is different + * than what we have stored, but the + * valid lifetime is invalid, just + * reset prefered_lft. + * + * We must set the valid lifetime + * to the stored lifetime since we'll + * be updating the timestamp below, + * else we'll set it back to the + * minumum. + */ + if (prefered_lft != ifp->prefered_lft) { + valid_lft = stored_lft; + update_lft = 1; + } } else { valid_lft = MIN_VALID_LIFETIME; if (valid_lft < prefered_lft) @@ -3085,7 +3109,7 @@ restart: spin_unlock(&ifp->lock); continue; } else if (age >= ifp->prefered_lft) { - /* jiffies - ifp->tsamp > age >= ifp->prefered_lft */ + /* jiffies - ifp->tstamp > age >= ifp->prefered_lft */ int deprecate = 0; if (!(ifp->flags&IFA_F_DEPRECATED)) { -- cgit v1.2.3 From 4322c5bee85ed58042ec04235ec7086065ad5074 Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Thu, 2 Jul 2009 06:06:06 +0000 Subject: qlge: Expand coverage of hw lock for config register. The hardware semaphore covers the configuration register as well as the ICB registers. The ICB high and low regs contain the address of the initialization control block and the config register is used to signal the hardware that a block is ready to be downloaded. Currently we were only protecting the ICB regs. This changes expands to cover the config register as well. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge_main.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 90d1f76c0e8..7f372672ac4 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -214,6 +214,10 @@ int ql_write_cfg(struct ql_adapter *qdev, void *ptr, int size, u32 bit, return -ENOMEM; } + status = ql_sem_spinlock(qdev, SEM_ICB_MASK); + if (status) + return status; + status = ql_wait_cfg(qdev, bit); if (status) { QPRINTK(qdev, IFUP, ERR, @@ -221,12 +225,8 @@ int ql_write_cfg(struct ql_adapter *qdev, void *ptr, int size, u32 bit, goto exit; } - status = ql_sem_spinlock(qdev, SEM_ICB_MASK); - if (status) - goto exit; ql_write32(qdev, ICB_L, (u32) map); ql_write32(qdev, ICB_H, (u32) (map >> 32)); - ql_sem_unlock(qdev, SEM_ICB_MASK); /* does flush too */ mask = CFG_Q_MASK | (bit << 16); value = bit | (q_id << CFG_Q_SHIFT); @@ -237,6 +237,7 @@ int ql_write_cfg(struct ql_adapter *qdev, void *ptr, int size, u32 bit, */ status = ql_wait_cfg(qdev, bit); exit: + ql_sem_unlock(qdev, SEM_ICB_MASK); /* does flush too */ pci_unmap_single(qdev->pdev, map, size, direction); return status; } -- cgit v1.2.3 From a5f59dc926844bf95be2261c1bb0a24597b7a8c5 Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Thu, 2 Jul 2009 06:06:07 +0000 Subject: qlge: Clear frame to queue routing before reset. Not clearing the routing bits can cause frames to erroneously get routed to management processor. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge_main.c | 41 ++++++++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 7f372672ac4..1da831e9942 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -3040,25 +3040,40 @@ static int ql_start_rss(struct ql_adapter *qdev) return status; } -/* Initialize the frame-to-queue routing. */ -static int ql_route_initialize(struct ql_adapter *qdev) +static int ql_clear_routing_entries(struct ql_adapter *qdev) { - int status = 0; - int i; + int i, status = 0; status = ql_sem_spinlock(qdev, SEM_RT_IDX_MASK); if (status) return status; - /* Clear all the entries in the routing table. */ for (i = 0; i < 16; i++) { status = ql_set_routing_reg(qdev, i, 0, 0); if (status) { QPRINTK(qdev, IFUP, ERR, - "Failed to init routing register for CAM packets.\n"); - goto exit; + "Failed to init routing register for CAM " + "packets.\n"); + break; } } + ql_sem_unlock(qdev, SEM_RT_IDX_MASK); + return status; +} + +/* Initialize the frame-to-queue routing. */ +static int ql_route_initialize(struct ql_adapter *qdev) +{ + int status = 0; + + status = ql_sem_spinlock(qdev, SEM_RT_IDX_MASK); + if (status) + return status; + + /* Clear all the entries in the routing table. */ + status = ql_clear_routing_entries(qdev); + if (status) + goto exit; status = ql_set_routing_reg(qdev, RT_IDX_ALL_ERR_SLOT, RT_IDX_ERR, 1); if (status) { @@ -3211,9 +3226,17 @@ static int ql_adapter_reset(struct ql_adapter *qdev) { u32 value; int status = 0; - unsigned long end_jiffies = jiffies + - max((unsigned long)1, usecs_to_jiffies(30)); + unsigned long end_jiffies; + /* Clear all the entries in the routing table. */ + status = ql_clear_routing_entries(qdev); + if (status) { + QPRINTK(qdev, IFUP, ERR, "Failed to clear routing bits.\n"); + return status; + } + + end_jiffies = jiffies + + max((unsigned long)1, usecs_to_jiffies(30)); ql_write32(qdev, RST_FO, (RST_FO_FR << 16) | RST_FO_FR); do { -- cgit v1.2.3 From 8b007de19026e91991ae70ca0def31c42435e008 Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Thu, 2 Jul 2009 06:06:08 +0000 Subject: qlge: Fix carrier on condition. We were turning on the carrier without verifying the link was up. This adds link up to the link initialize check before turning carrier on. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge_main.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 1da831e9942..c226257dc43 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -3343,7 +3343,11 @@ static int ql_adapter_up(struct ql_adapter *qdev) } set_bit(QL_ADAPTER_UP, &qdev->flags); ql_alloc_rx_buffers(qdev); - if ((ql_read32(qdev, STS) & qdev->port_init)) + /* If the port is initialized and the + * link is up the turn on the carrier. + */ + if ((ql_read32(qdev, STS) & qdev->port_init) && + (ql_read32(qdev, STS) & qdev->port_link_up)) netif_carrier_on(qdev->ndev); ql_enable_interrupts(qdev); ql_enable_all_completion_interrupts(qdev); -- cgit v1.2.3 From 6e9e4795e688fd61fa83f7f4cad4992939fd4ca3 Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Thu, 2 Jul 2009 06:06:09 +0000 Subject: qlge: Fix redundant call to free resources. The caller will free acquired resouces if a failure occurs. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge_main.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index c226257dc43..1b75f6efd7f 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -3374,11 +3374,6 @@ static int ql_get_adapter_resources(struct ql_adapter *qdev) return -ENOMEM; } status = ql_request_irq(qdev); - if (status) - goto err_irq; - return status; -err_irq: - ql_free_mem_resources(qdev); return status; } -- cgit v1.2.3 From 13cfd5be53d01a9316907512f17f34d3858450e8 Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Thu, 2 Jul 2009 06:06:10 +0000 Subject: qlge: Fix tx byte counter. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 1b75f6efd7f..74ed84a288c 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -1629,7 +1629,7 @@ static void ql_process_mac_tx_intr(struct ql_adapter *qdev, tx_ring = &qdev->tx_ring[mac_rsp->txq_idx]; tx_ring_desc = &tx_ring->q[mac_rsp->tid]; ql_unmap_send(qdev, tx_ring_desc, tx_ring_desc->map_cnt); - qdev->stats.tx_bytes += tx_ring_desc->map_cnt; + qdev->stats.tx_bytes += (tx_ring_desc->skb)->len; qdev->stats.tx_packets++; dev_kfree_skb(tx_ring_desc->skb); tx_ring_desc->skb = NULL; -- cgit v1.2.3 From 7fab3bfe08a2c5c4221685499ec4fef83ad82f83 Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Thu, 2 Jul 2009 06:06:11 +0000 Subject: qlge: Fix MAC address bonding issue. This addes functionality to set/clear the MAC address in the hardware when the link goes up/down. The MAC address register is persistent across function resets. In bonding the same address can bounce from one port to the other. This can cause packets to be delivered to the wrong port. This patch clears the MAC address in the hardware when the link is down and sets it when the link comes up. It was found that pulling/pushing the cable from one port to another causes the same MAC address to be in both ports. The next patch in this series will use this functionality as well. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge_main.c | 50 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 7 deletions(-) diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 74ed84a288c..46dea2bd94d 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -413,6 +413,41 @@ exit: return status; } +/* Set or clear MAC address in hardware. We sometimes + * have to clear it to prevent wrong frame routing + * especially in a bonding environment. + */ +static int ql_set_mac_addr(struct ql_adapter *qdev, int set) +{ + int status; + char zero_mac_addr[ETH_ALEN]; + char *addr; + + if (set) { + addr = &qdev->ndev->dev_addr[0]; + QPRINTK(qdev, IFUP, DEBUG, + "Set Mac addr %02x:%02x:%02x:%02x:%02x:%02x\n", + addr[0], addr[1], addr[2], addr[3], + addr[4], addr[5]); + } else { + memset(zero_mac_addr, 0, ETH_ALEN); + addr = &zero_mac_addr[0]; + QPRINTK(qdev, IFUP, DEBUG, + "Clearing MAC address on %s\n", + qdev->ndev->name); + } + status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK); + if (status) + return status; + status = ql_set_mac_addr_reg(qdev, (u8 *) addr, + MAC_ADDR_TYPE_CAM_MAC, qdev->func * MAX_CQ); + ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK); + if (status) + QPRINTK(qdev, IFUP, ERR, "Failed to init mac " + "address.\n"); + return status; +} + /* Get a specific frame routing value from the CAM. * Used for debug and reg dump. */ @@ -3112,14 +3147,15 @@ exit: int ql_cam_route_initialize(struct ql_adapter *qdev) { - int status; + int status, set; - status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK); - if (status) - return status; - status = ql_set_mac_addr_reg(qdev, (u8 *) qdev->ndev->perm_addr, - MAC_ADDR_TYPE_CAM_MAC, qdev->func * MAX_CQ); - ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK); + /* If check if the link is up and use to + * determine if we are setting or clearing + * the MAC address in the CAM. + */ + set = ql_read32(qdev, STS); + set &= qdev->port_link_up; + status = ql_set_mac_addr(qdev, set); if (status) { QPRINTK(qdev, IFUP, ERR, "Failed to init mac address.\n"); return status; -- cgit v1.2.3 From 6a47330892e697ae27d2d56a3c4c7fec2015be93 Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Thu, 2 Jul 2009 06:06:12 +0000 Subject: qlge: Add/use function for link up/down. We need to set/clear the mac address register when the link goes up/down respectively. Without this both ports of a 2-port device can end up with the same mac address in a bonding scenario. The new ql_link_on() and ql_link_off() will also be used in handling certain firmware events. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge.h | 2 ++ drivers/net/qlge/qlge_main.c | 26 +++++++++++++++++++++----- drivers/net/qlge/qlge_mpi.c | 6 +++--- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h index 156e02e8905..6ed5317ab1c 100644 --- a/drivers/net/qlge/qlge.h +++ b/drivers/net/qlge/qlge.h @@ -1607,6 +1607,8 @@ int ql_mb_get_fw_state(struct ql_adapter *qdev); int ql_cam_route_initialize(struct ql_adapter *qdev); int ql_read_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 *data); int ql_mb_about_fw(struct ql_adapter *qdev); +void ql_link_on(struct ql_adapter *qdev); +void ql_link_off(struct ql_adapter *qdev); #if 1 #define QL_ALL_DUMP diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 46dea2bd94d..35ba95a9b5d 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -448,6 +448,22 @@ static int ql_set_mac_addr(struct ql_adapter *qdev, int set) return status; } +void ql_link_on(struct ql_adapter *qdev) +{ + QPRINTK(qdev, LINK, ERR, "%s: Link is up.\n", + qdev->ndev->name); + netif_carrier_on(qdev->ndev); + ql_set_mac_addr(qdev, 1); +} + +void ql_link_off(struct ql_adapter *qdev) +{ + QPRINTK(qdev, LINK, ERR, "%s: Link is down.\n", + qdev->ndev->name); + netif_carrier_off(qdev->ndev); + ql_set_mac_addr(qdev, 0); +} + /* Get a specific frame routing value from the CAM. * Used for debug and reg dump. */ @@ -1696,13 +1712,13 @@ static void ql_process_mac_tx_intr(struct ql_adapter *qdev, /* Fire up a handler to reset the MPI processor. */ void ql_queue_fw_error(struct ql_adapter *qdev) { - netif_carrier_off(qdev->ndev); + ql_link_off(qdev); queue_delayed_work(qdev->workqueue, &qdev->mpi_reset_work, 0); } void ql_queue_asic_error(struct ql_adapter *qdev) { - netif_carrier_off(qdev->ndev); + ql_link_off(qdev); ql_disable_interrupts(qdev); /* Clear adapter up bit to signal the recovery * process that it shouldn't kill the reset worker @@ -3312,7 +3328,7 @@ static int ql_adapter_down(struct ql_adapter *qdev) int i, status = 0; struct rx_ring *rx_ring; - netif_carrier_off(qdev->ndev); + ql_link_off(qdev); /* Don't kill the reset worker thread if we * are in the process of recovery. @@ -3384,7 +3400,7 @@ static int ql_adapter_up(struct ql_adapter *qdev) */ if ((ql_read32(qdev, STS) & qdev->port_init) && (ql_read32(qdev, STS) & qdev->port_link_up)) - netif_carrier_on(qdev->ndev); + ql_link_on(qdev); ql_enable_interrupts(qdev); ql_enable_all_completion_interrupts(qdev); netif_tx_start_all_queues(qdev->ndev); @@ -4035,7 +4051,7 @@ static int __devinit qlge_probe(struct pci_dev *pdev, pci_disable_device(pdev); return err; } - netif_carrier_off(ndev); + ql_link_off(qdev); ql_display_dev_info(ndev); cards_found++; return 0; diff --git a/drivers/net/qlge/qlge_mpi.c b/drivers/net/qlge/qlge_mpi.c index 71afbf8b9c5..6685bd97da9 100644 --- a/drivers/net/qlge/qlge_mpi.c +++ b/drivers/net/qlge/qlge_mpi.c @@ -238,7 +238,7 @@ static void ql_link_up(struct ql_adapter *qdev, struct mbox_params *mbcp) &qdev->mpi_port_cfg_work, 0); } - netif_carrier_on(qdev->ndev); + ql_link_on(qdev); } static void ql_link_down(struct ql_adapter *qdev, struct mbox_params *mbcp) @@ -251,7 +251,7 @@ static void ql_link_down(struct ql_adapter *qdev, struct mbox_params *mbcp) if (status) QPRINTK(qdev, DRV, ERR, "Link down AEN broken!\n"); - netif_carrier_off(qdev->ndev); + ql_link_off(qdev); } static int ql_sfp_in(struct ql_adapter *qdev, struct mbox_params *mbcp) @@ -849,7 +849,7 @@ void ql_mpi_idc_work(struct work_struct *work) case MB_CMD_PORT_RESET: case MB_CMD_SET_PORT_CFG: case MB_CMD_STOP_FW: - netif_carrier_off(qdev->ndev); + ql_link_off(qdev); /* Signal the resulting link up AEN * that the frame routing and mac addr * needs to be set. -- cgit v1.2.3 From e332471c035708441de89d4c59f7f7cdc2700c0d Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Thu, 2 Jul 2009 06:06:13 +0000 Subject: qlge: Fix sizeof usage. Some usage was only sizing a pointer rather than the data type. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge_ethtool.c | 4 ++-- drivers/net/qlge/qlge_main.c | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/net/qlge/qlge_ethtool.c b/drivers/net/qlge/qlge_ethtool.c index 37c99fe7977..eb6a9ee640e 100644 --- a/drivers/net/qlge/qlge_ethtool.c +++ b/drivers/net/qlge/qlge_ethtool.c @@ -59,7 +59,7 @@ static int ql_update_ring_coalescing(struct ql_adapter *qdev) cqicb->pkt_delay = cpu_to_le16(qdev->tx_max_coalesced_frames); cqicb->flags = FLAGS_LI; - status = ql_write_cfg(qdev, cqicb, sizeof(cqicb), + status = ql_write_cfg(qdev, cqicb, sizeof(*cqicb), CFG_LCQ, rx_ring->cq_id); if (status) { QPRINTK(qdev, IFUP, ERR, @@ -82,7 +82,7 @@ static int ql_update_ring_coalescing(struct ql_adapter *qdev) cqicb->pkt_delay = cpu_to_le16(qdev->rx_max_coalesced_frames); cqicb->flags = FLAGS_LI; - status = ql_write_cfg(qdev, cqicb, sizeof(cqicb), + status = ql_write_cfg(qdev, cqicb, sizeof(*cqicb), CFG_LCQ, rx_ring->cq_id); if (status) { QPRINTK(qdev, IFUP, ERR, diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 35ba95a9b5d..5768af17f16 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -2156,7 +2156,7 @@ static int qlge_send(struct sk_buff *skb, struct net_device *ndev) } tx_ring_desc = &tx_ring->q[tx_ring->prod_idx]; mac_iocb_ptr = tx_ring_desc->queue_entry; - memset((void *)mac_iocb_ptr, 0, sizeof(mac_iocb_ptr)); + memset((void *)mac_iocb_ptr, 0, sizeof(*mac_iocb_ptr)); mac_iocb_ptr->opcode = OPCODE_OB_MAC_IOCB; mac_iocb_ptr->tid = tx_ring_desc->index; @@ -2795,7 +2795,7 @@ static int ql_start_tx_ring(struct ql_adapter *qdev, struct tx_ring *tx_ring) ql_init_tx_ring(qdev, tx_ring); - err = ql_write_cfg(qdev, wqicb, sizeof(wqicb), CFG_LRQ, + err = ql_write_cfg(qdev, wqicb, sizeof(*wqicb), CFG_LRQ, (u16) tx_ring->wq_id); if (err) { QPRINTK(qdev, IFUP, ERR, "Failed to load tx_ring.\n"); @@ -3060,7 +3060,7 @@ static int ql_start_rss(struct ql_adapter *qdev) int i; u8 *hash_id = (u8 *) ricb->hash_cq_id; - memset((void *)ricb, 0, sizeof(ricb)); + memset((void *)ricb, 0, sizeof(*ricb)); ricb->base_cq = qdev->rss_ring_first_cq_id | RSS_L4K; ricb->flags = @@ -3082,7 +3082,7 @@ static int ql_start_rss(struct ql_adapter *qdev) QPRINTK(qdev, IFUP, DEBUG, "Initializing RSS.\n"); - status = ql_write_cfg(qdev, ricb, sizeof(ricb), CFG_LR, 0); + status = ql_write_cfg(qdev, ricb, sizeof(*ricb), CFG_LR, 0); if (status) { QPRINTK(qdev, IFUP, ERR, "Failed to load RICB.\n"); return status; @@ -3489,7 +3489,7 @@ static int ql_configure_rings(struct ql_adapter *qdev) for (i = 0; i < qdev->tx_ring_count; i++) { tx_ring = &qdev->tx_ring[i]; - memset((void *)tx_ring, 0, sizeof(tx_ring)); + memset((void *)tx_ring, 0, sizeof(*tx_ring)); tx_ring->qdev = qdev; tx_ring->wq_id = i; tx_ring->wq_len = qdev->tx_ring_size; @@ -3505,7 +3505,7 @@ static int ql_configure_rings(struct ql_adapter *qdev) for (i = 0; i < qdev->rx_ring_count; i++) { rx_ring = &qdev->rx_ring[i]; - memset((void *)rx_ring, 0, sizeof(rx_ring)); + memset((void *)rx_ring, 0, sizeof(*rx_ring)); rx_ring->qdev = qdev; rx_ring->cq_id = i; rx_ring->cpu = i % cpu_cnt; /* CPU to run handler on. */ @@ -3864,7 +3864,7 @@ static int __devinit ql_init_device(struct pci_dev *pdev, int pos, err = 0; u16 val16; - memset((void *)qdev, 0, sizeof(qdev)); + memset((void *)qdev, 0, sizeof(*qdev)); err = pci_enable_device(pdev); if (err) { dev_err(&pdev->dev, "PCI device enable failed.\n"); -- cgit v1.2.3 From 63d6e1d80a8c3118be2ca0f1f21ba883f282060c Mon Sep 17 00:00:00 2001 From: Don Skidmore Date: Thu, 2 Jul 2009 12:50:12 +0000 Subject: ixgbe: fix issues with failing to detect insert of unsupported module Several small fixes around negative test case of the insertion of a IXGBE_ERR_NOT_SUPPORTED module. - mdio45_probe call was always failing due to mdio.prtad not being set. The function set to mdio.mdio_read was still working as we just happen to always be at prtad == 0. This will allow us to set the phy_id and phy.type correctly now. - There was timing issue with i2c calls when initiated from a tasklet. A small delay was added to allow the electrical oscillation to calm down. - Logic change in ixgbe_sfp_task that allows NOT_SUPPORTED condition to be recognized. Signed-off-by: Don Skidmore Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_main.c | 8 ++++++-- drivers/net/ixgbe/ixgbe_phy.c | 3 +++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 5588ef493a3..aaf482c0d52 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -3724,7 +3724,7 @@ static void ixgbe_sfp_task(struct work_struct *work) if ((hw->phy.type == ixgbe_phy_nl) && (hw->phy.sfp_type == ixgbe_sfp_type_not_present)) { s32 ret = hw->phy.ops.identify_sfp(hw); - if (ret) + if (ret == IXGBE_ERR_SFP_NOT_PRESENT) goto reschedule; ret = hw->phy.ops.reset(hw); if (ret == IXGBE_ERR_SFP_NOT_SUPPORTED) { @@ -4534,13 +4534,17 @@ static void ixgbe_sfp_config_module_task(struct work_struct *work) u32 err; adapter->flags |= IXGBE_FLAG_IN_SFP_MOD_TASK; + + /* Time for electrical oscillations to settle down */ + msleep(100); err = hw->phy.ops.identify_sfp(hw); + if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { dev_err(&adapter->pdev->dev, "failed to initialize because " "an unsupported SFP+ module type was detected.\n" "Reload the driver after installing a supported " "module.\n"); - ixgbe_down(adapter); + unregister_netdev(adapter->netdev); return; } hw->mac.ops.setup_sfp(hw); diff --git a/drivers/net/ixgbe/ixgbe_phy.c b/drivers/net/ixgbe/ixgbe_phy.c index 453e966762f..9ecad17522c 100644 --- a/drivers/net/ixgbe/ixgbe_phy.c +++ b/drivers/net/ixgbe/ixgbe_phy.c @@ -60,6 +60,7 @@ s32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw) if (hw->phy.type == ixgbe_phy_unknown) { for (phy_addr = 0; phy_addr < IXGBE_MAX_PHY_ADDR; phy_addr++) { + hw->phy.mdio.prtad = phy_addr; if (mdio45_probe(&hw->phy.mdio, phy_addr) == 0) { ixgbe_get_phy_id(hw); hw->phy.type = @@ -68,6 +69,8 @@ s32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw) break; } } + /* clear value if nothing found */ + hw->phy.mdio.prtad = 0; } else { status = 0; } -- cgit v1.2.3 From 19343de279d28e4ed039c8ad00510d19dc4d6d12 Mon Sep 17 00:00:00 2001 From: Don Skidmore Date: Thu, 2 Jul 2009 12:50:31 +0000 Subject: ixgbe: fix regression on some 82598 adapters The change to check the SFP+ module again on open() was causing the XFP (non-SFP+) adapters to be rejected. We only want to try and re-identify the SFP+ module if the original probe found that this device was an SFP+ device. So for this code path (driver loaded with SFP module, module inserted, ifconfig up of the device) the type will be ixgbe_phy_unknown for an unidentified SFP+ module. So we only check if that is the case. This problem also shows up on Copper devices. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: Don Skidmore Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_main.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index aaf482c0d52..cf39f5a4703 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -2697,19 +2697,23 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter) /* * For hot-pluggable SFP+ devices, a new SFP+ module may have - * arrived before interrupts were enabled. We need to kick off - * the SFP+ module setup first, then try to bring up link. + * arrived before interrupts were enabled but after probe. Such + * devices wouldn't have their type identified yet. We need to + * kick off the SFP+ module setup first, then try to bring up link. * If we're not hot-pluggable SFP+, we just need to configure link * and bring it up. */ - err = hw->phy.ops.identify(hw); - if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { - dev_err(&adapter->pdev->dev, "failed to initialize because " - "an unsupported SFP+ module type was detected.\n" - "Reload the driver after installing a supported " - "module.\n"); - ixgbe_down(adapter); - return err; + if (hw->phy.type == ixgbe_phy_unknown) { + err = hw->phy.ops.identify(hw); + if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { + dev_err(&adapter->pdev->dev, "failed to initialize " + "because an unsupported SFP+ module type " + "was detected.\n" + "Reload the driver after installing a " + "supported module.\n"); + ixgbe_down(adapter); + return err; + } } if (ixgbe_is_sfp(hw)) { -- cgit v1.2.3 From 5da43c1a78cbc16518017dfb058da6ec4829781b Mon Sep 17 00:00:00 2001 From: Don Skidmore Date: Thu, 2 Jul 2009 12:50:52 +0000 Subject: ixgbe: fix inconsistent SFP/SFP+ failure results. Currently if we loaded the driver, insert an unsupported module, and then attempt to "ifconfig up" the device it will be brought down but the netdev would not be unregistered. This behavior is different than all other code paths. This patch corrects that by down'ing the device and then scheduling the sfp_config_module_task tasklet. The tasklet will detect this condition (like it does with other code paths) and do the unregister_netdev(). I also removed the log message as this condition (an unsupported SFP+ module) will be logged in sfp_config_module_task. Signed-off-by: Don Skidmore Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_main.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index cf39f5a4703..a3061aacffd 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -2706,12 +2706,12 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter) if (hw->phy.type == ixgbe_phy_unknown) { err = hw->phy.ops.identify(hw); if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { - dev_err(&adapter->pdev->dev, "failed to initialize " - "because an unsupported SFP+ module type " - "was detected.\n" - "Reload the driver after installing a " - "supported module.\n"); + /* + * Take the device down and schedule the sfp tasklet + * which will unregister_netdev and log it. + */ ixgbe_down(adapter); + schedule_work(&adapter->sfp_config_module_task); return err; } } -- cgit v1.2.3 From e5d57af52464f37dd3c67906a493a6400bc51b43 Mon Sep 17 00:00:00 2001 From: Mallikarjuna R Chilakala Date: Thu, 2 Jul 2009 12:51:10 +0000 Subject: ixgbe: Not allow 8259x unsupported wol options change from ethtool Wake-on-lan is currently only supported by 82599 KX4 devices, in all other cases return a proper value from ixgbe_wol_exclusion function call. Otherwise from ethtool we will be able to change wol options of unsupported 8259x devices. Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_ethtool.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 0f7b6a3a2e6..2a978008fd6 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -1830,7 +1830,6 @@ static int ixgbe_wol_exclusion(struct ixgbe_adapter *adapter, break; default: wol->supported = 0; - retval = 0; } return retval; -- cgit v1.2.3 From e65fa87c225fadd1980068b7d360e08ac0e985dd Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Wed, 1 Jul 2009 13:27:31 +0000 Subject: e1000e: PHY loopback broken on 82578 PHY loopback on 82578 fails to work as a result of flushing the packets in the FIFO buffer in the link stall workaround. Don't perform the workaround if in PHY loopback mode. Signed-off-by: Bruce Allan Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/e1000e/defines.h | 2 ++ drivers/net/e1000e/phy.c | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/drivers/net/e1000e/defines.h b/drivers/net/e1000e/defines.h index 8890c97e112..4329ec34b17 100644 --- a/drivers/net/e1000e/defines.h +++ b/drivers/net/e1000e/defines.h @@ -575,6 +575,8 @@ #define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */ #define PHY_EXT_STATUS 0x0F /* Extended Status Reg */ +#define PHY_CONTROL_LB 0x4000 /* PHY Loopback bit */ + /* NVM Control */ #define E1000_EECD_SK 0x00000001 /* NVM Clock */ #define E1000_EECD_CS 0x00000002 /* NVM Chip Select */ diff --git a/drivers/net/e1000e/phy.c b/drivers/net/e1000e/phy.c index e23459cf3d0..d8453946bff 100644 --- a/drivers/net/e1000e/phy.c +++ b/drivers/net/e1000e/phy.c @@ -2737,6 +2737,11 @@ s32 e1000_link_stall_workaround_hv(struct e1000_hw *hw) if (hw->phy.type != e1000_phy_82578) goto out; + /* Do not apply workaround if in PHY loopback bit 14 set */ + hw->phy.ops.read_phy_reg(hw, PHY_CONTROL, &data); + if (data & PHY_CONTROL_LB) + goto out; + /* check if link is up and at 1Gbps */ ret_val = hw->phy.ops.read_phy_reg(hw, BM_CS_STATUS, &data); if (ret_val) -- cgit v1.2.3 From fc0c7760aea07c74af3395ad18f96ba62eecac36 Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Wed, 1 Jul 2009 13:27:55 +0000 Subject: e1000e: delay after LCD reset and proper checks for PHY configuration done A previous workaround for 82578 to avoid link stall causes some PHY registers to get cleared inadvertently. Add a delay after all LCD resets to make sure PHY registers are in a stable state before continuing. Also, after resets check the EEC register for the state of PHY configuration performed by the MAC for ICH9 and earlier parts (as done before), but check the LAN_INIT_DONE bit in the STATUS register for ICH10 and newer parts (EEC doesn't exist in these newer parts). Signed-off-by: Bruce Allan Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/e1000e/defines.h | 1 + drivers/net/e1000e/ich8lan.c | 125 ++++++++++++++++++++++++++++--------------- 2 files changed, 82 insertions(+), 44 deletions(-) diff --git a/drivers/net/e1000e/defines.h b/drivers/net/e1000e/defines.h index 4329ec34b17..c0f185beb8b 100644 --- a/drivers/net/e1000e/defines.h +++ b/drivers/net/e1000e/defines.h @@ -238,6 +238,7 @@ #define E1000_STATUS_SPEED_100 0x00000040 /* Speed 100Mb/s */ #define E1000_STATUS_SPEED_1000 0x00000080 /* Speed 1000Mb/s */ #define E1000_STATUS_LAN_INIT_DONE 0x00000200 /* Lan Init Completion by NVM */ +#define E1000_STATUS_PHYRA 0x00000400 /* PHY Reset Asserted */ #define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Status of Master requests. */ /* Constants used to interpret the masked PCI-X bus speed. */ diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c index 9e23f50fb9c..438778fef5a 100644 --- a/drivers/net/e1000e/ich8lan.c +++ b/drivers/net/e1000e/ich8lan.c @@ -693,6 +693,38 @@ static s32 e1000_hv_phy_workarounds_ich8lan(struct e1000_hw *hw) return ret_val; } +/** + * e1000_lan_init_done_ich8lan - Check for PHY config completion + * @hw: pointer to the HW structure + * + * Check the appropriate indication the MAC has finished configuring the + * PHY after a software reset. + **/ +static void e1000_lan_init_done_ich8lan(struct e1000_hw *hw) +{ + u32 data, loop = E1000_ICH8_LAN_INIT_TIMEOUT; + + /* Wait for basic configuration completes before proceeding */ + do { + data = er32(STATUS); + data &= E1000_STATUS_LAN_INIT_DONE; + udelay(100); + } while ((!data) && --loop); + + /* + * If basic configuration is incomplete before the above loop + * count reaches 0, loading the configuration from NVM will + * leave the PHY in a bad state possibly resulting in no link. + */ + if (loop == 0) + hw_dbg(hw, "LAN_INIT_DONE not set, increase timeout\n"); + + /* Clear the Init Done bit for the next init event */ + data = er32(STATUS); + data &= ~E1000_STATUS_LAN_INIT_DONE; + ew32(STATUS, data); +} + /** * e1000_phy_hw_reset_ich8lan - Performs a PHY reset * @hw: pointer to the HW structure @@ -707,13 +739,15 @@ static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw) u32 i; u32 data, cnf_size, cnf_base_addr, sw_cfg_mask; s32 ret_val; - u16 loop = E1000_ICH8_LAN_INIT_TIMEOUT; u16 word_addr, reg_data, reg_addr, phy_page = 0; ret_val = e1000e_phy_hw_reset_generic(hw); if (ret_val) return ret_val; + /* Allow time for h/w to get to a quiescent state after reset */ + mdelay(10); + if (hw->mac.type == e1000_pchlan) { ret_val = e1000_hv_phy_workarounds_ich8lan(hw); if (ret_val) @@ -741,26 +775,8 @@ static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw) if (!(data & sw_cfg_mask)) return 0; - /* Wait for basic configuration completes before proceeding*/ - do { - data = er32(STATUS); - data &= E1000_STATUS_LAN_INIT_DONE; - udelay(100); - } while ((!data) && --loop); - - /* - * If basic configuration is incomplete before the above loop - * count reaches 0, loading the configuration from NVM will - * leave the PHY in a bad state possibly resulting in no link. - */ - if (loop == 0) { - hw_dbg(hw, "LAN_INIT_DONE not set, increase timeout\n"); - } - - /* Clear the Init Done bit for the next init event */ - data = er32(STATUS); - data &= ~E1000_STATUS_LAN_INIT_DONE; - ew32(STATUS, data); + /* Wait for basic configuration completes before proceeding */ + e1000_lan_init_done_ich8lan(hw); /* * Make sure HW does not configure LCD from PHY @@ -2143,6 +2159,12 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw) ctrl = er32(CTRL); if (!e1000_check_reset_block(hw)) { + /* Clear PHY Reset Asserted bit */ + if (hw->mac.type >= e1000_pchlan) { + u32 status = er32(STATUS); + ew32(STATUS, status & ~E1000_STATUS_PHYRA); + } + /* * PHY HW reset requires MAC CORE reset at the same * time to make sure the interface between MAC and the @@ -2156,21 +2178,24 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw) ew32(CTRL, (ctrl | E1000_CTRL_RST)); msleep(20); - if (!ret_val) { - /* release the swflag because it is not reset by - * hardware reset - */ + if (!ret_val) e1000_release_swflag_ich8lan(hw); - } - ret_val = e1000e_get_auto_rd_done(hw); - if (ret_val) { - /* - * When auto config read does not complete, do not - * return with an error. This can happen in situations - * where there is no eeprom and prevents getting link. - */ - hw_dbg(hw, "Auto Read Done did not complete\n"); + if (ctrl & E1000_CTRL_PHY_RST) + ret_val = hw->phy.ops.get_cfg_done(hw); + + if (hw->mac.type >= e1000_ich10lan) { + e1000_lan_init_done_ich8lan(hw); + } else { + ret_val = e1000e_get_auto_rd_done(hw); + if (ret_val) { + /* + * When auto config read does not complete, do not + * return with an error. This can happen in situations + * where there is no eeprom and prevents getting link. + */ + hw_dbg(hw, "Auto Read Done did not complete\n"); + } } ew32(IMC, 0xffffffff); @@ -2222,6 +2247,18 @@ static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw) for (i = 0; i < mac->mta_reg_count; i++) E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0); + /* + * The 82578 Rx buffer will stall if wakeup is enabled in host and + * the ME. Reading the BM_WUC register will clear the host wakeup bit. + * Reset the phy after disabling host wakeup to reset the Rx buffer. + */ + if (hw->phy.type == e1000_phy_82578) { + hw->phy.ops.read_phy_reg(hw, BM_WUC, &i); + ret_val = e1000_phy_hw_reset_ich8lan(hw); + if (ret_val) + return ret_val; + } + /* Setup link and flow control */ ret_val = e1000_setup_link_ich8lan(hw); @@ -2253,16 +2290,6 @@ static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw) ctrl_ext |= E1000_CTRL_EXT_RO_DIS; ew32(CTRL_EXT, ctrl_ext); - /* - * The 82578 Rx buffer will stall if wakeup is enabled in host and - * the ME. Reading the BM_WUC register will clear the host wakeup bit. - * Reset the phy after disabling host wakeup to reset the Rx buffer. - */ - if (hw->phy.type == e1000_phy_82578) { - e1e_rphy(hw, BM_WUC, &i); - e1000e_phy_hw_reset_generic(hw); - } - /* * Clear all of the statistics registers (clear on read). It is * important that we do this after we have tried to establish link @@ -2850,6 +2877,16 @@ static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw) { u32 bank = 0; + if (hw->mac.type >= e1000_pchlan) { + u32 status = er32(STATUS); + + if (status & E1000_STATUS_PHYRA) + ew32(STATUS, status & ~E1000_STATUS_PHYRA); + else + hw_dbg(hw, + "PHY Reset Asserted not set - needs delay\n"); + } + e1000e_get_cfg_done(hw); /* If EEPROM is not marked present, init the IGP 3 PHY manually */ -- cgit v1.2.3 From 60f1292fcbdff03ef5caea56404d3d81d05026f6 Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Wed, 1 Jul 2009 13:28:14 +0000 Subject: e1000e: do not write SmartSpeed register bits on parts without support The driver was accessing register bits for features on parts that do not support that feature. This could cause problems in the hardware. Signed-off-by: Bruce Allan Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/e1000e/ich8lan.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c index 438778fef5a..bf9b97db76b 100644 --- a/drivers/net/e1000e/ich8lan.c +++ b/drivers/net/e1000e/ich8lan.c @@ -977,12 +977,14 @@ static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, bool active) phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU; ew32(PHY_CTRL, phy_ctrl); + if (phy->type != e1000_phy_igp_3) + return 0; + /* * Call gig speed drop workaround on LPLU before accessing * any PHY registers */ - if ((hw->mac.type == e1000_ich8lan) && - (hw->phy.type == e1000_phy_igp_3)) + if (hw->mac.type == e1000_ich8lan) e1000e_gig_downshift_workaround_ich8lan(hw); /* When LPLU is enabled, we should disable SmartSpeed */ @@ -995,6 +997,9 @@ static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, bool active) phy_ctrl &= ~E1000_PHY_CTRL_D0A_LPLU; ew32(PHY_CTRL, phy_ctrl); + if (phy->type != e1000_phy_igp_3) + return 0; + /* * LPLU and SmartSpeed are mutually exclusive. LPLU is used * during Dx states where the power conservation is most @@ -1054,6 +1059,10 @@ static s32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, bool active) if (!active) { phy_ctrl &= ~E1000_PHY_CTRL_NOND0A_LPLU; ew32(PHY_CTRL, phy_ctrl); + + if (phy->type != e1000_phy_igp_3) + return 0; + /* * LPLU and SmartSpeed are mutually exclusive. LPLU is used * during Dx states where the power conservation is most @@ -1089,12 +1098,14 @@ static s32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, bool active) phy_ctrl |= E1000_PHY_CTRL_NOND0A_LPLU; ew32(PHY_CTRL, phy_ctrl); + if (phy->type != e1000_phy_igp_3) + return 0; + /* * Call gig speed drop workaround on LPLU before accessing * any PHY registers */ - if ((hw->mac.type == e1000_ich8lan) && - (hw->phy.type == e1000_phy_igp_3)) + if (hw->mac.type == e1000_ich8lan) e1000e_gig_downshift_workaround_ich8lan(hw); /* When LPLU is enabled, we should disable SmartSpeed */ -- cgit v1.2.3 From 28c9195a570a32de2760310ca278d44a4fd060a4 Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Wed, 1 Jul 2009 13:28:32 +0000 Subject: e1000e: prevent NVM corruption on sectors larger than 4K Limit NVM writes to 4K sections to prevent NVM corruption on larger sector allocations (up to 64K). Signed-off-by: Bruce Allan Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/e1000e/ich8lan.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c index bf9b97db76b..0e0755f0db3 100644 --- a/drivers/net/e1000e/ich8lan.c +++ b/drivers/net/e1000e/ich8lan.c @@ -338,6 +338,7 @@ static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw) { struct e1000_nvm_info *nvm = &hw->nvm; struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; + union ich8_hws_flash_status hsfsts; u32 gfpreg; u32 sector_base_addr; u32 sector_end_addr; @@ -374,6 +375,20 @@ static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw) /* Adjust to word count */ nvm->flash_bank_size /= sizeof(u16); + /* + * Make sure the flash bank size does not overwrite the 4k + * sector ranges. We may have 64k allotted to us but we only care + * about the first 2 4k sectors. Therefore, if we have anything less + * than 64k set in the HSFSTS register, we will reduce the bank size + * down to 4k and let the rest remain unused. If berasesz == 3, then + * we are working in 64k mode. Otherwise we are not. + */ + if (nvm->flash_bank_size > E1000_ICH8_SHADOW_RAM_WORDS) { + hsfsts.regval = er16flash(ICH_FLASH_HSFSTS); + if (hsfsts.hsf_status.berasesz != 3) + nvm->flash_bank_size = E1000_ICH8_SHADOW_RAM_WORDS; + } + nvm->word_size = E1000_ICH8_SHADOW_RAM_WORDS; /* Clear shadow ram */ @@ -1932,7 +1947,7 @@ static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank) break; case 1: sector_size = ICH_FLASH_SEG_SIZE_4K; - iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_4K; + iteration = 1; break; case 2: if (hw->mac.type == e1000_ich9lan) { @@ -1944,7 +1959,7 @@ static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank) break; case 3: sector_size = ICH_FLASH_SEG_SIZE_64K; - iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_64K; + iteration = 1; break; default: return -E1000_ERR_NVM; -- cgit v1.2.3 From 906e8d9792b1c4a8b58c1383f4c00fc4c9936fc3 Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Wed, 1 Jul 2009 13:28:50 +0000 Subject: e1000e: delay second read of PHY_STATUS register on failure of first read Some PHYs may require two reads of the PHY_STATUS register to determine the link status. If the PHY is being accessed by another thread it is possible the first read could timeout and fail. In this case, put a delay in so the second read will pick up the correct link status. Signed-off-by: Bruce Allan Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/e1000e/phy.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/e1000e/phy.c b/drivers/net/e1000e/phy.c index d8453946bff..994401fd066 100644 --- a/drivers/net/e1000e/phy.c +++ b/drivers/net/e1000e/phy.c @@ -1531,7 +1531,12 @@ s32 e1000e_phy_has_link_generic(struct e1000_hw *hw, u32 iterations, */ ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status); if (ret_val) - break; + /* + * If the first read fails, another entity may have + * ownership of the resources, wait and try again to + * see if they have relinquished the resources yet. + */ + udelay(usec_interval); ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status); if (ret_val) break; -- cgit v1.2.3 From 7d3cabbcc86f7f69c47cb20c23ee84350ae6cfbb Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Wed, 1 Jul 2009 13:29:08 +0000 Subject: e1000e: disable K1 at 1000Mbps for 82577/82578 This workaround is required for an issue in hardware where noise on the interconnect between the MAC and PHY could be generated by a lower power mode (K1) at 1000Mbps resulting in bad packets. Disable K1 while at 1000 Mbps but keep it enabled for 10/100Mbps and when the cable is disconnected. Signed-off-by: Bruce Allan Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/e1000e/hw.h | 4 ++ drivers/net/e1000e/ich8lan.c | 107 ++++++++++++++++++++++++++++++++++++++++++- drivers/net/e1000e/lib.c | 6 --- 3 files changed, 110 insertions(+), 7 deletions(-) diff --git a/drivers/net/e1000e/hw.h b/drivers/net/e1000e/hw.h index 163c1c0cfee..fd44d9f9076 100644 --- a/drivers/net/e1000e/hw.h +++ b/drivers/net/e1000e/hw.h @@ -215,6 +215,7 @@ enum e1e_registers { E1000_SWSM = 0x05B50, /* SW Semaphore */ E1000_FWSM = 0x05B54, /* FW Semaphore */ E1000_SWSM2 = 0x05B58, /* Driver-only SW semaphore */ + E1000_CRC_OFFSET = 0x05F50, /* CRC Offset register */ E1000_HICR = 0x08F00, /* Host Interface Control */ }; @@ -302,6 +303,9 @@ enum e1e_registers { #define E1000_KMRNCTRLSTA_REN 0x00200000 #define E1000_KMRNCTRLSTA_DIAG_OFFSET 0x3 /* Kumeran Diagnostic */ #define E1000_KMRNCTRLSTA_DIAG_NELPBK 0x1000 /* Nearend Loopback mode */ +#define E1000_KMRNCTRLSTA_K1_CONFIG 0x7 +#define E1000_KMRNCTRLSTA_K1_ENABLE 0x140E +#define E1000_KMRNCTRLSTA_K1_DISABLE 0x1400 #define IFE_PHY_EXTENDED_STATUS_CONTROL 0x10 #define IFE_PHY_SPECIAL_CONTROL 0x11 /* 100BaseTx PHY Special Control */ diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c index 0e0755f0db3..d56c7473144 100644 --- a/drivers/net/e1000e/ich8lan.c +++ b/drivers/net/e1000e/ich8lan.c @@ -461,6 +461,95 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_adapter *adapter) return 0; } +/** + * e1000_check_for_copper_link_ich8lan - Check for link (Copper) + * @hw: pointer to the HW structure + * + * Checks to see of the link status of the hardware has changed. If a + * change in link status has been detected, then we read the PHY registers + * to get the current speed/duplex if link exists. + **/ +static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + s32 ret_val; + bool link; + + /* + * We only want to go out to the PHY registers to see if Auto-Neg + * has completed and/or if our link status has changed. The + * get_link_status flag is set upon receiving a Link Status + * Change or Rx Sequence Error interrupt. + */ + if (!mac->get_link_status) { + ret_val = 0; + goto out; + } + + if (hw->mac.type == e1000_pchlan) { + ret_val = e1000e_write_kmrn_reg(hw, + E1000_KMRNCTRLSTA_K1_CONFIG, + E1000_KMRNCTRLSTA_K1_ENABLE); + if (ret_val) + goto out; + } + + /* + * First we want to see if the MII Status Register reports + * link. If so, then we want to get the current speed/duplex + * of the PHY. + */ + ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link); + if (ret_val) + goto out; + + if (!link) + goto out; /* No link detected */ + + mac->get_link_status = false; + + if (hw->phy.type == e1000_phy_82578) { + ret_val = e1000_link_stall_workaround_hv(hw); + if (ret_val) + goto out; + } + + /* + * Check if there was DownShift, must be checked + * immediately after link-up + */ + e1000e_check_downshift(hw); + + /* + * If we are forcing speed/duplex, then we simply return since + * we have already determined whether we have link or not. + */ + if (!mac->autoneg) { + ret_val = -E1000_ERR_CONFIG; + goto out; + } + + /* + * Auto-Neg is enabled. Auto Speed Detection takes care + * of MAC speed/duplex configuration. So we only need to + * configure Collision Distance in the MAC. + */ + e1000e_config_collision_dist(hw); + + /* + * Configure Flow Control now that Auto-Neg has completed. + * First, we need to restore the desired flow control + * settings because we may have had to re-autoneg with a + * different link partner. + */ + ret_val = e1000e_config_fc_after_link_up(hw); + if (ret_val) + hw_dbg(hw, "Error configuring flow control\n"); + +out: + return ret_val; +} + static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter) { struct e1000_hw *hw = &adapter->hw; @@ -2224,6 +2313,14 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw) } } + /* + * For PCH, this write will make sure that any noise + * will be detected as a CRC error and be dropped rather than show up + * as a bad packet to the DMA engine. + */ + if (hw->mac.type == e1000_pchlan) + ew32(CRC_OFFSET, 0x65656565); + ew32(IMC, 0xffffffff); icr = er32(ICR); @@ -2538,6 +2635,14 @@ static s32 e1000_get_link_up_info_ich8lan(struct e1000_hw *hw, u16 *speed, if (ret_val) return ret_val; + if ((hw->mac.type == e1000_pchlan) && (*speed == SPEED_1000)) { + ret_val = e1000e_write_kmrn_reg(hw, + E1000_KMRNCTRLSTA_K1_CONFIG, + E1000_KMRNCTRLSTA_K1_DISABLE); + if (ret_val) + return ret_val; + } + if ((hw->mac.type == e1000_ich8lan) && (hw->phy.type == e1000_phy_igp_3) && (*speed == SPEED_1000)) { @@ -2984,7 +3089,7 @@ static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw) static struct e1000_mac_operations ich8_mac_ops = { .id_led_init = e1000e_id_led_init, .check_mng_mode = e1000_check_mng_mode_ich8lan, - .check_for_link = e1000e_check_for_copper_link, + .check_for_link = e1000_check_for_copper_link_ich8lan, /* cleanup_led dependent on mac type */ .clear_hw_cntrs = e1000_clear_hw_cntrs_ich8lan, .get_bus_info = e1000_get_bus_info_ich8lan, diff --git a/drivers/net/e1000e/lib.c b/drivers/net/e1000e/lib.c index be6d9e99037..99ba2b8a2a0 100644 --- a/drivers/net/e1000e/lib.c +++ b/drivers/net/e1000e/lib.c @@ -378,12 +378,6 @@ s32 e1000e_check_for_copper_link(struct e1000_hw *hw) mac->get_link_status = 0; - if (hw->phy.type == e1000_phy_82578) { - ret_val = e1000_link_stall_workaround_hv(hw); - if (ret_val) - return ret_val; - } - /* * Check if there was DownShift, must be checked * immediately after link-up -- cgit v1.2.3 From c001c213b109c8baeeb6d012b422bf059b18368f Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Wed, 1 Jul 2009 01:06:07 +0000 Subject: be2net: fix spurious interrupt handling in intx mode Occasionally we may see an interrupt without an event in the eq. In intx, we currently see the event queue and return IRQ_NONE causing a the irq to be disabled ("no one cared".) Instead, read the CEV_ISR reg to check the existence of the interrupt. Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/benet/be_hw.h | 4 ++++ drivers/net/benet/be_main.c | 16 +++++++++------- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/net/benet/be_hw.h b/drivers/net/benet/be_hw.h index b02e805c1db..29c33c709c6 100644 --- a/drivers/net/benet/be_hw.h +++ b/drivers/net/benet/be_hw.h @@ -55,6 +55,10 @@ #define MEMBAR_CTRL_INT_CTRL_PFUNC_MASK 0x7 /* bits 26 - 28 */ #define MEMBAR_CTRL_INT_CTRL_PFUNC_SHIFT 26 +/********* ISR0 Register offset **********/ +#define CEV_ISR0_OFFSET 0xC18 +#define CEV_ISR_SIZE 4 + /********* Event Q door bell *************/ #define DB_EQ_OFFSET DB_CQ_OFFSET #define DB_EQ_RING_ID_MASK 0x1FF /* bits 0 - 8 */ diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 308eb09ca56..c43f6a11929 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -1274,15 +1274,17 @@ static irqreturn_t be_intx(int irq, void *dev) { struct be_adapter *adapter = dev; struct be_ctrl_info *ctrl = &adapter->ctrl; - int rx, tx; + int isr; - tx = event_handle(ctrl, &adapter->tx_eq); - rx = event_handle(ctrl, &adapter->rx_eq); + isr = ioread32(ctrl->csr + CEV_ISR0_OFFSET + + ctrl->pci_func * CEV_ISR_SIZE); + if (!isr) + return IRQ_NONE; - if (rx || tx) - return IRQ_HANDLED; - else - return IRQ_NONE; + event_handle(ctrl, &adapter->tx_eq); + event_handle(ctrl, &adapter->rx_eq); + + return IRQ_HANDLED; } static irqreturn_t be_msix_rx(int irq, void *dev) -- cgit v1.2.3 From d23e43658aed286b885d398ff0810f04f6aae97f Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 2 Jul 2009 23:03:55 +0000 Subject: tun: Fix device unregister race It is currently possible for an asynchronous device unregister to cause the same tun device to be unregistered twice. This is because the unregister in tun_chr_close only checks whether __tun_get(tfile) != NULL. This however has nothing to do with whether the device has already been unregistered. All it tells you is whether __tun_detach has been called. This patch fixes this by using the most obvious thing to test whether the device has been unregistered. It also moves __tun_detach outside of rtnl_unlock since nothing that it does requires that lock. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- drivers/net/tun.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 11a0ba47b67..b393536012f 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1324,20 +1324,22 @@ static int tun_chr_close(struct inode *inode, struct file *file) struct tun_file *tfile = file->private_data; struct tun_struct *tun; - - rtnl_lock(); tun = __tun_get(tfile); if (tun) { - DBG(KERN_INFO "%s: tun_chr_close\n", tun->dev->name); + struct net_device *dev = tun->dev; + + DBG(KERN_INFO "%s: tun_chr_close\n", dev->name); __tun_detach(tun); /* If desireable, unregister the netdevice. */ - if (!(tun->flags & TUN_PERSIST)) - unregister_netdevice(tun->dev); - + if (!(tun->flags & TUN_PERSIST)) { + rtnl_lock(); + if (dev->reg_state == NETREG_REGISTERED) + unregister_netdevice(dev); + rtnl_unlock(); + } } - rtnl_unlock(); tun = tfile->tun; if (tun) -- cgit v1.2.3 From 3799cf47e3497a472b05f88e7a52a14931597d78 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Sun, 5 Jul 2009 04:18:12 +0000 Subject: bnx2x: Disable HC coalescing when setting timeout to zero. Problem reported by Flavio Leitner : When setting rx/tx coalescing timeout to the values less than 12 traffic was stopped. The FW supports coalescing in 12us granularity, and so value of less then 12 should be interpreted as disabling coalescing Signed-off-by: Vlad Zolotarov Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 951714a7f90..5737b751900 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -4434,7 +4434,7 @@ static void bnx2x_update_coalesce(struct bnx2x *bp) REG_WR16(bp, BAR_USTRORM_INTMEM + USTORM_SB_HC_DISABLE_OFFSET(port, sb_id, U_SB_ETH_RX_CQ_INDEX), - bp->rx_ticks ? 0 : 1); + (bp->rx_ticks/12) ? 0 : 1); /* HC_INDEX_C_ETH_TX_CQ_CONS */ REG_WR8(bp, BAR_CSTRORM_INTMEM + @@ -4444,7 +4444,7 @@ static void bnx2x_update_coalesce(struct bnx2x *bp) REG_WR16(bp, BAR_CSTRORM_INTMEM + CSTORM_SB_HC_DISABLE_OFFSET(port, sb_id, C_SB_ETH_TX_CQ_INDEX), - bp->tx_ticks ? 0 : 1); + (bp->tx_ticks/12) ? 0 : 1); } } -- cgit v1.2.3 From 1e9d9987598fa58f4bd8e72ee152c879136d6723 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Sun, 5 Jul 2009 04:18:14 +0000 Subject: bnx2x: Fix the maximal values of coalescing timeouts. This patch properly defines the maximum values for rx/tx coalescing timeouts. Signed-off-by: Vlad Zolotarov Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x.h | 2 ++ drivers/net/bnx2x_main.c | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h index 8678457849f..85a737c5c23 100644 --- a/drivers/net/bnx2x.h +++ b/drivers/net/bnx2x.h @@ -902,6 +902,8 @@ struct bnx2x { u16 rx_quick_cons_trip; u16 rx_ticks_int; u16 rx_ticks; +/* Maximal coalescing timeout in us */ +#define BNX2X_MAX_COALESCE_TOUT (0xf0*12) u32 lin_cnt; diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 5737b751900..6c67be67976 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -9069,12 +9069,12 @@ static int bnx2x_set_coalesce(struct net_device *dev, struct bnx2x *bp = netdev_priv(dev); bp->rx_ticks = (u16) coal->rx_coalesce_usecs; - if (bp->rx_ticks > 3000) - bp->rx_ticks = 3000; + if (bp->rx_ticks > BNX2X_MAX_COALESCE_TOUT) + bp->rx_ticks = BNX2X_MAX_COALESCE_TOUT; bp->tx_ticks = (u16) coal->tx_coalesce_usecs; - if (bp->tx_ticks > 0x3000) - bp->tx_ticks = 0x3000; + if (bp->tx_ticks > BNX2X_MAX_COALESCE_TOUT) + bp->tx_ticks = BNX2X_MAX_COALESCE_TOUT; if (netif_running(dev)) bnx2x_update_coalesce(bp); -- cgit v1.2.3 From 4c3dd308adbda61f2ab46a14a0adcca8e1338ea5 Mon Sep 17 00:00:00 2001 From: Ken Kawasaki Date: Sat, 4 Jul 2009 14:17:10 +0000 Subject: pcnet_cs: add new id add new id (RIOS System PC CARD3 ETHERNET). Signed-off-by: Ken Kawasaki Signed-off-by: David S. Miller --- drivers/net/pcmcia/pcnet_cs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index 652a3688836..9ef1c1bfa83 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -1727,6 +1727,7 @@ static struct pcmcia_device_id pcnet_ids[] = { PCMCIA_DEVICE_PROD_ID12("PRETEC", "Ethernet CompactLAN 10BaseT 3.3V", 0xebf91155, 0x7f5a4f50), PCMCIA_DEVICE_PROD_ID12("Psion Dacom", "Gold Card Ethernet", 0xf5f025c2, 0x3a30e110), PCMCIA_DEVICE_PROD_ID12("=RELIA==", "Ethernet", 0xcdd0644a, 0x00b2e941), + PCMCIA_DEVICE_PROD_ID12("RIOS Systems Co.", "PC CARD3 ETHERNET", 0x7dd33481, 0x10b41826), PCMCIA_DEVICE_PROD_ID12("RP", "1625B Ethernet NE2000 Compatible", 0xe3e66e22, 0xb96150df), PCMCIA_DEVICE_PROD_ID12("RPTI", "EP400 Ethernet NE2000 Compatible", 0xdc6f88fd, 0x4a7e2ae0), PCMCIA_DEVICE_PROD_ID12("RPTI", "EP401 Ethernet NE2000 Compatible", 0xdc6f88fd, 0x4bcbd7fd), -- cgit v1.2.3 From 3942453948015228d6b1ae9835a6f6ca3e842aaa Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 4 Jul 2009 11:31:47 +0000 Subject: drivers/net/smsc911x.c: Fix resource size off by 1 error The call resource_size(res) returns res->end - res->start + 1 and thus the second change is semantics-preserving. res_size is then used as the second argument of a call to request_mem_region, and the memory allocated by this call appears to be the same as what is released in the two calls to release_mem_region. So the size argument for those calls should be resource_size(size) as well. Alternatively, in the second call to release_mem_region, the second argument could be res_size, as that variable has already been initialized at the point of this call. The problem was found using the following semantic patch: (http://www.emn.fr/x-info/coccinelle/) // @@ struct resource *res; @@ - (res->end - res->start) + 1 + resource_size(res) @@ struct resource *res; @@ - res->end - res->start + BAD(resource_size(res)) // Signed-off-by: Julia Lawall Signed-off-by: David S. Miller --- drivers/net/smsc911x.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c index b60639bd181..66067f9d91c 100644 --- a/drivers/net/smsc911x.c +++ b/drivers/net/smsc911x.c @@ -1938,7 +1938,7 @@ static int __devexit smsc911x_drv_remove(struct platform_device *pdev) if (!res) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, res->end - res->start); + release_mem_region(res->start, resource_size(res)); iounmap(pdata->ioaddr); @@ -1976,7 +1976,7 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) retval = -ENODEV; goto out_0; } - res_size = res->end - res->start + 1; + res_size = resource_size(res); irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!irq_res) { @@ -2104,7 +2104,7 @@ out_unmap_io_3: out_free_netdev_2: free_netdev(dev); out_release_io_1: - release_mem_region(res->start, res->end - res->start); + release_mem_region(res->start, resource_size(res)); out_0: return retval; } -- cgit v1.2.3 From 78c29bd95bd8d2c3bcf7932cb3ab8ae01cd8f58f Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 2 Jul 2009 04:04:45 +0000 Subject: forcedeth: Fix NAPI race. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Eric Dumazet a écrit : > Ingo Molnar a écrit : >>> The following changes since commit 52989765629e7d182b4f146050ebba0abf2cb0b7: >>> Linus Torvalds (1): >>> Merge git://git.kernel.org/.../davem/net-2.6 >>> >>> are available in the git repository at: >>> >>> master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6.git master >> Hm, something in this lot quickly wrecked networking here - see the >> tx timeout dump below. It starts with: >> >> [ 351.004596] WARNING: at net/sched/sch_generic.c:246 dev_watchdog+0x10b/0x19c() >> [ 351.011815] Hardware name: System Product Name >> [ 351.016220] NETDEV WATCHDOG: eth0 (forcedeth): transmit queue 0 timed out >> >> Config attached. Unfortunately i've got no time to do bisection >> today. > > > > forcedeth might have a problem, in its netif_wake_queue() logic, but > I could not see why a recent patch could make this problem visible now. > > CPU0/1: AMD Athlon(tm) 64 X2 Dual Core Processor 3800+ stepping 02 > is not a new cpu either :) > > forcedeth uses an internal tx_stop without appropriate barrier. > > Could you try following patch ? > > (random guess as I dont have much time right now) We might have a race in napi_schedule(), leaving interrupts disabled forever. I cannot test this patch, I dont have the hardware... Tested-by: Ingo Molnar Signed-off-by: David S. Miller --- drivers/net/forcedeth.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 1094d292630..3b4e0766c7b 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -3514,11 +3514,13 @@ static irqreturn_t nv_nic_irq(int foo, void *data) nv_msi_workaround(np); #ifdef CONFIG_FORCEDETH_NAPI - napi_schedule(&np->napi); - - /* Disable furthur irq's - (msix not enabled with napi) */ - writel(0, base + NvRegIrqMask); + if (napi_schedule_prep(&np->napi)) { + /* + * Disable further irq's (msix not enabled with napi) + */ + writel(0, base + NvRegIrqMask); + __napi_schedule(&np->napi); + } #else do @@ -3615,12 +3617,13 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data) nv_msi_workaround(np); #ifdef CONFIG_FORCEDETH_NAPI - napi_schedule(&np->napi); - - /* Disable furthur irq's - (msix not enabled with napi) */ - writel(0, base + NvRegIrqMask); - + if (napi_schedule_prep(&np->napi)) { + /* + * Disable further irq's (msix not enabled with napi) + */ + writel(0, base + NvRegIrqMask); + __napi_schedule(&np->napi); + } #else do { -- cgit v1.2.3 From 1ded3f59f35a2642852b3e2a1c0fa8a97777e9af Mon Sep 17 00:00:00 2001 From: Stephane Contri Date: Thu, 2 Jul 2009 23:26:48 +0000 Subject: dsa: fix 88e6xxx statistics counter snapshotting The bit that tells us whether a statistics counter snapshot operation has completed is located in the GLOBAL register block, not in the GLOBAL2 register block, so fix up mv88e6xxx_stats_wait() to poll the right register address. Signed-off-by: Stephane Contri Signed-off-by: Lennert Buytenhek Cc: stable@kernel.org Signed-off-by: David S. Miller --- net/dsa/mv88e6xxx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/dsa/mv88e6xxx.c b/net/dsa/mv88e6xxx.c index 4e4d8b5ad03..efe661a9def 100644 --- a/net/dsa/mv88e6xxx.c +++ b/net/dsa/mv88e6xxx.c @@ -418,7 +418,7 @@ static int mv88e6xxx_stats_wait(struct dsa_switch *ds) int i; for (i = 0; i < 10; i++) { - ret = REG_READ(REG_GLOBAL2, 0x1d); + ret = REG_READ(REG_GLOBAL, 0x1d); if ((ret & 0x8000) == 0) return 0; } -- cgit v1.2.3 From 3c8a9c63d5fd738c261bd0ceece04d9c8357ca13 Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Sun, 5 Jul 2009 19:48:35 +0000 Subject: tun/tap: Fix crashes if open() /dev/net/tun and then poll() it. Fix NULL pointer dereference in tun_chr_pool() introduced by commit 33dccbb050bbe35b88ca8cf1228dcf3e4d4b3554 ("tun: Limit amount of queued packets per device") and triggered by this code: int fd; struct pollfd pfd; fd = open("/dev/net/tun", O_RDWR); pfd.fd = fd; pfd.events = POLLIN | POLLOUT; poll(&pfd, 1, 0); Reported-by: Eugene Kapun Signed-off-by: Mariusz Kozlowski Signed-off-by: David S. Miller --- drivers/net/tun.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index b393536012f..027f7aba26a 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -486,12 +486,14 @@ static unsigned int tun_chr_poll(struct file *file, poll_table * wait) { struct tun_file *tfile = file->private_data; struct tun_struct *tun = __tun_get(tfile); - struct sock *sk = tun->sk; + struct sock *sk; unsigned int mask = 0; if (!tun) return POLLERR; + sk = tun->sk; + DBG(KERN_INFO "%s: tun_chr_poll\n", tun->dev->name); poll_wait(file, &tun->socket.wait, wait); -- cgit v1.2.3 From 1bc4ee4088c9a502db0e9c87f675e61e57fa1734 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sun, 5 Jul 2009 19:45:48 +0000 Subject: sctp: fix warning at inet_sock_destruct() while release sctp socket Commit 'net: Move rx skb_orphan call to where needed' broken sctp protocol with warning at inet_sock_destruct(). Actually, sctp can do this right with sctp_sock_rfree_frag() and sctp_skb_set_owner_r_frag() pair. sctp_sock_rfree_frag(skb); sctp_skb_set_owner_r_frag(skb, newsk); This patch not revert the commit d55d87fdff8252d0e2f7c28c2d443aee17e9d70f, instead remove the sctp_sock_rfree_frag() function. ------------[ cut here ]------------ WARNING: at net/ipv4/af_inet.c:151 inet_sock_destruct+0xe0/0x142() Modules linked in: sctp ipv6 dm_mirror dm_region_hash dm_log dm_multipath scsi_mod ext3 jbd uhci_hcd ohci_hcd ehci_hcd [last unloaded: scsi_wait_scan] Pid: 1808, comm: sctp_test Not tainted 2.6.31-rc2 #40 Call Trace: [] warn_slowpath_common+0x6a/0x81 [] ? inet_sock_destruct+0xe0/0x142 [] warn_slowpath_null+0x12/0x15 [] inet_sock_destruct+0xe0/0x142 [] __sk_free+0x19/0xcc [] sk_free+0x18/0x1a [] sctp_close+0x192/0x1a1 [sctp] [] inet_release+0x47/0x4d [] sock_release+0x19/0x5e [] sock_close+0x21/0x25 [] __fput+0xde/0x189 [] fput+0x18/0x1a [] filp_close+0x56/0x60 [] put_files_struct+0x5d/0xa1 [] exit_files+0x39/0x3d [] do_exit+0x1a5/0x5dd [] ? d_kill+0x35/0x3b [] ? dequeue_signal+0xa6/0x115 [] do_group_exit+0x63/0x8a [] get_signal_to_deliver+0x2e1/0x2f9 [] do_notify_resume+0x7c/0x6b5 [] ? autoremove_wake_function+0x0/0x34 [] ? __d_free+0x3d/0x40 [] ? d_free+0x2a/0x3c [] ? vfs_write+0x103/0x117 [] ? sys_socketcall+0x178/0x182 [] work_notifysig+0x13/0x19 ---[ end trace 9db92c463e789fba ]--- Signed-off-by: Wei Yongjun Acked-by: Herbert Xu Acked-by: Vlad Yasevich Signed-off-by: David S. Miller --- net/sctp/socket.c | 25 ++----------------------- 1 file changed, 2 insertions(+), 23 deletions(-) diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 35ba035970a..971890dbfea 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -6652,21 +6652,6 @@ static void sctp_wait_for_close(struct sock *sk, long timeout) finish_wait(sk->sk_sleep, &wait); } -static void sctp_sock_rfree_frag(struct sk_buff *skb) -{ - struct sk_buff *frag; - - if (!skb->data_len) - goto done; - - /* Don't forget the fragments. */ - skb_walk_frags(skb, frag) - sctp_sock_rfree_frag(frag); - -done: - sctp_sock_rfree(skb); -} - static void sctp_skb_set_owner_r_frag(struct sk_buff *skb, struct sock *sk) { struct sk_buff *frag; @@ -6776,7 +6761,6 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, sctp_skb_for_each(skb, &oldsk->sk_receive_queue, tmp) { event = sctp_skb2event(skb); if (event->asoc == assoc) { - sctp_sock_rfree_frag(skb); __skb_unlink(skb, &oldsk->sk_receive_queue); __skb_queue_tail(&newsk->sk_receive_queue, skb); sctp_skb_set_owner_r_frag(skb, newsk); @@ -6807,7 +6791,6 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, sctp_skb_for_each(skb, &oldsp->pd_lobby, tmp) { event = sctp_skb2event(skb); if (event->asoc == assoc) { - sctp_sock_rfree_frag(skb); __skb_unlink(skb, &oldsp->pd_lobby); __skb_queue_tail(queue, skb); sctp_skb_set_owner_r_frag(skb, newsk); @@ -6822,15 +6805,11 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, } - sctp_skb_for_each(skb, &assoc->ulpq.reasm, tmp) { - sctp_sock_rfree_frag(skb); + sctp_skb_for_each(skb, &assoc->ulpq.reasm, tmp) sctp_skb_set_owner_r_frag(skb, newsk); - } - sctp_skb_for_each(skb, &assoc->ulpq.lobby, tmp) { - sctp_sock_rfree_frag(skb); + sctp_skb_for_each(skb, &assoc->ulpq.lobby, tmp) sctp_skb_set_owner_r_frag(skb, newsk); - } /* Set the type of socket to indicate that it is peeled off from the * original UDP-style socket or created with the accept() call on a -- cgit v1.2.3 From 0ca1b08eba627b4245efd0f71b55a062bf163777 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 6 Jul 2009 12:49:18 -0700 Subject: Revert "p54: Use SKB list handling helpers instead of by-hand code." This reverts commit a1091aae19b1d9c85d91c86915a611387f67a26b. --- drivers/net/wireless/p54/p54common.c | 46 +++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index b618bd14583..48d81d98e12 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -823,30 +823,30 @@ void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb) struct p54_tx_info *range; unsigned long flags; - if (unlikely(!skb || !dev || skb_queue_empty(&priv->tx_queue))) + if (unlikely(!skb || !dev || !skb_queue_len(&priv->tx_queue))) return; - /* There used to be a check here to see if the SKB was on the - * TX queue or not. This can never happen because all SKBs we - * see here successfully went through p54_assign_address() - * which means the SKB is on the ->tx_queue. + /* + * don't try to free an already unlinked skb */ + if (unlikely((!skb->next) || (!skb->prev))) + return; spin_lock_irqsave(&priv->tx_queue.lock, flags); info = IEEE80211_SKB_CB(skb); range = (void *)info->rate_driver_data; - if (!skb_queue_is_first(&priv->tx_queue, skb)) { + if (skb->prev != (struct sk_buff *)&priv->tx_queue) { struct ieee80211_tx_info *ni; struct p54_tx_info *mr; - ni = IEEE80211_SKB_CB(skb_queue_prev(&priv->tx_queue, skb)); + ni = IEEE80211_SKB_CB(skb->prev); mr = (struct p54_tx_info *)ni->rate_driver_data; } - if (!skb_queue_is_last(&priv->tx_queue, skb)) { + if (skb->next != (struct sk_buff *)&priv->tx_queue) { struct ieee80211_tx_info *ni; struct p54_tx_info *mr; - ni = IEEE80211_SKB_CB(skb_queue_next(&priv->tx_queue, skb)); + ni = IEEE80211_SKB_CB(skb->next); mr = (struct p54_tx_info *)ni->rate_driver_data; } __skb_unlink(skb, &priv->tx_queue); @@ -864,13 +864,15 @@ static struct sk_buff *p54_find_tx_entry(struct ieee80211_hw *dev, unsigned long flags; spin_lock_irqsave(&priv->tx_queue.lock, flags); - skb_queue_walk(&priv->tx_queue, entry) { + entry = priv->tx_queue.next; + while (entry != (struct sk_buff *)&priv->tx_queue) { struct p54_hdr *hdr = (struct p54_hdr *) entry->data; if (hdr->req_id == req_id) { spin_unlock_irqrestore(&priv->tx_queue.lock, flags); return entry; } + entry = entry->next; } spin_unlock_irqrestore(&priv->tx_queue.lock, flags); return NULL; @@ -888,22 +890,24 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) int count, idx; spin_lock_irqsave(&priv->tx_queue.lock, flags); - skb_queue_walk(&priv->tx_queue, entry) { + entry = (struct sk_buff *) priv->tx_queue.next; + while (entry != (struct sk_buff *)&priv->tx_queue) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry); struct p54_hdr *entry_hdr; struct p54_tx_data *entry_data; unsigned int pad = 0, frame_len; range = (void *)info->rate_driver_data; - if (range->start_addr != addr) + if (range->start_addr != addr) { + entry = entry->next; continue; + } - if (!skb_queue_is_last(&priv->tx_queue, entry)) { + if (entry->next != (struct sk_buff *)&priv->tx_queue) { struct ieee80211_tx_info *ni; struct p54_tx_info *mr; - ni = IEEE80211_SKB_CB(skb_queue_next(&priv->tx_queue, - entry)); + ni = IEEE80211_SKB_CB(entry->next); mr = (struct p54_tx_info *)ni->rate_driver_data; } @@ -1164,21 +1168,23 @@ static int p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, } } - skb_queue_walk(&priv->tx_queue, entry) { + entry = priv->tx_queue.next; + while (left--) { u32 hole_size; info = IEEE80211_SKB_CB(entry); range = (void *)info->rate_driver_data; hole_size = range->start_addr - last_addr; if (!target_skb && hole_size >= len) { - target_skb = skb_queue_prev(&priv->tx_queue, entry); + target_skb = entry->prev; hole_size -= len; target_addr = last_addr; } largest_hole = max(largest_hole, hole_size); last_addr = range->end_addr; + entry = entry->next; } if (!target_skb && priv->rx_end - last_addr >= len) { - target_skb = skb_peek_tail(&priv->tx_queue); + target_skb = priv->tx_queue.prev; largest_hole = max(largest_hole, priv->rx_end - last_addr - len); if (!skb_queue_empty(&priv->tx_queue)) { info = IEEE80211_SKB_CB(target_skb); @@ -2084,6 +2090,7 @@ out: static void p54_stop(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; + struct sk_buff *skb; mutex_lock(&priv->conf_mutex); priv->mode = NL80211_IFTYPE_UNSPECIFIED; @@ -2098,7 +2105,8 @@ static void p54_stop(struct ieee80211_hw *dev) p54_tx_cancel(dev, priv->cached_beacon); priv->stop(dev); - skb_queue_purge(&priv->tx_queue); + while ((skb = skb_dequeue(&priv->tx_queue))) + kfree_skb(skb); priv->cached_beacon = NULL; priv->tsf_high32 = priv->tsf_low32 = 0; mutex_unlock(&priv->conf_mutex); -- cgit v1.2.3