From 5236467ae72ecd71baa162b7734c57bfe8fa0ff9 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Fri, 10 Mar 2006 23:24:55 +0100 Subject: [SCSI] megaraid/megaraid_mm.c: fix a NULL pointer dereference This patch fixes a NULL pointer dereference spotted by the Coverity checker. Signed-off-by: Adrian Bunk Signed-off-by: James Bottomley --- drivers/scsi/megaraid/megaraid_mm.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_mm.c b/drivers/scsi/megaraid/megaraid_mm.c index 8f3ce0432295..e8f534fb336b 100644 --- a/drivers/scsi/megaraid/megaraid_mm.c +++ b/drivers/scsi/megaraid/megaraid_mm.c @@ -898,10 +898,8 @@ mraid_mm_register_adp(mraid_mmadp_t *lld_adp) adapter = kmalloc(sizeof(mraid_mmadp_t), GFP_KERNEL); - if (!adapter) { - rval = -ENOMEM; - goto memalloc_error; - } + if (!adapter) + return -ENOMEM; memset(adapter, 0, sizeof(mraid_mmadp_t)); -- cgit v1.2.3-70-g09d2 From a0f9b48dc0954c48a6b0342d9697886be6b0e4d3 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sat, 15 Apr 2006 11:52:56 -0400 Subject: [SCSI] lpfc 8.1.5 : Fix Discovery processing for NPorts that hit nodev_tmo during discovery Fix Discovery processing for NPorts that hit nodev_tmo during discovery Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_disc.h | 1 + drivers/scsi/lpfc/lpfc_hbadisc.c | 2 + drivers/scsi/lpfc/lpfc_nportdisc.c | 98 +++++++++++++++++++++++++++++--------- 3 files changed, 79 insertions(+), 22 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h index 8932b1be2b60..41cf5d3ea6ce 100644 --- a/drivers/scsi/lpfc/lpfc_disc.h +++ b/drivers/scsi/lpfc/lpfc_disc.h @@ -113,6 +113,7 @@ struct lpfc_nodelist { #define NLP_NPR_ADISC 0x2000000 /* Issue ADISC when dq'ed from NPR list */ #define NLP_DELAY_REMOVE 0x4000000 /* Defer removal till end of DSM */ +#define NLP_NODEV_REMOVE 0x8000000 /* Defer removal till discovery ends */ /* Defines for list searchs */ #define NLP_SEARCH_MAPPED 0x1 /* search mapped */ diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 6721e679df62..2a2e2eb406ac 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -1238,6 +1238,7 @@ lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list) evt_listp); } + nlp->nlp_flag &= ~NLP_NODEV_REMOVE; nlp->nlp_type |= NLP_FC_NODE; break; case NLP_MAPPED_LIST: @@ -1258,6 +1259,7 @@ lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list) evt_listp); } + nlp->nlp_flag &= ~NLP_NODEV_REMOVE; break; case NLP_NPR_LIST: nlp->nlp_flag |= list; diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 3d77bd999b70..c48ec631a33b 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -832,11 +832,17 @@ static uint32_t lpfc_device_rm_plogi_issue(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, void *arg, uint32_t evt) { - /* software abort outstanding PLOGI */ - lpfc_els_abort(phba, ndlp, 1); + if(ndlp->nlp_flag & NLP_NPR_2B_DISC) { + ndlp->nlp_flag |= NLP_NODEV_REMOVE; + return ndlp->nlp_state; + } + else { + /* software abort outstanding PLOGI */ + lpfc_els_abort(phba, ndlp, 1); - lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); - return NLP_STE_FREED_NODE; + lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); + return NLP_STE_FREED_NODE; + } } static uint32_t @@ -851,7 +857,7 @@ lpfc_device_recov_plogi_issue(struct lpfc_hba * phba, ndlp->nlp_state = NLP_STE_NPR_NODE; lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST); spin_lock_irq(phba->host->host_lock); - ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; + ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); spin_unlock_irq(phba->host->host_lock); return ndlp->nlp_state; @@ -987,11 +993,17 @@ lpfc_device_rm_adisc_issue(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, void *arg, uint32_t evt) { - /* software abort outstanding ADISC */ - lpfc_els_abort(phba, ndlp, 1); + if(ndlp->nlp_flag & NLP_NPR_2B_DISC) { + ndlp->nlp_flag |= NLP_NODEV_REMOVE; + return ndlp->nlp_state; + } + else { + /* software abort outstanding ADISC */ + lpfc_els_abort(phba, ndlp, 1); - lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); - return NLP_STE_FREED_NODE; + lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); + return NLP_STE_FREED_NODE; + } } static uint32_t @@ -1006,7 +1018,7 @@ lpfc_device_recov_adisc_issue(struct lpfc_hba * phba, ndlp->nlp_state = NLP_STE_NPR_NODE; lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST); spin_lock_irq(phba->host->host_lock); - ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; + ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); ndlp->nlp_flag |= NLP_NPR_ADISC; spin_unlock_irq(phba->host->host_lock); @@ -1133,8 +1145,14 @@ lpfc_device_rm_reglogin_issue(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, void *arg, uint32_t evt) { - lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); - return NLP_STE_FREED_NODE; + if(ndlp->nlp_flag & NLP_NPR_2B_DISC) { + ndlp->nlp_flag |= NLP_NODEV_REMOVE; + return ndlp->nlp_state; + } + else { + lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); + return NLP_STE_FREED_NODE; + } } static uint32_t @@ -1146,7 +1164,7 @@ lpfc_device_recov_reglogin_issue(struct lpfc_hba * phba, ndlp->nlp_state = NLP_STE_NPR_NODE; lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST); spin_lock_irq(phba->host->host_lock); - ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; + ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); spin_unlock_irq(phba->host->host_lock); return ndlp->nlp_state; } @@ -1278,11 +1296,17 @@ static uint32_t lpfc_device_rm_prli_issue(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, void *arg, uint32_t evt) { - /* software abort outstanding PRLI */ - lpfc_els_abort(phba, ndlp, 1); + if(ndlp->nlp_flag & NLP_NPR_2B_DISC) { + ndlp->nlp_flag |= NLP_NODEV_REMOVE; + return ndlp->nlp_state; + } + else { + /* software abort outstanding PLOGI */ + lpfc_els_abort(phba, ndlp, 1); - lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); - return NLP_STE_FREED_NODE; + lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); + return NLP_STE_FREED_NODE; + } } @@ -1313,7 +1337,7 @@ lpfc_device_recov_prli_issue(struct lpfc_hba * phba, ndlp->nlp_state = NLP_STE_NPR_NODE; lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST); spin_lock_irq(phba->host->host_lock); - ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; + ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); spin_unlock_irq(phba->host->host_lock); return ndlp->nlp_state; } @@ -1386,7 +1410,7 @@ lpfc_device_recov_unmap_node(struct lpfc_hba * phba, ndlp->nlp_prev_state = NLP_STE_UNMAPPED_NODE; ndlp->nlp_state = NLP_STE_NPR_NODE; lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST); - ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; + ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); lpfc_disc_set_adisc(phba, ndlp); return ndlp->nlp_state; @@ -1469,7 +1493,7 @@ lpfc_device_recov_mapped_node(struct lpfc_hba * phba, ndlp->nlp_state = NLP_STE_NPR_NODE; lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST); spin_lock_irq(phba->host->host_lock); - ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; + ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); spin_unlock_irq(phba->host->host_lock); lpfc_disc_set_adisc(phba, ndlp); return ndlp->nlp_state; @@ -1617,9 +1641,16 @@ lpfc_cmpl_plogi_npr_node(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, void *arg, uint32_t evt) { struct lpfc_iocbq *cmdiocb, *rspiocb; + IOCB_t *irsp; cmdiocb = (struct lpfc_iocbq *) arg; rspiocb = cmdiocb->context_un.rsp_iocb; + + irsp = &rspiocb->iocb; + if (irsp->ulpStatus) { + lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); + return NLP_STE_FREED_NODE; + } return ndlp->nlp_state; } @@ -1628,9 +1659,16 @@ lpfc_cmpl_prli_npr_node(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, void *arg, uint32_t evt) { struct lpfc_iocbq *cmdiocb, *rspiocb; + IOCB_t *irsp; cmdiocb = (struct lpfc_iocbq *) arg; rspiocb = cmdiocb->context_un.rsp_iocb; + + irsp = &rspiocb->iocb; + if (irsp->ulpStatus && (ndlp->nlp_flag & NLP_NODEV_REMOVE)) { + lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); + return NLP_STE_FREED_NODE; + } return ndlp->nlp_state; } @@ -1649,9 +1687,16 @@ lpfc_cmpl_adisc_npr_node(struct lpfc_hba * phba, uint32_t evt) { struct lpfc_iocbq *cmdiocb, *rspiocb; + IOCB_t *irsp; cmdiocb = (struct lpfc_iocbq *) arg; rspiocb = cmdiocb->context_un.rsp_iocb; + + irsp = &rspiocb->iocb; + if (irsp->ulpStatus && (ndlp->nlp_flag & NLP_NODEV_REMOVE)) { + lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); + return NLP_STE_FREED_NODE; + } return ndlp->nlp_state; } @@ -1668,7 +1713,12 @@ lpfc_cmpl_reglogin_npr_node(struct lpfc_hba * phba, if (!mb->mbxStatus) ndlp->nlp_rpi = mb->un.varWords[0]; - + else { + if (ndlp->nlp_flag & NLP_NODEV_REMOVE) { + lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); + return NLP_STE_FREED_NODE; + } + } return ndlp->nlp_state; } @@ -1677,6 +1727,10 @@ lpfc_device_rm_npr_node(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, void *arg, uint32_t evt) { + if (ndlp->nlp_flag & NLP_NPR_2B_DISC) { + ndlp->nlp_flag |= NLP_NODEV_REMOVE; + return ndlp->nlp_state; + } lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); return NLP_STE_FREED_NODE; } @@ -1687,7 +1741,7 @@ lpfc_device_recov_npr_node(struct lpfc_hba * phba, uint32_t evt) { spin_lock_irq(phba->host->host_lock); - ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; + ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); spin_unlock_irq(phba->host->host_lock); if (ndlp->nlp_flag & NLP_DELAY_TMO) { lpfc_cancel_retry_delay_tmo(phba, ndlp); -- cgit v1.2.3-70-g09d2 From 4b0b91d4611aba058c16440f9841906853741330 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sat, 15 Apr 2006 11:53:00 -0400 Subject: [SCSI] lpfc 8.1.5 : Use asynchronous ABTS completion to speed up abort completions Use asynchronous ABTS completion to speed up abort completions Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_crtn.h | 1 - drivers/scsi/lpfc/lpfc_els.c | 7 ------- drivers/scsi/lpfc/lpfc_hw.h | 1 + drivers/scsi/lpfc/lpfc_init.c | 9 --------- drivers/scsi/lpfc/lpfc_mbox.c | 33 +++------------------------------ drivers/scsi/lpfc/lpfc_nportdisc.c | 4 ---- 6 files changed, 4 insertions(+), 51 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index fad607b2e6f4..ee22173fce43 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -27,7 +27,6 @@ void lpfc_config_link(struct lpfc_hba *, LPFC_MBOXQ_t *); int lpfc_read_sparam(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_read_config(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_read_lnk_stat(struct lpfc_hba *, LPFC_MBOXQ_t *); -void lpfc_set_slim(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t); int lpfc_reg_login(struct lpfc_hba *, uint32_t, uint8_t *, LPFC_MBOXQ_t *, uint32_t); void lpfc_unreg_login(struct lpfc_hba *, uint32_t, LPFC_MBOXQ_t *); diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 4813beaaca8f..45abc76ff898 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -302,10 +302,6 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, if (lpfc_reg_login(phba, Fabric_DID, (uint8_t *) sp, mbox, 0)) goto fail_free_mbox; - /* - * set_slim mailbox command needs to execute first, - * queue this command to be processed later. - */ mbox->mbox_cmpl = lpfc_mbx_cmpl_fabric_reg_login; mbox->context2 = ndlp; @@ -1872,9 +1868,6 @@ lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, if (mbox) { if ((rspiocb->iocb.ulpStatus == 0) && (ndlp->nlp_flag & NLP_ACC_REGLOGIN)) { - /* set_slim mailbox command needs to execute first, - * queue this command to be processed later. - */ lpfc_unreg_rpi(phba, ndlp); mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login; mbox->context2 = ndlp; diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index 54d04188f7cc..b12569eefd1c 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -1539,6 +1539,7 @@ typedef struct { #define FLAGS_TOPOLOGY_FAILOVER 0x0400 /* Bit 10 */ #define FLAGS_LINK_SPEED 0x0800 /* Bit 11 */ +#define FLAGS_IMED_ABORT 0x04000 /* Bit 14 */ uint32_t link_speed; #define LINK_SPEED_AUTO 0 /* Auto selection */ diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 66d5d003555d..033778ced16c 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -294,15 +294,6 @@ lpfc_config_port_post(struct lpfc_hba * phba) } } - /* This should turn on DELAYED ABTS for ELS timeouts */ - lpfc_set_slim(phba, pmb, 0x052198, 0x1); - if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) { - phba->hba_state = LPFC_HBA_ERROR; - mempool_free( pmb, phba->mbox_mem_pool); - return -EIO; - } - - lpfc_read_config(phba, pmb); if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) { lpfc_printf_log(phba, diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index c585e2b2e589..e42f22aaf71b 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -200,6 +200,9 @@ lpfc_init_link(struct lpfc_hba * phba, break; } + /* Enable asynchronous ABTS responses from firmware */ + mb->un.varInitLnk.link_flags |= FLAGS_IMED_ABORT; + /* NEW_FEATURE * Setting up the link speed */ @@ -292,36 +295,6 @@ lpfc_unreg_did(struct lpfc_hba * phba, uint32_t did, LPFC_MBOXQ_t * pmb) return; } -/***********************************************/ - -/* command to write slim */ -/***********************************************/ -void -lpfc_set_slim(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, uint32_t addr, - uint32_t value) -{ - MAILBOX_t *mb; - - mb = &pmb->mb; - memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); - - /* addr = 0x090597 is AUTO ABTS disable for ELS commands */ - /* addr = 0x052198 is DELAYED ABTS enable for ELS commands */ - - /* - * Always turn on DELAYED ABTS for ELS timeouts - */ - if ((addr == 0x052198) && (value == 0)) - value = 1; - - mb->un.varWords[0] = addr; - mb->un.varWords[1] = value; - - mb->mbxCommand = MBX_SET_SLIM; - mb->mbxOwner = OWN_HOST; - return; -} - /**********************************************/ /* lpfc_read_nv Issue a READ CONFIG */ /* mailbox command */ diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index c48ec631a33b..adebe626a23f 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -788,10 +788,6 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_hba * phba, if (lpfc_reg_login (phba, irsp->un.elsreq64.remoteID, (uint8_t *) sp, mbox, 0) == 0) { - /* set_slim mailbox command needs to - * execute first, queue this command to - * be processed later. - */ switch (ndlp->nlp_DID) { case NameServer_DID: mbox->mbox_cmpl = -- cgit v1.2.3-70-g09d2 From 82d9a2a2900b17223117dc10b56503acc678c337 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sat, 15 Apr 2006 11:53:05 -0400 Subject: [SCSI] lpfc 8.1.5 : Fixed FC protocol violation in handling of PRLO. Fixed FC protocol violation in handling of PRLO. Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_els.c | 18 ++++++++++++++++++ drivers/scsi/lpfc/lpfc_hw.h | 2 ++ drivers/scsi/lpfc/lpfc_nportdisc.c | 32 ++++++++++++++++++-------------- 3 files changed, 38 insertions(+), 14 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 45abc76ff898..e3d8b7f47f12 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -1913,6 +1913,7 @@ lpfc_els_rsp_acc(struct lpfc_hba * phba, uint32_t flag, uint8_t *pcmd; uint16_t cmdsize; int rc; + ELS_PKT *els_pkt_ptr; psli = &phba->sli; pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */ @@ -1951,6 +1952,23 @@ lpfc_els_rsp_acc(struct lpfc_hba * phba, uint32_t flag, pcmd += sizeof (uint32_t); memcpy(pcmd, &phba->fc_sparam, sizeof (struct serv_parm)); break; + case ELS_CMD_PRLO: + cmdsize = sizeof (uint32_t) + sizeof (PRLO); + elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry, + ndlp, ndlp->nlp_DID, ELS_CMD_PRLO); + if (!elsiocb) + return 1; + + icmd = &elsiocb->iocb; + icmd->ulpContext = oldcmd->ulpContext; /* Xri */ + pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt); + + memcpy(pcmd, ((struct lpfc_dmabuf *) oldiocb->context2)->virt, + sizeof (uint32_t) + sizeof (PRLO)); + *((uint32_t *) (pcmd)) = ELS_CMD_PRLO_ACC; + els_pkt_ptr = (ELS_PKT *) pcmd; + els_pkt_ptr->un.prlo.acceptRspCode = PRLO_REQ_EXECUTED; + break; default: return 1; } diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index b12569eefd1c..eedf98801366 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -449,6 +449,7 @@ struct serv_parm { /* Structure is in Big Endian format */ #define ELS_CMD_RRQ 0x12000000 #define ELS_CMD_PRLI 0x20100014 #define ELS_CMD_PRLO 0x21100014 +#define ELS_CMD_PRLO_ACC 0x02100014 #define ELS_CMD_PDISC 0x50000000 #define ELS_CMD_FDISC 0x51000000 #define ELS_CMD_ADISC 0x52000000 @@ -484,6 +485,7 @@ struct serv_parm { /* Structure is in Big Endian format */ #define ELS_CMD_RRQ 0x12 #define ELS_CMD_PRLI 0x14001020 #define ELS_CMD_PRLO 0x14001021 +#define ELS_CMD_PRLO_ACC 0x14001002 #define ELS_CMD_PDISC 0x50 #define ELS_CMD_FDISC 0x51 #define ELS_CMD_ADISC 0x52 diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index adebe626a23f..27d60ad897cd 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -465,14 +465,18 @@ lpfc_rcv_padisc(struct lpfc_hba * phba, static int lpfc_rcv_logo(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, - struct lpfc_iocbq *cmdiocb) + struct lpfc_iocbq *cmdiocb, + uint32_t els_cmd) { /* Put ndlp on NPR list with 1 sec timeout for plogi, ACC logo */ /* Only call LOGO ACC for first LOGO, this avoids sending unnecessary * PLOGIs during LOGO storms from a device. */ ndlp->nlp_flag |= NLP_LOGO_ACC; - lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0); + if (els_cmd == ELS_CMD_PRLO) + lpfc_els_rsp_acc(phba, ELS_CMD_PRLO, cmdiocb, ndlp, NULL, 0); + else + lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0); if (!(ndlp->nlp_type & NLP_FABRIC) || (ndlp->nlp_state == NLP_STE_ADISC_ISSUE)) { @@ -681,7 +685,7 @@ lpfc_rcv_logo_plogi_issue(struct lpfc_hba * phba, /* software abort outstanding PLOGI */ lpfc_els_abort(phba, ndlp, 1); - lpfc_rcv_logo(phba, ndlp, cmdiocb); + lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO); return ndlp->nlp_state; } @@ -907,7 +911,7 @@ lpfc_rcv_logo_adisc_issue(struct lpfc_hba * phba, /* software abort outstanding ADISC */ lpfc_els_abort(phba, ndlp, 0); - lpfc_rcv_logo(phba, ndlp, cmdiocb); + lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO); return ndlp->nlp_state; } @@ -934,7 +938,7 @@ lpfc_rcv_prlo_adisc_issue(struct lpfc_hba * phba, cmdiocb = (struct lpfc_iocbq *) arg; /* Treat like rcv logo */ - lpfc_rcv_logo(phba, ndlp, cmdiocb); + lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_PRLO); return ndlp->nlp_state; } @@ -1056,7 +1060,7 @@ lpfc_rcv_logo_reglogin_issue(struct lpfc_hba * phba, cmdiocb = (struct lpfc_iocbq *) arg; - lpfc_rcv_logo(phba, ndlp, cmdiocb); + lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO); return ndlp->nlp_state; } @@ -1081,7 +1085,7 @@ lpfc_rcv_prlo_reglogin_issue(struct lpfc_hba * phba, struct lpfc_iocbq *cmdiocb; cmdiocb = (struct lpfc_iocbq *) arg; - lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0); + lpfc_els_rsp_acc(phba, ELS_CMD_PRLO, cmdiocb, ndlp, NULL, 0); return ndlp->nlp_state; } @@ -1200,7 +1204,7 @@ lpfc_rcv_logo_prli_issue(struct lpfc_hba * phba, /* Software abort outstanding PRLI before sending acc */ lpfc_els_abort(phba, ndlp, 1); - lpfc_rcv_logo(phba, ndlp, cmdiocb); + lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO); return ndlp->nlp_state; } @@ -1228,7 +1232,7 @@ lpfc_rcv_prlo_prli_issue(struct lpfc_hba * phba, struct lpfc_iocbq *cmdiocb; cmdiocb = (struct lpfc_iocbq *) arg; - lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0); + lpfc_els_rsp_acc(phba, ELS_CMD_PRLO, cmdiocb, ndlp, NULL, 0); return ndlp->nlp_state; } @@ -1371,7 +1375,7 @@ lpfc_rcv_logo_unmap_node(struct lpfc_hba * phba, cmdiocb = (struct lpfc_iocbq *) arg; - lpfc_rcv_logo(phba, ndlp, cmdiocb); + lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO); return ndlp->nlp_state; } @@ -1395,7 +1399,7 @@ lpfc_rcv_prlo_unmap_node(struct lpfc_hba * phba, cmdiocb = (struct lpfc_iocbq *) arg; - lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0); + lpfc_els_rsp_acc(phba, ELS_CMD_PRLO, cmdiocb, ndlp, NULL, 0); return ndlp->nlp_state; } @@ -1444,7 +1448,7 @@ lpfc_rcv_logo_mapped_node(struct lpfc_hba * phba, cmdiocb = (struct lpfc_iocbq *) arg; - lpfc_rcv_logo(phba, ndlp, cmdiocb); + lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO); return ndlp->nlp_state; } @@ -1476,7 +1480,7 @@ lpfc_rcv_prlo_mapped_node(struct lpfc_hba * phba, spin_unlock_irq(phba->host->host_lock); /* Treat like rcv logo */ - lpfc_rcv_logo(phba, ndlp, cmdiocb); + lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_PRLO); return ndlp->nlp_state; } @@ -1571,7 +1575,7 @@ lpfc_rcv_logo_npr_node(struct lpfc_hba * phba, cmdiocb = (struct lpfc_iocbq *) arg; - lpfc_rcv_logo(phba, ndlp, cmdiocb); + lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO); return ndlp->nlp_state; } -- cgit v1.2.3-70-g09d2 From defbcf11ab56e09965b2135d70f44a82a5ab5fc3 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sun, 16 Apr 2006 22:26:50 -0400 Subject: [SCSI] lpfc 8.1.5 : Fix cleanup code in the lpfc_pci_probe_one() error code path Fix cleanup code in the lpfc_pci_probe_one() error code path. This changes the original patch by: - hardsetting the return value from lpfc_pci_probe_one() to -ENODEV (negative value) if we fail attach - removes the checks from lpfc_pci_remove_one() validating the host and phba pointers as it's no longer needed. Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_init.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 033778ced16c..1b16ca0f5007 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1618,7 +1618,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) error = lpfc_alloc_sysfs_attr(phba); if (error) - goto out_kthread_stop; + goto out_remove_host; error = request_irq(phba->pcidev->irq, lpfc_intr_handler, SA_SHIRQ, LPFC_DRIVER_NAME, phba); @@ -1635,8 +1635,10 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET; error = lpfc_sli_hba_setup(phba); - if (error) + if (error) { + error = -ENODEV; goto out_free_irq; + } if (phba->cfg_poll & DISABLE_FCP_RING_INT) { spin_lock_irq(phba->host->host_lock); @@ -1691,6 +1693,9 @@ out_free_irq: free_irq(phba->pcidev->irq, phba); out_free_sysfs_attr: lpfc_free_sysfs_attr(phba); +out_remove_host: + fc_remove_host(phba->host); + scsi_remove_host(phba->host); out_kthread_stop: kthread_stop(phba->worker_thread); out_free_iocbq: @@ -1712,12 +1717,14 @@ out_iounmap_slim: out_idr_remove: idr_remove(&lpfc_hba_index, phba->brd_no); out_put_host: + phba->host = NULL; scsi_host_put(host); out_release_regions: pci_release_regions(pdev); out_disable_device: pci_disable_device(pdev); out: + pci_set_drvdata(pdev, NULL); return error; } -- cgit v1.2.3-70-g09d2 From 10d4e957e027b96adfed05c3af1d3fd782a242fe Mon Sep 17 00:00:00 2001 From: James Smart Date: Sat, 15 Apr 2006 11:53:15 -0400 Subject: [SCSI] lpfc 8.1.5 : Additional fixes to LOGO, PLOGI, and RSCN processing Additional fixes to LOGO, PLOGI, and RSCN processing Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_els.c | 68 +++++++++++++++++++++------------------- drivers/scsi/lpfc/lpfc_hbadisc.c | 2 ++ 2 files changed, 37 insertions(+), 33 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index e3d8b7f47f12..806c337b630b 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -777,25 +777,26 @@ lpfc_cmpl_els_plogi(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, if (disc && phba->num_disc_nodes) { /* Check to see if there are more PLOGIs to be sent */ lpfc_more_plogi(phba); - } - if (phba->num_disc_nodes == 0) { - spin_lock_irq(phba->host->host_lock); - phba->fc_flag &= ~FC_NDISC_ACTIVE; - spin_unlock_irq(phba->host->host_lock); + if (phba->num_disc_nodes == 0) { + spin_lock_irq(phba->host->host_lock); + phba->fc_flag &= ~FC_NDISC_ACTIVE; + spin_unlock_irq(phba->host->host_lock); - lpfc_can_disctmo(phba); - if (phba->fc_flag & FC_RSCN_MODE) { - /* Check to see if more RSCNs came in while we were - * processing this one. - */ - if ((phba->fc_rscn_id_cnt == 0) && - (!(phba->fc_flag & FC_RSCN_DISCOVERY))) { - spin_lock_irq(phba->host->host_lock); - phba->fc_flag &= ~FC_RSCN_MODE; - spin_unlock_irq(phba->host->host_lock); - } else { - lpfc_els_handle_rscn(phba); + lpfc_can_disctmo(phba); + if (phba->fc_flag & FC_RSCN_MODE) { + /* + * Check to see if more RSCNs came in while + * we were processing this one. + */ + if ((phba->fc_rscn_id_cnt == 0) && + (!(phba->fc_flag & FC_RSCN_DISCOVERY))) { + spin_lock_irq(phba->host->host_lock); + phba->fc_flag &= ~FC_RSCN_MODE; + spin_unlock_irq(phba->host->host_lock); + } else { + lpfc_els_handle_rscn(phba); + } } } } @@ -1259,7 +1260,7 @@ lpfc_issue_els_logo(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, psli = &phba->sli; pring = &psli->ring[LPFC_ELS_RING]; - cmdsize = 2 * (sizeof (uint32_t) + sizeof (struct lpfc_name)); + cmdsize = (2 * sizeof (uint32_t)) + sizeof (struct lpfc_name); elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, ndlp, ndlp->nlp_DID, ELS_CMD_LOGO); if (!elsiocb) @@ -1447,22 +1448,23 @@ lpfc_cancel_retry_delay_tmo(struct lpfc_hba *phba, struct lpfc_nodelist * nlp) * PLOGIs to be sent */ lpfc_more_plogi(phba); - } - if (phba->num_disc_nodes == 0) { - phba->fc_flag &= ~FC_NDISC_ACTIVE; - lpfc_can_disctmo(phba); - if (phba->fc_flag & FC_RSCN_MODE) { - /* Check to see if more RSCNs - * came in while we were - * processing this one. - */ - if((phba->fc_rscn_id_cnt==0) && - (!(phba->fc_flag & FC_RSCN_DISCOVERY))) { - phba->fc_flag &= ~FC_RSCN_MODE; - } - else { - lpfc_els_handle_rscn(phba); + if (phba->num_disc_nodes == 0) { + phba->fc_flag &= ~FC_NDISC_ACTIVE; + lpfc_can_disctmo(phba); + if (phba->fc_flag & FC_RSCN_MODE) { + /* + * Check to see if more RSCNs + * came in while we were + * processing this one. + */ + if((phba->fc_rscn_id_cnt==0) && + !(phba->fc_flag & FC_RSCN_DISCOVERY)) { + phba->fc_flag &= ~FC_RSCN_MODE; + } + else { + lpfc_els_handle_rscn(phba); + } } } } diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 2a2e2eb406ac..798977de1a66 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -1404,6 +1404,8 @@ lpfc_check_sli_ndlp(struct lpfc_hba * phba, if (icmd->ulpContext == (volatile ushort)ndlp->nlp_rpi) return 1; case CMD_ELS_REQUEST64_CR: + if (icmd->un.elsreq64.remoteID == ndlp->nlp_DID) + return 1; case CMD_XMIT_ELS_RSP64_CX: if (iocb->context1 == (uint8_t *) ndlp) return 1; -- cgit v1.2.3-70-g09d2 From 071fbd3de93fdbe059d492e6a0b691e84cf7be68 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sat, 15 Apr 2006 11:53:20 -0400 Subject: [SCSI] lpfc 8.1.5 : Misc small fixes Contains the following misc fixes: - Fix build warnings - Race condition in lpfc_workq_post_event() could corrupt phba->work_list. - nlp_sid was not being initialized properly - Fix some RSCN handling during the re-discovery after Link Up event. Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_els.c | 2 +- drivers/scsi/lpfc/lpfc_hbadisc.c | 14 ++++++-------- drivers/scsi/lpfc/lpfc_init.c | 2 +- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 806c337b630b..283b7d824c34 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -2511,7 +2511,7 @@ lpfc_els_rcv_rscn(struct lpfc_hba * phba, /* If we are about to begin discovery, just ACC the RSCN. * Discovery processing will satisfy it. */ - if (phba->hba_state < LPFC_NS_QRY) { + if (phba->hba_state <= LPFC_NS_QRY) { lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, newnode); return 0; diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 798977de1a66..adb086009ae0 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -311,8 +311,8 @@ lpfc_workq_post_event(struct lpfc_hba * phba, void *arg1, void *arg2, evtp->evt_arg2 = arg2; evtp->evt = evt; - list_add_tail(&evtp->evt_listp, &phba->work_list); spin_lock_irq(phba->host->host_lock); + list_add_tail(&evtp->evt_listp, &phba->work_list); if (phba->work_wait) wake_up(phba->work_wait); spin_unlock_irq(phba->host->host_lock); @@ -1071,10 +1071,6 @@ lpfc_register_remote_port(struct lpfc_hba * phba, /* initialize static port data */ rport->maxframe_size = ndlp->nlp_maxframe; rport->supported_classes = ndlp->nlp_class_sup; - if ((rport->scsi_target_id != -1) && - (rport->scsi_target_id < MAX_FCP_TARGET)) { - ndlp->nlp_sid = rport->scsi_target_id; - } rdata = rport->dd_data; rdata->pnode = ndlp; @@ -1087,6 +1083,10 @@ lpfc_register_remote_port(struct lpfc_hba * phba, if (rport_ids.roles != FC_RPORT_ROLE_UNKNOWN) fc_remote_port_rolechg(rport, rport_ids.roles); + if ((rport->scsi_target_id != -1) && + (rport->scsi_target_id < MAX_FCP_TARGET)) { + ndlp->nlp_sid = rport->scsi_target_id; + } return; } @@ -1905,10 +1905,8 @@ lpfc_setup_disc_node(struct lpfc_hba * phba, uint32_t did) */ if (ndlp->nlp_flag & NLP_DELAY_TMO) lpfc_cancel_retry_delay_tmo(phba, ndlp); - } else { - ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; + } else ndlp = NULL; - } } else { flg = ndlp->nlp_flag & NLP_LIST_MASK; if ((flg == NLP_ADISC_LIST) || (flg == NLP_PLOGI_LIST)) diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 1b16ca0f5007..908d0f27706f 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -795,7 +795,7 @@ lpfc_get_hba_model_desc(struct lpfc_hba * phba, uint8_t * mdp, uint8_t * descp) int max_speed; char * ports; char * bus; - } m; + } m = {"", 0, "", ""}; pci_read_config_byte(phba->pcidev, PCI_HEADER_TYPE, &hdrtype); ports = (hdrtype == 0x80) ? "2-port " : ""; -- cgit v1.2.3-70-g09d2 From 36ab26185c0b6060203829bce32eaeab0fa781ae Mon Sep 17 00:00:00 2001 From: James Smart Date: Sat, 15 Apr 2006 11:53:24 -0400 Subject: [SCSI] lpfc 8.1.5 : Change version number to 8.1.5 Change version number to 8.1.5 Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 4cf1366108b7..d0f2dc310b00 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -18,7 +18,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "8.1.4" +#define LPFC_DRIVER_VERSION "8.1.5" #define LPFC_DRIVER_NAME "lpfc" -- cgit v1.2.3-70-g09d2 From 1a34456bbbdaa939ffa567d15a0797c269f901b7 Mon Sep 17 00:00:00 2001 From: Eric Sesterhenn Date: Tue, 18 Apr 2006 21:09:20 -0700 Subject: [SCSI] Overrun in drivers/scsi/sim710.c This fixes coverity bug id #480. Since id_array is declared as id_array[MAX_SLOTS], the check for i>MAX_SLOTS is obviously false. Signed-off-by: Eric Sesterhenn Cc: James Bottomley Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/scsi/sim710.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/sim710.c b/drivers/scsi/sim710.c index 3274ab76c8d3..255886a9ac55 100644 --- a/drivers/scsi/sim710.c +++ b/drivers/scsi/sim710.c @@ -75,7 +75,7 @@ param_setup(char *str) else if(!strncmp(pos, "id:", 3)) { if(slot == -1) { printk(KERN_WARNING "sim710: Must specify slot for id parameter\n"); - } else if(slot > MAX_SLOTS) { + } else if(slot >= MAX_SLOTS) { printk(KERN_WARNING "sim710: Illegal slot %d for id %d\n", slot, val); } else { id_array[slot] = val; -- cgit v1.2.3-70-g09d2 From 77347ff7554b317a0120cb774b3bd6258a2c4bb4 Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Tue, 18 Apr 2006 21:09:22 -0700 Subject: [SCSI] qla2xxx: only free_irq() after request_irq() succeeds If qla2x00_probe_one() fails before calling request_irq() but gets to qla2x00_free_device() then it will mistakenly try to free an irq it didn't request. It's chosing to free based on ha->pdev->irq which is always set. host->irq is set after request_irq() succeeds so let's use that to decide to free or not. This was observed and tested when a silly set of circumstances lead to firmware loading failing on a 2100. Signed-off-by: Zach Brown Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_os.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 017729c59a49..bef84966d7ad 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1700,8 +1700,8 @@ qla2x00_free_device(scsi_qla_host_t *ha) ha->flags.online = 0; /* Detach interrupts */ - if (ha->pdev->irq) - free_irq(ha->pdev->irq, ha); + if (ha->host->irq) + free_irq(ha->host->irq, ha); /* release io space registers */ if (ha->iobase) -- cgit v1.2.3-70-g09d2 From 52988410587db6b4992a8c1e6193777e27f37dc7 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 18 Apr 2006 21:09:10 -0700 Subject: [SCSI] megaraid: unused variable drivers/scsi/megaraid.c: In function `mega_internal_command': drivers/scsi/megaraid.c:4474: warning: unused variable `flags' Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/scsi/megaraid.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index 80b68a2481b3..de35ffe2f79d 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -4471,7 +4471,6 @@ mega_internal_command(adapter_t *adapter, megacmd_t *mc, mega_passthru *pthru) { Scsi_Cmnd *scmd; struct scsi_device *sdev; - unsigned long flags = 0; scb_t *scb; int rval; -- cgit v1.2.3-70-g09d2 From c42bcefb5891c362b72e47070fbf7973e4eb8e1e Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Tue, 18 Apr 2006 21:09:22 -0700 Subject: [SCSI] aic7xxx: ahc_pci_write_config() fix Fix ahc_pci_write_config's (wrong order of arguments). Signed-off-by: Denis Vlasenko Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic7xxx_pci.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/aic7xxx/aic7xxx_pci.c b/drivers/scsi/aic7xxx/aic7xxx_pci.c index 5f586140e057..3adecef21783 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_pci.c +++ b/drivers/scsi/aic7xxx/aic7xxx_pci.c @@ -2036,12 +2036,12 @@ ahc_pci_resume(struct ahc_softc *ahc) * that the OS doesn't know about and rely on our chip * reset handler to handle the rest. */ - ahc_pci_write_config(ahc->dev_softc, DEVCONFIG, /*bytes*/4, - ahc->bus_softc.pci_softc.devconfig); - ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/1, - ahc->bus_softc.pci_softc.command); - ahc_pci_write_config(ahc->dev_softc, CSIZE_LATTIME, /*bytes*/1, - ahc->bus_softc.pci_softc.csize_lattime); + ahc_pci_write_config(ahc->dev_softc, DEVCONFIG, + ahc->bus_softc.pci_softc.devconfig, /*bytes*/4); + ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, + ahc->bus_softc.pci_softc.command, /*bytes*/1); + ahc_pci_write_config(ahc->dev_softc, CSIZE_LATTIME, + ahc->bus_softc.pci_softc.csize_lattime, /*bytes*/1); if ((ahc->flags & AHC_HAS_TERM_LOGIC) != 0) { struct seeprom_descriptor sd; u_int sxfrctl1; -- cgit v1.2.3-70-g09d2 From bd23e94cd70f18700fc366451a8f1427e56ed137 Mon Sep 17 00:00:00 2001 From: "Moore, Eric" Date: Mon, 17 Apr 2006 12:43:04 -0600 Subject: [SCSI] mptfusion: bug fix's for raid components adding/deleting This patch handles case where raid hidden components are not being removed when power turned off to device attached to expander, as well as the case of exposing raid components when power is turned back on to devices attached to an expander. (This is a repost of this patch, with mptsas_is_end_device declared further up in the code.) This patch contains some other miscellaneous bug fix's. Signed-off-by: Eric Moore Signed-off-by: James Bottomley --- drivers/message/fusion/mptbase.c | 4 +- drivers/message/fusion/mptsas.c | 99 ++++++++++++++++++++++++++++----------- drivers/message/fusion/mptscsih.c | 2 +- 3 files changed, 73 insertions(+), 32 deletions(-) diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index 266414ca2814..ac66a658aa11 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -5741,6 +5741,7 @@ static void EventDescriptionStr(u8 event, u32 evData0, char *evStr) { char *ds; + char buf[50]; switch(event) { case MPI_EVENT_NONE: @@ -5841,7 +5842,6 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr) break; case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: { - char buf[50]; u8 id = (u8)(evData0); u8 ReasonCode = (u8)(evData0 >> 16); switch (ReasonCode) { @@ -5878,7 +5878,6 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr) break; case MPI_EVENT_SAS_PHY_LINK_STATUS: { - char buf[50]; u8 LinkRates = (u8)(evData0 >> 8); u8 PhyNumber = (u8)(evData0); LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >> @@ -5921,7 +5920,6 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr) case MPI_EVENT_IR_RESYNC_UPDATE: { u8 resync_complete = (u8)(evData0 >> 16); - char buf[40]; sprintf(buf,"IR Resync Update: Complete = %d:",resync_complete); ds = buf; break; diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index e9716b10acea..af6ec553ff7c 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -91,6 +91,7 @@ enum mptsas_hotplug_action { MPTSAS_DEL_DEVICE, MPTSAS_ADD_RAID, MPTSAS_DEL_RAID, + MPTSAS_IGNORE_EVENT, }; struct mptsas_hotplug_event { @@ -298,6 +299,26 @@ mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle) return rc; } +/* + * Returns true if there is a scsi end device + */ +static inline int +mptsas_is_end_device(struct mptsas_devinfo * attached) +{ + if ((attached->handle) && + (attached->device_info & + MPI_SAS_DEVICE_INFO_END_DEVICE) && + ((attached->device_info & + MPI_SAS_DEVICE_INFO_SSP_TARGET) | + (attached->device_info & + MPI_SAS_DEVICE_INFO_STP_TARGET) | + (attached->device_info & + MPI_SAS_DEVICE_INFO_SATA_DEVICE))) + return 1; + else + return 0; +} + static int mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure, u32 form, u32 form_specific) @@ -872,7 +893,11 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info, SasDevicePage0_t *buffer; dma_addr_t dma_handle; __le64 sas_address; - int error; + int error=0; + + if (ioc->sas_discovery_runtime && + mptsas_is_end_device(device_info)) + goto out; hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION; hdr.ExtPageLength = 0; @@ -1009,7 +1034,11 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, CONFIGPARMS cfg; SasExpanderPage1_t *buffer; dma_addr_t dma_handle; - int error; + int error=0; + + if (ioc->sas_discovery_runtime && + mptsas_is_end_device(&phy_info->attached)) + goto out; hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION; hdr.ExtPageLength = 0; @@ -1068,26 +1097,6 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, return error; } -/* - * Returns true if there is a scsi end device - */ -static inline int -mptsas_is_end_device(struct mptsas_devinfo * attached) -{ - if ((attached->handle) && - (attached->device_info & - MPI_SAS_DEVICE_INFO_END_DEVICE) && - ((attached->device_info & - MPI_SAS_DEVICE_INFO_SSP_TARGET) | - (attached->device_info & - MPI_SAS_DEVICE_INFO_STP_TARGET) | - (attached->device_info & - MPI_SAS_DEVICE_INFO_SATA_DEVICE))) - return 1; - else - return 0; -} - static void mptsas_parse_device_info(struct sas_identify *identify, struct mptsas_devinfo *device_info) @@ -1737,6 +1746,9 @@ mptsas_hotplug_work(void *arg) break; case MPTSAS_ADD_DEVICE: + if (ev->phys_disk_num_valid) + mpt_findImVolumes(ioc); + /* * Refresh sas device pg0 data */ @@ -1868,6 +1880,9 @@ mptsas_hotplug_work(void *arg) scsi_device_put(sdev); mpt_findImVolumes(ioc); break; + case MPTSAS_IGNORE_EVENT: + default: + break; } kfree(ev); @@ -1940,7 +1955,8 @@ mptscsih_send_raid_event(MPT_ADAPTER *ioc, EVENT_DATA_RAID *raid_event_data) { struct mptsas_hotplug_event *ev; - RAID_VOL0_STATUS * volumeStatus; + int status = le32_to_cpu(raid_event_data->SettingsStatus); + int state = (status >> 8) & 0xff; if (ioc->bus_type != SAS) return; @@ -1955,6 +1971,7 @@ mptscsih_send_raid_event(MPT_ADAPTER *ioc, INIT_WORK(&ev->work, mptsas_hotplug_work, ev); ev->ioc = ioc; ev->id = raid_event_data->VolumeID; + ev->event_type = MPTSAS_IGNORE_EVENT; switch (raid_event_data->ReasonCode) { case MPI_EVENT_RAID_RC_PHYSDISK_DELETED: @@ -1966,6 +1983,25 @@ mptscsih_send_raid_event(MPT_ADAPTER *ioc, ev->phys_disk_num = raid_event_data->PhysDiskNum; ev->event_type = MPTSAS_DEL_DEVICE; break; + case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED: + switch (state) { + case MPI_PD_STATE_ONLINE: + ioc->raid_data.isRaid = 1; + ev->phys_disk_num_valid = 1; + ev->phys_disk_num = raid_event_data->PhysDiskNum; + ev->event_type = MPTSAS_ADD_DEVICE; + break; + case MPI_PD_STATE_MISSING: + case MPI_PD_STATE_NOT_COMPATIBLE: + case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST: + case MPI_PD_STATE_FAILED_AT_HOST_REQUEST: + case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON: + ev->event_type = MPTSAS_DEL_DEVICE; + break; + default: + break; + } + break; case MPI_EVENT_RAID_RC_VOLUME_DELETED: ev->event_type = MPTSAS_DEL_RAID; break; @@ -1973,11 +2009,18 @@ mptscsih_send_raid_event(MPT_ADAPTER *ioc, ev->event_type = MPTSAS_ADD_RAID; break; case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED: - volumeStatus = (RAID_VOL0_STATUS *) & - raid_event_data->SettingsStatus; - ev->event_type = (volumeStatus->State == - MPI_RAIDVOL0_STATUS_STATE_FAILED) ? - MPTSAS_DEL_RAID : MPTSAS_ADD_RAID; + switch (state) { + case MPI_RAIDVOL0_STATUS_STATE_FAILED: + case MPI_RAIDVOL0_STATUS_STATE_MISSING: + ev->event_type = MPTSAS_DEL_RAID; + break; + case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL: + case MPI_RAIDVOL0_STATUS_STATE_DEGRADED: + ev->event_type = MPTSAS_ADD_RAID; + break; + default: + break; + } break; default: break; diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index 3729062db317..6a71b066bd21 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -877,7 +877,7 @@ mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice) struct scsi_cmnd *sc; dsprintk((KERN_INFO MYNAM ": search_running target %d lun %d max %d\n", - vdevice->target_id, vdevice->lun, max)); + vdevice->vtarget->target_id, vdevice->lun, max)); for (ii=0; ii < max; ii++) { if ((sc = hd->ScsiLookup[ii]) != NULL) { -- cgit v1.2.3-70-g09d2 From 65207fedcf57dcb854a3ebb9da43c745106fe8d5 Mon Sep 17 00:00:00 2001 From: "Moore, Eric" Date: Fri, 21 Apr 2006 16:14:35 -0600 Subject: [SCSI] - fusion - mptfc bug fix's to prevent deadlock situations mptbase.h bump version number to 3.03.09 remove unneeded flags define workq and remove old fc specific locks mptbase.c initialize new lock and don't initialize two removed locks mptscsih.c when firmware reports target is no longer there, return DID_REQUEUE for fc hosts so that i/o doesn't get killed until the transport has an opportunity to manage the loss via its dev loss timer when the "eh_abort" routine is called, check to see if the driver has the command or not before looking to see if a reset is pending. James Smart and I talked about this and believe that the API for this routine is: if driver doesn't have command, return SUCCESS. This change helps prevent a target from being taken offline. SUCCESS is returned because it's likely that the command completed after error recovery timed it out but before it could be aborted. provide a routine to queue work to newly created workq, and use it. remove "ioc" from mptscsih_abort() it was only used one time. the other references were via hd->ioc, so I just moved it.... net change in references to ioc via hd->ioc is zero move hd->resetPending test and hd->timeouts increment to after the test for whether the command to be aborted remains known to the driver Make certain that the workq exists before queuing work to it. mptfc.c no longer need to lock rport data structures as I was able to single thread the code! I fixed up the debug code to eliminate compilation messages due to type mismatch in the printk. Got rid of some no longer needed rport flags. Initialize and destroy the workq used for the rescan work. simplify the logic regarding the increment of fc_rescan_work_count. use post increment and test for zero vs. pre increment and test for one; eliminate work_count variable: queue_work can be called with the work_lock held as it doesn't sleep Signed-off-by: Michael Reed Signed-off-by: Eric Moore Signed-off-by: James Bottomley --- drivers/message/fusion/mptbase.c | 1 - drivers/message/fusion/mptbase.h | 10 ++- drivers/message/fusion/mptfc.c | 125 +++++++++++++++++++++++--------------- drivers/message/fusion/mptscsih.c | 48 ++++++++------- 4 files changed, 107 insertions(+), 77 deletions(-) diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index ac66a658aa11..5fe6e8df50ab 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -1189,7 +1189,6 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) ioc->diagPending = 0; spin_lock_init(&ioc->diagLock); spin_lock_init(&ioc->fc_rescan_work_lock); - spin_lock_init(&ioc->fc_rport_lock); spin_lock_init(&ioc->initializing_hba_lock); /* Initialize the event logging. diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h index be7e8501b53c..f673cca507e1 100644 --- a/drivers/message/fusion/mptbase.h +++ b/drivers/message/fusion/mptbase.h @@ -76,8 +76,8 @@ #define COPYRIGHT "Copyright (c) 1999-2005 " MODULEAUTHOR #endif -#define MPT_LINUX_VERSION_COMMON "3.03.08" -#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.03.08" +#define MPT_LINUX_VERSION_COMMON "3.03.09" +#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.03.09" #define WHAT_MAGIC_STRING "@" "(" "#" ")" #define show_mptmod_ver(s,ver) \ @@ -489,7 +489,6 @@ typedef struct _RaidCfgData { #define MPT_RPORT_INFO_FLAGS_REGISTERED 0x01 /* rport registered */ #define MPT_RPORT_INFO_FLAGS_MISSING 0x02 /* missing from DevPage0 scan */ -#define MPT_RPORT_INFO_FLAGS_MAPPED_VDEV 0x04 /* target mapped in vdev */ /* * data allocated for each fc rport device @@ -501,7 +500,6 @@ struct mptfc_rport_info struct scsi_target *starget; FCDevicePage0_t pg0; u8 flags; - u8 remap_needed; }; /* @@ -628,11 +626,11 @@ typedef struct _MPT_ADAPTER struct work_struct mptscsih_persistTask; struct list_head fc_rports; - spinlock_t fc_rport_lock; /* list and ri flags */ spinlock_t fc_rescan_work_lock; int fc_rescan_work_count; struct work_struct fc_rescan_work; - + char fc_rescan_work_q_name[KOBJ_NAME_LEN]; + struct workqueue_struct *fc_rescan_work_q; } MPT_ADAPTER; /* diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c index b343f2a68b1c..e1fb5a166366 100644 --- a/drivers/message/fusion/mptfc.c +++ b/drivers/message/fusion/mptfc.c @@ -355,15 +355,13 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0) struct fc_rport *rport; struct mptfc_rport_info *ri; int new_ri = 1; - u64 pn; - unsigned long flags; + u64 pn, nn; VirtTarget *vtarget; if (mptfc_generate_rport_ids(pg0, &rport_ids) < 0) return; /* scan list looking for a match */ - spin_lock_irqsave(&ioc->fc_rport_lock, flags); list_for_each_entry(ri, &ioc->fc_rports, list) { pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low; if (pn == rport_ids.port_name) { /* match */ @@ -373,11 +371,9 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0) } } if (new_ri) { /* allocate one */ - spin_unlock_irqrestore(&ioc->fc_rport_lock, flags); ri = kzalloc(sizeof(struct mptfc_rport_info), GFP_KERNEL); if (!ri) return; - spin_lock_irqsave(&ioc->fc_rport_lock, flags); list_add_tail(&ri->list, &ioc->fc_rports); } @@ -387,14 +383,11 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0) /* MPT_RPORT_INFO_FLAGS_REGISTERED - rport not previously deleted */ if (!(ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED)) { ri->flags |= MPT_RPORT_INFO_FLAGS_REGISTERED; - spin_unlock_irqrestore(&ioc->fc_rport_lock, flags); rport = fc_remote_port_add(ioc->sh, channel, &rport_ids); - spin_lock_irqsave(&ioc->fc_rport_lock, flags); if (rport) { ri->rport = rport; if (new_ri) /* may have been reset by user */ rport->dev_loss_tmo = mptfc_dev_loss_tmo; - *((struct mptfc_rport_info **)rport->dd_data) = ri; /* * if already mapped, remap here. If not mapped, * target_alloc will allocate vtarget and map, @@ -406,16 +399,20 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0) vtarget->target_id = pg0->CurrentTargetID; vtarget->bus_id = pg0->CurrentBus; } - ri->remap_needed = 0; } + /* once dd_data is filled in, commands will issue to hardware */ + *((struct mptfc_rport_info **)rport->dd_data) = ri; + + pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low; + nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low; dfcprintk ((MYIOC_s_INFO_FMT "mptfc_reg_dev.%d: %x, %llx / %llx, tid %d, " "rport tid %d, tmo %d\n", ioc->name, ioc->sh->host_no, pg0->PortIdentifier, - pg0->WWNN, - pg0->WWPN, + (unsigned long long)nn, + (unsigned long long)pn, pg0->CurrentTargetID, ri->rport->scsi_target_id, ri->rport->dev_loss_tmo)); @@ -425,8 +422,6 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0) ri = NULL; } } - spin_unlock_irqrestore(&ioc->fc_rport_lock,flags); - } /* @@ -476,7 +471,6 @@ mptfc_target_alloc(struct scsi_target *starget) vtarget->target_id = ri->pg0.CurrentTargetID; vtarget->bus_id = ri->pg0.CurrentBus; ri->starget = starget; - ri->remap_needed = 0; rc = 0; } } @@ -502,10 +496,10 @@ mptfc_slave_alloc(struct scsi_device *sdev) VirtDevice *vdev; struct scsi_target *starget; struct fc_rport *rport; - unsigned long flags; - rport = starget_to_rport(scsi_target(sdev)); + starget = scsi_target(sdev); + rport = starget_to_rport(starget); if (!rport || fc_remote_port_chkready(rport)) return -ENXIO; @@ -519,10 +513,8 @@ mptfc_slave_alloc(struct scsi_device *sdev) return -ENOMEM; } - spin_lock_irqsave(&hd->ioc->fc_rport_lock,flags); sdev->hostdata = vdev; - starget = scsi_target(sdev); vtarget = starget->hostdata; if (vtarget->num_luns == 0) { @@ -535,14 +527,16 @@ mptfc_slave_alloc(struct scsi_device *sdev) vdev->vtarget = vtarget; vdev->lun = sdev->lun; - spin_unlock_irqrestore(&hd->ioc->fc_rport_lock,flags); - vtarget->num_luns++; + #ifdef DMPT_DEBUG_FC - { + { + u64 nn, pn; struct mptfc_rport_info *ri; ri = *((struct mptfc_rport_info **)rport->dd_data); + pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low; + nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low; dfcprintk ((MYIOC_s_INFO_FMT "mptfc_slv_alloc.%d: num_luns %d, sdev.id %d, " "CurrentTargetID %d, %x %llx %llx\n", @@ -550,7 +544,9 @@ mptfc_slave_alloc(struct scsi_device *sdev) sdev->host->host_no, vtarget->num_luns, sdev->id, ri->pg0.CurrentTargetID, - ri->pg0.PortIdentifier, ri->pg0.WWPN, ri->pg0.WWNN)); + ri->pg0.PortIdentifier, + (unsigned long long)pn, + (unsigned long long)nn)); } #endif @@ -570,11 +566,31 @@ mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) done(SCpnt); return 0; } + + /* dd_data is null until finished adding target */ ri = *((struct mptfc_rport_info **)rport->dd_data); - if (unlikely(ri->remap_needed)) - return SCSI_MLQUEUE_HOST_BUSY; + if (unlikely(!ri)) { + dfcprintk ((MYIOC_s_INFO_FMT + "mptfc_qcmd.%d: %d:%d, dd_data is null.\n", + ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->name, + ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->sh->host_no, + SCpnt->device->id,SCpnt->device->lun)); + SCpnt->result = DID_IMM_RETRY << 16; + done(SCpnt); + return 0; + } - return mptscsih_qcmd(SCpnt,done); + err = mptscsih_qcmd(SCpnt,done); +#ifdef DMPT_DEBUG_FC + if (unlikely(err)) { + dfcprintk ((MYIOC_s_INFO_FMT + "mptfc_qcmd.%d: %d:%d, mptscsih_qcmd returns non-zero.\n", + ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->name, + ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->sh->host_no, + SCpnt->device->id,SCpnt->device->lun)); + } +#endif + return err; } static void @@ -615,18 +631,17 @@ mptfc_rescan_devices(void *arg) MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg; int ii; int work_to_do; + u64 pn; unsigned long flags; struct mptfc_rport_info *ri; do { /* start by tagging all ports as missing */ - spin_lock_irqsave(&ioc->fc_rport_lock,flags); list_for_each_entry(ri, &ioc->fc_rports, list) { if (ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED) { ri->flags |= MPT_RPORT_INFO_FLAGS_MISSING; } } - spin_unlock_irqrestore(&ioc->fc_rport_lock,flags); /* * now rescan devices known to adapter, @@ -639,33 +654,24 @@ mptfc_rescan_devices(void *arg) } /* delete devices still missing */ - spin_lock_irqsave(&ioc->fc_rport_lock, flags); list_for_each_entry(ri, &ioc->fc_rports, list) { /* if newly missing, delete it */ - if ((ri->flags & (MPT_RPORT_INFO_FLAGS_REGISTERED | - MPT_RPORT_INFO_FLAGS_MISSING)) - == (MPT_RPORT_INFO_FLAGS_REGISTERED | - MPT_RPORT_INFO_FLAGS_MISSING)) { + if (ri->flags & MPT_RPORT_INFO_FLAGS_MISSING) { ri->flags &= ~(MPT_RPORT_INFO_FLAGS_REGISTERED| MPT_RPORT_INFO_FLAGS_MISSING); - ri->remap_needed = 1; - fc_remote_port_delete(ri->rport); - /* - * remote port not really deleted 'cause - * binding is by WWPN and driver only - * registers FCP_TARGETs but cannot trust - * data structures. - */ + fc_remote_port_delete(ri->rport); /* won't sleep */ ri->rport = NULL; + + pn = (u64)ri->pg0.WWPN.High << 32 | + (u64)ri->pg0.WWPN.Low; dfcprintk ((MYIOC_s_INFO_FMT "mptfc_rescan.%d: %llx deleted\n", ioc->name, ioc->sh->host_no, - ri->pg0.WWPN)); + (unsigned long long)pn)); } } - spin_unlock_irqrestore(&ioc->fc_rport_lock,flags); /* * allow multiple passes as target state @@ -870,10 +876,23 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto out_mptfc_probe; } - for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) { - mptfc_init_host_attr(ioc,ii); - mptfc_GetFcDevPage0(ioc,ii,mptfc_register_dev); - } + /* initialize workqueue */ + + snprintf(ioc->fc_rescan_work_q_name, KOBJ_NAME_LEN, "mptfc_wq_%d", + sh->host_no); + ioc->fc_rescan_work_q = + create_singlethread_workqueue(ioc->fc_rescan_work_q_name); + if (!ioc->fc_rescan_work_q) + goto out_mptfc_probe; + + /* + * scan for rports - + * by doing it via the workqueue, some locking is eliminated + */ + + ioc->fc_rescan_work_count = 1; + queue_work(ioc->fc_rescan_work_q, &ioc->fc_rescan_work); + flush_workqueue(ioc->fc_rescan_work_q); return 0; @@ -949,8 +968,18 @@ mptfc_init(void) static void __devexit mptfc_remove(struct pci_dev *pdev) { - MPT_ADAPTER *ioc = pci_get_drvdata(pdev); - struct mptfc_rport_info *p, *n; + MPT_ADAPTER *ioc = pci_get_drvdata(pdev); + struct mptfc_rport_info *p, *n; + struct workqueue_struct *work_q; + unsigned long flags; + + /* destroy workqueue */ + if ((work_q=ioc->fc_rescan_work_q)) { + spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags); + ioc->fc_rescan_work_q = NULL; + spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags); + destroy_workqueue(work_q); + } fc_remove_host(ioc->sh); diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index 6a71b066bd21..84fa271eb8f4 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -632,7 +632,11 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */ /* Spoof to SCSI Selection Timeout! */ - sc->result = DID_NO_CONNECT << 16; + if (ioc->bus_type != FC) + sc->result = DID_NO_CONNECT << 16; + /* else fibre, just stall until rescan event */ + else + sc->result = DID_REQUEUE << 16; if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF) hd->sel_timeout[pScsiReq->TargetID]++; @@ -1645,7 +1649,6 @@ int mptscsih_abort(struct scsi_cmnd * SCpnt) { MPT_SCSI_HOST *hd; - MPT_ADAPTER *ioc; MPT_FRAME_HDR *mf; u32 ctx2abort; int scpnt_idx; @@ -1663,14 +1666,6 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) return FAILED; } - ioc = hd->ioc; - if (hd->resetPending) { - return FAILED; - } - - if (hd->timeouts < -1) - hd->timeouts++; - /* Find this command */ if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) { @@ -1684,6 +1679,13 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) return SUCCESS; } + if (hd->resetPending) { + return FAILED; + } + + if (hd->timeouts < -1) + hd->timeouts++; + printk(KERN_WARNING MYNAM ": %s: attempting task abort! (sc=%p)\n", hd->ioc->name, SCpnt); scsi_print_command(SCpnt); @@ -1703,7 +1705,7 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) vdev = SCpnt->device->hostdata; retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK, vdev->vtarget->bus_id, vdev->vtarget->target_id, vdev->lun, - ctx2abort, mptscsih_get_tm_timeout(ioc)); + ctx2abort, mptscsih_get_tm_timeout(hd->ioc)); printk (KERN_WARNING MYNAM ": %s: task abort: %s (sc=%p)\n", hd->ioc->name, @@ -2521,15 +2523,15 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) /* 7. FC: Rescan for blocked rports which might have returned. */ - else if (ioc->bus_type == FC) { - int work_count; - unsigned long flags; - + if (ioc->bus_type == FC) { spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags); - work_count = ++ioc->fc_rescan_work_count; + if (ioc->fc_rescan_work_q) { + if (ioc->fc_rescan_work_count++ == 0) { + queue_work(ioc->fc_rescan_work_q, + &ioc->fc_rescan_work); + } + } spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags); - if (work_count == 1) - schedule_work(&ioc->fc_rescan_work); } dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name)); @@ -2544,7 +2546,6 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) { MPT_SCSI_HOST *hd; u8 event = le32_to_cpu(pEvReply->Event) & 0xFF; - int work_count; unsigned long flags; devtverboseprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n", @@ -2569,10 +2570,13 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) case MPI_EVENT_RESCAN: /* 06 */ spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags); - work_count = ++ioc->fc_rescan_work_count; + if (ioc->fc_rescan_work_q) { + if (ioc->fc_rescan_work_count++ == 0) { + queue_work(ioc->fc_rescan_work_q, + &ioc->fc_rescan_work); + } + } spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags); - if (work_count == 1) - schedule_work(&ioc->fc_rescan_work); break; /* -- cgit v1.2.3-70-g09d2 From 4a6fae1d9c0d879d5d46a2a4962220dbf53ac72b Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Sun, 23 Apr 2006 20:16:02 +0200 Subject: [SCSI] SCSI: aic7xxx_osm_pci resource leak fix. Fix resource leak in drivers/scsi/aic7xxx/aic7xxx_osm_pci.c::ahc_linux_pci_dev_probe() Found by the coverity checker (#668) Signed-off-by: Jesper Juhl Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic7xxx_osm_pci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c index cb30d9c1153d..0c9c2f400bf6 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c @@ -219,6 +219,7 @@ ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ahc->flags |= AHC_39BIT_ADDRESSING; } else { if (dma_set_mask(dev, DMA_32BIT_MASK)) { + ahc_free(ahc); printk(KERN_WARNING "aic7xxx: No suitable DMA available.\n"); return (-ENODEV); } -- cgit v1.2.3-70-g09d2 From f3e93f735321ea75108b41cb654c16f92d3f264c Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Tue, 25 Apr 2006 16:48:30 -0500 Subject: [SCSI] Fix DVD burning issues. Some pioneer DVDs are apparently returning odd "not ready" status codes that the mid-layer doesn't recognise and so passes back to the user as errors. This patch overhauls our not-ready handling and adds transparent retries for: format in progress rebuild in progress recalculation in progress operation in progress Long write in progress self test in progress The Pioneer was actually returning "long write in progress" Signed-off-by: James Bottomley --- drivers/scsi/scsi_lib.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 7b0f9a3810d2..764a8b375ead 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1067,16 +1067,29 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes, break; case NOT_READY: /* - * If the device is in the process of becoming ready, - * retry. + * If the device is in the process of becoming + * ready, or has a temporary blockage, retry. */ - if (sshdr.asc == 0x04 && sshdr.ascq == 0x01) { - scsi_requeue_command(q, cmd); - return; + if (sshdr.asc == 0x04) { + switch (sshdr.ascq) { + case 0x01: /* becoming ready */ + case 0x04: /* format in progress */ + case 0x05: /* rebuild in progress */ + case 0x06: /* recalculation in progress */ + case 0x07: /* operation in progress */ + case 0x08: /* Long write in progress */ + case 0x09: /* self test in progress */ + scsi_requeue_command(q, cmd); + return; + default: + break; + } } - if (!(req->flags & REQ_QUIET)) + if (!(req->flags & REQ_QUIET)) { scmd_printk(KERN_INFO, cmd, - "Device not ready.\n"); + "Device not ready: "); + scsi_print_sense_hdr("", &sshdr); + } scsi_end_request(cmd, 0, this_count, 1); return; case VOLUME_OVERFLOW: -- cgit v1.2.3-70-g09d2 From f2536cbd12e5182558cce42efd41072bd558596b Mon Sep 17 00:00:00 2001 From: Brian King Date: Wed, 26 Apr 2006 13:48:11 -0500 Subject: [SCSI] scsi: Add IBM 2104-DU3 to blist Some versions of the IBM 2104-DU3 disk enclosure have been observed to hang Inquiries to non zero LUNs to the SES device. This device only has LUN 0, so this patch adds it to the BLIST to prevent scsi core from scanning beyond LUN 0. Signed-off-by: Brian King Signed-off-by: James Bottomley --- drivers/scsi/scsi_devinfo.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index c750d3399a97..941c1e15c899 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -56,6 +56,8 @@ static struct { {"DENON", "DRD-25X", "V", BLIST_NOLUN}, /* locks up */ {"HITACHI", "DK312C", "CM81", BLIST_NOLUN}, /* responds to all lun */ {"HITACHI", "DK314C", "CR21", BLIST_NOLUN}, /* responds to all lun */ + {"IBM", "2104-DU3", NULL, BLIST_NOLUN}, /* locks up */ + {"IBM", "2104-TU3", NULL, BLIST_NOLUN}, /* locks up */ {"IMS", "CDD521/10", "2.06", BLIST_NOLUN}, /* locks up */ {"MAXTOR", "XT-3280", "PR02", BLIST_NOLUN}, /* locks up */ {"MAXTOR", "XT-4380S", "B3C", BLIST_NOLUN}, /* locks up */ -- cgit v1.2.3-70-g09d2 From 509e5e5d206ff7ba08011b61a882d09369ec20c3 Mon Sep 17 00:00:00 2001 From: Eric Moore Date: Wed, 26 Apr 2006 13:22:37 -0600 Subject: [SCSI] fusion - bug fix stack overflow in mptbase Bug fix for stack overflow in EventDescriptionStr, (a function for debuging firmware events). We allocated 50 bytes on local stack for buff[], however there are places in the code where we've attempted copying in greater than 50 bytes into buff[]. Signed-off-by: Eric Moore Signed-off-by: James Bottomley --- drivers/message/fusion/mptbase.c | 60 +++++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index 5fe6e8df50ab..9080853fe283 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -5735,12 +5735,13 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag) return rc; } +# define EVENT_DESCR_STR_SZ 100 + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ static void EventDescriptionStr(u8 event, u32 evData0, char *evStr) { - char *ds; - char buf[50]; + char *ds = NULL; switch(event) { case MPI_EVENT_NONE: @@ -5777,9 +5778,9 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr) if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP) ds = "Loop State(LIP) Change"; else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE) - ds = "Loop State(LPE) Change"; /* ??? */ + ds = "Loop State(LPE) Change"; /* ??? */ else - ds = "Loop State(LPB) Change"; /* ??? */ + ds = "Loop State(LPB) Change"; /* ??? */ break; case MPI_EVENT_LOGOUT: ds = "Logout"; @@ -5845,22 +5846,28 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr) u8 ReasonCode = (u8)(evData0 >> 16); switch (ReasonCode) { case MPI_EVENT_SAS_DEV_STAT_RC_ADDED: - sprintf(buf,"SAS Device Status Change: Added: id=%d", id); + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS Device Status Change: Added: id=%d", id); break; case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING: - sprintf(buf,"SAS Device Status Change: Deleted: id=%d", id); + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS Device Status Change: Deleted: id=%d", id); break; case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA: - sprintf(buf,"SAS Device Status Change: SMART Data: id=%d", id); + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS Device Status Change: SMART Data: id=%d", + id); break; case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED: - sprintf(buf,"SAS Device Status Change: No Persistancy Added: id=%d", id); + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS Device Status Change: No Persistancy " + "Added: id=%d", id); break; default: - sprintf(buf,"SAS Device Status Change: Unknown: id=%d", id); - break; + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS Device Status Change: Unknown: id=%d", id); + break; } - ds = buf; break; } case MPI_EVENT_ON_BUS_TIMER_EXPIRED: @@ -5883,34 +5890,40 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr) MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT; switch (LinkRates) { case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN: - sprintf(buf,"SAS PHY Link Status: Phy=%d:" + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS PHY Link Status: Phy=%d:" " Rate Unknown",PhyNumber); break; case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED: - sprintf(buf,"SAS PHY Link Status: Phy=%d:" + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS PHY Link Status: Phy=%d:" " Phy Disabled",PhyNumber); break; case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION: - sprintf(buf,"SAS PHY Link Status: Phy=%d:" + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS PHY Link Status: Phy=%d:" " Failed Speed Nego",PhyNumber); break; case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE: - sprintf(buf,"SAS PHY Link Status: Phy=%d:" + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS PHY Link Status: Phy=%d:" " Sata OOB Completed",PhyNumber); break; case MPI_EVENT_SAS_PLS_LR_RATE_1_5: - sprintf(buf,"SAS PHY Link Status: Phy=%d:" + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS PHY Link Status: Phy=%d:" " Rate 1.5 Gbps",PhyNumber); break; case MPI_EVENT_SAS_PLS_LR_RATE_3_0: - sprintf(buf,"SAS PHY Link Status: Phy=%d:" + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS PHY Link Status: Phy=%d:" " Rate 3.0 Gpbs",PhyNumber); break; default: - sprintf(buf,"SAS PHY Link Status: Phy=%d", PhyNumber); + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS PHY Link Status: Phy=%d", PhyNumber); break; } - ds = buf; break; } case MPI_EVENT_SAS_DISCOVERY_ERROR: @@ -5919,8 +5932,8 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr) case MPI_EVENT_IR_RESYNC_UPDATE: { u8 resync_complete = (u8)(evData0 >> 16); - sprintf(buf,"IR Resync Update: Complete = %d:",resync_complete); - ds = buf; + snprintf(evStr, EVENT_DESCR_STR_SZ, + "IR Resync Update: Complete = %d:",resync_complete); break; } case MPI_EVENT_IR2: @@ -5973,7 +5986,8 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr) ds = "Unknown"; break; } - strcpy(evStr,ds); + if (ds) + strncpy(evStr, ds, EVENT_DESCR_STR_SZ); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -5995,7 +6009,7 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply int ii; int r = 0; int handlers = 0; - char evStr[100]; + char evStr[EVENT_DESCR_STR_SZ]; u8 event; /* -- cgit v1.2.3-70-g09d2 From c005fb4fb2d23ba29ad21dee5042b2f8451ca8ba Mon Sep 17 00:00:00 2001 From: "Ju, Seokmann" Date: Thu, 27 Apr 2006 02:33:06 -0700 Subject: [SCSI] megaraid_{mm,mbox}: fix a bug in reset handler When abort failed, the driver gets reset handleer called. In the reset handler, driver calls 'scsi_done()' callback for same SCSI command packet (struct scsi_cmnd) multiple times if there are multiple SCSI command packet in the pend_list. More over, if there are entry in the pend_lsit with IOCTL packet associated, the driver returns it to wrong free_list so that, in turn, the driver could end up with 'NULL pointer dereference..' during I/O command building with incorrect resource. Also, the patch contains several minor/cosmetic changes besides this. Signed-off-by: Seokmann Ju Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- Documentation/scsi/ChangeLog.megaraid | 25 +++++++++++++++ drivers/scsi/megaraid/megaraid_mbox.c | 59 ++++++++++++++++++++++++----------- drivers/scsi/megaraid/megaraid_mbox.h | 7 +++-- 3 files changed, 71 insertions(+), 20 deletions(-) diff --git a/Documentation/scsi/ChangeLog.megaraid b/Documentation/scsi/ChangeLog.megaraid index 09f6300eda4b..c173806c91fa 100644 --- a/Documentation/scsi/ChangeLog.megaraid +++ b/Documentation/scsi/ChangeLog.megaraid @@ -1,3 +1,28 @@ +Release Date : Mon Apr 11 12:27:22 EST 2006 - Seokmann Ju +Current Version : 2.20.4.8 (scsi module), 2.20.2.6 (cmm module) +Older Version : 2.20.4.7 (scsi module), 2.20.2.6 (cmm module) + +1. Fixed a bug in megaraid_reset_handler(). + Customer reported "Unable to handle kernel NULL pointer dereference + at virtual address 00000000" when system goes to reset condition + for some reason. It happened randomly. + Root Cause: in the megaraid_reset_handler(), there is possibility not + returning pending packets in the pend_list if there are multiple + pending packets. + Fix: Made the change in the driver so that it will return all packets + in the pend_list. + +2. Added change request. + As found in the following URL, rmb() only didn't help the + problem. I had to increase the loop counter to 0xFFFFFF. (6 F's) + http://marc.theaimsgroup.com/?l=linux-scsi&m=110971060502497&w=2 + + I attached a patch for your reference, too. + Could you check and get this fix in your driver? + + Best Regards, + Jun'ichi Nomura + Release Date : Fri Nov 11 12:27:22 EST 2005 - Seokmann Ju Current Version : 2.20.4.7 (scsi module), 2.20.2.6 (cmm module) Older Version : 2.20.4.6 (scsi module), 2.20.2.6 (cmm module) diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c index c11e5ce6865e..bec1424eda85 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.c +++ b/drivers/scsi/megaraid/megaraid_mbox.c @@ -10,7 +10,7 @@ * 2 of the License, or (at your option) any later version. * * FILE : megaraid_mbox.c - * Version : v2.20.4.7 (Nov 14 2005) + * Version : v2.20.4.8 (Apr 11 2006) * * Authors: * Atul Mukker @@ -2278,6 +2278,7 @@ megaraid_mbox_dpc(unsigned long devp) unsigned long flags; uint8_t c; int status; + uioc_t *kioc; if (!adapter) return; @@ -2320,6 +2321,9 @@ megaraid_mbox_dpc(unsigned long devp) // remove from local clist list_del_init(&scb->list); + kioc = (uioc_t *)scb->gp; + kioc->status = 0; + megaraid_mbox_mm_done(adapter, scb); continue; @@ -2636,6 +2640,7 @@ megaraid_reset_handler(struct scsi_cmnd *scp) int recovery_window; int recovering; int i; + uioc_t *kioc; adapter = SCP2ADAPTER(scp); raid_dev = ADAP2RAIDDEV(adapter); @@ -2655,32 +2660,51 @@ megaraid_reset_handler(struct scsi_cmnd *scp) // Also, reset all the commands currently owned by the driver spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags); list_for_each_entry_safe(scb, tmp, &adapter->pend_list, list) { - list_del_init(&scb->list); // from pending list - con_log(CL_ANN, (KERN_WARNING - "megaraid: %ld:%d[%d:%d], reset from pending list\n", - scp->serial_number, scb->sno, - scb->dev_channel, scb->dev_target)); + if (scb->sno >= MBOX_MAX_SCSI_CMDS) { + con_log(CL_ANN, (KERN_WARNING + "megaraid: IOCTL packet with %d[%d:%d] being reset\n", + scb->sno, scb->dev_channel, scb->dev_target)); - scp->result = (DID_RESET << 16); - scp->scsi_done(scp); + scb->status = -1; - megaraid_dealloc_scb(adapter, scb); + kioc = (uioc_t *)scb->gp; + kioc->status = -EFAULT; + + megaraid_mbox_mm_done(adapter, scb); + } else { + if (scb->scp == scp) { // Found command + con_log(CL_ANN, (KERN_WARNING + "megaraid: %ld:%d[%d:%d], reset from pending list\n", + scp->serial_number, scb->sno, + scb->dev_channel, scb->dev_target)); + } else { + con_log(CL_ANN, (KERN_WARNING + "megaraid: IO packet with %d[%d:%d] being reset\n", + scb->sno, scb->dev_channel, scb->dev_target)); + } + + scb->scp->result = (DID_RESET << 16); + scb->scp->scsi_done(scb->scp); + + megaraid_dealloc_scb(adapter, scb); + } } spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags); if (adapter->outstanding_cmds) { con_log(CL_ANN, (KERN_NOTICE "megaraid: %d outstanding commands. Max wait %d sec\n", - adapter->outstanding_cmds, MBOX_RESET_WAIT)); + adapter->outstanding_cmds, + (MBOX_RESET_WAIT + MBOX_RESET_EXT_WAIT))); } recovery_window = MBOX_RESET_WAIT + MBOX_RESET_EXT_WAIT; recovering = adapter->outstanding_cmds; - for (i = 0; i < recovery_window && adapter->outstanding_cmds; i++) { + for (i = 0; i < recovery_window; i++) { megaraid_ack_sequence(adapter); @@ -2689,12 +2713,11 @@ megaraid_reset_handler(struct scsi_cmnd *scp) con_log(CL_ANN, ( "megaraid mbox: Wait for %d commands to complete:%d\n", adapter->outstanding_cmds, - MBOX_RESET_WAIT - i)); + (MBOX_RESET_WAIT + MBOX_RESET_EXT_WAIT) - i)); } // bailout if no recovery happended in reset time - if ((i == MBOX_RESET_WAIT) && - (recovering == adapter->outstanding_cmds)) { + if (adapter->outstanding_cmds == 0) { break; } @@ -2918,12 +2941,13 @@ mbox_post_sync_cmd_fast(adapter_t *adapter, uint8_t raw_mbox[]) wmb(); WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x1); - for (i = 0; i < 0xFFFFF; i++) { + for (i = 0; i < MBOX_SYNC_WAIT_CNT; i++) { if (mbox->numstatus != 0xFF) break; rmb(); + udelay(MBOX_SYNC_DELAY_200); } - if (i == 0xFFFFF) { + if (i == MBOX_SYNC_WAIT_CNT) { // We may need to re-calibrate the counter con_log(CL_ANN, (KERN_CRIT "megaraid: fast sync command timed out\n")); @@ -3475,7 +3499,7 @@ megaraid_cmm_register(adapter_t *adapter) adp.drvr_data = (unsigned long)adapter; adp.pdev = adapter->pdev; adp.issue_uioc = megaraid_mbox_mm_handler; - adp.timeout = 300; + adp.timeout = MBOX_RESET_WAIT + MBOX_RESET_EXT_WAIT; adp.max_kioc = MBOX_MAX_USER_CMDS; if ((rval = mraid_mm_register_adp(&adp)) != 0) { @@ -3702,7 +3726,6 @@ megaraid_mbox_mm_done(adapter_t *adapter, scb_t *scb) unsigned long flags; kioc = (uioc_t *)scb->gp; - kioc->status = 0; mbox64 = (mbox64_t *)(unsigned long)kioc->cmdbuf; mbox64->mbox32.status = scb->status; raw_mbox = (uint8_t *)&mbox64->mbox32; diff --git a/drivers/scsi/megaraid/megaraid_mbox.h b/drivers/scsi/megaraid/megaraid_mbox.h index 882fb1a0b575..868fb0ec93e7 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.h +++ b/drivers/scsi/megaraid/megaraid_mbox.h @@ -21,8 +21,8 @@ #include "megaraid_ioctl.h" -#define MEGARAID_VERSION "2.20.4.7" -#define MEGARAID_EXT_VERSION "(Release Date: Mon Nov 14 12:27:22 EST 2005)" +#define MEGARAID_VERSION "2.20.4.8" +#define MEGARAID_EXT_VERSION "(Release Date: Mon Apr 11 12:27:22 EST 2006)" /* @@ -100,6 +100,9 @@ #define MBOX_BUSY_WAIT 10 // max usec to wait for busy mailbox #define MBOX_RESET_WAIT 180 // wait these many seconds in reset #define MBOX_RESET_EXT_WAIT 120 // extended wait reset +#define MBOX_SYNC_WAIT_CNT 0xFFFF // wait loop index for synchronous mode + +#define MBOX_SYNC_DELAY_200 200 // 200 micro-seconds /* * maximum transfer that can happen through the firmware commands issued -- cgit v1.2.3-70-g09d2 From 2ea0020250f6aeaec1ed3adf9069973a91eff57c Mon Sep 17 00:00:00 2001 From: Michael Reed Date: Thu, 27 Apr 2006 16:25:30 -0700 Subject: [SCSI] qla2xxx: Correct eh_abort recovery logic. Fix the driver to return SUCCESS if the firmware or driver doesn't have a command to abort, i.e., it's already been returned. Without this patch, error recovery will take the target offline as it tries harder and harder to get the driver to return the command it no longer has. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_os.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index bef84966d7ad..584fe5d8e507 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -599,6 +599,7 @@ qla2x00_wait_for_loop_ready(scsi_qla_host_t *ha) * Either SUCCESS or FAILED. * * Note: +* Only return FAILED if command not returned by firmware. **************************************************************************/ int qla2xxx_eh_abort(struct scsi_cmnd *cmd) @@ -609,11 +610,12 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) unsigned int id, lun; unsigned long serial; unsigned long flags; + int wait = 0; if (!CMD_SP(cmd)) - return FAILED; + return SUCCESS; - ret = FAILED; + ret = SUCCESS; id = cmd->device->id; lun = cmd->device->lun; @@ -642,7 +644,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) } else { DEBUG3(printk("%s(%ld): abort_command " "mbx success.\n", __func__, ha->host_no)); - ret = SUCCESS; + wait = 1; } spin_lock_irqsave(&ha->hardware_lock, flags); @@ -651,17 +653,18 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) spin_unlock_irqrestore(&ha->hardware_lock, flags); /* Wait for the command to be returned. */ - if (ret == SUCCESS) { + if (wait) { if (qla2x00_eh_wait_on_command(ha, cmd) != QLA_SUCCESS) { qla_printk(KERN_ERR, ha, "scsi(%ld:%d:%d): Abort handler timed out -- %lx " "%x.\n", ha->host_no, id, lun, serial, ret); + ret = FAILED; } } qla_printk(KERN_INFO, ha, - "scsi(%ld:%d:%d): Abort command issued -- %lx %x.\n", ha->host_no, - id, lun, serial, ret); + "scsi(%ld:%d:%d): Abort command issued -- %d %lx %x.\n", + ha->host_no, id, lun, wait, serial, ret); return ret; } -- cgit v1.2.3-70-g09d2 From e5dbfa6621732a110514fb10f9a43f0e8f4befd4 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Fri, 14 Apr 2006 13:52:18 +0900 Subject: [SCSI] ibmvscsi: fix leak when failing to send srp event Signed-off-by: FUJITA Tomonori Signed-off-by: James Bottomley --- drivers/scsi/ibmvscsi/ibmvscsi.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 0a8ad37ae899..2e9be83a697f 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -739,7 +739,8 @@ static void send_mad_adapter_info(struct ibmvscsi_host_data *hostdata) { struct viosrp_adapter_info *req; struct srp_event_struct *evt_struct; - + dma_addr_t addr; + evt_struct = get_event_struct(&hostdata->pool); if (!evt_struct) { printk(KERN_ERR "ibmvscsi: couldn't allocate an event " @@ -757,10 +758,10 @@ static void send_mad_adapter_info(struct ibmvscsi_host_data *hostdata) req->common.type = VIOSRP_ADAPTER_INFO_TYPE; req->common.length = sizeof(hostdata->madapter_info); - req->buffer = dma_map_single(hostdata->dev, - &hostdata->madapter_info, - sizeof(hostdata->madapter_info), - DMA_BIDIRECTIONAL); + req->buffer = addr = dma_map_single(hostdata->dev, + &hostdata->madapter_info, + sizeof(hostdata->madapter_info), + DMA_BIDIRECTIONAL); if (dma_mapping_error(req->buffer)) { printk(KERN_ERR @@ -770,8 +771,13 @@ static void send_mad_adapter_info(struct ibmvscsi_host_data *hostdata) return; } - if (ibmvscsi_send_srp_event(evt_struct, hostdata)) + if (ibmvscsi_send_srp_event(evt_struct, hostdata)) { printk(KERN_ERR "ibmvscsi: couldn't send ADAPTER_INFO_REQ!\n"); + dma_unmap_single(hostdata->dev, + addr, + sizeof(hostdata->madapter_info), + DMA_BIDIRECTIONAL); + } }; /** @@ -1259,6 +1265,7 @@ static int ibmvscsi_do_host_config(struct ibmvscsi_host_data *hostdata, { struct viosrp_host_config *host_config; struct srp_event_struct *evt_struct; + dma_addr_t addr; int rc; evt_struct = get_event_struct(&hostdata->pool); @@ -1279,8 +1286,9 @@ static int ibmvscsi_do_host_config(struct ibmvscsi_host_data *hostdata, memset(host_config, 0x00, sizeof(*host_config)); host_config->common.type = VIOSRP_HOST_CONFIG_TYPE; host_config->common.length = length; - host_config->buffer = dma_map_single(hostdata->dev, buffer, length, - DMA_BIDIRECTIONAL); + host_config->buffer = addr = dma_map_single(hostdata->dev, buffer, + length, + DMA_BIDIRECTIONAL); if (dma_mapping_error(host_config->buffer)) { printk(KERN_ERR @@ -1291,11 +1299,9 @@ static int ibmvscsi_do_host_config(struct ibmvscsi_host_data *hostdata, init_completion(&evt_struct->comp); rc = ibmvscsi_send_srp_event(evt_struct, hostdata); - if (rc == 0) { + if (rc == 0) wait_for_completion(&evt_struct->comp); - dma_unmap_single(hostdata->dev, host_config->buffer, - length, DMA_BIDIRECTIONAL); - } + dma_unmap_single(hostdata->dev, addr, length, DMA_BIDIRECTIONAL); return rc; } -- cgit v1.2.3-70-g09d2 From ec448a0a361ce3fa97a32a5c267a680163ffe8c5 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 18 Apr 2006 09:05:39 -0700 Subject: [SCSI] srp.h: avoid padding of structs Several structs in get padded to a multiple of 8 bytes on 64-bit architectures and end up with a size that does not match the definition in the SRP spec: SRP spec 64-bit sizeof (struct indirect_buf) 20 24 sizeof (struct srp_login_rsp) 52 56 sizeof (struct srp_rsp) 36 40 Fix this by adding __attribute__((packed)) to the offending structs. Problem pointed out by Arne Redlich . Signed-off-by: Roland Dreier Signed-off-by: James Bottomley --- include/scsi/srp.h | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/include/scsi/srp.h b/include/scsi/srp.h index 6c2681dc5b46..637f77eccf0c 100644 --- a/include/scsi/srp.h +++ b/include/scsi/srp.h @@ -95,14 +95,15 @@ struct srp_direct_buf { /* * We need the packed attribute because the SRP spec puts the list of - * descriptors at an offset of 20, which is not aligned to the size - * of struct srp_direct_buf. + * descriptors at an offset of 20, which is not aligned to the size of + * struct srp_direct_buf. The whole structure must be packed to avoid + * having the 20-byte structure padded to 24 bytes on 64-bit architectures. */ struct srp_indirect_buf { struct srp_direct_buf table_desc; __be32 len; - struct srp_direct_buf desc_list[0] __attribute__((packed)); -}; + struct srp_direct_buf desc_list[0]; +} __attribute__((packed)); enum { SRP_MULTICHAN_SINGLE = 0, @@ -122,6 +123,11 @@ struct srp_login_req { u8 target_port_id[16]; }; +/* + * The SRP spec defines the size of the LOGIN_RSP structure to be 52 + * bytes, so it needs to be packed to avoid having it padded to 56 + * bytes on 64-bit architectures. + */ struct srp_login_rsp { u8 opcode; u8 reserved1[3]; @@ -132,7 +138,7 @@ struct srp_login_rsp { __be16 buf_fmt; u8 rsp_flags; u8 reserved2[25]; -}; +} __attribute__((packed)); struct srp_login_rej { u8 opcode; @@ -207,6 +213,11 @@ enum { SRP_RSP_FLAG_DIUNDER = 1 << 5 }; +/* + * The SRP spec defines the size of the RSP structure to be 36 bytes, + * so it needs to be packed to avoid having it padded to 40 bytes on + * 64-bit architectures. + */ struct srp_rsp { u8 opcode; u8 sol_not; @@ -221,6 +232,6 @@ struct srp_rsp { __be32 sense_data_len; __be32 resp_data_len; u8 data[0]; -}; +} __attribute__((packed)); #endif /* SCSI_SRP_H */ -- cgit v1.2.3-70-g09d2 From 68ac64cd3fd89fdaa091701f6ab98a9065e9b1b5 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 30 Apr 2006 11:13:50 +0100 Subject: [SERIAL] Clean up serial locking when obtaining a reference to a port The locking for the uart_port is over complicated, and can be simplified if we introduce a flag to indicate that a port is "dead" and will be removed. This also helps the validator because it removes a case of non-nested unlock ordering. Signed-off-by: Russell King Signed-off-by: Ingo Molnar Signed-off-by: Andrew Morton --- drivers/serial/serial_core.c | 114 +++++++++++++++++++++++-------------------- include/linux/serial_core.h | 1 + 2 files changed, 61 insertions(+), 54 deletions(-) diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index fcd7744c4253..aeb8153ccf24 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -1500,20 +1500,18 @@ uart_block_til_ready(struct file *filp, struct uart_state *state) static struct uart_state *uart_get(struct uart_driver *drv, int line) { struct uart_state *state; + int ret = 0; - mutex_lock(&port_mutex); state = drv->state + line; if (mutex_lock_interruptible(&state->mutex)) { - state = ERR_PTR(-ERESTARTSYS); - goto out; + ret = -ERESTARTSYS; + goto err; } state->count++; - if (!state->port) { - state->count--; - mutex_unlock(&state->mutex); - state = ERR_PTR(-ENXIO); - goto out; + if (!state->port || state->port->flags & UPF_DEAD) { + ret = -ENXIO; + goto err_unlock; } if (!state->info) { @@ -1531,15 +1529,17 @@ static struct uart_state *uart_get(struct uart_driver *drv, int line) tasklet_init(&state->info->tlet, uart_tasklet_action, (unsigned long)state); } else { - state->count--; - mutex_unlock(&state->mutex); - state = ERR_PTR(-ENOMEM); + ret = -ENOMEM; + goto err_unlock; } } - - out: - mutex_unlock(&port_mutex); return state; + + err_unlock: + state->count--; + mutex_unlock(&state->mutex); + err: + return ERR_PTR(ret); } /* @@ -2085,45 +2085,6 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state, } } -/* - * This reverses the effects of uart_configure_port, hanging up the - * port before removal. - */ -static void -uart_unconfigure_port(struct uart_driver *drv, struct uart_state *state) -{ - struct uart_port *port = state->port; - struct uart_info *info = state->info; - - if (info && info->tty) - tty_vhangup(info->tty); - - mutex_lock(&state->mutex); - - state->info = NULL; - - /* - * Free the port IO and memory resources, if any. - */ - if (port->type != PORT_UNKNOWN) - port->ops->release_port(port); - - /* - * Indicate that there isn't a port here anymore. - */ - port->type = PORT_UNKNOWN; - - /* - * Kill the tasklet, and free resources. - */ - if (info) { - tasklet_kill(&info->tlet); - kfree(info); - } - - mutex_unlock(&state->mutex); -} - static struct tty_operations uart_ops = { .open = uart_open, .close = uart_close, @@ -2270,6 +2231,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port) state = drv->state + port->line; mutex_lock(&port_mutex); + mutex_lock(&state->mutex); if (state->port) { ret = -EINVAL; goto out; @@ -2304,7 +2266,13 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port) port->cons && !(port->cons->flags & CON_ENABLED)) register_console(port->cons); + /* + * Ensure UPF_DEAD is not set. + */ + port->flags &= ~UPF_DEAD; + out: + mutex_unlock(&state->mutex); mutex_unlock(&port_mutex); return ret; @@ -2322,6 +2290,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port) int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port) { struct uart_state *state = drv->state + port->line; + struct uart_info *info; BUG_ON(in_interrupt()); @@ -2331,12 +2300,49 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port) mutex_lock(&port_mutex); + /* + * Mark the port "dead" - this prevents any opens from + * succeeding while we shut down the port. + */ + mutex_lock(&state->mutex); + port->flags |= UPF_DEAD; + mutex_unlock(&state->mutex); + /* * Remove the devices from devfs */ tty_unregister_device(drv->tty_driver, port->line); - uart_unconfigure_port(drv, state); + info = state->info; + if (info && info->tty) + tty_vhangup(info->tty); + + /* + * All users of this port should now be disconnected from + * this driver, and the port shut down. We should be the + * only thread fiddling with this port from now on. + */ + state->info = NULL; + + /* + * Free the port IO and memory resources, if any. + */ + if (port->type != PORT_UNKNOWN) + port->ops->release_port(port); + + /* + * Indicate that there isn't a port here anymore. + */ + port->type = PORT_UNKNOWN; + + /* + * Kill the tasklet, and free resources. + */ + if (info) { + tasklet_kill(&info->tlet); + kfree(info); + } + state->port = NULL; mutex_unlock(&port_mutex); diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index c32e60e79dea..bd14858121ea 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -254,6 +254,7 @@ struct uart_port { #define UPF_CONS_FLOW ((__force upf_t) (1 << 23)) #define UPF_SHARE_IRQ ((__force upf_t) (1 << 24)) #define UPF_BOOT_AUTOCONF ((__force upf_t) (1 << 28)) +#define UPF_DEAD ((__force upf_t) (1 << 30)) #define UPF_IOREMAP ((__force upf_t) (1 << 31)) #define UPF_CHANGE_MASK ((__force upf_t) (0x17fff)) -- cgit v1.2.3-70-g09d2 From 85835f442e5bbf9d3b8f6e574751da8db77016d2 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Sun, 30 Apr 2006 11:15:58 +0100 Subject: [SERIAL] AMD Alchemy UART: claim memory range I've noticed that the 8250/Au1x00 driver (drivers/serial/8250_au1x00.c) doesn't claim UART memory ranges and uses wrong (KSEG1-based) UART addresses instead of the physical ones. Signed-off-by: Sergei Shtylyov Signed-off-by: Russell King --- drivers/serial/8250.c | 6 ++++++ drivers/serial/8250_au1x00.c | 5 ++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 674b15c78f68..d641ac4e976e 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -1906,6 +1906,9 @@ static int serial8250_request_std_resource(struct uart_8250_port *up) int ret = 0; switch (up->port.iotype) { + case UPIO_AU: + size = 0x100000; + /* fall thru */ case UPIO_MEM: if (!up->port.mapbase) break; @@ -1938,6 +1941,9 @@ static void serial8250_release_std_resource(struct uart_8250_port *up) unsigned int size = 8 << up->port.regshift; switch (up->port.iotype) { + case UPIO_AU: + size = 0x100000; + /* fall thru */ case UPIO_MEM: if (!up->port.mapbase) break; diff --git a/drivers/serial/8250_au1x00.c b/drivers/serial/8250_au1x00.c index 3d1bfd07208d..58015fd14be9 100644 --- a/drivers/serial/8250_au1x00.c +++ b/drivers/serial/8250_au1x00.c @@ -30,13 +30,12 @@ { \ .iobase = _base, \ .membase = (void __iomem *)_base,\ - .mapbase = _base, \ + .mapbase = CPHYSADDR(_base), \ .irq = _irq, \ .uartclk = 0, /* filled */ \ .regshift = 2, \ .iotype = UPIO_AU, \ - .flags = UPF_SKIP_TEST | \ - UPF_IOREMAP, \ + .flags = UPF_SKIP_TEST \ } static struct plat_serial8250_port au1x00_data[] = { -- cgit v1.2.3-70-g09d2 From b32b19b8ffc05cbd3bf91c65e205f6a912ca15d9 Mon Sep 17 00:00:00 2001 From: Jon Anders Haugum Date: Sun, 30 Apr 2006 11:20:56 +0100 Subject: [SERIAL] 8250: set divisor register correctly for AMD Alchemy SoC uart Alchemy SoC uart have got a non-standard divisor register that needs some special handling. This patch adds divisor read/write functions with test and special handling for Alchemy internal uart. Signed-off-by: Jon Anders Haugum Signed-off-by: Russell King --- drivers/serial/8250.c | 55 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 13 deletions(-) diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index d641ac4e976e..9cc74712795d 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -362,6 +362,40 @@ serial_out(struct uart_8250_port *up, int offset, int value) #define serial_inp(up, offset) serial_in(up, offset) #define serial_outp(up, offset, value) serial_out(up, offset, value) +/* Uart divisor latch read */ +static inline int _serial_dl_read(struct uart_8250_port *up) +{ + return serial_inp(up, UART_DLL) | serial_inp(up, UART_DLM) << 8; +} + +/* Uart divisor latch write */ +static inline void _serial_dl_write(struct uart_8250_port *up, int value) +{ + serial_outp(up, UART_DLL, value & 0xff); + serial_outp(up, UART_DLM, value >> 8 & 0xff); +} + +#ifdef CONFIG_SERIAL_8250_AU1X00 +/* Au1x00 haven't got a standard divisor latch */ +static int serial_dl_read(struct uart_8250_port *up) +{ + if (up->port.iotype == UPIO_AU) + return __raw_readl(up->port.membase + 0x28); + else + return _serial_dl_read(up); +} + +static void serial_dl_write(struct uart_8250_port *up, int value) +{ + if (up->port.iotype == UPIO_AU) + __raw_writel(value, up->port.membase + 0x28); + else + _serial_dl_write(up, value); +} +#else +#define serial_dl_read(up) _serial_dl_read(up) +#define serial_dl_write(up, value) _serial_dl_write(up, value) +#endif /* * For the 16C950 @@ -494,7 +528,8 @@ static void disable_rsa(struct uart_8250_port *up) */ static int size_fifo(struct uart_8250_port *up) { - unsigned char old_fcr, old_mcr, old_dll, old_dlm, old_lcr; + unsigned char old_fcr, old_mcr, old_lcr; + unsigned short old_dl; int count; old_lcr = serial_inp(up, UART_LCR); @@ -505,10 +540,8 @@ static int size_fifo(struct uart_8250_port *up) UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); serial_outp(up, UART_MCR, UART_MCR_LOOP); serial_outp(up, UART_LCR, UART_LCR_DLAB); - old_dll = serial_inp(up, UART_DLL); - old_dlm = serial_inp(up, UART_DLM); - serial_outp(up, UART_DLL, 0x01); - serial_outp(up, UART_DLM, 0x00); + old_dl = serial_dl_read(up); + serial_dl_write(up, 0x0001); serial_outp(up, UART_LCR, 0x03); for (count = 0; count < 256; count++) serial_outp(up, UART_TX, count); @@ -519,8 +552,7 @@ static int size_fifo(struct uart_8250_port *up) serial_outp(up, UART_FCR, old_fcr); serial_outp(up, UART_MCR, old_mcr); serial_outp(up, UART_LCR, UART_LCR_DLAB); - serial_outp(up, UART_DLL, old_dll); - serial_outp(up, UART_DLM, old_dlm); + serial_dl_write(up, old_dl); serial_outp(up, UART_LCR, old_lcr); return count; @@ -750,8 +782,7 @@ static void autoconfig_16550a(struct uart_8250_port *up) serial_outp(up, UART_LCR, 0xE0); - quot = serial_inp(up, UART_DLM) << 8; - quot += serial_inp(up, UART_DLL); + quot = serial_dl_read(up); quot <<= 3; status1 = serial_in(up, 0x04); /* EXCR1 */ @@ -759,8 +790,7 @@ static void autoconfig_16550a(struct uart_8250_port *up) status1 |= 0x10; /* 1.625 divisor for baud_base --> 921600 */ serial_outp(up, 0x04, status1); - serial_outp(up, UART_DLL, quot & 0xff); - serial_outp(up, UART_DLM, quot >> 8); + serial_dl_write(up, quot); serial_outp(up, UART_LCR, 0); @@ -1862,8 +1892,7 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios, serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */ } - serial_outp(up, UART_DLL, quot & 0xff); /* LS of divisor */ - serial_outp(up, UART_DLM, quot >> 8); /* MS of divisor */ + serial_dl_write(up, quot); /* * LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR -- cgit v1.2.3-70-g09d2 From a88d75b257b2b28b26d7d4d2b640f05feb00ad53 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 30 Apr 2006 11:30:15 +0100 Subject: [SERIAL] Remove unconditional enable of TX irq for console A bug report from Gerd Hoffmann has highlighted that unconditionally enabling the transmit interrupt at the end of console writes is very bad. In Gerd's case, it causes the test for buggy UARTs to give false positives, incorrectly identifying ports as buggy when they are not. Moreover, if we unconditionally enable the interrupt, and the port is sharing it's interrupt with other ports, there is the very real possibility that we'll cause an interrupt storm. (Not all ports use OUT2 as an interrupt mask.) Hence, revert part of f91a3715db2bb44fcf08cec642e68f919b70f7f4 and all of f5968b37b3ad35b682b574b578843a0361218aff until a better solution can be found. Signed-off-by: Russell King --- drivers/serial/8250.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 9cc74712795d..e001ea0606ec 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -2256,8 +2256,7 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count) * and restore the IER */ wait_for_xmitr(up, BOTH_EMPTY); - up->ier |= UART_IER_THRI; - serial_out(up, UART_IER, ier | UART_IER_THRI); + serial_out(up, UART_IER, ier); } static int serial8250_console_setup(struct console *co, char *options) -- cgit v1.2.3-70-g09d2 From cd95842ca0ffb0e3df3b459832a60f9f4544ed9e Mon Sep 17 00:00:00 2001 From: Markus Gutschke Date: Sun, 30 Apr 2006 15:34:29 +0100 Subject: [ARM] 3486/1: Mark memory as clobbered by the ARM _syscallX() macros Patch from Markus Gutschke In order to prevent gcc from making incorrect optimizations, all asm() statements that define system calls should report memory as clobbered. Recent versions of the headers for i386 have been changed accordingly, but the ARM headers are still defective. This patch fixes the bug tracked at http://bugzilla.kernel.org/show_bug.cgi?id=6205 Signed-off-by: Markus Gutschke Signed-off-by: Russell King --- drivers/input/touchscreen/corgi_ts.c | 2 +- include/asm-arm/unistd.h | 21 ++++++++++++++------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/drivers/input/touchscreen/corgi_ts.c b/drivers/input/touchscreen/corgi_ts.c index 1042987856f7..5013703db0e6 100644 --- a/drivers/input/touchscreen/corgi_ts.c +++ b/drivers/input/touchscreen/corgi_ts.c @@ -17,7 +17,7 @@ #include #include #include -#include +//#include #include #include diff --git a/include/asm-arm/unistd.h b/include/asm-arm/unistd.h index ee8dfea549bc..26f2f4828e03 100644 --- a/include/asm-arm/unistd.h +++ b/include/asm-arm/unistd.h @@ -410,7 +410,8 @@ type name(void) { \ __asm__ __volatile__ ( \ __syscall(name) \ : "=r" (__res_r0) \ - : __SYS_REG_LIST() ); \ + : __SYS_REG_LIST() \ + : "memory" ); \ __res = __res_r0; \ __syscall_return(type,__res); \ } @@ -424,7 +425,8 @@ type name(type1 arg1) { \ __asm__ __volatile__ ( \ __syscall(name) \ : "=r" (__res_r0) \ - : __SYS_REG_LIST( "0" (__r0) ) ); \ + : __SYS_REG_LIST( "0" (__r0) ) \ + : "memory" ); \ __res = __res_r0; \ __syscall_return(type,__res); \ } @@ -439,7 +441,8 @@ type name(type1 arg1,type2 arg2) { \ __asm__ __volatile__ ( \ __syscall(name) \ : "=r" (__res_r0) \ - : __SYS_REG_LIST( "0" (__r0), "r" (__r1) ) ); \ + : __SYS_REG_LIST( "0" (__r0), "r" (__r1) ) \ + : "memory" ); \ __res = __res_r0; \ __syscall_return(type,__res); \ } @@ -456,7 +459,8 @@ type name(type1 arg1,type2 arg2,type3 arg3) { \ __asm__ __volatile__ ( \ __syscall(name) \ : "=r" (__res_r0) \ - : __SYS_REG_LIST( "0" (__r0), "r" (__r1), "r" (__r2) ) ); \ + : __SYS_REG_LIST( "0" (__r0), "r" (__r1), "r" (__r2) ) \ + : "memory" ); \ __res = __res_r0; \ __syscall_return(type,__res); \ } @@ -474,7 +478,8 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ __asm__ __volatile__ ( \ __syscall(name) \ : "=r" (__res_r0) \ - : __SYS_REG_LIST( "0" (__r0), "r" (__r1), "r" (__r2), "r" (__r3) ) ); \ + : __SYS_REG_LIST( "0" (__r0), "r" (__r1), "r" (__r2), "r" (__r3) ) \ + : "memory" ); \ __res = __res_r0; \ __syscall_return(type,__res); \ } @@ -494,7 +499,8 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) { \ __syscall(name) \ : "=r" (__res_r0) \ : __SYS_REG_LIST( "0" (__r0), "r" (__r1), "r" (__r2), \ - "r" (__r3), "r" (__r4) ) ); \ + "r" (__r3), "r" (__r4) ) \ + : "memory" ); \ __res = __res_r0; \ __syscall_return(type,__res); \ } @@ -514,7 +520,8 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6 __syscall(name) \ : "=r" (__res_r0) \ : __SYS_REG_LIST( "0" (__r0), "r" (__r1), "r" (__r2), \ - "r" (__r3), "r" (__r4), "r" (__r5) ) ); \ + "r" (__r3), "r" (__r4), "r" (__r5) ) \ + : "memory" ); \ __res = __res_r0; \ __syscall_return(type,__res); \ } -- cgit v1.2.3-70-g09d2 From 76bbb00288e569e7bd9ec18f45e4f814352260dd Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Sun, 30 Apr 2006 15:34:29 +0100 Subject: [ARM] 3487/1: IXP4xx: Support non-PCI systems Patch from Deepak Saxena This patch allows for the addition of IXP4xx systems that do not make use of the PCI interface by moving the CONFIG_PCI symbol selection to be platform-specific instead of for all of IXP4xx. If at least one machine with PCI support is built, the PCI code will be compiled in, but when building !PCI, this will drastically shrink the kernel size. Signed-off-by: Deepak Saxena Signed-off-by: Russell King --- arch/arm/Kconfig | 2 -- arch/arm/mach-ixp4xx/Kconfig | 15 ++++++++++++++- arch/arm/mach-ixp4xx/Makefile | 3 ++- include/asm-arm/arch-ixp4xx/io.h | 7 +++++++ include/asm-arm/arch-ixp4xx/memory.h | 2 +- 5 files changed, 24 insertions(+), 5 deletions(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 1dbf6ddb300d..08b7cc900cae 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -150,8 +150,6 @@ config ARCH_IOP3XX config ARCH_IXP4XX bool "IXP4xx-based" - select DMABOUNCE - select PCI help Support for Intel's IXP4XX (XScale) family of processors. diff --git a/arch/arm/mach-ixp4xx/Kconfig b/arch/arm/mach-ixp4xx/Kconfig index 5bf50a2a737d..2a39f9e481ad 100644 --- a/arch/arm/mach-ixp4xx/Kconfig +++ b/arch/arm/mach-ixp4xx/Kconfig @@ -11,6 +11,7 @@ comment "IXP4xx Platforms" config MACH_NSLU2 bool prompt "Linksys NSLU2" + select PCI help Say 'Y' here if you want your kernel to support Linksys's NSLU2 NAS device. For more information on this platform, @@ -18,6 +19,7 @@ config MACH_NSLU2 config ARCH_AVILA bool "Avila" + select PCI help Say 'Y' here if you want your kernel to support the Gateworks Avila Network Platform. For more information on this platform, @@ -25,6 +27,7 @@ config ARCH_AVILA config ARCH_ADI_COYOTE bool "Coyote" + select PCI help Say 'Y' here if you want your kernel to support the ADI Engineering Coyote Gateway Reference Platform. For more @@ -32,6 +35,7 @@ config ARCH_ADI_COYOTE config ARCH_IXDP425 bool "IXDP425" + select PCI help Say 'Y' here if you want your kernel to support Intel's IXDP425 Development Platform (Also known as Richfield). @@ -39,6 +43,7 @@ config ARCH_IXDP425 config MACH_IXDPG425 bool "IXDPG425" + select PCI help Say 'Y' here if you want your kernel to support Intel's IXDPG425 Development Platform (Also known as Montajade). @@ -46,6 +51,7 @@ config MACH_IXDPG425 config MACH_IXDP465 bool "IXDP465" + select PCI help Say 'Y' here if you want your kernel to support Intel's IXDP465 Development Platform (Also known as BMP). @@ -72,6 +78,7 @@ config ARCH_PRPMC1100 config MACH_NAS100D bool prompt "NAS100D" + select PCI help Say 'Y' here if you want your kernel to support Iomega's NAS 100d device. For more information on this platform, @@ -96,6 +103,7 @@ config CPU_IXP46X config MACH_GTWX5715 bool "Gemtek WX5715 (Linksys WRV54G)" depends on ARCH_IXP4XX + select PCI help This board is currently inside the Linksys WRV54G Gateways. @@ -110,11 +118,16 @@ config MACH_GTWX5715 "High Speed" UART is n/c (as far as I can tell) 20 Pin ARM/Xscale JTAG interface on J2 - comment "IXP4xx Options" +config DMABOUNCE + bool + default y + depends on PCI + config IXP4XX_INDIRECT_PCI bool "Use indirect PCI memory access" + depends on PCI help IXP4xx provides two methods of accessing PCI memory space: diff --git a/arch/arm/mach-ixp4xx/Makefile b/arch/arm/mach-ixp4xx/Makefile index 0471044fa179..5a4aaa0e0a09 100644 --- a/arch/arm/mach-ixp4xx/Makefile +++ b/arch/arm/mach-ixp4xx/Makefile @@ -2,8 +2,9 @@ # Makefile for the linux kernel. # -obj-y += common.o common-pci.o +obj-y += common.o +obj-$(CONFIG_PCI) += common-pci.o obj-$(CONFIG_ARCH_IXDP4XX) += ixdp425-pci.o ixdp425-setup.o obj-$(CONFIG_MACH_IXDPG425) += ixdpg425-pci.o coyote-setup.o obj-$(CONFIG_ARCH_ADI_COYOTE) += coyote-pci.o coyote-setup.o diff --git a/include/asm-arm/arch-ixp4xx/io.h b/include/asm-arm/arch-ixp4xx/io.h index 942b622455bc..b59520e56fc7 100644 --- a/include/asm-arm/arch-ixp4xx/io.h +++ b/include/asm-arm/arch-ixp4xx/io.h @@ -260,6 +260,12 @@ out: #endif +#ifndef CONFIG_PCI + +#define __io(v) v + +#else + /* * IXP4xx does not have a transparent cpu -> PCI I/O translation * window. Instead, it has a set of registers that must be tweaked @@ -578,6 +584,7 @@ __ixp4xx_iowrite32_rep(void __iomem *addr, const void *vaddr, u32 count) #define ioport_map(port, nr) ((void __iomem*)(port + PIO_OFFSET)) #define ioport_unmap(addr) +#endif // !CONFIG_PCI #endif // __ASM_ARM_ARCH_IO_H diff --git a/include/asm-arm/arch-ixp4xx/memory.h b/include/asm-arm/arch-ixp4xx/memory.h index ee211d28a3ef..af9667b57ab3 100644 --- a/include/asm-arm/arch-ixp4xx/memory.h +++ b/include/asm-arm/arch-ixp4xx/memory.h @@ -14,7 +14,7 @@ */ #define PHYS_OFFSET UL(0x00000000) -#ifndef __ASSEMBLY__ +#if !defined(__ASSEMBLY__) && defined(CONFIG_PCI) void ixp4xx_adjust_zones(int node, unsigned long *size, unsigned long *holes); -- cgit v1.2.3-70-g09d2 From 81d38428df26377c91e7e193aa4d2fdfdcda300a Mon Sep 17 00:00:00 2001 From: Pavel Pisa Date: Sun, 30 Apr 2006 15:35:54 +0100 Subject: [ARM] 3485/1: i.MX: MX1 SD/MMC fix of unintentional double start possibility Patch from Pavel Pisa The clock starting imxmci_start_clock() function contains hardware issue workaround, which repeats start attempt, if SDHC does not react on the first trial. But the second start attempt can be taken even, if the first succeed and test code misses time limited clock running phase due to delay caused by schedule to other task or some another device interrupt. This change enables to detect such situation. The performance is not issue, because usually at full clock rate only about six loops in delay cycle are needed. Signed-off-by: Pavel Pisa Acked-by: Sascha Hauer Signed-off-by: Russell King --- drivers/mmc/imxmmc.c | 54 +++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 11 deletions(-) diff --git a/drivers/mmc/imxmmc.c b/drivers/mmc/imxmmc.c index ffb7f55d3467..07f36c454bd6 100644 --- a/drivers/mmc/imxmmc.c +++ b/drivers/mmc/imxmmc.c @@ -102,6 +102,7 @@ struct imxmci_host { #define IMXMCI_PEND_CPU_DATA_b 5 #define IMXMCI_PEND_CARD_XCHG_b 6 #define IMXMCI_PEND_SET_INIT_b 7 +#define IMXMCI_PEND_STARTED_b 8 #define IMXMCI_PEND_IRQ_m (1 << IMXMCI_PEND_IRQ_b) #define IMXMCI_PEND_DMA_END_m (1 << IMXMCI_PEND_DMA_END_b) @@ -111,6 +112,7 @@ struct imxmci_host { #define IMXMCI_PEND_CPU_DATA_m (1 << IMXMCI_PEND_CPU_DATA_b) #define IMXMCI_PEND_CARD_XCHG_m (1 << IMXMCI_PEND_CARD_XCHG_b) #define IMXMCI_PEND_SET_INIT_m (1 << IMXMCI_PEND_SET_INIT_b) +#define IMXMCI_PEND_STARTED_m (1 << IMXMCI_PEND_STARTED_b) static void imxmci_stop_clock(struct imxmci_host *host) { @@ -131,23 +133,52 @@ static void imxmci_stop_clock(struct imxmci_host *host) dev_dbg(mmc_dev(host->mmc), "imxmci_stop_clock blocked, no luck\n"); } -static void imxmci_start_clock(struct imxmci_host *host) +static int imxmci_start_clock(struct imxmci_host *host) { - int i = 0; + unsigned int trials = 0; + unsigned int delay_limit = 128; + unsigned long flags; + MMC_STR_STP_CLK &= ~STR_STP_CLK_STOP_CLK; - while(i < 0x1000) { - if(!(i & 0x7f)) - MMC_STR_STP_CLK |= STR_STP_CLK_START_CLK; - if(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN) { - /* Check twice before cut */ + clear_bit(IMXMCI_PEND_STARTED_b, &host->pending_events); + + /* + * Command start of the clock, this usually succeeds in less + * then 6 delay loops, but during card detection (low clockrate) + * it takes up to 5000 delay loops and sometimes fails for the first time + */ + MMC_STR_STP_CLK |= STR_STP_CLK_START_CLK; + + do { + unsigned int delay = delay_limit; + + while(delay--){ if(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN) - return; + /* Check twice before cut */ + if(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN) + return 0; + + if(test_bit(IMXMCI_PEND_STARTED_b, &host->pending_events)) + return 0; } - i++; - } - dev_dbg(mmc_dev(host->mmc), "imxmci_start_clock blocked, no luck\n"); + local_irq_save(flags); + /* + * Ensure, that request is not doubled under all possible circumstances. + * It is possible, that cock running state is missed, because some other + * IRQ or schedule delays this function execution and the clocks has + * been already stopped by other means (response processing, SDHC HW) + */ + if(!test_bit(IMXMCI_PEND_STARTED_b, &host->pending_events)) + MMC_STR_STP_CLK |= STR_STP_CLK_START_CLK; + local_irq_restore(flags); + + } while(++trials<256); + + dev_err(mmc_dev(host->mmc), "imxmci_start_clock blocked, no luck\n"); + + return -1; } static void imxmci_softreset(void) @@ -622,6 +653,7 @@ static irqreturn_t imxmci_irq(int irq, void *devid, struct pt_regs *regs) atomic_set(&host->stuck_timeout, 0); host->status_reg = stat; set_bit(IMXMCI_PEND_IRQ_b, &host->pending_events); + set_bit(IMXMCI_PEND_STARTED_b, &host->pending_events); tasklet_schedule(&host->tasklet); return IRQ_RETVAL(handled);; -- cgit v1.2.3-70-g09d2 From c8d8b837ebe4b4f11e1b0c4a2bdc358c697692ed Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Tue, 25 Apr 2006 01:53:43 +0900 Subject: kbuild: fix modpost segfault for 64bit mipsel kernel 64bit mips has different r_info layout. This patch fixes modpost segfault for 64bit little endian mips kernel. Signed-off-by: Atsushi Nemoto Signed-off-by: Sam Ravnborg --- scripts/mod/modpost.c | 11 +++++++++-- scripts/mod/modpost.h | 19 +++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index cd00e9f07589..fcd4306fa002 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -709,10 +709,17 @@ static void check_sec_ref(struct module *mod, const char *modname, for (rela = start; rela < stop; rela++) { Elf_Rela r; const char *secname; + unsigned int r_sym; r.r_offset = TO_NATIVE(rela->r_offset); - r.r_info = TO_NATIVE(rela->r_info); + if (hdr->e_ident[EI_CLASS] == ELFCLASS64 && + hdr->e_machine == EM_MIPS) { + r_sym = ELF64_MIPS_R_SYM(rela->r_info); + r_sym = TO_NATIVE(r_sym); + } else { + r_sym = ELF_R_SYM(TO_NATIVE(rela->r_info)); + } r.r_addend = TO_NATIVE(rela->r_addend); - sym = elf->symtab_start + ELF_R_SYM(r.r_info); + sym = elf->symtab_start + r_sym; /* Skip special sections */ if (sym->st_shndx >= SHN_LORESERVE) continue; diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h index b14255c72a37..89b96c6d8ef5 100644 --- a/scripts/mod/modpost.h +++ b/scripts/mod/modpost.h @@ -39,6 +39,25 @@ #define ELF_R_TYPE ELF64_R_TYPE #endif +/* The 64-bit MIPS ELF ABI uses an unusual reloc format. */ +typedef struct +{ + Elf32_Word r_sym; /* Symbol index */ + unsigned char r_ssym; /* Special symbol for 2nd relocation */ + unsigned char r_type3; /* 3rd relocation type */ + unsigned char r_type2; /* 2nd relocation type */ + unsigned char r_type1; /* 1st relocation type */ +} _Elf64_Mips_R_Info; + +typedef union +{ + Elf64_Xword r_info_number; + _Elf64_Mips_R_Info r_info_fields; +} _Elf64_Mips_R_Info_union; + +#define ELF64_MIPS_R_SYM(i) \ + ((__extension__ (_Elf64_Mips_R_Info_union)(i)).r_info_fields.r_sym) + #if KERNEL_ELFDATA != HOST_ELFDATA static inline void __endian(const void *src, void *dest, unsigned int size) -- cgit v1.2.3-70-g09d2 From fca1dff218163ffd34d1e9e0b9b244e8c8803601 Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Mon, 24 Apr 2006 15:55:27 -0400 Subject: kbuild: removing .tmp_versions considered harmful Remove *.mod files but not .tmp_versions for external builds When "make install" is run as root, .tmp_versions is re-created and becomes owned by root. Subsequent "make" run by user fails because .tmp_versions cannot be removed. Signed-off-by: Pavel Roskin Signed-off-by: Sam Ravnborg --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 6bf99624bd4c..8517f7ba2473 100644 --- a/Makefile +++ b/Makefile @@ -796,8 +796,8 @@ prepare2: prepare3 outputmakefile prepare1: prepare2 include/linux/version.h include/asm \ include/config/MARKER ifneq ($(KBUILD_MODULES),) - $(Q)rm -rf $(MODVERDIR) $(Q)mkdir -p $(MODVERDIR) + $(Q)rm -f $(MODVERDIR)/* endif archprepare: prepare1 scripts_basic @@ -1086,8 +1086,8 @@ else # KBUILD_EXTMOD KBUILD_MODULES := 1 PHONY += crmodverdir crmodverdir: - $(Q)rm -rf $(MODVERDIR) $(Q)mkdir -p $(MODVERDIR) + $(Q)rm -f $(MODVERDIR)/* PHONY += $(objtree)/Module.symvers $(objtree)/Module.symvers: -- cgit v1.2.3-70-g09d2 From 72ee59b5797e5d6fe32b5cf3473660a50a02db40 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 15 Apr 2006 11:17:12 -0700 Subject: kbuild modpost - relax driver data name Relax driver data name from *_driver to *driver. This fixes the 26 section mismatch warnings in drivers/ide/pci. Signed-off-by: Randy Dunlap Signed-off-by: Sam Ravnborg --- scripts/mod/modpost.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index fcd4306fa002..b36e884f5f96 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -487,14 +487,14 @@ static int strrcmp(const char *s, const char *sub) * atsym =__param* * * Pattern 2: - * Many drivers utilise a *_driver container with references to + * Many drivers utilise a *driver container with references to * add, remove, probe functions etc. * These functions may often be marked __init and we do not want to * warn here. * the pattern is identified by: * tosec = .init.text | .exit.text | .init.data * fromsec = .data - * atsym = *_driver, *_template, *_sht, *_ops, *_probe, *probe_one + * atsym = *driver, *_template, *_sht, *_ops, *_probe, *probe_one **/ static int secref_whitelist(const char *tosec, const char *fromsec, const char *atsym) @@ -502,7 +502,7 @@ static int secref_whitelist(const char *tosec, const char *fromsec, int f1 = 1, f2 = 1; const char **s; const char *pat2sym[] = { - "_driver", + "driver", "_template", /* scsi uses *_template a lot */ "_sht", /* scsi also used *_sht to some extent */ "_ops", -- cgit v1.2.3-70-g09d2 From 46ed981d5d203703a01137cc58c841d34e90c147 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Sun, 30 Apr 2006 23:56:33 +0200 Subject: kbuild: fix gen_initramfs_list.sh Create correct dependencies when specifying your own file with list of files etc. to include in initramfs. Reported by: Andre Noll Signed-off-by: Sam Ravnborg --- scripts/gen_initramfs_list.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/gen_initramfs_list.sh b/scripts/gen_initramfs_list.sh index 56b3bed1108f..331c079f029b 100644 --- a/scripts/gen_initramfs_list.sh +++ b/scripts/gen_initramfs_list.sh @@ -200,7 +200,11 @@ input_file() { print_mtime "$1" >> ${output} cat "$1" >> ${output} else - grep ^file "$1" | cut -d ' ' -f 3 + cat "$1" | while read type dir file perm ; do + if [ "$type" == "file" ]; then + echo "$file \\"; + fi + done fi elif [ -d "$1" ]; then dir_filelist "$1" -- cgit v1.2.3-70-g09d2 From cc873e1aa1fa916a485294117a9846e668505671 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Sun, 30 Apr 2006 23:59:16 +0200 Subject: kbuild: drivers/video/logo/ - fix ident glitch Jan Engelhardt wrote: while compiling 2.6.17-rc2 with allyesconfig, this showed up: ... LOGO drivers/video/logo/logo_superh_clut224.c CC drivers/video/logo/logo_linux_mono.o ... A tab had sneaked in. Convert it to a few spaces. Signed-off-by: Sam Ravnborg --- drivers/video/logo/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/logo/Makefile b/drivers/video/logo/Makefile index 4ef5cd19609d..b985dfad6c63 100644 --- a/drivers/video/logo/Makefile +++ b/drivers/video/logo/Makefile @@ -34,7 +34,7 @@ extra-y += $(call logo-cfiles,_clut224,ppm) extra-y += $(call logo-cfiles,_gray256,pgm) # Create commands like "pnmtologo -t mono -n logo_mac_mono -o ..." -quiet_cmd_logo = LOGO $@ +quiet_cmd_logo = LOGO $@ cmd_logo = scripts/pnmtologo \ -t $(patsubst $*_%,%,$(notdir $(basename $<))) \ -n $(notdir $(basename $<)) -o $@ $< -- cgit v1.2.3-70-g09d2 From d8a5a8d7cc32e4474326e0ecc1b959063490efc9 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 2 May 2006 16:04:29 +0100 Subject: [SERIAL] 8250: add locking to console write function x86 SMP breaks as a result of the previous change, we have no real option other than to add locking to the 8250 console write function. If an oops is in progress, try to acquire the lock. If we fail to do so, continue anyway. Signed-off-by: Russell King --- drivers/serial/8250.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index e001ea0606ec..bbf78aaf9e01 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -2235,10 +2235,17 @@ static void serial8250_console_write(struct console *co, const char *s, unsigned int count) { struct uart_8250_port *up = &serial8250_ports[co->index]; + unsigned long flags; unsigned int ier; + int locked = 1; touch_nmi_watchdog(); + if (oops_in_progress) { + locked = spin_trylock_irqsave(&up->port.lock, flags); + } else + spin_lock_irqsave(&up->port.lock, flags); + /* * First save the IER then disable the interrupts */ @@ -2257,6 +2264,9 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count) */ wait_for_xmitr(up, BOTH_EMPTY); serial_out(up, UART_IER, ier); + + if (locked) + spin_unlock_irqrestore(&up->port.lock, flags); } static int serial8250_console_setup(struct console *co, char *options) -- cgit v1.2.3-70-g09d2 From 37be4e7809e0581db85387e126ae4da68c3d6286 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 2 May 2006 17:24:59 +0100 Subject: [MMC] extend data timeout for writes The CSD contains a "read2write factor" which determines the multiplier to be applied to the read timeout to obtain the write timeout. We were ignoring this parameter, resulting in the possibility for writes being timed out too early. Signed-off-by: Russell King --- drivers/mmc/mmc.c | 2 ++ drivers/mmc/mmc_block.c | 6 ++++++ include/linux/mmc/card.h | 1 + 3 files changed, 9 insertions(+) diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index da6ddd910fc5..05aa4d6b4f24 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -549,6 +549,7 @@ static void mmc_decode_csd(struct mmc_card *card) csd->read_partial = UNSTUFF_BITS(resp, 79, 1); csd->write_misalign = UNSTUFF_BITS(resp, 78, 1); csd->read_misalign = UNSTUFF_BITS(resp, 77, 1); + csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3); csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4); csd->write_partial = UNSTUFF_BITS(resp, 21, 1); } else { @@ -583,6 +584,7 @@ static void mmc_decode_csd(struct mmc_card *card) csd->read_partial = UNSTUFF_BITS(resp, 79, 1); csd->write_misalign = UNSTUFF_BITS(resp, 78, 1); csd->read_misalign = UNSTUFF_BITS(resp, 77, 1); + csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3); csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4); csd->write_partial = UNSTUFF_BITS(resp, 21, 1); } diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c index 8eb2a2ede64b..06bd1f4cb9b1 100644 --- a/drivers/mmc/mmc_block.c +++ b/drivers/mmc/mmc_block.c @@ -187,6 +187,12 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) brq.cmd.opcode = MMC_WRITE_BLOCK; brq.data.flags |= MMC_DATA_WRITE; brq.data.blocks = 1; + + /* + * Scale up the timeout by the r2w factor + */ + brq.data.timeout_ns <<= card->csd.r2w_factor; + brq.data.timeout_clks <<= card->csd.r2w_factor; } if (brq.data.blocks > 1) { diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 30dd978c1ec8..991a37382a22 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -28,6 +28,7 @@ struct mmc_csd { unsigned short cmdclass; unsigned short tacc_clks; unsigned int tacc_ns; + unsigned int r2w_factor; unsigned int max_dtr; unsigned int read_blkbits; unsigned int write_blkbits; -- cgit v1.2.3-70-g09d2 From 58741e8b3603e56c3699550e8bc89cb136329343 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 2 May 2006 20:02:39 +0100 Subject: [MMC] PXA and i.MX: don't avoid sending stop command on error Always send a stop command at the end of a data transfer. If we avoid sending the stop command, some cards remain in data transfer mode, and refuse to accept further read/write commands. Signed-off-by: Russell King --- drivers/mmc/imxmmc.c | 2 +- drivers/mmc/pxamci.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/imxmmc.c b/drivers/mmc/imxmmc.c index 07f36c454bd6..bc271925099a 100644 --- a/drivers/mmc/imxmmc.c +++ b/drivers/mmc/imxmmc.c @@ -529,7 +529,7 @@ static int imxmci_data_done(struct imxmci_host *host, unsigned int stat) data_error = imxmci_finish_data(host, stat); - if (host->req->stop && (data_error == MMC_ERR_NONE)) { + if (host->req->stop) { imxmci_stop_clock(host); imxmci_start_cmd(host, host->req->stop, 0); } else { diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c index eb42cb349420..15a5caa0bdeb 100644 --- a/drivers/mmc/pxamci.c +++ b/drivers/mmc/pxamci.c @@ -291,7 +291,7 @@ static int pxamci_data_done(struct pxamci_host *host, unsigned int stat) pxamci_disable_irq(host, DATA_TRAN_DONE); host->data = NULL; - if (host->mrq->stop && data->error == MMC_ERR_NONE) { + if (host->mrq->stop) { pxamci_stop_clock(host); pxamci_start_cmd(host, host->mrq->stop, 0); } else { -- cgit v1.2.3-70-g09d2 From d78e9079af7526c4661ff484322094832776ef41 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 2 May 2006 20:18:53 +0100 Subject: [MMC] PXA: reduce the number of lines PXAMCI debug uses There's no reason for the PXAMCI debug code to print so many lines - it causes the kernel buffer to overflow when trying to debug this driver. Remove some debug messages which are duplicated by core code, and combine other messages, resulting in fewer characters written to the kernel log. Signed-off-by: Russell King --- drivers/mmc/pxamci.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c index 15a5caa0bdeb..40970c4ae3e6 100644 --- a/drivers/mmc/pxamci.c +++ b/drivers/mmc/pxamci.c @@ -198,7 +198,6 @@ static void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd, static void pxamci_finish_request(struct pxamci_host *host, struct mmc_request *mrq) { - pr_debug("PXAMCI: request done\n"); host->mrq = NULL; host->cmd = NULL; host->data = NULL; @@ -309,12 +308,10 @@ static irqreturn_t pxamci_irq(int irq, void *devid, struct pt_regs *regs) ireg = readl(host->base + MMC_I_REG); - pr_debug("PXAMCI: irq %08x\n", ireg); - if (ireg) { unsigned stat = readl(host->base + MMC_STAT); - pr_debug("PXAMCI: stat %08x\n", stat); + pr_debug("PXAMCI: irq %08x stat %08x\n", ireg, stat); if (ireg & END_CMD_RES) handled |= pxamci_cmd_done(host, stat); @@ -368,7 +365,7 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct pxamci_host *host = mmc_priv(mmc); - pr_debug("pxamci_set_ios: clock %u power %u vdd %u.%02u\n", + pr_debug("PXAMCI: clock %u power %u vdd %u.%02u\n", ios->clock, ios->power_mode, ios->vdd / 100, ios->vdd % 100); @@ -397,7 +394,7 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) host->cmdat |= CMDAT_INIT; } - pr_debug("pxamci_set_ios: clkrt = %x cmdat = %x\n", + pr_debug("PXAMCI: clkrt = %x cmdat = %x\n", host->clkrt, host->cmdat); } -- cgit v1.2.3-70-g09d2 From b2556da55f78a9dbe92830b1d1c0b612edfea9fd Mon Sep 17 00:00:00 2001 From: Uwe Zeisberger Date: Tue, 2 May 2006 20:40:56 +0100 Subject: [ARM] 3488/1: make icedcc_putc do the right thing Patch from Uwe Zeisberger a) use coprocessor 14 b) make reading the dcc status volatile Signed-off-by: Uwe Zeisberger Signed-off-by: Russell King --- arch/arm/boot/compressed/misc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/compressed/misc.c b/arch/arm/boot/compressed/misc.c index 0af3772efcb7..ace3fb5835d9 100644 --- a/arch/arm/boot/compressed/misc.c +++ b/arch/arm/boot/compressed/misc.c @@ -38,10 +38,10 @@ static void icedcc_putc(int ch) if (--i < 0) return; - asm("mrc p14, 0, %0, c0, c0, 0" : "=r" (status)); + asm volatile ("mrc p14, 0, %0, c0, c0, 0" : "=r" (status)); } while (status & 2); - asm("mcr p15, 0, %0, c1, c0, 0" : : "r" (ch)); + asm("mcr p14, 0, %0, c1, c0, 0" : : "r" (ch)); } #define putc(ch) icedcc_putc(ch) -- cgit v1.2.3-70-g09d2 From 054d8ff37710efaebd1998ce94d366df315a354f Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Thu, 27 Apr 2006 02:31:20 -0700 Subject: [PATCH] powerpc/pseries: avoid crash in PCI code if mem system not up The powerpc code is currently performing PCI setup before memory initialization. PCI setup touches PCI config space registers. If the PCI card is bad, this will evoke an error, which currrently can't be handled, as the PCI error recovery code expects kmalloc() to be functional. This patch will cause the system to punt instead of crashing with cpu 0x0: Vector: 300 (Data Access) at [c0000000004434d0] pc: c0000000000c06b4: .kmem_cache_alloc+0x8c/0xf4 lr: c00000000004ad6c: .eeh_send_failure_event+0x48/0xfc This patch will also print name of the offending pci device. Signed-off-by: Linas Vepstas Cc: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pseries/eeh_event.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/powerpc/platforms/pseries/eeh_event.c b/arch/powerpc/platforms/pseries/eeh_event.c index a1bda6f96fd1..40020c65c89e 100644 --- a/arch/powerpc/platforms/pseries/eeh_event.c +++ b/arch/powerpc/platforms/pseries/eeh_event.c @@ -118,7 +118,15 @@ int eeh_send_failure_event (struct device_node *dn, { unsigned long flags; struct eeh_event *event; + char *location; + if (!mem_init_done) { + printk(KERN_ERR "EEH: event during early boot not handled\n"); + location = (char *) get_property(dn, "ibm,loc-code", NULL); + printk(KERN_ERR "EEH: device node = %s\n", dn->full_name); + printk(KERN_ERR "EEH: PCI location = %s\n", location); + return 1; + } event = kmalloc(sizeof(*event), GFP_ATOMIC); if (event == NULL) { printk (KERN_ERR "EEH: out of memory, event not handled\n"); -- cgit v1.2.3-70-g09d2 From 0ccde0a290b44b8296b82a7683b4c299eb51ba6b Mon Sep 17 00:00:00 2001 From: Ananth N Mavinakayanahalli Date: Fri, 28 Apr 2006 17:38:42 +0530 Subject: [PATCH] powerpc/kprobes: fix singlestep out-of-line We currently single-step inline if the instruction on which a kprobe is inserted is a trap variant. - variants (such as tdnei, used by BUG()) typically evaluate a condition and cause a trap only if the condition is satisfied. - kprobes uses the unconditional "trap" (0x7fe00008) and single-stepping again on this instruction, resulting in another trap without evaluating the condition is obviously incorrect. Signed-off-by: Ananth N Mavinakayanahalli Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/kprobes.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c index 856ef1a832b9..f78866367b70 100644 --- a/arch/powerpc/kernel/kprobes.c +++ b/arch/powerpc/kernel/kprobes.c @@ -90,15 +90,15 @@ void __kprobes arch_remove_kprobe(struct kprobe *p) static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs) { - kprobe_opcode_t insn = *p->ainsn.insn; - regs->msr |= MSR_SE; - /* single step inline if it is a trap variant */ - if (is_trap(insn)) - regs->nip = (unsigned long)p->addr; - else - regs->nip = (unsigned long)p->ainsn.insn; + /* + * On powerpc we should single step on the original + * instruction even if the probed insn is a trap + * variant as values in regs could play a part in + * if the trap is taken or not + */ + regs->nip = (unsigned long)p->ainsn.insn; } static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb) -- cgit v1.2.3-70-g09d2 From 61f5657c50341198ff05e375e6f1fc0476556562 Mon Sep 17 00:00:00 2001 From: Vitaly Bordug Date: Sat, 29 Apr 2006 22:32:44 +0400 Subject: [PATCH] ppc32 CPM_UART: Fixed break send on SCC SCC uart sends a break sequence each time it is stopped with the CPM_CR_STOP_TX command. That means that each time an application closes the serial device, a break is transmitted. To fix this, graceful tx stop is issued for SCC. Signed-off-by: David Jander Signed-off-by: Vitaly Bordug Signed-off-by: Paul Mackerras --- drivers/serial/cpm_uart/cpm_uart_core.c | 6 +++++- include/asm-ppc/commproc.h | 1 + include/asm-ppc/cpm2.h | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c index ced193bf9e1e..b9d1185df20c 100644 --- a/drivers/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/serial/cpm_uart/cpm_uart_core.c @@ -457,7 +457,11 @@ static void cpm_uart_shutdown(struct uart_port *port) } /* Shut them really down and reinit buffer descriptors */ - cpm_line_cr_cmd(line, CPM_CR_STOP_TX); + if (IS_SMC(pinfo)) + cpm_line_cr_cmd(line, CPM_CR_STOP_TX); + else + cpm_line_cr_cmd(line, CPM_CR_GRA_STOP_TX); + cpm_uart_initbd(pinfo); } } diff --git a/include/asm-ppc/commproc.h b/include/asm-ppc/commproc.h index 973e60908234..31f362966a58 100644 --- a/include/asm-ppc/commproc.h +++ b/include/asm-ppc/commproc.h @@ -35,6 +35,7 @@ #define CPM_CR_INIT_TX ((ushort)0x0002) #define CPM_CR_HUNT_MODE ((ushort)0x0003) #define CPM_CR_STOP_TX ((ushort)0x0004) +#define CPM_CR_GRA_STOP_TX ((ushort)0x0005) #define CPM_CR_RESTART_TX ((ushort)0x0006) #define CPM_CR_CLOSE_RX_BD ((ushort)0x0007) #define CPM_CR_SET_GADDR ((ushort)0x0008) diff --git a/include/asm-ppc/cpm2.h b/include/asm-ppc/cpm2.h index b638b87cebe3..c70344b91049 100644 --- a/include/asm-ppc/cpm2.h +++ b/include/asm-ppc/cpm2.h @@ -69,7 +69,7 @@ #define CPM_CR_INIT_TX ((ushort)0x0002) #define CPM_CR_HUNT_MODE ((ushort)0x0003) #define CPM_CR_STOP_TX ((ushort)0x0004) -#define CPM_CR_GRA_STOP_TX ((ushort)0x0005) +#define CPM_CR_GRA_STOP_TX ((ushort)0x0005) #define CPM_CR_RESTART_TX ((ushort)0x0006) #define CPM_CR_SET_GADDR ((ushort)0x0008) #define CPM_CR_START_IDMA ((ushort)0x0009) -- cgit v1.2.3-70-g09d2 From 6e1976961c9bd9a3dc368139fab1883961efc879 Mon Sep 17 00:00:00 2001 From: Vitaly Bordug Date: Sat, 29 Apr 2006 23:06:00 +0400 Subject: [PATCH] ppc32 CPM_UART: fixes and improvements A number of small issues are fixed, and added the header file, missed from the original series. With this, driver should be pretty stable as tested among both platform-device-driven and "old way" boards. Also added missing GPL statement , and updated year field on existing ones to reflect code update. Signed-off-by: Vitaly Bordug Signed-off-by: Paul Mackerras --- arch/ppc/platforms/mpc866ads_setup.c | 2 +- drivers/serial/cpm_uart/cpm_uart.h | 19 ++++++++--- drivers/serial/cpm_uart/cpm_uart_core.c | 31 +++++++++++++---- drivers/serial/cpm_uart/cpm_uart_cpm1.c | 2 ++ drivers/serial/cpm_uart/cpm_uart_cpm2.c | 2 ++ include/linux/fs_uart_pd.h | 60 +++++++++++++++++++++++++++++++++ 6 files changed, 104 insertions(+), 12 deletions(-) create mode 100644 include/linux/fs_uart_pd.h diff --git a/arch/ppc/platforms/mpc866ads_setup.c b/arch/ppc/platforms/mpc866ads_setup.c index 6ce3b842defe..d919dab61347 100644 --- a/arch/ppc/platforms/mpc866ads_setup.c +++ b/arch/ppc/platforms/mpc866ads_setup.c @@ -378,7 +378,7 @@ int __init mpc866ads_init(void) ppc_sys_device_setfunc(MPC8xx_CPM_SMC1, PPC_SYS_FUNC_UART); #endif -#ifdef CONFIG_SERIAL_CPM_SMCer +#ifdef CONFIG_SERIAL_CPM_SMC ppc_sys_device_enable(MPC8xx_CPM_SMC2); ppc_sys_device_setfunc(MPC8xx_CPM_SMC2, PPC_SYS_FUNC_UART); #endif diff --git a/drivers/serial/cpm_uart/cpm_uart.h b/drivers/serial/cpm_uart/cpm_uart.h index aa5eb7ddeda9..3b35cb779539 100644 --- a/drivers/serial/cpm_uart/cpm_uart.h +++ b/drivers/serial/cpm_uart/cpm_uart.h @@ -5,6 +5,13 @@ * * Copyright (C) 2004 Freescale Semiconductor, Inc. * + * 2006 (c) MontaVista Software, Inc. + * Vitaly Bordug + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + * */ #ifndef CPM_UART_H #define CPM_UART_H @@ -101,12 +108,13 @@ static inline unsigned long cpu2cpm_addr(void* addr, struct uart_cpm_port *pinfo int offset; u32 val = (u32)addr; /* sane check */ - if ((val >= (u32)pinfo->mem_addr) && + if (likely((val >= (u32)pinfo->mem_addr)) && (val<((u32)pinfo->mem_addr + pinfo->mem_size))) { offset = val - (u32)pinfo->mem_addr; return pinfo->dma_addr+offset; } - printk("%s(): address %x to translate out of range!\n", __FUNCTION__, val); + /* something nasty happened */ + BUG(); return 0; } @@ -115,12 +123,13 @@ static inline void *cpm2cpu_addr(unsigned long addr, struct uart_cpm_port *pinfo int offset; u32 val = addr; /* sane check */ - if ((val >= pinfo->dma_addr) && - (val<(pinfo->dma_addr + pinfo->mem_size))) { + if (likely((val >= pinfo->dma_addr) && + (val<(pinfo->dma_addr + pinfo->mem_size)))) { offset = val - (u32)pinfo->dma_addr; return (void*)(pinfo->mem_addr+offset); } - printk("%s(): address %x to translate out of range!\n", __FUNCTION__, val); + /* something nasty happened */ + BUG(); return 0; } diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c index b9d1185df20c..969f94900431 100644 --- a/drivers/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/serial/cpm_uart/cpm_uart_core.c @@ -12,7 +12,8 @@ * * Copyright (C) 2004 Freescale Semiconductor, Inc. * (C) 2004 Intracom, S.A. - * (C) 2005 MontaVista Software, Inc. by Vitaly Bordug + * (C) 2005-2006 MontaVista Software, Inc. + * Vitaly Bordug * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -81,7 +82,7 @@ early_uart_get_pdev(int index) } -void cpm_uart_count(void) +static void cpm_uart_count(void) { cpm_uart_nr = 0; #ifdef CONFIG_SERIAL_CPM_SMC1 @@ -104,6 +105,21 @@ void cpm_uart_count(void) #endif } +/* Get UART number by its id */ +static int cpm_uart_id2nr(int id) +{ + int i; + if (id < UART_NR) { + for (i=0; ifs_no; line++); + line = cpm_uart_id2nr(idx); + if(line < 0) { + printk(KERN_ERR"%s(): port %d is not registered", __FUNCTION__, idx); + return -1; + } pinfo = (struct uart_cpm_port *) &cpm_uart_ports[idx]; @@ -1245,8 +1265,7 @@ static int cpm_uart_drv_probe(struct device *dev) } pdata = pdev->dev.platform_data; - pr_debug("cpm_uart_drv_probe: Adding CPM UART %d\n", - cpm_uart_port_map[pdata->fs_no]); + pr_debug("cpm_uart_drv_probe: Adding CPM UART %d\n", cpm_uart_id2nr(pdata->fs_no)); if ((ret = cpm_uart_drv_get_platform_data(pdev, 0))) return ret; @@ -1265,7 +1284,7 @@ static int cpm_uart_drv_remove(struct device *dev) struct fs_uart_platform_info *pdata = pdev->dev.platform_data; pr_debug("cpm_uart_drv_remove: Removing CPM UART %d\n", - cpm_uart_port_map[pdata->fs_no]); + cpm_uart_id2nr(pdata->fs_no)); uart_remove_one_port(&cpm_reg, &cpm_uart_ports[pdata->fs_no].port); return 0; diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/serial/cpm_uart/cpm_uart_cpm1.c index a5a30622637a..17406a05ce1f 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm1.c +++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.c @@ -8,6 +8,8 @@ * * Copyright (C) 2004 Freescale Semiconductor, Inc. * (C) 2004 Intracom, S.A. + * (C) 2006 MontaVista Software, Inc. + * Vitaly Bordug * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/serial/cpm_uart/cpm_uart_cpm2.c index 7c6b07aeea92..4b2de08f46d0 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm2.c +++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.c @@ -8,6 +8,8 @@ * * Copyright (C) 2004 Freescale Semiconductor, Inc. * (C) 2004 Intracom, S.A. + * (C) 2006 MontaVista Software, Inc. + * Vitaly Bordug * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/include/linux/fs_uart_pd.h b/include/linux/fs_uart_pd.h new file mode 100644 index 000000000000..f5975126b712 --- /dev/null +++ b/include/linux/fs_uart_pd.h @@ -0,0 +1,60 @@ +/* + * Platform information definitions for the CPM Uart driver. + * + * 2006 (c) MontaVista Software, Inc. + * Vitaly Bordug + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#ifndef FS_UART_PD_H +#define FS_UART_PD_H + +#include +#include + +enum fs_uart_id { + fsid_smc1_uart, + fsid_smc2_uart, + fsid_scc1_uart, + fsid_scc2_uart, + fsid_scc3_uart, + fsid_scc4_uart, + fs_uart_nr, +}; + +static inline int fs_uart_id_scc2fsid(int id) +{ + return fsid_scc1_uart + id - 1; +} + +static inline int fs_uart_id_fsid2scc(int id) +{ + return id - fsid_scc1_uart + 1; +} + +static inline int fs_uart_id_smc2fsid(int id) +{ + return fsid_smc1_uart + id - 1; +} + +static inline int fs_uart_id_fsid2smc(int id) +{ + return id - fsid_smc1_uart + 1; +} + +struct fs_uart_platform_info { + void(*init_ioports)(void); + /* device specific information */ + int fs_no; /* controller index */ + u32 uart_clk; + u8 tx_num_fifo; + u8 tx_buf_size; + u8 rx_num_fifo; + u8 rx_buf_size; + u8 brg; +}; + +#endif -- cgit v1.2.3-70-g09d2 From 6bfd93c32a5065d0e858780b3beb0b667081601c Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 3 May 2006 23:02:04 +1000 Subject: powerpc: Fix incorrect might_sleep in __get_user/__put_user on kernel addresses We have a case where __get_user and __put_user can validly be used on kernel addresses in interrupt context - namely, the alignment exception handler, as our get/put_unaligned just do a single access and rely on the alignment exception handler to fix things up in the rare cases where the cpu can't handle it in hardware. Thus we can get alignment exceptions in the network stack at interrupt level. The alignment exception handler does a __get_user to read the instruction and blows up in might_sleep(). Since a __get_user on a kernel address won't actually ever sleep, this makes the might_sleep conditional on the address being less than PAGE_OFFSET. Signed-off-by: Paul Mackerras --- include/asm-powerpc/uaccess.h | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/include/asm-powerpc/uaccess.h b/include/asm-powerpc/uaccess.h index 3872e924cdd6..d83fc29c2bbf 100644 --- a/include/asm-powerpc/uaccess.h +++ b/include/asm-powerpc/uaccess.h @@ -7,6 +7,7 @@ #include #include #include +#include #define VERIFY_READ 0 #define VERIFY_WRITE 1 @@ -179,9 +180,11 @@ do { \ #define __put_user_nocheck(x, ptr, size) \ ({ \ long __pu_err; \ - might_sleep(); \ + __typeof__(*(ptr)) __user *__pu_addr = (ptr); \ + if (!is_kernel_addr((unsigned long)__pu_addr)) \ + might_sleep(); \ __chk_user_ptr(ptr); \ - __put_user_size((x), (ptr), (size), __pu_err); \ + __put_user_size((x), __pu_addr, (size), __pu_err); \ __pu_err; \ }) @@ -258,9 +261,11 @@ do { \ ({ \ long __gu_err; \ unsigned long __gu_val; \ + const __typeof__(*(ptr)) __user *__gu_addr = (ptr); \ __chk_user_ptr(ptr); \ - might_sleep(); \ - __get_user_size(__gu_val, (ptr), (size), __gu_err); \ + if (!is_kernel_addr((unsigned long)__gu_addr)) \ + might_sleep(); \ + __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \ (x) = (__typeof__(*(ptr)))__gu_val; \ __gu_err; \ }) @@ -270,9 +275,11 @@ do { \ ({ \ long __gu_err; \ long long __gu_val; \ + const __typeof__(*(ptr)) __user *__gu_addr = (ptr); \ __chk_user_ptr(ptr); \ - might_sleep(); \ - __get_user_size(__gu_val, (ptr), (size), __gu_err); \ + if (!is_kernel_addr((unsigned long)__gu_addr)) \ + might_sleep(); \ + __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \ (x) = (__typeof__(*(ptr)))__gu_val; \ __gu_err; \ }) -- cgit v1.2.3-70-g09d2 From d205819e2346d20fee41297ea6cf789c591abccf Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 3 May 2006 23:04:37 +1000 Subject: [PATCH] powerpc: Use the ibm,pa-features property if available Forthcoming IBM machines will have a "ibm,pa-features" property on CPU nodes, that contains bits indicating which optional architecture features are implemented by the CPU. This adds code to use the property, if present, to update our CPU feature bitmaps. Note that this means we can both set and clear feature bits based on what the firmware tells us. This is based on a patch by Will Schmidt . Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/prom.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 1cb69e8fb0b1..9a07f97f0712 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -885,6 +885,74 @@ void __init unflatten_device_tree(void) DBG(" <- unflatten_device_tree()\n"); } +/* + * ibm,pa-features is a per-cpu property that contains a string of + * attribute descriptors, each of which has a 2 byte header plus up + * to 254 bytes worth of processor attribute bits. First header + * byte specifies the number of bytes following the header. + * Second header byte is an "attribute-specifier" type, of which + * zero is the only currently-defined value. + * Implementation: Pass in the byte and bit offset for the feature + * that we are interested in. The function will return -1 if the + * pa-features property is missing, or a 1/0 to indicate if the feature + * is supported/not supported. Note that the bit numbers are + * big-endian to match the definition in PAPR. + */ +static struct ibm_pa_feature { + unsigned long cpu_features; /* CPU_FTR_xxx bit */ + unsigned int cpu_user_ftrs; /* PPC_FEATURE_xxx bit */ + unsigned char pabyte; /* byte number in ibm,pa-features */ + unsigned char pabit; /* bit number (big-endian) */ + unsigned char invert; /* if 1, pa bit set => clear feature */ +} ibm_pa_features[] __initdata = { + {0, PPC_FEATURE_HAS_MMU, 0, 0, 0}, + {0, PPC_FEATURE_HAS_FPU, 0, 1, 0}, + {CPU_FTR_SLB, 0, 0, 2, 0}, + {CPU_FTR_CTRL, 0, 0, 3, 0}, + {CPU_FTR_NOEXECUTE, 0, 0, 6, 0}, + {CPU_FTR_NODSISRALIGN, 0, 1, 1, 1}, + {CPU_FTR_CI_LARGE_PAGE, 0, 1, 2, 0}, +}; + +static void __init check_cpu_pa_features(unsigned long node) +{ + unsigned char *pa_ftrs; + unsigned long len, tablelen, i, bit; + + pa_ftrs = of_get_flat_dt_prop(node, "ibm,pa-features", &tablelen); + if (pa_ftrs == NULL) + return; + + /* find descriptor with type == 0 */ + for (;;) { + if (tablelen < 3) + return; + len = 2 + pa_ftrs[0]; + if (tablelen < len) + return; /* descriptor 0 not found */ + if (pa_ftrs[1] == 0) + break; + tablelen -= len; + pa_ftrs += len; + } + + /* loop over bits we know about */ + for (i = 0; i < ARRAY_SIZE(ibm_pa_features); ++i) { + struct ibm_pa_feature *fp = &ibm_pa_features[i]; + + if (fp->pabyte >= pa_ftrs[0]) + continue; + bit = (pa_ftrs[2 + fp->pabyte] >> (7 - fp->pabit)) & 1; + if (bit ^ fp->invert) { + cur_cpu_spec->cpu_features |= fp->cpu_features; + cur_cpu_spec->cpu_user_features |= fp->cpu_user_ftrs; + } else { + cur_cpu_spec->cpu_features &= ~fp->cpu_features; + cur_cpu_spec->cpu_user_features &= ~fp->cpu_user_ftrs; + } + } +} + static int __init early_init_dt_scan_cpus(unsigned long node, const char *uname, int depth, void *data) @@ -969,6 +1037,8 @@ static int __init early_init_dt_scan_cpus(unsigned long node, } #endif /* CONFIG_ALTIVEC */ + check_cpu_pa_features(node); + #ifdef CONFIG_PPC_PSERIES if (nthreads > 1) cur_cpu_spec->cpu_features |= CPU_FTR_SMT; -- cgit v1.2.3-70-g09d2 From 30d55280b867aa0cae99f836ad0181bb0bf8f9cb Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Wed, 3 May 2006 10:52:36 -0400 Subject: [PATCH] selinux: Clear selinux_enabled flag upon runtime disable. Clear selinux_enabled flag upon runtime disable of SELinux by userspace, and make sure it is defined even if selinux= boot parameter support is not enabled in configuration. Signed-off-by: Stephen Smalley Acked-by: James Morris Tested-by: Jon Smirl Acked-by: Al Viro Signed-off-by: Linus Torvalds --- security/selinux/hooks.c | 3 +++ security/selinux/include/security.h | 5 ----- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 3cf368a16448..d987048d3f33 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -101,6 +101,8 @@ static int __init selinux_enabled_setup(char *str) return 1; } __setup("selinux=", selinux_enabled_setup); +#else +int selinux_enabled = 1; #endif /* Original (dummy) security module. */ @@ -4535,6 +4537,7 @@ int selinux_disable(void) printk(KERN_INFO "SELinux: Disabled at runtime.\n"); selinux_disabled = 1; + selinux_enabled = 0; /* Reset security_ops to the secondary module, dummy or capability. */ security_ops = secondary_ops; diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 5f016c98056f..063af47bb231 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -29,12 +29,7 @@ #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE #define POLICYDB_VERSION_MAX POLICYDB_VERSION_AVTAB -#ifdef CONFIG_SECURITY_SELINUX_BOOTPARAM extern int selinux_enabled; -#else -#define selinux_enabled 1 -#endif - extern int selinux_mls_enabled; int security_load_policy(void * data, size_t len); -- cgit v1.2.3-70-g09d2 From 6e1cad02763edec83dba8559d4be8d518a6562a5 Mon Sep 17 00:00:00 2001 From: Eric Moore Date: Tue, 25 Apr 2006 17:38:58 -0600 Subject: [SCSI] mptspi: revalidate negotiation parameters after host reset and resume This is a bug fix for mptspi driver, where after a host reset or resume, we revalidate the negotiation parameters for all devices. This bug was introduced when the driver was ported to use the spi transport layer. Signed-off-by: Eric Moore Signed-off-by: James Bottomley --- drivers/message/fusion/mptspi.c | 68 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 66 insertions(+), 2 deletions(-) diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c index 09c745b19cc8..f2a4d382ea19 100644 --- a/drivers/message/fusion/mptspi.c +++ b/drivers/message/fusion/mptspi.c @@ -783,6 +783,70 @@ static struct pci_device_id mptspi_pci_table[] = { }; MODULE_DEVICE_TABLE(pci, mptspi_pci_table); + +/* + * renegotiate for a given target + */ +static void +mptspi_dv_renegotiate_work(void *data) +{ + struct work_queue_wrapper *wqw = (struct work_queue_wrapper *)data; + struct _MPT_SCSI_HOST *hd = wqw->hd; + struct scsi_device *sdev; + + kfree(wqw); + + shost_for_each_device(sdev, hd->ioc->sh) + mptspi_dv_device(hd, sdev); +} + +static void +mptspi_dv_renegotiate(struct _MPT_SCSI_HOST *hd) +{ + struct work_queue_wrapper *wqw = kmalloc(sizeof(*wqw), GFP_ATOMIC); + + if (!wqw) + return; + + INIT_WORK(&wqw->work, mptspi_dv_renegotiate_work, wqw); + wqw->hd = hd; + + schedule_work(&wqw->work); +} + +/* + * spi module reset handler + */ +static int +mptspi_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) +{ + struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)ioc->sh->hostdata; + int rc; + + rc = mptscsih_ioc_reset(ioc, reset_phase); + + if (reset_phase == MPT_IOC_POST_RESET) + mptspi_dv_renegotiate(hd); + + return rc; +} + +/* + * spi module resume handler + */ +static int +mptspi_resume(struct pci_dev *pdev) +{ + MPT_ADAPTER *ioc = pci_get_drvdata(pdev); + struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)ioc->sh->hostdata; + int rc; + + rc = mptscsih_resume(pdev); + mptspi_dv_renegotiate(hd); + + return rc; +} + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -1032,7 +1096,7 @@ static struct pci_driver mptspi_driver = { .shutdown = mptscsih_shutdown, #ifdef CONFIG_PM .suspend = mptscsih_suspend, - .resume = mptscsih_resume, + .resume = mptspi_resume, #endif }; @@ -1061,7 +1125,7 @@ mptspi_init(void) ": Registered for IOC event notifications\n")); } - if (mpt_reset_register(mptspiDoneCtx, mptscsih_ioc_reset) == 0) { + if (mpt_reset_register(mptspiDoneCtx, mptspi_ioc_reset) == 0) { dprintk((KERN_INFO MYNAM ": Registered for IOC reset notifications\n")); } -- cgit v1.2.3-70-g09d2 From 0b18ac42aa036c7fa217f178aa6a02c66e19e0a1 Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 1 May 2006 21:50:40 -0400 Subject: [SCSI] lpfc 8.1.6 : Fix Data Corruption in Bus Reset Path This patch updates the lpfc driver to revision 8.1.6, which includes the following changes: - Fix data corruption in SCSI BUS reset path, due to reusing the same request structure for each target. - Change version number to 8.1.6 Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_scsi.c | 68 +++++++++++----------------------------- drivers/scsi/lpfc/lpfc_version.h | 2 +- 2 files changed, 20 insertions(+), 50 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index f93799873721..7dc4c2e6bed2 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -629,8 +629,7 @@ lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq; IOCB_t *piocb; struct fcp_cmnd *fcp_cmnd; - struct scsi_device *scsi_dev = lpfc_cmd->pCmd->device; - struct lpfc_rport_data *rdata = scsi_dev->hostdata; + struct lpfc_rport_data *rdata = lpfc_cmd->rdata; struct lpfc_nodelist *ndlp = rdata->pnode; if ((ndlp == NULL) || (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) { @@ -665,56 +664,18 @@ lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_hba *phba, piocb->ulpTimeout = lpfc_cmd->timeout; } - lpfc_cmd->rdata = rdata; - - switch (task_mgmt_cmd) { - case FCP_LUN_RESET: - /* Issue LUN Reset to TGT LUN */ - lpfc_printf_log(phba, - KERN_INFO, - LOG_FCP, - "%d:0703 Issue LUN Reset to TGT %d LUN %d " - "Data: x%x x%x\n", - phba->brd_no, - scsi_dev->id, scsi_dev->lun, - ndlp->nlp_rpi, ndlp->nlp_flag); - - break; - case FCP_ABORT_TASK_SET: - /* Issue Abort Task Set to TGT LUN */ - lpfc_printf_log(phba, - KERN_INFO, - LOG_FCP, - "%d:0701 Issue Abort Task Set to TGT %d LUN %d " - "Data: x%x x%x\n", - phba->brd_no, - scsi_dev->id, scsi_dev->lun, - ndlp->nlp_rpi, ndlp->nlp_flag); - - break; - case FCP_TARGET_RESET: - /* Issue Target Reset to TGT */ - lpfc_printf_log(phba, - KERN_INFO, - LOG_FCP, - "%d:0702 Issue Target Reset to TGT %d " - "Data: x%x x%x\n", - phba->brd_no, - scsi_dev->id, ndlp->nlp_rpi, - ndlp->nlp_flag); - break; - } - return (1); } static int -lpfc_scsi_tgt_reset(struct lpfc_scsi_buf * lpfc_cmd, struct lpfc_hba * phba) +lpfc_scsi_tgt_reset(struct lpfc_scsi_buf * lpfc_cmd, struct lpfc_hba * phba, + unsigned tgt_id, struct lpfc_rport_data *rdata) { struct lpfc_iocbq *iocbq; struct lpfc_iocbq *iocbqrsp; int ret; + lpfc_cmd->rdata = rdata; ret = lpfc_scsi_prep_task_mgmt_cmd(phba, lpfc_cmd, FCP_TARGET_RESET); if (!ret) return FAILED; @@ -726,6 +687,13 @@ lpfc_scsi_tgt_reset(struct lpfc_scsi_buf * lpfc_cmd, struct lpfc_hba * phba) if (!iocbqrsp) return FAILED; + /* Issue Target Reset to TGT */ + lpfc_printf_log(phba, KERN_INFO, LOG_FCP, + "%d:0702 Issue Target Reset to TGT %d " + "Data: x%x x%x\n", + phba->brd_no, tgt_id, rdata->pnode->nlp_rpi, + rdata->pnode->nlp_flag); + ret = lpfc_sli_issue_iocb_wait(phba, &phba->sli.ring[phba->sli.fcp_ring], iocbq, iocbqrsp, lpfc_cmd->timeout); @@ -1021,6 +989,7 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd) lpfc_cmd->pCmd = cmnd; lpfc_cmd->timeout = 60; lpfc_cmd->scsi_hba = phba; + lpfc_cmd->rdata = rdata; ret = lpfc_scsi_prep_task_mgmt_cmd(phba, lpfc_cmd, FCP_LUN_RESET); if (!ret) @@ -1033,6 +1002,11 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd) if (iocbqrsp == NULL) goto out_free_scsi_buf; + lpfc_printf_log(phba, KERN_INFO, LOG_FCP, + "%d:0703 Issue LUN Reset to TGT %d LUN %d " + "Data: x%x x%x\n", phba->brd_no, cmnd->device->id, + cmnd->device->lun, pnode->nlp_rpi, pnode->nlp_flag); + ret = lpfc_sli_issue_iocb_wait(phba, &phba->sli.ring[phba->sli.fcp_ring], iocbq, iocbqrsp, lpfc_cmd->timeout); @@ -1104,7 +1078,6 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd) int match; int ret = FAILED, i, err_count = 0; int cnt, loopcnt; - unsigned int midlayer_id = 0; struct lpfc_scsi_buf * lpfc_cmd; lpfc_block_requests(phba); @@ -1124,7 +1097,6 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd) * targets known to the driver. Should any target reset * fail, this routine returns failure to the midlayer. */ - midlayer_id = cmnd->device->id; for (i = 0; i < MAX_FCP_TARGET; i++) { /* Search the mapped list for this target ID */ match = 0; @@ -1137,9 +1109,8 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd) if (!match) continue; - lpfc_cmd->pCmd->device->id = i; - lpfc_cmd->pCmd->device->hostdata = ndlp->rport->dd_data; - ret = lpfc_scsi_tgt_reset(lpfc_cmd, phba); + ret = lpfc_scsi_tgt_reset(lpfc_cmd, phba, + i, ndlp->rport->dd_data); if (ret != SUCCESS) { lpfc_printf_log(phba, KERN_ERR, LOG_FCP, "%d:0713 Bus Reset on target %d failed\n", @@ -1158,7 +1129,6 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd) * the targets. Unfortunately, some targets do not abide by * this forcing the driver to double check. */ - cmnd->device->id = midlayer_id; cnt = lpfc_sli_sum_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring], 0, 0, LPFC_CTX_HOST); if (cnt) diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index d0f2dc310b00..6b737568b831 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -18,7 +18,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "8.1.5" +#define LPFC_DRIVER_VERSION "8.1.6" #define LPFC_DRIVER_NAME "lpfc" -- cgit v1.2.3-70-g09d2 From 8c45112b823972e9ff7bbca77dc592ca2224951b Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 3 May 2006 13:55:46 -0700 Subject: [SPARC]: Hook up vmsplice into syscall tables. Signed-off-by: David S. Miller --- arch/sparc/kernel/systbls.S | 2 +- arch/sparc64/kernel/sys32.S | 1 + arch/sparc64/kernel/systbls.S | 4 ++-- include/asm-sparc/unistd.h | 2 +- include/asm-sparc64/unistd.h | 2 +- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/arch/sparc/kernel/systbls.S b/arch/sparc/kernel/systbls.S index db8faa75f94d..6e1135cc03b0 100644 --- a/arch/sparc/kernel/systbls.S +++ b/arch/sparc/kernel/systbls.S @@ -23,7 +23,7 @@ sys_call_table: /*10*/ .long sys_unlink, sunos_execv, sys_chdir, sys_chown16, sys_mknod /*15*/ .long sys_chmod, sys_lchown16, sparc_brk, sys_nis_syscall, sys_lseek /*20*/ .long sys_getpid, sys_capget, sys_capset, sys_setuid16, sys_getuid16 -/*25*/ .long sys_time, sys_ptrace, sys_alarm, sys_sigaltstack, sys_pause +/*25*/ .long sys_vmsplice, sys_ptrace, sys_alarm, sys_sigaltstack, sys_pause /*30*/ .long sys_utime, sys_lchown, sys_fchown, sys_access, sys_nice /*35*/ .long sys_chown, sys_sync, sys_kill, sys_newstat, sys_sendfile /*40*/ .long sys_newlstat, sys_dup, sys_pipe, sys_times, sys_getuid diff --git a/arch/sparc64/kernel/sys32.S b/arch/sparc64/kernel/sys32.S index f9b75760163c..bdf1f4d02e3f 100644 --- a/arch/sparc64/kernel/sys32.S +++ b/arch/sparc64/kernel/sys32.S @@ -139,6 +139,7 @@ SIGN3(sys32_ioprio_set, sys_ioprio_set, %o0, %o1, %o2) SIGN2(sys32_splice, sys_splice, %o0, %o1) SIGN2(sys32_sync_file_range, compat_sync_file_range, %o0, %o5) SIGN2(sys32_tee, sys_tee, %o0, %o1) +SIGN1(sys32_vmsplice, compat_sys_vmsplice, %o0) .globl sys32_mmap2 sys32_mmap2: diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S index 62672cd92eca..d4b39cd30310 100644 --- a/arch/sparc64/kernel/systbls.S +++ b/arch/sparc64/kernel/systbls.S @@ -25,7 +25,7 @@ sys_call_table32: /*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys32_chown16, sys32_mknod /*15*/ .word sys_chmod, sys32_lchown16, sparc_brk, sys32_perfctr, sys32_lseek /*20*/ .word sys_getpid, sys_capget, sys_capset, sys32_setuid16, sys32_getuid16 -/*25*/ .word compat_sys_time, sys_ptrace, sys_alarm, sys32_sigaltstack, sys32_pause +/*25*/ .word sys32_vmsplice, sys_ptrace, sys_alarm, sys32_sigaltstack, sys32_pause /*30*/ .word compat_sys_utime, sys_lchown, sys_fchown, sys32_access, sys32_nice .word sys_chown, sys_sync, sys32_kill, compat_sys_newstat, sys32_sendfile /*40*/ .word compat_sys_newlstat, sys_dup, sys_pipe, compat_sys_times, sys_getuid @@ -94,7 +94,7 @@ sys_call_table: /*10*/ .word sys_unlink, sys_nis_syscall, sys_chdir, sys_chown, sys_mknod /*15*/ .word sys_chmod, sys_lchown, sparc_brk, sys_perfctr, sys_lseek /*20*/ .word sys_getpid, sys_capget, sys_capset, sys_setuid, sys_getuid -/*25*/ .word sys_nis_syscall, sys_ptrace, sys_alarm, sys_sigaltstack, sys_nis_syscall +/*25*/ .word sys_vmsplice, sys_ptrace, sys_alarm, sys_sigaltstack, sys_nis_syscall /*30*/ .word sys_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice .word sys_nis_syscall, sys_sync, sys_kill, sys_newstat, sys_sendfile64 /*40*/ .word sys_newlstat, sys_dup, sys_pipe, sys_times, sys_nis_syscall diff --git a/include/asm-sparc/unistd.h b/include/asm-sparc/unistd.h index 32a48f623e2b..f5611a721fbd 100644 --- a/include/asm-sparc/unistd.h +++ b/include/asm-sparc/unistd.h @@ -41,7 +41,7 @@ #define __NR_capset 22 /* Linux Specific */ #define __NR_setuid 23 /* Implemented via setreuid in SunOS */ #define __NR_getuid 24 /* Common */ -/* #define __NR_time alias 25 ENOSYS under SunOS */ +#define __NR_vmsplice 25 /* ENOSYS under SunOS */ #define __NR_ptrace 26 /* Common */ #define __NR_alarm 27 /* Implemented via setitimer in SunOS */ #define __NR_sigaltstack 28 /* Common */ diff --git a/include/asm-sparc64/unistd.h b/include/asm-sparc64/unistd.h index ca80e8aca128..68705748bec0 100644 --- a/include/asm-sparc64/unistd.h +++ b/include/asm-sparc64/unistd.h @@ -41,7 +41,7 @@ #define __NR_capset 22 /* Linux Specific */ #define __NR_setuid 23 /* Implemented via setreuid in SunOS */ #define __NR_getuid 24 /* Common */ -/* #define __NR_time alias 25 ENOSYS under SunOS */ +#define __NR_vmsplice 25 /* ENOSYS under SunOS */ #define __NR_ptrace 26 /* Common */ #define __NR_alarm 27 /* Implemented via setitimer in SunOS */ #define __NR_sigaltstack 28 /* Common */ -- cgit v1.2.3-70-g09d2 From f0ec5e39765cd254d436a6d86e211d81795952a4 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Wed, 3 May 2006 19:54:57 -0700 Subject: [PATCH] Remove wrong cpu_has_apic checks that came from mismerging We only need to check cpu_has_apic in the IO-APIC/L-APIC parsing, not for all of ACPI. Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/acpi/boot.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c index 4c785a67d585..40e5aba3ad3d 100644 --- a/arch/i386/kernel/acpi/boot.c +++ b/arch/i386/kernel/acpi/boot.c @@ -1102,9 +1102,6 @@ int __init acpi_boot_table_init(void) dmi_check_system(acpi_dmi_table); #endif - if (!cpu_has_apic) - return -ENODEV; - /* * If acpi_disabled, bail out * One exception: acpi=ht continues far enough to enumerate LAPICs @@ -1151,9 +1148,6 @@ int __init acpi_boot_init(void) acpi_table_parse(ACPI_BOOT, acpi_parse_sbf); - if (!cpu_has_apic) - return -ENODEV; - /* * set sci_int and PM timer address */ -- cgit v1.2.3-70-g09d2 From 6760da0197a6ee327a09dafc070b26e2f02651fe Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Wed, 3 May 2006 19:55:03 -0700 Subject: [PATCH] uml: change timer initialization inet_init, which schedules, is called before the UML timer_init, which sets up the timer. The result is the interval timers being manipulated before the appropriate signal handlers are established, causing unhandled timers. This is fixed by making timer_init be called earlier. Signed-off-by: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/kernel/time_kern.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/um/kernel/time_kern.c b/arch/um/kernel/time_kern.c index 3c7626cdba4b..528cf623f8b4 100644 --- a/arch/um/kernel/time_kern.c +++ b/arch/um/kernel/time_kern.c @@ -209,4 +209,4 @@ int __init timer_init(void) return(0); } -__initcall(timer_init); +arch_initcall(timer_init); -- cgit v1.2.3-70-g09d2 From 96941026a51e9cb8c2d2be7499301b7fcd9ee225 Mon Sep 17 00:00:00 2001 From: mark gross Date: Wed, 3 May 2006 19:55:07 -0700 Subject: [PATCH] EDAC Coexistence with BIOS Address the issue of EDAC/BIOS coexistence for the e752x chip-sets. We have found a problem where the BIOS will start the system with the error registers (dev0:fun1) hidden and assuming it has exclusive access to them. The edac driver violates this assumption. The workaround this patch offers is to honor the hidden-ness as an indication that it is not safe to use those registers. Signed-off-by: Mark Gross Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/edac/e752x_edac.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c index 66572c5323ad..fce31936e6d7 100644 --- a/drivers/edac/e752x_edac.c +++ b/drivers/edac/e752x_edac.c @@ -25,6 +25,8 @@ #include #include "edac_mc.h" +static int force_function_unhide; + #define e752x_printk(level, fmt, arg...) \ edac_printk(level, "e752x", fmt, ##arg) @@ -782,8 +784,16 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx) debugf0("%s(): mci\n", __func__); debugf0("Starting Probe1\n"); - /* enable device 0 function 1 */ + /* check to see if device 0 function 1 is enabled; if it isn't, we + * assume the BIOS has reserved it for a reason and is expecting + * exclusive access, we take care not to violate that assumption and + * fail the probe. */ pci_read_config_byte(pdev, E752X_DEVPRES1, &stat8); + if (!force_function_unhide && !(stat8 & (1 << 5))) { + printk(KERN_INFO "Contact your BIOS vendor to see if the " + "E752x error registers can be safely un-hidden\n"); + goto fail; + } stat8 |= (1 << 5); pci_write_config_byte(pdev, E752X_DEVPRES1, stat8); @@ -1063,3 +1073,8 @@ module_exit(e752x_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Linux Networx (http://lnxi.com) Tom Zimmerman\n"); MODULE_DESCRIPTION("MC support for Intel e752x memory controllers"); + +module_param(force_function_unhide, int, 0444); +MODULE_PARM_DESC(force_function_unhide, "if BIOS sets Dev0:Fun1 up as hidden:" +" 1=force unhide and hope BIOS doesn't fight driver for Dev0:Fun1 access"); + -- cgit v1.2.3-70-g09d2 From 8683dc9990158c221e05959935e7dd50a956c574 Mon Sep 17 00:00:00 2001 From: Brent Casavant Date: Wed, 3 May 2006 19:55:10 -0700 Subject: [PATCH] Altix: correct ioc4 port order Currently loading the ioc3 as a module will cause the ports to be numbered in reverse order. This mod maintains the proper order of cards for port numbering. Signed-off-by: Brent Casavant Cc: Pat Gefre Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/sn/ioc4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/sn/ioc4.c b/drivers/sn/ioc4.c index 67140a5804f5..cdeff909403e 100644 --- a/drivers/sn/ioc4.c +++ b/drivers/sn/ioc4.c @@ -310,7 +310,7 @@ ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) pci_set_drvdata(idd->idd_pdev, idd); mutex_lock(&ioc4_mutex); - list_add(&idd->idd_list, &ioc4_devices); + list_add_tail(&idd->idd_list, &ioc4_devices); /* Add this IOC4 to all submodules */ list_for_each_entry(is, &ioc4_submodules, is_list) { -- cgit v1.2.3-70-g09d2 From 5dea5176e5c32ef9f0d1a41d28427b3bf6881b3a Mon Sep 17 00:00:00 2001 From: Mingming Cao Date: Wed, 3 May 2006 19:55:12 -0700 Subject: [PATCH] ext3: multile block allocate little endian fixes Some places in ext3 multiple block allocation code (in 2.6.17-rc3) don't handle the little endian well. This was resulting in *wrong* block numbers being assigned to in-memory block variables and then stored on disk eventually. The following patch has been verified to fix an ext3 filesystem failure when run ltp test on a 64 bit machine. Signed-off-by; Mingming Cao Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ext3/inode.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 48ae0339af17..2edd7eec88fd 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -711,7 +711,7 @@ static int ext3_splice_branch(handle_t *handle, struct inode *inode, * direct blocks blocks */ if (num == 0 && blks > 1) { - current_block = le32_to_cpu(where->key + 1); + current_block = le32_to_cpu(where->key) + 1; for (i = 1; i < blks; i++) *(where->p + i ) = cpu_to_le32(current_block++); } @@ -724,7 +724,7 @@ static int ext3_splice_branch(handle_t *handle, struct inode *inode, if (block_i) { block_i->last_alloc_logical_block = block + blks - 1; block_i->last_alloc_physical_block = - le32_to_cpu(where[num].key + blks - 1); + le32_to_cpu(where[num].key) + blks - 1; } /* We are done with atomic stuff, now do the rest of housekeeping */ @@ -814,11 +814,13 @@ int ext3_get_blocks_handle(handle_t *handle, struct inode *inode, /* Simplest case - block found, no allocation needed */ if (!partial) { - first_block = chain[depth - 1].key; + first_block = le32_to_cpu(chain[depth - 1].key); clear_buffer_new(bh_result); count++; /*map more blocks*/ while (count < maxblocks && count <= blocks_to_boundary) { + unsigned long blk; + if (!verify_chain(chain, partial)) { /* * Indirect block might be removed by @@ -831,8 +833,9 @@ int ext3_get_blocks_handle(handle_t *handle, struct inode *inode, count = 0; break; } - if (le32_to_cpu(*(chain[depth-1].p+count) == - (first_block + count))) + blk = le32_to_cpu(*(chain[depth-1].p + count)); + + if (blk == first_block + count) count++; else break; -- cgit v1.2.3-70-g09d2 From bfc4ee39fdbb2deb8864785d5e5bc5cdd3b31a69 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Wed, 3 May 2006 10:35:10 +0200 Subject: [PATCH] splice: fix unlocking of page on error ->prepare_write() Looking at generic_file_buffered_write(), we need to unlock_page() if prepare write fails and it isn't due to racing with truncate(). Also trim the size if ->prepare_write() fails, if we have to. Signed-off-by: Jens Axboe --- fs/splice.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/fs/splice.c b/fs/splice.c index 7fb04970c72d..27f5e3738a7b 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -647,11 +647,24 @@ find_page: } ret = mapping->a_ops->prepare_write(file, page, offset, offset+this_len); - if (ret == AOP_TRUNCATED_PAGE) { + if (unlikely(ret)) { + loff_t isize = i_size_read(mapping->host); + + if (ret != AOP_TRUNCATED_PAGE) + unlock_page(page); page_cache_release(page); - goto find_page; - } else if (ret) + if (ret == AOP_TRUNCATED_PAGE) + goto find_page; + + /* + * prepare_write() may have instantiated a few blocks + * outside i_size. Trim these off again. + */ + if (sd->pos + this_len > isize) + vmtruncate(mapping->host, isize); + goto out; + } if (buf->page != page) { /* -- cgit v1.2.3-70-g09d2 From 1432873af7ae29d4bb3c56114c05b539d078ca62 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Wed, 3 May 2006 10:35:26 +0200 Subject: [PATCH] splice: LRU fixups Nick says that the current construct isn't safe. This goes back to the original, but sets PIPE_BUF_FLAG_LRU on user pages as well as they all seem to be on the LRU in the first place. Signed-off-by: Jens Axboe --- fs/splice.c | 33 +++++++++++---------------------- include/linux/pipe_fs_i.h | 5 +++-- 2 files changed, 14 insertions(+), 24 deletions(-) diff --git a/fs/splice.c b/fs/splice.c index 27f5e3738a7b..0b202425b0b5 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -78,6 +78,7 @@ static int page_cache_pipe_buf_steal(struct pipe_inode_info *info, return 1; } + buf->flags |= PIPE_BUF_FLAG_LRU; return 0; } @@ -85,6 +86,7 @@ static void page_cache_pipe_buf_release(struct pipe_inode_info *info, struct pipe_buffer *buf) { page_cache_release(buf->page); + buf->flags &= ~PIPE_BUF_FLAG_LRU; } static int page_cache_pipe_buf_pin(struct pipe_inode_info *info, @@ -141,6 +143,7 @@ static int user_page_pipe_buf_steal(struct pipe_inode_info *pipe, if (!(buf->flags & PIPE_BUF_FLAG_GIFT)) return 1; + buf->flags |= PIPE_BUF_FLAG_LRU; return generic_pipe_buf_steal(pipe, buf); } @@ -566,37 +569,23 @@ static int pipe_to_file(struct pipe_inode_info *info, struct pipe_buffer *buf, */ if ((sd->flags & SPLICE_F_MOVE) && this_len == PAGE_CACHE_SIZE) { /* - * If steal succeeds, buf->page is now pruned from the vm - * side (page cache) and we can reuse it. The page will also - * be locked on successful return. + * If steal succeeds, buf->page is now pruned from the + * pagecache and we can reuse it. The page will also be + * locked on successful return. */ if (buf->ops->steal(info, buf)) goto find_page; page = buf->page; - page_cache_get(page); - - /* - * page must be on the LRU for adding to the pagecache. - * Check this without grabbing the zone lock, if it isn't - * the do grab the zone lock, recheck, and add if necessary. - */ - if (!PageLRU(page)) { - struct zone *zone = page_zone(page); - - spin_lock_irq(&zone->lru_lock); - if (!PageLRU(page)) { - SetPageLRU(page); - add_page_to_inactive_list(zone, page); - } - spin_unlock_irq(&zone->lru_lock); - } - if (add_to_page_cache(page, mapping, index, gfp_mask)) { - page_cache_release(page); unlock_page(page); goto find_page; } + + page_cache_get(page); + + if (!(buf->flags & PIPE_BUF_FLAG_LRU)) + lru_cache_add(page); } else { find_page: page = find_lock_page(mapping, index); diff --git a/include/linux/pipe_fs_i.h b/include/linux/pipe_fs_i.h index ba73108cbf8b..ea4f7cd7bfd8 100644 --- a/include/linux/pipe_fs_i.h +++ b/include/linux/pipe_fs_i.h @@ -5,8 +5,9 @@ #define PIPE_BUFFERS (16) -#define PIPE_BUF_FLAG_ATOMIC 0x01 /* was atomically mapped */ -#define PIPE_BUF_FLAG_GIFT 0x02 /* page is a gift */ +#define PIPE_BUF_FLAG_LRU 0x01 /* page is on the LRU */ +#define PIPE_BUF_FLAG_ATOMIC 0x02 /* was atomically mapped */ +#define PIPE_BUF_FLAG_GIFT 0x04 /* page is a gift */ struct pipe_buffer { struct page *page; -- cgit v1.2.3-70-g09d2 From 76ad4d11105ccd40a536db1057083f28326019fd Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Wed, 3 May 2006 10:41:33 +0200 Subject: [PATCH] splice: rename remaining info variables to pipe Same thing was done in fs/pipe.c and most of fs/splice.c, but we had a few missing still. Signed-off-by: Jens Axboe --- fs/splice.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/fs/splice.c b/fs/splice.c index 0b202425b0b5..8fa9217ed585 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -51,7 +51,7 @@ struct splice_pipe_desc { * addition of remove_mapping(). If success is returned, the caller may * attempt to reuse this page for another destination. */ -static int page_cache_pipe_buf_steal(struct pipe_inode_info *info, +static int page_cache_pipe_buf_steal(struct pipe_inode_info *pipe, struct pipe_buffer *buf) { struct page *page = buf->page; @@ -82,14 +82,14 @@ static int page_cache_pipe_buf_steal(struct pipe_inode_info *info, return 0; } -static void page_cache_pipe_buf_release(struct pipe_inode_info *info, +static void page_cache_pipe_buf_release(struct pipe_inode_info *pipe, struct pipe_buffer *buf) { page_cache_release(buf->page); buf->flags &= ~PIPE_BUF_FLAG_LRU; } -static int page_cache_pipe_buf_pin(struct pipe_inode_info *info, +static int page_cache_pipe_buf_pin(struct pipe_inode_info *pipe, struct pipe_buffer *buf) { struct page *page = buf->page; @@ -500,14 +500,14 @@ EXPORT_SYMBOL(generic_file_splice_read); * Send 'sd->len' bytes to socket from 'sd->file' at position 'sd->pos' * using sendpage(). Return the number of bytes sent. */ -static int pipe_to_sendpage(struct pipe_inode_info *info, +static int pipe_to_sendpage(struct pipe_inode_info *pipe, struct pipe_buffer *buf, struct splice_desc *sd) { struct file *file = sd->file; loff_t pos = sd->pos; int ret, more; - ret = buf->ops->pin(info, buf); + ret = buf->ops->pin(pipe, buf); if (!ret) { more = (sd->flags & SPLICE_F_MORE) || sd->len < sd->total_len; @@ -538,7 +538,7 @@ static int pipe_to_sendpage(struct pipe_inode_info *info, * SPLICE_F_MOVE isn't set, or we cannot move the page, we simply create * a new page in the output file page cache and fill/dirty that. */ -static int pipe_to_file(struct pipe_inode_info *info, struct pipe_buffer *buf, +static int pipe_to_file(struct pipe_inode_info *pipe, struct pipe_buffer *buf, struct splice_desc *sd) { struct file *file = sd->file; @@ -552,7 +552,7 @@ static int pipe_to_file(struct pipe_inode_info *info, struct pipe_buffer *buf, /* * make sure the data in this buffer is uptodate */ - ret = buf->ops->pin(info, buf); + ret = buf->ops->pin(pipe, buf); if (unlikely(ret)) return ret; @@ -573,7 +573,7 @@ static int pipe_to_file(struct pipe_inode_info *info, struct pipe_buffer *buf, * pagecache and we can reuse it. The page will also be * locked on successful return. */ - if (buf->ops->steal(info, buf)) + if (buf->ops->steal(pipe, buf)) goto find_page; page = buf->page; @@ -659,13 +659,13 @@ find_page: /* * Careful, ->map() uses KM_USER0! */ - char *src = buf->ops->map(info, buf, 1); + char *src = buf->ops->map(pipe, buf, 1); char *dst = kmap_atomic(page, KM_USER1); memcpy(dst + offset, src + buf->offset, this_len); flush_dcache_page(page); kunmap_atomic(dst, KM_USER1); - buf->ops->unmap(info, buf, src); + buf->ops->unmap(pipe, buf, src); } ret = mapping->a_ops->commit_write(file, page, offset, offset+this_len); -- cgit v1.2.3-70-g09d2 From a0548871ed267ae12eb1c860c5aaebd9e466b34e Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Wed, 3 May 2006 10:58:22 +0200 Subject: [PATCH] splice: redo page lookup if add_to_page_cache() returns -EEXIST This can happen quite easily, if several processes are trying to splice the same file at the same time. It's not a failure, it just means someone raced with us in allocating this file page. So just dump the allocated page and relookup the original. Signed-off-by: Jens Axboe --- fs/splice.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/splice.c b/fs/splice.c index 8fa9217ed585..a285fd746dc0 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -324,6 +324,8 @@ __generic_file_splice_read(struct file *in, loff_t *ppos, mapping_gfp_mask(mapping)); if (unlikely(error)) { page_cache_release(page); + if (error == -EEXIST) + continue; break; } /* -- cgit v1.2.3-70-g09d2 From 6fd737031eb6869430d0f3cf6bf1440adf7aedf5 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 3 May 2006 23:16:29 -0700 Subject: [NETFILTER]: H.323 helper: fix endless loop caused by invalid TPKT len When the TPKT len included in the packet is below the lowest valid value of 4 an underflow occurs which results in an endless loop. Found by testcase 0000058 from the PROTOS c07-h2250v4 testsuite. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/ip_conntrack_helper_h323.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323.c b/net/ipv4/netfilter/ip_conntrack_helper_h323.c index 2c2fb700d835..518f581d39ec 100644 --- a/net/ipv4/netfilter/ip_conntrack_helper_h323.c +++ b/net/ipv4/netfilter/ip_conntrack_helper_h323.c @@ -162,6 +162,8 @@ static int get_tpkt_data(struct sk_buff **pskb, struct ip_conntrack *ct, /* Validate TPKT length */ tpktlen = tpkt[2] * 256 + tpkt[3]; + if (tpktlen < 4) + goto clear_out; if (tpktlen > tcpdatalen) { if (tcpdatalen == 4) { /* Separate TPKT header */ /* Netmeeting sends TPKT header and data separately */ -- cgit v1.2.3-70-g09d2 From 4228e2a9890cd01b0c8cc58af6fd9e08a4b5e8a7 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 3 May 2006 23:17:11 -0700 Subject: [NETFILTER]: H.323 helper: fix use of uninitialized data When a Choice element contains an unsupported choice no error is returned and parsing continues normally, but the choice value is not set and contains data from the last parsed message. This may in turn lead to parsing of more stale data and following crashes. Fixes a crash triggered by testcase 0003243 from the PROTOS c07-h2250v4 testsuite following random other testcases: CPU: 0 EIP: 0060:[] Not tainted VLI EFLAGS: 00210646 (2.6.17-rc2 #3) EIP is at memmove+0x19/0x22 eax: d7be0307 ebx: d7be0307 ecx: e841fcf9 edx: d7be0307 esi: bfffffff edi: bfffffff ebp: da5eb980 esp: c0347e2c ds: 007b es: 007b ss: 0068 Process events/0 (pid: 4, threadinfo=c0347000 task=dff86a90) Stack: <0>00000006 c0347ea6 d7be0301 e09a6b2c 00000006 da5eb980 d7be003e d7be0052 c0347f6c e09a6d9c 00000006 c0347ea6 00000006 00000000 d7b9a548 00000000 c0347f6c d7b9a548 00000004 e0a1a119 0000028f 00000006 c0347ea6 00000006 Call Trace: [] mangle_contents+0x40/0xd8 [ip_nat] [] ip_nat_mangle_tcp_packet+0xa1/0x191 [ip_nat] [] set_addr+0x60/0x14d [ip_nat_h323] [] q931_help+0x2da/0x71a [ip_conntrack_h323] [] q931_help+0x30c/0x71a [ip_conntrack_h323] [] ip_conntrack_help+0x22/0x2f [ip_conntrack] [] nf_iterate+0x2e/0x5f [] xfrm4_output_finish+0x0/0x39f [] nf_hook_slow+0x42/0xb0 [] xfrm4_output_finish+0x0/0x39f [] xfrm4_output+0x3c/0x4e [] xfrm4_output_finish+0x0/0x39f [] ip_forward+0x1c2/0x1fa [] ip_rcv+0x388/0x3b5 [] netif_receive_skb+0x2bc/0x2ec [] process_backlog+0x6b/0xd0 [] net_rx_action+0x4b/0xb7 [] __do_softirq+0x35/0x7d [] do_softirq+0x38/0x3f Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c b/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c index 48078002e450..f52d2c45a6ae 100644 --- a/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c +++ b/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c @@ -703,6 +703,10 @@ int decode_choice(bitstr_t * bs, field_t * f, char *base, int level) type = get_bits(bs, f->sz); } + /* Write Type */ + if (base) + *(unsigned *) base = type; + /* Check Range */ if (type >= f->ub) { /* Newer version? */ BYTE_ALIGN(bs); @@ -712,10 +716,6 @@ int decode_choice(bitstr_t * bs, field_t * f, char *base, int level) return H323_ERROR_NONE; } - /* Write Type */ - if (base) - *(unsigned *) base = type; - /* Transfer to son level */ son = &f->fields[type]; if (son->attr & STOP) { -- cgit v1.2.3-70-g09d2 From 2354feaeb2acb78f6aabdf8410d55b44492a7949 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 3 May 2006 23:19:26 -0700 Subject: [NETFILTER]: NAT: silence unused variable warnings with CONFIG_XFRM=n net/ipv4/netfilter/ip_nat_standalone.c: In function 'ip_nat_out': net/ipv4/netfilter/ip_nat_standalone.c:223: warning: unused variable 'ctinfo' net/ipv4/netfilter/ip_nat_standalone.c:222: warning: unused variable 'ct' Surprisingly no complaints so far .. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/ip_nat_standalone.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c index 8f760b28617e..67e676783da9 100644 --- a/net/ipv4/netfilter/ip_nat_standalone.c +++ b/net/ipv4/netfilter/ip_nat_standalone.c @@ -219,8 +219,10 @@ ip_nat_out(unsigned int hooknum, const struct net_device *out, int (*okfn)(struct sk_buff *)) { +#ifdef CONFIG_XFRM struct ip_conntrack *ct; enum ip_conntrack_info ctinfo; +#endif unsigned int ret; /* root is playing with raw sockets. */ -- cgit v1.2.3-70-g09d2 From 7582e9d17edbabab6cbe59467c5d1b5e8c04fca8 Mon Sep 17 00:00:00 2001 From: Jing Min Zhao Date: Wed, 3 May 2006 23:19:59 -0700 Subject: [NETFILTER]: H.323 helper: Change author's email address Signed-off-by: Jing Min Zhao Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter_ipv4/ip_conntrack_helper_h323_asn1.h | 2 +- net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/netfilter_ipv4/ip_conntrack_helper_h323_asn1.h b/include/linux/netfilter_ipv4/ip_conntrack_helper_h323_asn1.h index 0bd828081c0c..c6e9a0b6d30b 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack_helper_h323_asn1.h +++ b/include/linux/netfilter_ipv4/ip_conntrack_helper_h323_asn1.h @@ -2,7 +2,7 @@ * ip_conntrack_helper_h323_asn1.h - BER and PER decoding library for H.323 * conntrack/NAT module. * - * Copyright (c) 2006 by Jing Min Zhao + * Copyright (c) 2006 by Jing Min Zhao * * This source code is licensed under General Public License version 2. * diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c b/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c index f52d2c45a6ae..355a53a5b6cd 100644 --- a/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c +++ b/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c @@ -2,7 +2,7 @@ * ip_conntrack_helper_h323_asn1.c - BER and PER decoding library for H.323 * conntrack/NAT module. * - * Copyright (c) 2006 by Jing Min Zhao + * Copyright (c) 2006 by Jing Min Zhao * * This source code is licensed under General Public License version 2. * -- cgit v1.2.3-70-g09d2 From 7800007c1e2d42cd4120b87b0ba3f3480f17f30a Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 3 May 2006 23:20:27 -0700 Subject: [NETFILTER]: x_tables: don't use __copy_{from,to}_user on unchecked memory in compat layer Noticed by Linus Torvalds Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/ip_tables.c | 6 +++--- net/netfilter/x_tables.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 6d1c11563943..cee3397ec277 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -1441,7 +1441,7 @@ static int compat_copy_entry_to_user(struct ipt_entry *e, ret = -EFAULT; origsize = *size; ce = (struct compat_ipt_entry __user *)*dstptr; - if (__copy_to_user(ce, e, sizeof(struct ipt_entry))) + if (copy_to_user(ce, e, sizeof(struct ipt_entry))) goto out; *dstptr += sizeof(struct compat_ipt_entry); @@ -1459,9 +1459,9 @@ static int compat_copy_entry_to_user(struct ipt_entry *e, goto out; ret = -EFAULT; next_offset = e->next_offset - (origsize - *size); - if (__put_user(target_offset, &ce->target_offset)) + if (put_user(target_offset, &ce->target_offset)) goto out; - if (__put_user(next_offset, &ce->next_offset)) + if (put_user(next_offset, &ce->next_offset)) goto out; return 0; out: diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 17abf60f9570..99293c63ff73 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -289,7 +289,7 @@ int xt_compat_match(void *match, void **dstptr, int *size, int convert) case COMPAT_TO_USER: pm = (struct xt_entry_match *)match; msize = pm->u.user.match_size; - if (__copy_to_user(*dstptr, pm, msize)) { + if (copy_to_user(*dstptr, pm, msize)) { ret = -EFAULT; break; } @@ -366,7 +366,7 @@ int xt_compat_target(void *target, void **dstptr, int *size, int convert) case COMPAT_TO_USER: pt = (struct xt_entry_target *)target; tsize = pt->u.user.target_size; - if (__copy_to_user(*dstptr, pt, tsize)) { + if (copy_to_user(*dstptr, pt, tsize)) { ret = -EFAULT; break; } -- cgit v1.2.3-70-g09d2 From 0cc5ae24af08abe8e2a467f45b54c48a0f52670f Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 3 May 2006 23:22:01 -0700 Subject: [ROSE]: Remove useless prototype for rose_remove_neigh(). Signed-off-by: Ralf Baechle Signed-off-by: David S. Miller --- net/rose/rose_route.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c index 8631b65a7312..4cb6bfa6fcbd 100644 --- a/net/rose/rose_route.c +++ b/net/rose/rose_route.c @@ -48,8 +48,6 @@ static DEFINE_SPINLOCK(rose_route_list_lock); struct rose_neigh *rose_loopback_neigh; -static void rose_remove_neigh(struct rose_neigh *); - /* * Add a new route to a node, and in the process add the node and the * neighbour if it is new. -- cgit v1.2.3-70-g09d2 From 3f072310d0ca85891323e9d325c37c76de389387 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 3 May 2006 23:22:36 -0700 Subject: [AX.25]: Spelling fix Signed-off-by: Ralf Baechle Signed-off-by: David S. Miller --- net/ax25/ax25_route.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ax25/ax25_route.c b/net/ax25/ax25_route.c index f04f8630fd28..5ac98250797b 100644 --- a/net/ax25/ax25_route.c +++ b/net/ax25/ax25_route.c @@ -360,7 +360,7 @@ struct file_operations ax25_route_fops = { /* * Find AX.25 route * - * Only routes with a refernce rout of zero can be destroyed. + * Only routes with a reference count of zero can be destroyed. */ static ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev) { -- cgit v1.2.3-70-g09d2 From 86cfcb95ec60e910d7efcb35ae89bf3403befaad Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 3 May 2006 23:23:48 -0700 Subject: [AX25, ROSE]: Remove useless SET_MODULE_OWNER calls. Signed-off-by: Ralf Baechle Signed-off-by: David S. Miller --- net/netrom/nr_dev.c | 1 - net/rose/rose_dev.c | 1 - 2 files changed, 2 deletions(-) diff --git a/net/netrom/nr_dev.c b/net/netrom/nr_dev.c index 509afddae569..621e5586ab03 100644 --- a/net/netrom/nr_dev.c +++ b/net/netrom/nr_dev.c @@ -185,7 +185,6 @@ static struct net_device_stats *nr_get_stats(struct net_device *dev) void nr_setup(struct net_device *dev) { - SET_MODULE_OWNER(dev); dev->mtu = NR_MAX_PACKET_SIZE; dev->hard_start_xmit = nr_xmit; dev->open = nr_open; diff --git a/net/rose/rose_dev.c b/net/rose/rose_dev.c index d297af737d10..2a1bf8e119e5 100644 --- a/net/rose/rose_dev.c +++ b/net/rose/rose_dev.c @@ -135,7 +135,6 @@ static struct net_device_stats *rose_get_stats(struct net_device *dev) void rose_setup(struct net_device *dev) { - SET_MODULE_OWNER(dev); dev->mtu = ROSE_MAX_PACKET_SIZE - 2; dev->hard_start_xmit = rose_xmit; dev->open = rose_open; -- cgit v1.2.3-70-g09d2 From 3ab33dcc82e014c69ebad3b524d0053378ef76c3 Mon Sep 17 00:00:00 2001 From: Ralf Baechle DL5RB Date: Wed, 3 May 2006 23:24:35 -0700 Subject: [HAMRADIO]: Remove remaining SET_MODULE_OWNER calls from hamradio drivers. Signed-off-by: Ralf Baechle DL5RB Signed-off-by: David S. Miller --- drivers/net/hamradio/dmascc.c | 1 - drivers/net/hamradio/scc.c | 1 - drivers/net/hamradio/yam.c | 1 - 3 files changed, 3 deletions(-) diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c index 79a8fbcf5f93..0d5fccc984bb 100644 --- a/drivers/net/hamradio/dmascc.c +++ b/drivers/net/hamradio/dmascc.c @@ -582,7 +582,6 @@ static int __init setup_adapter(int card_base, int type, int n) INIT_WORK(&priv->rx_work, rx_bh, priv); dev->priv = priv; sprintf(dev->name, "dmascc%i", 2 * n + i); - SET_MODULE_OWNER(dev); dev->base_addr = card_base; dev->irq = irq; dev->open = scc_open; diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c index 6ace0e914fd1..5927784df3f9 100644 --- a/drivers/net/hamradio/scc.c +++ b/drivers/net/hamradio/scc.c @@ -1550,7 +1550,6 @@ static unsigned char ax25_nocall[AX25_ADDR_LEN] = static void scc_net_setup(struct net_device *dev) { - SET_MODULE_OWNER(dev); dev->tx_queue_len = 16; /* should be enough... */ dev->open = scc_net_open; diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c index fe22479eb202..b49884048caa 100644 --- a/drivers/net/hamradio/yam.c +++ b/drivers/net/hamradio/yam.c @@ -1098,7 +1098,6 @@ static void yam_setup(struct net_device *dev) dev->base_addr = yp->iobase; dev->irq = yp->irq; - SET_MODULE_OWNER(dev); dev->open = yam_open; dev->stop = yam_close; -- cgit v1.2.3-70-g09d2 From 70868eace5031298c6f6e991a40a2106957f582c Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 3 May 2006 23:25:17 -0700 Subject: [AX.25]: Move AX.25 symbol exports Move AX.25 symbol exports to next to their definitions where they're supposed to be these days. Signed-off-by: Ralf Baechle Signed-off-by: David S. Miller --- net/ax25/af_ax25.c | 20 ++------------------ net/ax25/ax25_addr.c | 9 +++++++++ net/ax25/ax25_iface.c | 13 +++++++++++++ net/ax25/ax25_ip.c | 3 +++ net/ax25/ax25_out.c | 3 +++ net/ax25/ax25_timer.c | 3 +++ net/ax25/ax25_uid.c | 4 ++++ 7 files changed, 37 insertions(+), 18 deletions(-) diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index dbf9b47681f7..a9f13dfde07e 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -228,6 +228,8 @@ ax25_cb *ax25_find_cb(ax25_address *src_addr, ax25_address *dest_addr, return NULL; } +EXPORT_SYMBOL(ax25_find_cb); + void ax25_send_to_raw(ax25_address *addr, struct sk_buff *skb, int proto) { ax25_cb *s; @@ -1979,24 +1981,6 @@ static struct notifier_block ax25_dev_notifier = { .notifier_call =ax25_device_event, }; -EXPORT_SYMBOL(ax25_hard_header); -EXPORT_SYMBOL(ax25_rebuild_header); -EXPORT_SYMBOL(ax25_findbyuid); -EXPORT_SYMBOL(ax25_find_cb); -EXPORT_SYMBOL(ax25_linkfail_register); -EXPORT_SYMBOL(ax25_linkfail_release); -EXPORT_SYMBOL(ax25_listen_register); -EXPORT_SYMBOL(ax25_listen_release); -EXPORT_SYMBOL(ax25_protocol_register); -EXPORT_SYMBOL(ax25_protocol_release); -EXPORT_SYMBOL(ax25_send_frame); -EXPORT_SYMBOL(ax25_uid_policy); -EXPORT_SYMBOL(ax25cmp); -EXPORT_SYMBOL(ax2asc); -EXPORT_SYMBOL(asc2ax); -EXPORT_SYMBOL(null_ax25_address); -EXPORT_SYMBOL(ax25_display_timer); - static int __init ax25_init(void) { int rc = proto_register(&ax25_proto, 0); diff --git a/net/ax25/ax25_addr.c b/net/ax25/ax25_addr.c index 0164a155b8c4..5f0896ad0042 100644 --- a/net/ax25/ax25_addr.c +++ b/net/ax25/ax25_addr.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -33,6 +34,8 @@ */ ax25_address null_ax25_address = {{0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00}}; +EXPORT_SYMBOL(null_ax25_address); + /* * ax25 -> ascii conversion */ @@ -64,6 +67,8 @@ char *ax2asc(char *buf, ax25_address *a) } +EXPORT_SYMBOL(ax2asc); + /* * ascii -> ax25 conversion */ @@ -97,6 +102,8 @@ void asc2ax(ax25_address *addr, char *callsign) addr->ax25_call[6] &= 0x1E; } +EXPORT_SYMBOL(asc2ax); + /* * Compare two ax.25 addresses */ @@ -116,6 +123,8 @@ int ax25cmp(ax25_address *a, ax25_address *b) return 2; /* Partial match */ } +EXPORT_SYMBOL(ax25cmp); + /* * Compare two AX.25 digipeater paths. */ diff --git a/net/ax25/ax25_iface.c b/net/ax25/ax25_iface.c index d68aff100729..3bb152710b77 100644 --- a/net/ax25/ax25_iface.c +++ b/net/ax25/ax25_iface.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -74,6 +75,8 @@ int ax25_protocol_register(unsigned int pid, return 1; } +EXPORT_SYMBOL(ax25_protocol_register); + void ax25_protocol_release(unsigned int pid) { struct protocol_struct *s, *protocol; @@ -106,6 +109,8 @@ void ax25_protocol_release(unsigned int pid) write_unlock(&protocol_list_lock); } +EXPORT_SYMBOL(ax25_protocol_release); + int ax25_linkfail_register(void (*func)(ax25_cb *, int)) { struct linkfail_struct *linkfail; @@ -123,6 +128,8 @@ int ax25_linkfail_register(void (*func)(ax25_cb *, int)) return 1; } +EXPORT_SYMBOL(ax25_linkfail_register); + void ax25_linkfail_release(void (*func)(ax25_cb *, int)) { struct linkfail_struct *s, *linkfail; @@ -155,6 +162,8 @@ void ax25_linkfail_release(void (*func)(ax25_cb *, int)) spin_unlock_bh(&linkfail_lock); } +EXPORT_SYMBOL(ax25_linkfail_release); + int ax25_listen_register(ax25_address *callsign, struct net_device *dev) { struct listen_struct *listen; @@ -176,6 +185,8 @@ int ax25_listen_register(ax25_address *callsign, struct net_device *dev) return 1; } +EXPORT_SYMBOL(ax25_listen_register); + void ax25_listen_release(ax25_address *callsign, struct net_device *dev) { struct listen_struct *s, *listen; @@ -208,6 +219,8 @@ void ax25_listen_release(ax25_address *callsign, struct net_device *dev) spin_unlock_bh(&listen_lock); } +EXPORT_SYMBOL(ax25_listen_release); + int (*ax25_protocol_function(unsigned int pid))(struct sk_buff *, ax25_cb *) { int (*res)(struct sk_buff *, ax25_cb *) = NULL; diff --git a/net/ax25/ax25_ip.c b/net/ax25/ax25_ip.c index d643dac3eccc..a0b534f80f17 100644 --- a/net/ax25/ax25_ip.c +++ b/net/ax25/ax25_ip.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -221,3 +222,5 @@ int ax25_rebuild_header(struct sk_buff *skb) #endif +EXPORT_SYMBOL(ax25_hard_header); +EXPORT_SYMBOL(ax25_rebuild_header); diff --git a/net/ax25/ax25_out.c b/net/ax25/ax25_out.c index 5fc048dcd39a..5d99852b239c 100644 --- a/net/ax25/ax25_out.c +++ b/net/ax25/ax25_out.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -104,6 +105,8 @@ ax25_cb *ax25_send_frame(struct sk_buff *skb, int paclen, ax25_address *src, ax2 return ax25; /* We had to create it */ } +EXPORT_SYMBOL(ax25_send_frame); + /* * All outgoing AX.25 I frames pass via this routine. Therefore this is * where the fragmentation of frames takes place. If fragment is set to diff --git a/net/ax25/ax25_timer.c b/net/ax25/ax25_timer.c index 7a6b50a14554..ec254057f212 100644 --- a/net/ax25/ax25_timer.c +++ b/net/ax25/ax25_timer.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -137,6 +138,8 @@ unsigned long ax25_display_timer(struct timer_list *timer) return timer->expires - jiffies; } +EXPORT_SYMBOL(ax25_display_timer); + static void ax25_heartbeat_expiry(unsigned long param) { int proto = AX25_PROTO_STD_SIMPLEX; diff --git a/net/ax25/ax25_uid.c b/net/ax25/ax25_uid.c index b8b5854bce9a..5e9a81e8b214 100644 --- a/net/ax25/ax25_uid.c +++ b/net/ax25/ax25_uid.c @@ -49,6 +49,8 @@ static DEFINE_RWLOCK(ax25_uid_lock); int ax25_uid_policy = 0; +EXPORT_SYMBOL(ax25_uid_policy); + ax25_uid_assoc *ax25_findbyuid(uid_t uid) { ax25_uid_assoc *ax25_uid, *res = NULL; @@ -67,6 +69,8 @@ ax25_uid_assoc *ax25_findbyuid(uid_t uid) return res; } +EXPORT_SYMBOL(ax25_findbyuid); + int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax) { ax25_uid_assoc *ax25_uid; -- cgit v1.2.3-70-g09d2 From 4cc7c2734e2b4032103e47d8f3e8b6fa3360d3f1 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 3 May 2006 23:26:20 -0700 Subject: [ROSE]: Fix routing table locking in rose_remove_neigh. The locking rule for rose_remove_neigh() are that the caller needs to hold rose_neigh_list_lock, so we better don't take it yet again in rose_neigh_list_lock. Signed-off-by: Ralf Baechle Signed-off-by: David S. Miller --- net/rose/rose_route.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c index 4cb6bfa6fcbd..a22542fa1bc8 100644 --- a/net/rose/rose_route.c +++ b/net/rose/rose_route.c @@ -233,11 +233,8 @@ static void rose_remove_neigh(struct rose_neigh *rose_neigh) skb_queue_purge(&rose_neigh->queue); - spin_lock_bh(&rose_neigh_list_lock); - if ((s = rose_neigh_list) == rose_neigh) { rose_neigh_list = rose_neigh->next; - spin_unlock_bh(&rose_neigh_list_lock); kfree(rose_neigh->digipeat); kfree(rose_neigh); return; @@ -246,7 +243,6 @@ static void rose_remove_neigh(struct rose_neigh *rose_neigh) while (s != NULL && s->next != NULL) { if (s->next == rose_neigh) { s->next = rose_neigh->next; - spin_unlock_bh(&rose_neigh_list_lock); kfree(rose_neigh->digipeat); kfree(rose_neigh); return; @@ -254,7 +250,6 @@ static void rose_remove_neigh(struct rose_neigh *rose_neigh) s = s->next; } - spin_unlock_bh(&rose_neigh_list_lock); } /* -- cgit v1.2.3-70-g09d2 From e1fdb5b39656ea2be8cadde565e543649a988af9 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 3 May 2006 23:27:16 -0700 Subject: [AX.25]: Eleminate HZ from AX.25 kernel interfaces Convert all AX.25 sysctl time values from jiffies to ms as units. Signed-off-by: Ralf Baechle Signed-off-by: David S. Miller --- include/net/ax25.h | 10 +++---- net/ax25/af_ax25.c | 73 ++++++++++++++++++++++++++-------------------- net/ax25/ax25_ds_timer.c | 3 +- net/ax25/sysctl_net_ax25.c | 10 +++---- 4 files changed, 53 insertions(+), 43 deletions(-) diff --git a/include/net/ax25.h b/include/net/ax25.h index d052b221dbcd..5bd997487054 100644 --- a/include/net/ax25.h +++ b/include/net/ax25.h @@ -145,14 +145,14 @@ enum { #define AX25_DEF_CONMODE 2 /* Connected mode allowed */ #define AX25_DEF_WINDOW 2 /* Window=2 */ #define AX25_DEF_EWINDOW 32 /* Module-128 Window=32 */ -#define AX25_DEF_T1 (10 * HZ) /* T1=10s */ -#define AX25_DEF_T2 (3 * HZ) /* T2=3s */ -#define AX25_DEF_T3 (300 * HZ) /* T3=300s */ +#define AX25_DEF_T1 10000 /* T1=10s */ +#define AX25_DEF_T2 3000 /* T2=3s */ +#define AX25_DEF_T3 300000 /* T3=300s */ #define AX25_DEF_N2 10 /* N2=10 */ -#define AX25_DEF_IDLE (0 * 60 * HZ) /* Idle=None */ +#define AX25_DEF_IDLE 0 /* Idle=None */ #define AX25_DEF_PACLEN 256 /* Paclen=256 */ #define AX25_DEF_PROTOCOL AX25_PROTO_STD_SIMPLEX /* Standard AX.25 */ -#define AX25_DEF_DS_TIMEOUT (3 * 60 * HZ) /* DAMA timeout 3 minutes */ +#define AX25_DEF_DS_TIMEOUT 180000 /* DAMA timeout 3 minutes */ typedef struct ax25_uid_assoc { struct hlist_node uid_node; diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index a9f13dfde07e..a2e0dd047e9f 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -426,6 +426,26 @@ static int ax25_ctl_ioctl(const unsigned int cmd, void __user *arg) return 0; } +static void ax25_fillin_cb_from_dev(ax25_cb *ax25, ax25_dev *ax25_dev) +{ + ax25->rtt = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_T1]) / 2; + ax25->t1 = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_T1]); + ax25->t2 = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_T2]); + ax25->t3 = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_T3]); + ax25->n2 = ax25_dev->values[AX25_VALUES_N2]; + ax25->paclen = ax25_dev->values[AX25_VALUES_PACLEN]; + ax25->idle = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_IDLE]); + ax25->backoff = ax25_dev->values[AX25_VALUES_BACKOFF]; + + if (ax25_dev->values[AX25_VALUES_AXDEFMODE]) { + ax25->modulus = AX25_EMODULUS; + ax25->window = ax25_dev->values[AX25_VALUES_EWINDOW]; + } else { + ax25->modulus = AX25_MODULUS; + ax25->window = ax25_dev->values[AX25_VALUES_WINDOW]; + } +} + /* * Fill in a created AX.25 created control block with the default * values for a particular device. @@ -435,39 +455,28 @@ void ax25_fillin_cb(ax25_cb *ax25, ax25_dev *ax25_dev) ax25->ax25_dev = ax25_dev; if (ax25->ax25_dev != NULL) { - ax25->rtt = ax25_dev->values[AX25_VALUES_T1] / 2; - ax25->t1 = ax25_dev->values[AX25_VALUES_T1]; - ax25->t2 = ax25_dev->values[AX25_VALUES_T2]; - ax25->t3 = ax25_dev->values[AX25_VALUES_T3]; - ax25->n2 = ax25_dev->values[AX25_VALUES_N2]; - ax25->paclen = ax25_dev->values[AX25_VALUES_PACLEN]; - ax25->idle = ax25_dev->values[AX25_VALUES_IDLE]; - ax25->backoff = ax25_dev->values[AX25_VALUES_BACKOFF]; - - if (ax25_dev->values[AX25_VALUES_AXDEFMODE]) { - ax25->modulus = AX25_EMODULUS; - ax25->window = ax25_dev->values[AX25_VALUES_EWINDOW]; - } else { - ax25->modulus = AX25_MODULUS; - ax25->window = ax25_dev->values[AX25_VALUES_WINDOW]; - } + ax25_fillin_cb_from_dev(ax25, ax25_dev); + return; + } + + /* + * No device, use kernel / AX.25 spec default values + */ + ax25->rtt = msecs_to_jiffies(AX25_DEF_T1) / 2; + ax25->t1 = msecs_to_jiffies(AX25_DEF_T1); + ax25->t2 = msecs_to_jiffies(AX25_DEF_T2); + ax25->t3 = msecs_to_jiffies(AX25_DEF_T3); + ax25->n2 = AX25_DEF_N2; + ax25->paclen = AX25_DEF_PACLEN; + ax25->idle = msecs_to_jiffies(AX25_DEF_IDLE); + ax25->backoff = AX25_DEF_BACKOFF; + + if (AX25_DEF_AXDEFMODE) { + ax25->modulus = AX25_EMODULUS; + ax25->window = AX25_DEF_EWINDOW; } else { - ax25->rtt = AX25_DEF_T1 / 2; - ax25->t1 = AX25_DEF_T1; - ax25->t2 = AX25_DEF_T2; - ax25->t3 = AX25_DEF_T3; - ax25->n2 = AX25_DEF_N2; - ax25->paclen = AX25_DEF_PACLEN; - ax25->idle = AX25_DEF_IDLE; - ax25->backoff = AX25_DEF_BACKOFF; - - if (AX25_DEF_AXDEFMODE) { - ax25->modulus = AX25_EMODULUS; - ax25->window = AX25_DEF_EWINDOW; - } else { - ax25->modulus = AX25_MODULUS; - ax25->window = AX25_DEF_WINDOW; - } + ax25->modulus = AX25_MODULUS; + ax25->window = AX25_DEF_WINDOW; } } diff --git a/net/ax25/ax25_ds_timer.c b/net/ax25/ax25_ds_timer.c index 061083efc1dc..5961459935eb 100644 --- a/net/ax25/ax25_ds_timer.c +++ b/net/ax25/ax25_ds_timer.c @@ -61,7 +61,8 @@ void ax25_ds_set_timer(ax25_dev *ax25_dev) return; del_timer(&ax25_dev->dama.slave_timer); - ax25_dev->dama.slave_timeout = ax25_dev->values[AX25_VALUES_DS_TIMEOUT] / 10; + ax25_dev->dama.slave_timeout = + msecs_to_jiffies(ax25_dev->values[AX25_VALUES_DS_TIMEOUT]) / 10; ax25_ds_add_timer(ax25_dev); } diff --git a/net/ax25/sysctl_net_ax25.c b/net/ax25/sysctl_net_ax25.c index 894a22558d9d..bdb64c36df12 100644 --- a/net/ax25/sysctl_net_ax25.c +++ b/net/ax25/sysctl_net_ax25.c @@ -18,14 +18,14 @@ static int min_backoff[1], max_backoff[] = {2}; static int min_conmode[1], max_conmode[] = {2}; static int min_window[] = {1}, max_window[] = {7}; static int min_ewindow[] = {1}, max_ewindow[] = {63}; -static int min_t1[] = {1}, max_t1[] = {30 * HZ}; -static int min_t2[] = {1}, max_t2[] = {20 * HZ}; -static int min_t3[1], max_t3[] = {3600 * HZ}; -static int min_idle[1], max_idle[] = {65535 * HZ}; +static int min_t1[] = {1}, max_t1[] = {30000}; +static int min_t2[] = {1}, max_t2[] = {20000}; +static int min_t3[1], max_t3[] = {3600000}; +static int min_idle[1], max_idle[] = {65535000}; static int min_n2[] = {1}, max_n2[] = {31}; static int min_paclen[] = {1}, max_paclen[] = {512}; static int min_proto[1], max_proto[] = { AX25_PROTO_MAX }; -static int min_ds_timeout[1], max_ds_timeout[] = {65535 * HZ}; +static int min_ds_timeout[1], max_ds_timeout[] = {65535000}; static struct ctl_table_header *ax25_table_header; -- cgit v1.2.3-70-g09d2 From 4d8937d0b113e8ec39f7d18cf13804f3b5fb8fd4 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 3 May 2006 23:27:47 -0700 Subject: [NETROM]: Eleminate HZ from NET/ROM kernel interfaces Convert all NET/ROM sysctl time values from jiffies to ms as units. Signed-off-by: Ralf Baechle Signed-off-by: David S. Miller --- include/net/netrom.h | 8 ++++---- net/netrom/af_netrom.c | 15 ++++++++++----- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/include/net/netrom.h b/include/net/netrom.h index a5ee53bce62f..e0ca112024a3 100644 --- a/include/net/netrom.h +++ b/include/net/netrom.h @@ -42,11 +42,11 @@ enum { #define NR_COND_PEER_RX_BUSY 0x04 #define NR_COND_OWN_RX_BUSY 0x08 -#define NR_DEFAULT_T1 (120 * HZ) /* Outstanding frames - 120 seconds */ -#define NR_DEFAULT_T2 (5 * HZ) /* Response delay - 5 seconds */ +#define NR_DEFAULT_T1 120000 /* Outstanding frames - 120 seconds */ +#define NR_DEFAULT_T2 5000 /* Response delay - 5 seconds */ #define NR_DEFAULT_N2 3 /* Number of Retries - 3 */ -#define NR_DEFAULT_T4 (180 * HZ) /* Busy Delay - 180 seconds */ -#define NR_DEFAULT_IDLE (0 * 60 * HZ) /* No Activity Timeout - none */ +#define NR_DEFAULT_T4 180000 /* Busy Delay - 180 seconds */ +#define NR_DEFAULT_IDLE 0 /* No Activity Timeout - none */ #define NR_DEFAULT_WINDOW 4 /* Default Window Size - 4 */ #define NR_DEFAULT_OBS 6 /* Default Obsolescence Count - 6 */ #define NR_DEFAULT_QUAL 10 /* Default Neighbour Quality - 10 */ diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index d44981f5a619..ecd288beca7c 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c @@ -425,11 +425,16 @@ static int nr_create(struct socket *sock, int protocol) nr_init_timers(sk); - nr->t1 = sysctl_netrom_transport_timeout; - nr->t2 = sysctl_netrom_transport_acknowledge_delay; - nr->n2 = sysctl_netrom_transport_maximum_tries; - nr->t4 = sysctl_netrom_transport_busy_delay; - nr->idle = sysctl_netrom_transport_no_activity_timeout; + nr->t1 = + msecs_to_jiffies(sysctl_netrom_transport_timeout); + nr->t2 = + msecs_to_jiffies(sysctl_netrom_transport_acknowledge_delay); + nr->n2 = + msecs_to_jiffies(sysctl_netrom_transport_maximum_tries); + nr->t4 = + msecs_to_jiffies(sysctl_netrom_transport_busy_delay); + nr->idle = + msecs_to_jiffies(sysctl_netrom_transport_no_activity_timeout); nr->window = sysctl_netrom_transport_requested_window_size; nr->bpqext = 1; -- cgit v1.2.3-70-g09d2 From 82e84249f0ee098e004c8bd6d90a1640bd56cfbb Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 3 May 2006 23:28:20 -0700 Subject: [ROSE]: Eleminate HZ from ROSE kernel interfaces Convert all ROSE sysctl time values from jiffies to ms as units. Signed-off-by: Ralf Baechle Signed-off-by: David S. Miller --- include/net/rose.h | 14 +++++++------- net/rose/af_rose.c | 10 +++++----- net/rose/rose_link.c | 6 ++++-- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/include/net/rose.h b/include/net/rose.h index 3249b979605a..012b09ed2401 100644 --- a/include/net/rose.h +++ b/include/net/rose.h @@ -49,14 +49,14 @@ enum { ROSE_STATE_5 /* Deferred Call Acceptance */ }; -#define ROSE_DEFAULT_T0 (180 * HZ) /* Default T10 T20 value */ -#define ROSE_DEFAULT_T1 (200 * HZ) /* Default T11 T21 value */ -#define ROSE_DEFAULT_T2 (180 * HZ) /* Default T12 T22 value */ -#define ROSE_DEFAULT_T3 (180 * HZ) /* Default T13 T23 value */ -#define ROSE_DEFAULT_HB (5 * HZ) /* Default Holdback value */ -#define ROSE_DEFAULT_IDLE (0 * 60 * HZ) /* No Activity Timeout - none */ +#define ROSE_DEFAULT_T0 180000 /* Default T10 T20 value */ +#define ROSE_DEFAULT_T1 200000 /* Default T11 T21 value */ +#define ROSE_DEFAULT_T2 180000 /* Default T12 T22 value */ +#define ROSE_DEFAULT_T3 180000 /* Default T13 T23 value */ +#define ROSE_DEFAULT_HB 5000 /* Default Holdback value */ +#define ROSE_DEFAULT_IDLE 0 /* No Activity Timeout - none */ #define ROSE_DEFAULT_ROUTING 1 /* Default routing flag */ -#define ROSE_DEFAULT_FAIL_TIMEOUT (120 * HZ) /* Time until link considered usable */ +#define ROSE_DEFAULT_FAIL_TIMEOUT 120000 /* Time until link considered usable */ #define ROSE_DEFAULT_MAXVC 50 /* Maximum number of VCs per neighbour */ #define ROSE_DEFAULT_WINDOW_SIZE 7 /* Default window size */ diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index ea65396d1619..ef4538ac84f0 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -518,11 +518,11 @@ static int rose_create(struct socket *sock, int protocol) init_timer(&rose->timer); init_timer(&rose->idletimer); - rose->t1 = sysctl_rose_call_request_timeout; - rose->t2 = sysctl_rose_reset_request_timeout; - rose->t3 = sysctl_rose_clear_request_timeout; - rose->hb = sysctl_rose_ack_hold_back_timeout; - rose->idle = sysctl_rose_no_activity_timeout; + rose->t1 = msecs_to_jiffies(sysctl_rose_call_request_timeout); + rose->t2 = msecs_to_jiffies(sysctl_rose_reset_request_timeout); + rose->t3 = msecs_to_jiffies(sysctl_rose_clear_request_timeout); + rose->hb = msecs_to_jiffies(sysctl_rose_ack_hold_back_timeout); + rose->idle = msecs_to_jiffies(sysctl_rose_no_activity_timeout); rose->state = ROSE_STATE_0; diff --git a/net/rose/rose_link.c b/net/rose/rose_link.c index 09e9e9d04d92..bd86a63960ce 100644 --- a/net/rose/rose_link.c +++ b/net/rose/rose_link.c @@ -40,7 +40,8 @@ void rose_start_ftimer(struct rose_neigh *neigh) neigh->ftimer.data = (unsigned long)neigh; neigh->ftimer.function = &rose_ftimer_expiry; - neigh->ftimer.expires = jiffies + sysctl_rose_link_fail_timeout; + neigh->ftimer.expires = + jiffies + msecs_to_jiffies(sysctl_rose_link_fail_timeout); add_timer(&neigh->ftimer); } @@ -51,7 +52,8 @@ static void rose_start_t0timer(struct rose_neigh *neigh) neigh->t0timer.data = (unsigned long)neigh; neigh->t0timer.function = &rose_t0timer_expiry; - neigh->t0timer.expires = jiffies + sysctl_rose_restart_request_timeout; + neigh->t0timer.expires = + jiffies + msecs_to_jiffies(sysctl_rose_restart_request_timeout); add_timer(&neigh->t0timer); } -- cgit v1.2.3-70-g09d2 From 75c2d9077c63ac21488129cc23561d4f4fd0f5e5 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 3 May 2006 23:31:35 -0700 Subject: [TCP]: Fix sock_orphan dead lock Calling sock_orphan inside bh_lock_sock in tcp_close can lead to dead locks. For example, the inet_diag code holds sk_callback_lock without disabling BH. If an inbound packet arrives during that admittedly tiny window, it will cause a dead lock on bh_lock_sock. Another possible path would be through sock_wfree if the network device driver frees the tx skb in process context with BH enabled. We can fix this by moving sock_orphan out of bh_lock_sock. The tricky bit is to work out when we need to destroy the socket ourselves and when it has already been destroyed by someone else. By moving sock_orphan before the release_sock we can solve this problem. This is because as long as we own the socket lock its state cannot change. So we simply record the socket state before the release_sock and then check the state again after we regain the socket lock. If the socket state has transitioned to TCP_CLOSE in the time being, we know that the socket has been destroyed. Otherwise the socket is still ours to keep. Note that I've also moved the increment on the orphan count forward. This may look like a problem as we're increasing it even if the socket is just about to be destroyed where it'll be decreased again. However, this simply enlarges a window that already exists. This also changes the orphan count test by one. Considering what the orphan count is meant to do this is no big deal. This problem was discoverd by Ingo Molnar using his lock validator. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/ipv4/tcp.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 87f68e787d0c..e2b7b8055037 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1468,6 +1468,7 @@ void tcp_close(struct sock *sk, long timeout) { struct sk_buff *skb; int data_was_unread = 0; + int state; lock_sock(sk); sk->sk_shutdown = SHUTDOWN_MASK; @@ -1544,6 +1545,11 @@ void tcp_close(struct sock *sk, long timeout) sk_stream_wait_close(sk, timeout); adjudge_to_death: + state = sk->sk_state; + sock_hold(sk); + sock_orphan(sk); + atomic_inc(sk->sk_prot->orphan_count); + /* It is the last release_sock in its life. It will remove backlog. */ release_sock(sk); @@ -1555,8 +1561,9 @@ adjudge_to_death: bh_lock_sock(sk); BUG_TRAP(!sock_owned_by_user(sk)); - sock_hold(sk); - sock_orphan(sk); + /* Have we already been destroyed by a softirq or backlog? */ + if (state != TCP_CLOSE && sk->sk_state == TCP_CLOSE) + goto out; /* This is a (useful) BSD violating of the RFC. There is a * problem with TCP as specified in that the other end could @@ -1584,7 +1591,6 @@ adjudge_to_death: if (tmo > TCP_TIMEWAIT_LEN) { inet_csk_reset_keepalive_timer(sk, tcp_fin_time(sk)); } else { - atomic_inc(sk->sk_prot->orphan_count); tcp_time_wait(sk, TCP_FIN_WAIT2, tmo); goto out; } @@ -1603,7 +1609,6 @@ adjudge_to_death: NET_INC_STATS_BH(LINUX_MIB_TCPABORTONMEMORY); } } - atomic_inc(sk->sk_prot->orphan_count); if (sk->sk_state == TCP_CLOSE) inet_csk_destroy_sock(sk); -- cgit v1.2.3-70-g09d2 From d1a649838802edd94b6335834919463c6ae61f40 Mon Sep 17 00:00:00 2001 From: Patrick Caulfield Date: Wed, 3 May 2006 23:36:23 -0700 Subject: [DECNET]: Fix level1 router hello This patch fixes hello messages sent when a node is a level 1 router. Slightly contrary to the spec (maybe) VMS ignores hello messages that do not name level2 routers that it also knows about. So, here we simply name all the routers that the node knows about rather just other level1 routers. (I hope the patch is clearer than the description. sorry). Signed-off-by: Patrick Caulfield Signed-off-by: David S. Miller --- net/decnet/dn_neigh.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/net/decnet/dn_neigh.c b/net/decnet/dn_neigh.c index 7c8692c26bfe..66e230c3b328 100644 --- a/net/decnet/dn_neigh.c +++ b/net/decnet/dn_neigh.c @@ -493,7 +493,6 @@ struct elist_cb_state { static void neigh_elist_cb(struct neighbour *neigh, void *_info) { struct elist_cb_state *s = _info; - struct dn_dev *dn_db; struct dn_neigh *dn; if (neigh->dev != s->dev) @@ -503,10 +502,6 @@ static void neigh_elist_cb(struct neighbour *neigh, void *_info) if (!(dn->flags & (DN_NDFLAG_R1|DN_NDFLAG_R2))) return; - dn_db = (struct dn_dev *) s->dev->dn_ptr; - if (dn_db->parms.forwarding == 1 && (dn->flags & DN_NDFLAG_R2)) - return; - if (s->t == s->n) s->rs = dn_find_slot(s->ptr, s->n, dn->priority); else -- cgit v1.2.3-70-g09d2 From 98232d504db0a1f91ecaa93686ed3bf61963103b Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 4 May 2006 09:13:49 +0200 Subject: [PATCH] compat_sys_vmsplice: one-off in UIO_MAXIOV check nr_segs may not be > UIO_MAXIOV, however it may be equal to. This makes the behaviour identical to the real sys_vmsplice(). The other foov syscalls also agree that this is the way to go. Signed-off-by: Jens Axboe --- fs/compat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/compat.c b/fs/compat.c index 3f3e8f4d43d6..970888aad843 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -1323,7 +1323,7 @@ compat_sys_vmsplice(int fd, const struct compat_iovec __user *iov32, { unsigned i; struct iovec *iov; - if (nr_segs >= UIO_MAXIOV) + if (nr_segs > UIO_MAXIOV) return -EINVAL; iov = compat_alloc_user_space(nr_segs * sizeof(struct iovec)); for (i = 0; i < nr_segs; i++) { -- cgit v1.2.3-70-g09d2 From fe10c6abea8bc83291a13e0580b3e4c355710b09 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 4 May 2006 13:51:45 +0100 Subject: [MMC] Correct mmc_request_done comments mmc_request_done should be called at the end of handling a request, not between the data and initial command parts of the request. Signed-off-by: Russell King --- drivers/mmc/mmc.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 05aa4d6b4f24..91c6b10dda9a 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -59,13 +59,12 @@ static const unsigned int tacc_mant[] = { /** - * mmc_request_done - finish processing an MMC command - * @host: MMC host which completed command - * @mrq: MMC request which completed + * mmc_request_done - finish processing an MMC request + * @host: MMC host which completed request + * @mrq: MMC request which request * * MMC drivers should call this function when they have completed - * their processing of a command. This should be called before the - * data part of the command has completed. + * their processing of a request. */ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) { -- cgit v1.2.3-70-g09d2 From 5b802344357338a4d645beac8ca97470bcbe3542 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 4 May 2006 14:07:42 +0100 Subject: [ARM] 3490/1: i.MX: move uart resources to board files Patch from Sascha Hauer This patch moves the i.MX uart resources and the gpio pin setup to the board files. This allows the boards to decide how many internal uarts are connected to the outside world and whether they use rts/cts or not. Signed-off-by: Sascha Hauer Signed-off-by: Russell King --- arch/arm/mach-imx/generic.c | 52 -------------------------- arch/arm/mach-imx/mx1ads.c | 74 +++++++++++++++++++++++++++++++++++++ drivers/serial/imx.c | 40 ++++++++------------ include/asm-arm/arch-imx/imx-uart.h | 10 +++++ 4 files changed, 100 insertions(+), 76 deletions(-) create mode 100644 include/asm-arm/arch-imx/imx-uart.h diff --git a/arch/arm/mach-imx/generic.c b/arch/arm/mach-imx/generic.c index 9d8331be2b58..12ea58a3b84f 100644 --- a/arch/arm/mach-imx/generic.c +++ b/arch/arm/mach-imx/generic.c @@ -195,56 +195,6 @@ void __init imx_set_mmc_info(struct imxmmc_platform_data *info) } EXPORT_SYMBOL(imx_set_mmc_info); -static struct resource imx_uart1_resources[] = { - [0] = { - .start = 0x00206000, - .end = 0x002060FF, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = (UART1_MINT_RX), - .end = (UART1_MINT_RX), - .flags = IORESOURCE_IRQ, - }, - [2] = { - .start = (UART1_MINT_TX), - .end = (UART1_MINT_TX), - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device imx_uart1_device = { - .name = "imx-uart", - .id = 0, - .num_resources = ARRAY_SIZE(imx_uart1_resources), - .resource = imx_uart1_resources, -}; - -static struct resource imx_uart2_resources[] = { - [0] = { - .start = 0x00207000, - .end = 0x002070FF, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = (UART2_MINT_RX), - .end = (UART2_MINT_RX), - .flags = IORESOURCE_IRQ, - }, - [2] = { - .start = (UART2_MINT_TX), - .end = (UART2_MINT_TX), - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device imx_uart2_device = { - .name = "imx-uart", - .id = 1, - .num_resources = ARRAY_SIZE(imx_uart2_resources), - .resource = imx_uart2_resources, -}; - static struct imxfb_mach_info imx_fb_info; void __init set_imx_fb_info(struct imxfb_mach_info *hard_imx_fb_info) @@ -283,8 +233,6 @@ static struct platform_device imxfb_device = { static struct platform_device *devices[] __initdata = { &imx_mmc_device, &imxfb_device, - &imx_uart1_device, - &imx_uart2_device, }; static struct map_desc imx_io_desc[] __initdata = { diff --git a/arch/arm/mach-imx/mx1ads.c b/arch/arm/mach-imx/mx1ads.c index e34d0df90aed..e1f6c0bbe1e7 100644 --- a/arch/arm/mach-imx/mx1ads.c +++ b/arch/arm/mach-imx/mx1ads.c @@ -26,6 +26,7 @@ #include #include +#include #include #include "generic.h" @@ -48,8 +49,70 @@ static struct platform_device cs89x0_device = { .resource = cs89x0_resources, }; +static struct imxuart_platform_data uart_pdata = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +static struct resource imx_uart1_resources[] = { + [0] = { + .start = 0x00206000, + .end = 0x002060FF, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = (UART1_MINT_RX), + .end = (UART1_MINT_RX), + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = (UART1_MINT_TX), + .end = (UART1_MINT_TX), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device imx_uart1_device = { + .name = "imx-uart", + .id = 0, + .num_resources = ARRAY_SIZE(imx_uart1_resources), + .resource = imx_uart1_resources, + .dev = { + .platform_data = &uart_pdata, + } +}; + +static struct resource imx_uart2_resources[] = { + [0] = { + .start = 0x00207000, + .end = 0x002070FF, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = (UART2_MINT_RX), + .end = (UART2_MINT_RX), + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = (UART2_MINT_TX), + .end = (UART2_MINT_TX), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device imx_uart2_device = { + .name = "imx-uart", + .id = 1, + .num_resources = ARRAY_SIZE(imx_uart2_resources), + .resource = imx_uart2_resources, + .dev = { + .platform_data = &uart_pdata, + } +}; + static struct platform_device *devices[] __initdata = { &cs89x0_device, + &imx_uart1_device, + &imx_uart2_device, }; #ifdef CONFIG_MMC_IMX @@ -75,6 +138,17 @@ mx1ads_init(void) imx_gpio_mode(GPIO_PORTB | GPIO_GIUS | GPIO_IN | 20); imx_set_mmc_info(&mx1ads_mmc_info); #endif + + imx_gpio_mode(PC9_PF_UART1_CTS); + imx_gpio_mode(PC10_PF_UART1_RTS); + imx_gpio_mode(PC11_PF_UART1_TXD); + imx_gpio_mode(PC12_PF_UART1_RXD); + + imx_gpio_mode(PB28_PF_UART2_CTS); + imx_gpio_mode(PB29_PF_UART2_RTS); + imx_gpio_mode(PB30_PF_UART2_TXD); + imx_gpio_mode(PB31_PF_UART2_RXD); + platform_add_devices(devices, ARRAY_SIZE(devices)); } diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index c3b7a6673e9c..d202eb4f3848 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -45,6 +45,7 @@ #include #include #include +#include /* We've been assigned a range on the "Low-density serial ports" major */ #define SERIAL_IMX_MAJOR 204 @@ -73,7 +74,8 @@ struct imx_port { struct uart_port port; struct timer_list timer; unsigned int old_status; - int txirq,rxirq,rtsirq; + int txirq,rxirq,rtsirq; + int have_rtscts:1; }; /* @@ -491,8 +493,12 @@ imx_set_termios(struct uart_port *port, struct termios *termios, ucr2 = UCR2_SRST | UCR2_IRTS; if (termios->c_cflag & CRTSCTS) { - ucr2 &= ~UCR2_IRTS; - ucr2 |= UCR2_CTSC; + if( sport->have_rtscts ) { + ucr2 &= ~UCR2_IRTS; + ucr2 |= UCR2_CTSC; + } else { + termios->c_cflag &= ~CRTSCTS; + } } if (termios->c_cflag & CSTOPB) @@ -719,27 +725,6 @@ static void __init imx_init_ports(void) imx_ports[i].timer.function = imx_timeout; imx_ports[i].timer.data = (unsigned long)&imx_ports[i]; } - - imx_gpio_mode(PC9_PF_UART1_CTS); - imx_gpio_mode(PC10_PF_UART1_RTS); - imx_gpio_mode(PC11_PF_UART1_TXD); - imx_gpio_mode(PC12_PF_UART1_RXD); - imx_gpio_mode(PB28_PF_UART2_CTS); - imx_gpio_mode(PB29_PF_UART2_RTS); - - imx_gpio_mode(PB30_PF_UART2_TXD); - imx_gpio_mode(PB31_PF_UART2_RXD); - -#if 0 /* We don't need these, on the mx1 the _modem_ side of the uart - * is implemented. - */ - imx_gpio_mode(PD7_AF_UART2_DTR); - imx_gpio_mode(PD8_AF_UART2_DCD); - imx_gpio_mode(PD9_AF_UART2_RI); - imx_gpio_mode(PD10_AF_UART2_DSR); -#endif - - } #ifdef CONFIG_SERIAL_IMX_CONSOLE @@ -932,7 +917,14 @@ static int serial_imx_resume(struct platform_device *dev) static int serial_imx_probe(struct platform_device *dev) { + struct imxuart_platform_data *pdata; + imx_ports[dev->id].port.dev = &dev->dev; + + pdata = (struct imxuart_platform_data *)dev->dev.platform_data; + if(pdata && (pdata->flags & IMXUART_HAVE_RTSCTS)) + imx_ports[dev->id].have_rtscts = 1; + uart_add_one_port(&imx_reg, &imx_ports[dev->id].port); platform_set_drvdata(dev, &imx_ports[dev->id]); return 0; diff --git a/include/asm-arm/arch-imx/imx-uart.h b/include/asm-arm/arch-imx/imx-uart.h new file mode 100644 index 000000000000..3a685e1780ea --- /dev/null +++ b/include/asm-arm/arch-imx/imx-uart.h @@ -0,0 +1,10 @@ +#ifndef ASMARM_ARCH_UART_H +#define ASMARM_ARCH_UART_H + +#define IMXUART_HAVE_RTSCTS (1<<0) + +struct imxuart_platform_data { + unsigned int flags; +}; + +#endif -- cgit v1.2.3-70-g09d2 From 920e70c5c603ada05dd480ca0ccc0ae12a5fdc39 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 4 May 2006 18:22:51 +0100 Subject: [MMC] Move set_ios debugging into mmc.c Rather than having every driver duplicate the set_ios debugging, provide a single version in mmc.c which can be expanded as we add additional functionality. Signed-off-by: Russell King --- drivers/mmc/at91_mci.c | 3 --- drivers/mmc/au1xmmc.c | 4 ---- drivers/mmc/imxmmc.c | 4 ---- drivers/mmc/mmc.c | 51 +++++++++++++++++++++++++++++++++----------------- drivers/mmc/mmci.c | 3 --- drivers/mmc/pxamci.c | 4 ---- drivers/mmc/sdhci.c | 4 ---- drivers/mmc/wbsd.c | 4 ---- 8 files changed, 34 insertions(+), 43 deletions(-) diff --git a/drivers/mmc/at91_mci.c b/drivers/mmc/at91_mci.c index 6061c2d101a0..88f0eef9cf33 100644 --- a/drivers/mmc/at91_mci.c +++ b/drivers/mmc/at91_mci.c @@ -621,9 +621,6 @@ static void at91_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) struct at91mci_host *host = mmc_priv(mmc); unsigned long at91_master_clock = clk_get_rate(mci_clk); - DBG("Clock %uHz, busmode %u, powermode %u, Vdd %u\n", - ios->clock, ios->bus_mode, ios->power_mode, ios->vdd); - if (host) host->bus_mode = ios->bus_mode; else diff --git a/drivers/mmc/au1xmmc.c b/drivers/mmc/au1xmmc.c index c0326bbc5f28..914d62b24064 100644 --- a/drivers/mmc/au1xmmc.c +++ b/drivers/mmc/au1xmmc.c @@ -720,10 +720,6 @@ static void au1xmmc_set_ios(struct mmc_host* mmc, struct mmc_ios* ios) { struct au1xmmc_host *host = mmc_priv(mmc); - DBG("set_ios (power=%u, clock=%uHz, vdd=%u, mode=%u)\n", - host->id, ios->power_mode, ios->clock, ios->vdd, - ios->bus_mode); - if (ios->power_mode == MMC_POWER_OFF) au1xmmc_set_power(host, 0); else if (ios->power_mode == MMC_POWER_ON) { diff --git a/drivers/mmc/imxmmc.c b/drivers/mmc/imxmmc.c index bc271925099a..79358e223f57 100644 --- a/drivers/mmc/imxmmc.c +++ b/drivers/mmc/imxmmc.c @@ -807,10 +807,6 @@ static void imxmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) struct imxmci_host *host = mmc_priv(mmc); int prescaler; - dev_dbg(mmc_dev(host->mmc), "clock %u power %u vdd %u width %u\n", - ios->clock, ios->power_mode, ios->vdd, - (ios->bus_width==MMC_BUS_WIDTH_4)?4:1); - if( ios->bus_width==MMC_BUS_WIDTH_4 ) { host->actual_bus_width = MMC_BUS_WIDTH_4; imx_gpio_mode(PB11_PF_SD_DAT3); diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 91c6b10dda9a..1ca2c8b9c9b5 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -69,10 +69,13 @@ static const unsigned int tacc_mant[] = { void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) { struct mmc_command *cmd = mrq->cmd; - int err = mrq->cmd->error; - pr_debug("MMC: req done (%02x): %d: %08x %08x %08x %08x\n", - cmd->opcode, err, cmd->resp[0], cmd->resp[1], - cmd->resp[2], cmd->resp[3]); + int err = cmd->error; + + pr_debug("%s: req done (CMD%u): %d/%d/%d: %08x %08x %08x %08x\n", + mmc_hostname(host), cmd->opcode, err, + mrq->data ? mrq->data->error : 0, + mrq->stop ? mrq->stop->error : 0, + cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]); if (err && cmd->retries) { cmd->retries--; @@ -96,8 +99,9 @@ EXPORT_SYMBOL(mmc_request_done); void mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) { - pr_debug("MMC: starting cmd %02x arg %08x flags %08x\n", - mrq->cmd->opcode, mrq->cmd->arg, mrq->cmd->flags); + pr_debug("%s: starting CMD%u arg %08x flags %08x\n", + mmc_hostname(host), mrq->cmd->opcode, + mrq->cmd->arg, mrq->cmd->flags); WARN_ON(host->card_busy == NULL); @@ -311,6 +315,18 @@ void mmc_release_host(struct mmc_host *host) EXPORT_SYMBOL(mmc_release_host); +static inline void mmc_set_ios(struct mmc_host *host) +{ + struct mmc_ios *ios = &host->ios; + + pr_debug("%s: clock %uHz busmode %u powermode %u cs %u Vdd %u width %u\n", + mmc_hostname(host), ios->clock, ios->bus_mode, + ios->power_mode, ios->chip_select, ios->vdd, + ios->bus_width); + + host->ops->set_ios(host, ios); +} + static int mmc_select_card(struct mmc_host *host, struct mmc_card *card) { int err; @@ -363,7 +379,7 @@ static int mmc_select_card(struct mmc_host *host, struct mmc_card *card) } } - host->ops->set_ios(host, &host->ios); + mmc_set_ios(host); return MMC_ERR_NONE; } @@ -414,7 +430,7 @@ static u32 mmc_select_voltage(struct mmc_host *host, u32 ocr) ocr = 3 << bit; host->ios.vdd = bit; - host->ops->set_ios(host, &host->ios); + mmc_set_ios(host); } else { ocr = 0; } @@ -667,7 +683,7 @@ static void mmc_idle_cards(struct mmc_host *host) struct mmc_command cmd; host->ios.chip_select = MMC_CS_HIGH; - host->ops->set_ios(host, &host->ios); + mmc_set_ios(host); mmc_delay(1); @@ -680,7 +696,7 @@ static void mmc_idle_cards(struct mmc_host *host) mmc_delay(1); host->ios.chip_select = MMC_CS_DONTCARE; - host->ops->set_ios(host, &host->ios); + mmc_set_ios(host); mmc_delay(1); } @@ -705,13 +721,13 @@ static void mmc_power_up(struct mmc_host *host) host->ios.chip_select = MMC_CS_DONTCARE; host->ios.power_mode = MMC_POWER_UP; host->ios.bus_width = MMC_BUS_WIDTH_1; - host->ops->set_ios(host, &host->ios); + mmc_set_ios(host); mmc_delay(1); host->ios.clock = host->f_min; host->ios.power_mode = MMC_POWER_ON; - host->ops->set_ios(host, &host->ios); + mmc_set_ios(host); mmc_delay(2); } @@ -724,7 +740,7 @@ static void mmc_power_off(struct mmc_host *host) host->ios.chip_select = MMC_CS_DONTCARE; host->ios.power_mode = MMC_POWER_OFF; host->ios.bus_width = MMC_BUS_WIDTH_1; - host->ops->set_ios(host, &host->ios); + mmc_set_ios(host); } static int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) @@ -972,7 +988,8 @@ static unsigned int mmc_calculate_clock(struct mmc_host *host) if (!mmc_card_dead(card) && max_dtr > card->csd.max_dtr) max_dtr = card->csd.max_dtr; - pr_debug("MMC: selected %d.%03dMHz transfer rate\n", + pr_debug("%s: selected %d.%03dMHz transfer rate\n", + mmc_hostname(host), max_dtr / 1000000, (max_dtr / 1000) % 1000); return max_dtr; @@ -1047,7 +1064,7 @@ static void mmc_setup(struct mmc_host *host) } else { host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; host->ios.clock = host->f_min; - host->ops->set_ios(host, &host->ios); + mmc_set_ios(host); /* * We should remember the OCR mask from the existing @@ -1083,7 +1100,7 @@ static void mmc_setup(struct mmc_host *host) * Ok, now switch to push-pull mode. */ host->ios.bus_mode = MMC_BUSMODE_PUSHPULL; - host->ops->set_ios(host, &host->ios); + mmc_set_ios(host); mmc_read_csds(host); @@ -1129,7 +1146,7 @@ static void mmc_rescan(void *data) * attached cards and the host support. */ host->ios.clock = mmc_calculate_clock(host); - host->ops->set_ios(host, &host->ios); + mmc_set_ios(host); } mmc_release_host(host); diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c index df7e861e2fc7..da8e4d7339cc 100644 --- a/drivers/mmc/mmci.c +++ b/drivers/mmc/mmci.c @@ -402,9 +402,6 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) struct mmci_host *host = mmc_priv(mmc); u32 clk = 0, pwr = 0; - DBG(host, "clock %uHz busmode %u powermode %u Vdd %u\n", - ios->clock, ios->bus_mode, ios->power_mode, ios->vdd); - if (ios->clock) { if (ios->clock >= host->mclk) { clk = MCI_CLK_BYPASS; diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c index 40970c4ae3e6..f97b472085cb 100644 --- a/drivers/mmc/pxamci.c +++ b/drivers/mmc/pxamci.c @@ -365,10 +365,6 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct pxamci_host *host = mmc_priv(mmc); - pr_debug("PXAMCI: clock %u power %u vdd %u.%02u\n", - ios->clock, ios->power_mode, ios->vdd / 100, - ios->vdd % 100); - if (ios->clock) { unsigned int clk = CLOCKRATE / ios->clock; if (CLOCKRATE / clk > ios->clock) diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index bdbfca050029..b0053280ff2d 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -570,10 +570,6 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) spin_lock_irqsave(&host->lock, flags); - DBG("clock %uHz busmode %u powermode %u cs %u Vdd %u width %u\n", - ios->clock, ios->bus_mode, ios->power_mode, ios->chip_select, - ios->vdd, ios->bus_width); - /* * Reset the chip on each power off. * Should clear out any weird states. diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c index 511f7b0b31d2..39b3d97f891e 100644 --- a/drivers/mmc/wbsd.c +++ b/drivers/mmc/wbsd.c @@ -931,10 +931,6 @@ static void wbsd_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) struct wbsd_host *host = mmc_priv(mmc); u8 clk, setup, pwr; - DBGF("clock %uHz busmode %u powermode %u cs %u Vdd %u width %u\n", - ios->clock, ios->bus_mode, ios->power_mode, ios->chip_select, - ios->vdd, ios->bus_width); - spin_lock_bh(&host->lock); /* -- cgit v1.2.3-70-g09d2 From fed3be9bd56e67c9b9324277b7f95c32e73a75bb Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 4 May 2006 13:23:40 -0400 Subject: CREDITS file update (Tristan Greaves) By request from Tristan. Signed-off-by: Linus Torvalds --- CREDITS | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/CREDITS b/CREDITS index 787564bc248b..6f50be37fa0f 100644 --- a/CREDITS +++ b/CREDITS @@ -1194,15 +1194,9 @@ S: Brecksville, OH 44141-1334 S: USA N: Tristan Greaves -E: Tristan.Greaves@icl.com -E: tmg296@ecs.soton.ac.uk -W: http://www.ecs.soton.ac.uk/~tmg296 +E: tristan@extricate.org +W: http://www.extricate.org/ D: Miscellaneous ipv4 sysctl patches -S: 15 Little Mead -S: Denmead -S: Hampshire -S: PO7 6HS -S: United Kingdom N: Michael A. Griffith E: grif@cs.ucr.edu -- cgit v1.2.3-70-g09d2 From ff10952a547dad934d9ed9afc5cf579ed1ccb53a Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Fri, 5 May 2006 15:11:14 +0100 Subject: [ARM] 3494/1: asm-arm/bug.h needs linux/stddef.h Patch from Nicolas Pitre ... for the definition of NULL. Signed-off-by: Nicolas Pitre Signed-off-by: Russell King --- include/asm-arm/bug.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/asm-arm/bug.h b/include/asm-arm/bug.h index 7fb02138f585..5ab8216f5204 100644 --- a/include/asm-arm/bug.h +++ b/include/asm-arm/bug.h @@ -2,6 +2,7 @@ #define _ASMARM_BUG_H #include +#include #ifdef CONFIG_BUG #ifdef CONFIG_DEBUG_BUGVERBOSE -- cgit v1.2.3-70-g09d2 From 2eb9d3157107497fdccb51e1570fea677f6e3c82 Mon Sep 17 00:00:00 2001 From: Uwe Zeisberger Date: Fri, 5 May 2006 15:11:14 +0100 Subject: [ARM] 3496/1: more constants for asm-offsets.h Patch from Uwe Zeisberger added the following constants: - MACHINFO_TYPE - MACHINFO_NAME - MACHINFO_PHYSIO - MACHINFO_PGOFFIO - PROCINFO_INITFUNC - PROCINFO_MMUFLAGS and removed their definition from head.S and head-nommu.S Signed-off-by: Uwe Zeisberger Signed-off-by: Russell King --- arch/arm/kernel/asm-offsets.c | 6 ++++++ arch/arm/kernel/head-nommu.S | 4 +--- arch/arm/kernel/head.S | 8 -------- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c index b324dcac1c56..45fdf4a51a2a 100644 --- a/arch/arm/kernel/asm-offsets.c +++ b/arch/arm/kernel/asm-offsets.c @@ -95,5 +95,11 @@ int main(void) DEFINE(SYS_ERROR0, 0x9f0000); BLANK(); DEFINE(SIZEOF_MACHINE_DESC, sizeof(struct machine_desc)); + DEFINE(MACHINFO_TYPE, offsetof(struct machine_desc, nr)); + DEFINE(MACHINFO_NAME, offsetof(struct machine_desc, name)); + DEFINE(MACHINFO_PHYSIO, offsetof(struct machine_desc, phys_io)); + DEFINE(MACHINFO_PGOFFIO, offsetof(struct machine_desc, io_pg_offst)); + DEFINE(PROCINFO_INITFUNC, offsetof(struct proc_info_list, __cpu_flush)); + DEFINE(PROCINFO_MMUFLAGS, offsetof(struct proc_info_list, __cpu_mmu_flags)); return 0; } diff --git a/arch/arm/kernel/head-nommu.S b/arch/arm/kernel/head-nommu.S index 0bea65864051..adf62e5eaad7 100644 --- a/arch/arm/kernel/head-nommu.S +++ b/arch/arm/kernel/head-nommu.S @@ -20,12 +20,10 @@ #include #include #include +#include #include #include -#define PROCINFO_INITFUNC 12 -#define MACHINFO_TYPE 0 - /* * Kernel startup entry point. * --------------------------- diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index 04b66a9328ef..04f7344e356a 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S @@ -24,14 +24,6 @@ #include #include -#define PROCINFO_MMUFLAGS 8 -#define PROCINFO_INITFUNC 12 - -#define MACHINFO_TYPE 0 -#define MACHINFO_PHYSIO 4 -#define MACHINFO_PGOFFIO 8 -#define MACHINFO_NAME 12 - #define KERNEL_RAM_ADDR (PAGE_OFFSET + TEXT_OFFSET) /* -- cgit v1.2.3-70-g09d2 From 56cf6504fc1c0c221b82cebc16a444b684140fb7 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 5 May 2006 17:57:52 +0100 Subject: [BLOCK] Fix oops on removal of SD/MMC card The block layer keeps a reference (driverfs_dev) to the struct device associated with the block device, and uses it internally for generating uevents in block_uevent. Block device uevents include umounting the partition, which can occur after the backing device has been removed. Unfortunately, this reference is not counted. This means that if the struct device is removed from the device tree, the block layers reference will become stale. Guard against this by holding a reference to the struct device in add_disk(), and only drop the reference when we're releasing the gendisk kobject - in other words when we can be sure that no further uevents will be generated for this block device. Signed-off-by: Russell King Acked-by: Jens Axboe --- block/genhd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/block/genhd.c b/block/genhd.c index 5a8d3bf02f17..d96572589621 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -182,6 +182,7 @@ static int exact_lock(dev_t dev, void *data) */ void add_disk(struct gendisk *disk) { + get_device(disk->driverfs_dev); disk->flags |= GENHD_FL_UP; blk_register_region(MKDEV(disk->major, disk->first_minor), disk->minors, NULL, exact_match, exact_lock, disk); @@ -427,6 +428,7 @@ static struct attribute * default_attrs[] = { static void disk_release(struct kobject * kobj) { struct gendisk *disk = to_disk(kobj); + put_device(disk->driverfs_dev); kfree(disk->random); kfree(disk->part); free_disk_stats(disk); -- cgit v1.2.3-70-g09d2 From 3e6e155646706f1ef9f791a4402d145f112a3f8d Mon Sep 17 00:00:00 2001 From: "Chen, Kenneth W" Date: Wed, 3 May 2006 11:53:43 -0700 Subject: [IA64] strcpy returns NULL pointer and not destination pointer Bob Picco noted that 6edfba1b33c701108717f4e036320fc39abe1912 dropped the -ffreestanding compiler flag from the top level Makefile, which allows the compiler to substitute memcpy() in places where strcpy() is used with a known size source string. But the ia64 memcpy() returns 0 for success, and "bytes copied" for failure. Fix to return the address of the destination string (like stdlibc version, and other architectures). There are no places where ia64 specific code makes use of the non-standard return value. Signed-off-by: Ken Chen Signed-off-by: Tony Luck --- arch/ia64/lib/memcpy_mck.S | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/arch/ia64/lib/memcpy_mck.S b/arch/ia64/lib/memcpy_mck.S index 46c9331e7ab5..9e534d52b1d5 100644 --- a/arch/ia64/lib/memcpy_mck.S +++ b/arch/ia64/lib/memcpy_mck.S @@ -6,7 +6,9 @@ * in1: source address * in2: number of bytes to copy * Output: - * 0 if success, or number of byte NOT copied if error occurred. + * for memcpy: return dest + * for copy_user: return 0 if success, + * or number of byte NOT copied if error occurred. * * Copyright (C) 2002 Intel Corp. * Copyright (C) 2002 Ken Chen @@ -73,6 +75,7 @@ GLOBAL_ENTRY(memcpy) and r28=0x7,in0 and r29=0x7,in1 mov f6=f0 + mov retval=in0 br.cond.sptk .common_code ;; END(memcpy) @@ -84,7 +87,7 @@ GLOBAL_ENTRY(__copy_user) mov f6=f1 mov saved_in0=in0 // save dest pointer mov saved_in1=in1 // save src pointer - mov saved_in2=in2 // save len + mov retval=r0 // initialize return value ;; .common_code: cmp.gt p15,p0=8,in2 // check for small size @@ -92,7 +95,7 @@ GLOBAL_ENTRY(__copy_user) cmp.ne p14,p0=0,r29 // check src alignment add src0=0,in1 sub r30=8,r28 // for .align_dest - mov retval=r0 // initialize return value + mov saved_in2=in2 // save len ;; add dst0=0,in0 add dst1=1,in0 // dest odd index -- cgit v1.2.3-70-g09d2 From 913ed41eb5c948d2f8b5deffd29c2638eceef3d7 Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Wed, 3 May 2006 17:26:58 -0500 Subject: [IA64] remove asm-ia64/bitops.h self-inclusion asm-ia64/bitops.h includes itself. The #ifndef _ASM_IA64_BITOPS_H prevents this from being an issue, but it should still be removed. Signed-off-by: Jon Mason Signed-off-by: Tony Luck --- include/asm-ia64/bitops.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/asm-ia64/bitops.h b/include/asm-ia64/bitops.h index 90921e162793..6cc517e212a9 100644 --- a/include/asm-ia64/bitops.h +++ b/include/asm-ia64/bitops.h @@ -11,7 +11,6 @@ #include #include -#include #include /** -- cgit v1.2.3-70-g09d2 From 995c99268e0b12eb3c8939211ba5368dd92d98d9 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Sun, 30 Apr 2006 19:49:30 +0100 Subject: [PATCH] softmac: don't reassociate if user asked for deauthentication When wpa_supplicant exits, it uses SIOCSIWMLME to request deauthentication. softmac then tries to reassociate without any user intervention, which isn't the desired behaviour of this signal. This change makes softmac only attempt reassociation if the remote network itself deauthenticated us. Signed-off-by: Daniel Drake Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/ieee80211/softmac/ieee80211softmac_auth.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/ieee80211/softmac/ieee80211softmac_auth.c b/net/ieee80211/softmac/ieee80211softmac_auth.c index 9a0eac6c61eb..d6a04f3ab86c 100644 --- a/net/ieee80211/softmac/ieee80211softmac_auth.c +++ b/net/ieee80211/softmac/ieee80211softmac_auth.c @@ -298,8 +298,6 @@ ieee80211softmac_deauth_from_net(struct ieee80211softmac_device *mac, /* can't transmit data right now... */ netif_carrier_off(mac->dev); - /* let's try to re-associate */ - schedule_work(&mac->associnfo.work); spin_unlock_irqrestore(&mac->lock, flags); } @@ -360,5 +358,8 @@ ieee80211softmac_deauth_resp(struct net_device *dev, struct ieee80211_deauth *de } ieee80211softmac_deauth_from_net(mac, net); + + /* let's try to re-associate */ + schedule_work(&mac->associnfo.work); return 0; } -- cgit v1.2.3-70-g09d2 From d57336e3f2dd7c2d1fbe4a8323029869fb6e1f00 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Sun, 30 Apr 2006 22:09:07 +0100 Subject: [PATCH] softmac: make non-operational after being stopped zd1211 with softmac and wpa_supplicant revealed an issue with softmac and the use of workqueues. Some of the work functions actually reschedule themselves, so this meant that there could still be pending work after flush_scheduled_work() had been called during ieee80211softmac_stop(). This patch introduces a "running" flag which is used to ensure that rescheduling does not happen in this situation. I also used this flag to ensure that softmac's hooks into ieee80211 are non-operational once the stop operation has been started. This simply makes softmac a little more robust, because I could crash it easily by receiving frames in the short timeframe after shutting down softmac and before turning off the ZD1211 radio. (ZD1211 is now fixed as well!) Signed-off-by: Daniel Drake Acked-by: Johannes Berg Signed-off-by: John W. Linville --- include/net/ieee80211softmac.h | 3 ++- net/ieee80211/softmac/ieee80211softmac_assoc.c | 17 +++++++++++++++-- net/ieee80211/softmac/ieee80211softmac_auth.c | 11 +++++++++++ net/ieee80211/softmac/ieee80211softmac_module.c | 4 ++++ net/ieee80211/softmac/ieee80211softmac_scan.c | 8 ++++++++ 5 files changed, 40 insertions(+), 3 deletions(-) diff --git a/include/net/ieee80211softmac.h b/include/net/ieee80211softmac.h index b1ebfbae397f..052ed596a4e4 100644 --- a/include/net/ieee80211softmac.h +++ b/include/net/ieee80211softmac.h @@ -204,7 +204,8 @@ struct ieee80211softmac_device { /* couple of flags */ u8 scanning:1, /* protects scanning from being done multiple times at once */ - associated:1; + associated:1, + running:1; struct ieee80211softmac_scaninfo *scaninfo; struct ieee80211softmac_assoc_info associnfo; diff --git a/net/ieee80211/softmac/ieee80211softmac_assoc.c b/net/ieee80211/softmac/ieee80211softmac_assoc.c index fb79ce7d6439..57ea9f6f465c 100644 --- a/net/ieee80211/softmac/ieee80211softmac_assoc.c +++ b/net/ieee80211/softmac/ieee80211softmac_assoc.c @@ -51,11 +51,12 @@ ieee80211softmac_assoc(struct ieee80211softmac_device *mac, struct ieee80211soft spin_lock_irqsave(&mac->lock, flags); mac->associnfo.associating = 1; mac->associated = 0; /* just to make sure */ - spin_unlock_irqrestore(&mac->lock, flags); /* Set a timer for timeout */ /* FIXME: make timeout configurable */ - schedule_delayed_work(&mac->associnfo.timeout, 5 * HZ); + if (likely(mac->running)) + schedule_delayed_work(&mac->associnfo.timeout, 5 * HZ); + spin_unlock_irqrestore(&mac->lock, flags); } void @@ -319,6 +320,9 @@ ieee80211softmac_handle_assoc_response(struct net_device * dev, u16 status = le16_to_cpup(&resp->status); struct ieee80211softmac_network *network = NULL; unsigned long flags; + + if (unlikely(!mac->running)) + return -ENODEV; spin_lock_irqsave(&mac->lock, flags); @@ -377,10 +381,16 @@ ieee80211softmac_handle_disassoc(struct net_device * dev, { struct ieee80211softmac_device *mac = ieee80211_priv(dev); unsigned long flags; + + if (unlikely(!mac->running)) + return -ENODEV; + if (memcmp(disassoc->header.addr2, mac->associnfo.bssid, ETH_ALEN)) return 0; + if (memcmp(disassoc->header.addr1, mac->dev->dev_addr, ETH_ALEN)) return 0; + dprintk(KERN_INFO PFX "got disassoc frame\n"); netif_carrier_off(dev); spin_lock_irqsave(&mac->lock, flags); @@ -400,6 +410,9 @@ ieee80211softmac_handle_reassoc_req(struct net_device * dev, struct ieee80211softmac_device *mac = ieee80211_priv(dev); struct ieee80211softmac_network *network; + if (unlikely(!mac->running)) + return -ENODEV; + network = ieee80211softmac_get_network_by_bssid(mac, resp->header.addr3); if (!network) { dprintkl(KERN_INFO PFX "reassoc request from unknown network\n"); diff --git a/net/ieee80211/softmac/ieee80211softmac_auth.c b/net/ieee80211/softmac/ieee80211softmac_auth.c index d6a04f3ab86c..06e332624665 100644 --- a/net/ieee80211/softmac/ieee80211softmac_auth.c +++ b/net/ieee80211/softmac/ieee80211softmac_auth.c @@ -86,6 +86,11 @@ ieee80211softmac_auth_queue(void *data) /* Lock and set flags */ spin_lock_irqsave(&mac->lock, flags); + if (unlikely(!mac->running)) { + /* Prevent reschedule on workqueue flush */ + spin_unlock_irqrestore(&mac->lock, flags); + return; + } net->authenticated = 0; net->authenticating = 1; /* add a timeout call so we eventually give up waiting for an auth reply */ @@ -124,6 +129,9 @@ ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth) unsigned long flags; u8 * data; + if (unlikely(!mac->running)) + return -ENODEV; + /* Find correct auth queue item */ spin_lock_irqsave(&mac->lock, flags); list_for_each(list_ptr, &mac->auth_queue) { @@ -336,6 +344,9 @@ ieee80211softmac_deauth_resp(struct net_device *dev, struct ieee80211_deauth *de struct ieee80211softmac_network *net = NULL; struct ieee80211softmac_device *mac = ieee80211_priv(dev); + if (unlikely(!mac->running)) + return -ENODEV; + if (!deauth) { dprintk("deauth without deauth packet. eek!\n"); return 0; diff --git a/net/ieee80211/softmac/ieee80211softmac_module.c b/net/ieee80211/softmac/ieee80211softmac_module.c index be83bdc1644a..6252be2c0db9 100644 --- a/net/ieee80211/softmac/ieee80211softmac_module.c +++ b/net/ieee80211/softmac/ieee80211softmac_module.c @@ -89,6 +89,8 @@ ieee80211softmac_clear_pending_work(struct ieee80211softmac_device *sm) ieee80211softmac_wait_for_scan(sm); spin_lock_irqsave(&sm->lock, flags); + sm->running = 0; + /* Free all pending assoc work items */ cancel_delayed_work(&sm->associnfo.work); @@ -204,6 +206,8 @@ void ieee80211softmac_start(struct net_device *dev) assert(0); if (mac->txrates_change) mac->txrates_change(dev, change, &oldrates); + + mac->running = 1; } EXPORT_SYMBOL_GPL(ieee80211softmac_start); diff --git a/net/ieee80211/softmac/ieee80211softmac_scan.c b/net/ieee80211/softmac/ieee80211softmac_scan.c index 2b9e7edfa3ce..d31cf77498c4 100644 --- a/net/ieee80211/softmac/ieee80211softmac_scan.c +++ b/net/ieee80211/softmac/ieee80211softmac_scan.c @@ -115,7 +115,15 @@ void ieee80211softmac_scan(void *d) // TODO: is this if correct, or should we do this only if scanning from assoc request? if (sm->associnfo.req_essid.len) ieee80211softmac_send_mgt_frame(sm, &sm->associnfo.req_essid, IEEE80211_STYPE_PROBE_REQ, 0); + + spin_lock_irqsave(&sm->lock, flags); + if (unlikely(!sm->running)) { + /* Prevent reschedule on workqueue flush */ + spin_unlock_irqrestore(&sm->lock, flags); + break; + } schedule_delayed_work(&si->softmac_scan, IEEE80211SOFTMAC_PROBE_DELAY); + spin_unlock_irqrestore(&sm->lock, flags); return; } else { dprintk(PFX "Not probing Channel %d (not allowed here)\n", si->channels[current_channel_idx].channel); -- cgit v1.2.3-70-g09d2 From 5b4b9775a00c20ade1b1ac8aa25e0e4059d6243e Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Mon, 1 May 2006 22:43:00 +0200 Subject: [PATCH] bcm43xx: fix iwmode crash when down This fixes a crash when iwconfig ethX mode foo is done before ifconfig ethX up or after ifconfig ethX down Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_wx.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c index 3edbb481a0a0..b45063974ae9 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c @@ -182,8 +182,11 @@ static int bcm43xx_wx_set_mode(struct net_device *net_dev, mode = BCM43xx_INITIAL_IWMODE; bcm43xx_lock_mmio(bcm, flags); - if (bcm->ieee->iw_mode != mode) - bcm43xx_set_iwmode(bcm, mode); + if (bcm->initialized) { + if (bcm->ieee->iw_mode != mode) + bcm43xx_set_iwmode(bcm, mode); + } else + bcm->ieee->iw_mode = mode; bcm43xx_unlock_mmio(bcm, flags); return 0; -- cgit v1.2.3-70-g09d2 From f21709d70ad6d7ad50288f7056c3a368138b017c Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 4 May 2006 19:47:19 +0200 Subject: [PATCH] ieee80211: Fix A band channel count (resent) The channel count for 802.11a is still not right. We better compute it from the min and max channel numbers, rather than hardcoding it. Signed-off-by: Jean Delvare Signed-off-by: John W. Linville --- include/net/ieee80211.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index 4725ff861c57..d5926bfb1fc9 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h @@ -955,11 +955,13 @@ enum ieee80211_state { #define IEEE80211_24GHZ_MIN_CHANNEL 1 #define IEEE80211_24GHZ_MAX_CHANNEL 14 -#define IEEE80211_24GHZ_CHANNELS 14 +#define IEEE80211_24GHZ_CHANNELS (IEEE80211_24GHZ_MAX_CHANNEL - \ + IEEE80211_24GHZ_MIN_CHANNEL + 1) #define IEEE80211_52GHZ_MIN_CHANNEL 34 #define IEEE80211_52GHZ_MAX_CHANNEL 165 -#define IEEE80211_52GHZ_CHANNELS 131 +#define IEEE80211_52GHZ_CHANNELS (IEEE80211_52GHZ_MAX_CHANNEL - \ + IEEE80211_52GHZ_MIN_CHANNEL + 1) enum { IEEE80211_CH_PASSIVE_ONLY = (1 << 0), -- cgit v1.2.3-70-g09d2 From f9f7b9602ecb66f55718d6d1afa3e2b1e721b22d Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Fri, 5 May 2006 01:26:29 +0200 Subject: [PATCH] bcm43xx: check for valid MAC address in SPROM Check for valid MAC address in SPROM fields instead of relying on PHY type while setting the MAC address in the networking subsystem, as some devices have multiple PHYs. Signed-off-by: Stefano Brivio Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 9a06e61df0a2..4be2d9b5749b 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -3482,7 +3482,7 @@ static int bcm43xx_attach_board(struct bcm43xx_private *bcm) bcm43xx_pctl_set_crystal(bcm, 0); /* Set the MAC address in the networking subsystem */ - if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A) + if (is_valid_ether_addr(bcm->sprom.et1macaddr)) memcpy(bcm->net_dev->dev_addr, bcm->sprom.et1macaddr, 6); else memcpy(bcm->net_dev->dev_addr, bcm->sprom.il0macaddr, 6); -- cgit v1.2.3-70-g09d2 From 869aaab1812c4212e65fb181e94b824cf49f9509 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 5 May 2006 17:23:51 +0200 Subject: [PATCH] bcm43xx: Fix array overrun in bcm43xx_geo_init The problem here is that the bcm34xx driver and the ieee80211 stack do not agree on what channels are possible for 802.11a. The ieee80211 stack only wants channels between 34 and 165, while the bcm43xx driver accepts anything from 0 to 200. I made the bcm43xx driver comply with the ieee80211 stack expectations, by using the proper constants. Signed-off-by: Jean Delvare [mb]: Reduce stack usage by kzalloc-ing ieee80211_geo Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 43 +++++++++++++++++------------ drivers/net/wireless/bcm43xx/bcm43xx_main.h | 6 ++-- 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 4be2d9b5749b..e2982a83ae42 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -939,9 +939,9 @@ static int bcm43xx_sprom_extract(struct bcm43xx_private *bcm) return 0; } -static void bcm43xx_geo_init(struct bcm43xx_private *bcm) +static int bcm43xx_geo_init(struct bcm43xx_private *bcm) { - struct ieee80211_geo geo; + struct ieee80211_geo *geo; struct ieee80211_channel *chan; int have_a = 0, have_bg = 0; int i; @@ -949,7 +949,10 @@ static void bcm43xx_geo_init(struct bcm43xx_private *bcm) struct bcm43xx_phyinfo *phy; const char *iso_country; - memset(&geo, 0, sizeof(geo)); + geo = kzalloc(sizeof(*geo), GFP_KERNEL); + if (!geo) + return -ENOMEM; + for (i = 0; i < bcm->nr_80211_available; i++) { phy = &(bcm->core_80211_ext[i].phy); switch (phy->type) { @@ -967,31 +970,36 @@ static void bcm43xx_geo_init(struct bcm43xx_private *bcm) iso_country = bcm43xx_locale_iso(bcm->sprom.locale); if (have_a) { - for (i = 0, channel = 0; channel < 201; channel++) { - chan = &geo.a[i++]; + for (i = 0, channel = IEEE80211_52GHZ_MIN_CHANNEL; + channel <= IEEE80211_52GHZ_MAX_CHANNEL; channel++) { + chan = &geo->a[i++]; chan->freq = bcm43xx_channel_to_freq_a(channel); chan->channel = channel; } - geo.a_channels = i; + geo->a_channels = i; } if (have_bg) { - for (i = 0, channel = 1; channel < 15; channel++) { - chan = &geo.bg[i++]; + for (i = 0, channel = IEEE80211_24GHZ_MIN_CHANNEL; + channel <= IEEE80211_24GHZ_MAX_CHANNEL; channel++) { + chan = &geo->bg[i++]; chan->freq = bcm43xx_channel_to_freq_bg(channel); chan->channel = channel; } - geo.bg_channels = i; + geo->bg_channels = i; } - memcpy(geo.name, iso_country, 2); + memcpy(geo->name, iso_country, 2); if (0 /*TODO: Outdoor use only */) - geo.name[2] = 'O'; + geo->name[2] = 'O'; else if (0 /*TODO: Indoor use only */) - geo.name[2] = 'I'; + geo->name[2] = 'I'; else - geo.name[2] = ' '; - geo.name[3] = '\0'; + geo->name[2] = ' '; + geo->name[3] = '\0'; + + ieee80211_set_geo(bcm->ieee, geo); + kfree(geo); - ieee80211_set_geo(bcm->ieee, &geo); + return 0; } /* DummyTransmission function, as documented on @@ -3479,6 +3487,9 @@ static int bcm43xx_attach_board(struct bcm43xx_private *bcm) goto err_80211_unwind; bcm43xx_wireless_core_disable(bcm); } + err = bcm43xx_geo_init(bcm); + if (err) + goto err_80211_unwind; bcm43xx_pctl_set_crystal(bcm, 0); /* Set the MAC address in the networking subsystem */ @@ -3487,8 +3498,6 @@ static int bcm43xx_attach_board(struct bcm43xx_private *bcm) else memcpy(bcm->net_dev->dev_addr, bcm->sprom.il0macaddr, 6); - bcm43xx_geo_init(bcm); - snprintf(bcm->nick, IW_ESSID_MAX_SIZE, "Broadcom %04X", bcm->chip_id); diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h index eca79a38594a..30a202b258b5 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h @@ -118,12 +118,14 @@ int bcm43xx_channel_to_freq(struct bcm43xx_private *bcm, static inline int bcm43xx_is_valid_channel_a(u8 channel) { - return (channel <= 200); + return (channel >= IEEE80211_52GHZ_MIN_CHANNEL + && channel <= IEEE80211_52GHZ_MAX_CHANNEL); } static inline int bcm43xx_is_valid_channel_bg(u8 channel) { - return (channel >= 1 && channel <= 14); + return (channel >= IEEE80211_24GHZ_MIN_CHANNEL + && channel <= IEEE80211_24GHZ_MAX_CHANNEL); } static inline int bcm43xx_is_valid_channel(struct bcm43xx_private *bcm, -- cgit v1.2.3-70-g09d2 From 178e0cc5ff249965c6cfbd78b1af6a5e614d837c Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Fri, 5 May 2006 18:19:37 +0100 Subject: [PATCH] bcm43xx: Fix access to non-existent PHY registers Fix the conditions under which we poke at the APHY registers in bcm43xx_phy_initg() to avoid a machine check on chips where they don't exist. Signed-off-by: David Woodhouse Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_phy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c index 33137165727f..b0abac515530 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c @@ -1287,7 +1287,7 @@ static void bcm43xx_phy_initg(struct bcm43xx_private *bcm) if (radio->revision == 8) bcm43xx_phy_write(bcm, 0x0805, 0x3230); bcm43xx_phy_init_pctl(bcm); - if (bcm->chip_id == 0x4306 && bcm->chip_package != 2) { + if (bcm->chip_id == 0x4306 && bcm->chip_package == 2) { bcm43xx_phy_write(bcm, 0x0429, bcm43xx_phy_read(bcm, 0x0429) & 0xBFFF); bcm43xx_phy_write(bcm, 0x04C3, -- cgit v1.2.3-70-g09d2 From b7d7ef87e15dea105be59ec8f14e2f92182dd421 Mon Sep 17 00:00:00 2001 From: "George G. Davis" Date: Fri, 5 May 2006 22:32:23 +0100 Subject: [ARM] 3499/1: Fix VFP FPSCR corruption for double exception case Patch from George G. Davis The ARM VFP FPSCR register is corrupted when a condition flags modifying VFP instruction is followed by a non-condition flags modifying VFP instruction and both instructions raise exceptions. The fix is to read the current FPSCR in between emulation of these two instructions and use the current FPSCR value when handling the second exception. Signed-off-by: George G. Davis Signed-off-by: Russell King --- arch/arm/vfp/vfpmodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index 37ff8145b5b5..03486be04193 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c @@ -245,7 +245,7 @@ void VFP9_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs) */ barrier(); trigger = fmrx(FPINST2); - fpscr = fmrx(FPSCR); + orig_fpscr = fpscr = fmrx(FPSCR); emulate: exceptions = vfp_emulate_instruction(trigger, fpscr, regs); -- cgit v1.2.3-70-g09d2 From 99532559dc7a8e686b2cef14c780a7ad5dbd4a31 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Fri, 5 May 2006 22:32:24 +0100 Subject: [ARM] 3500/1: fix PXA27x DMA allocation priority Patch from Nicolas Pitre Intel PXA27x developers manual section 5.4.1.1 lists a priority distribution for the DMA channels differently than what the code currently assumes. This patch fixes that. Noticed by Simon Vogl Signed-off-by: Nicolas Pitre Signed-off-by: Russell King --- arch/arm/mach-pxa/dma.c | 17 +++++------------ include/asm-arm/arch-pxa/dma.h | 26 ++++++++++++++------------ 2 files changed, 19 insertions(+), 24 deletions(-) diff --git a/arch/arm/mach-pxa/dma.c b/arch/arm/mach-pxa/dma.c index 458112b21e25..7d8c85486c66 100644 --- a/arch/arm/mach-pxa/dma.c +++ b/arch/arm/mach-pxa/dma.c @@ -45,23 +45,16 @@ int pxa_request_dma (char *name, pxa_dma_prio prio, local_irq_save(flags); - /* try grabbing a DMA channel with the requested priority */ - for (i = prio; i < prio + PXA_DMA_NBCH(prio); i++) { - if (!dma_channels[i].name) { - found = 1; - break; - } - } - - if (!found) { - /* requested prio group is full, try hier priorities */ - for (i = prio-1; i >= 0; i--) { + do { + /* try grabbing a DMA channel with the requested priority */ + pxa_for_each_dma_prio (i, prio) { if (!dma_channels[i].name) { found = 1; break; } } - } + /* if requested prio group is full, try a hier priority */ + } while (!found && prio--); if (found) { DCSR(i) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR; diff --git a/include/asm-arm/arch-pxa/dma.h b/include/asm-arm/arch-pxa/dma.h index 3e88a2a02a0f..a008150abc59 100644 --- a/include/asm-arm/arch-pxa/dma.h +++ b/include/asm-arm/arch-pxa/dma.h @@ -24,27 +24,29 @@ typedef struct pxa_dma_desc { volatile u32 dcmd; /* DCMD value for the current transfer */ } pxa_dma_desc; +typedef enum { + DMA_PRIO_HIGH = 0, + DMA_PRIO_MEDIUM = 1, + DMA_PRIO_LOW = 2 +} pxa_dma_prio; + #if defined(CONFIG_PXA27x) #define PXA_DMA_CHANNELS 32 -#define PXA_DMA_NBCH(prio) ((prio == DMA_PRIO_LOW) ? 16 : 8) -typedef enum { - DMA_PRIO_HIGH = 0, - DMA_PRIO_MEDIUM = 8, - DMA_PRIO_LOW = 16 -} pxa_dma_prio; +#define pxa_for_each_dma_prio(ch, prio) \ +for ( \ + ch = prio * 4; \ + ch != (4 << prio) + 16; \ + ch = (ch + 1 == (4 << prio)) ? (prio * 4 + 16) : (ch + 1) \ +) #elif defined(CONFIG_PXA25x) #define PXA_DMA_CHANNELS 16 -#define PXA_DMA_NBCH(prio) ((prio == DMA_PRIO_LOW) ? 8 : 4) -typedef enum { - DMA_PRIO_HIGH = 0, - DMA_PRIO_MEDIUM = 4, - DMA_PRIO_LOW = 8 -} pxa_dma_prio; +#define pxa_for_each_dma_prio(ch, prio) \ + for (ch = prio * 4; ch != (4 << prio); ch++) #endif -- cgit v1.2.3-70-g09d2 From 568cb09b9d889b6f2852ede19772b8e9eed36c1e Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Fri, 5 May 2006 22:35:05 +0100 Subject: [ARM] 3495/1: EABI: undefine removed syscalls, but... Patch from Nicolas Pitre ... but only for user space. Signed-off-by: Nicolas Pitre Signed-off-by: Russell King --- include/asm-arm/unistd.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/asm-arm/unistd.h b/include/asm-arm/unistd.h index 26f2f4828e03..cbf39a56dbe7 100644 --- a/include/asm-arm/unistd.h +++ b/include/asm-arm/unistd.h @@ -363,7 +363,7 @@ /* * The following syscalls are obsolete and no longer available for EABI. */ -#if defined(__ARM_EABI__) +#if defined(__ARM_EABI__) && !defined(__KERNEL__) #undef __NR_time #undef __NR_umount #undef __NR_stime -- cgit v1.2.3-70-g09d2 From 7c3ceb4fb9667f34f1599a062efecf4cdc4a4ce5 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Fri, 5 May 2006 17:02:09 -0700 Subject: [SCTP]: Allow spillover of receive buffer to avoid deadlock. This patch fixes a deadlock situation in the receive path by allowing temporary spillover of the receive buffer. - If the chunk we receive has a tsn that immediately follows the ctsn, accept it even if we run out of receive buffer space and renege data with higher TSNs. - Once we accept one chunk in a packet, accept all the remaining chunks even if we run out of receive buffer space. Signed-off-by: Neil Horman Acked-by: Mark Butler Acked-by: Vlad Yasevich Signed-off-by: Sridhar Samudrala Signed-off-by: David S. Miller --- include/net/sctp/structs.h | 1 + net/sctp/inqueue.c | 1 + net/sctp/sm_statefuns.c | 46 ++++++++++++++++++++++++++++++++++++---------- 3 files changed, 38 insertions(+), 10 deletions(-) diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index eba99f375517..7f4fea173fb1 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -712,6 +712,7 @@ struct sctp_chunk { __u8 tsn_gap_acked; /* Is this chunk acked by a GAP ACK? */ __s8 fast_retransmit; /* Is this chunk fast retransmitted? */ __u8 tsn_missing_report; /* Data chunk missing counter. */ + __u8 data_accepted; /* At least 1 chunk in this packet accepted */ }; void sctp_chunk_hold(struct sctp_chunk *); diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c index 297b8951463e..cf0c767d43ae 100644 --- a/net/sctp/inqueue.c +++ b/net/sctp/inqueue.c @@ -149,6 +149,7 @@ struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue) /* This is the first chunk in the packet. */ chunk->singleton = 1; ch = (sctp_chunkhdr_t *) chunk->skb->data; + chunk->data_accepted = 0; } chunk->chunk_hdr = ch; diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 2b9a832b29a7..f5d131f52a70 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -5151,7 +5151,9 @@ static int sctp_eat_data(const struct sctp_association *asoc, int tmp; __u32 tsn; int account_value; + struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map; struct sock *sk = asoc->base.sk; + int rcvbuf_over = 0; data_hdr = chunk->subh.data_hdr = (sctp_datahdr_t *)chunk->skb->data; skb_pull(chunk->skb, sizeof(sctp_datahdr_t)); @@ -5162,10 +5164,16 @@ static int sctp_eat_data(const struct sctp_association *asoc, /* ASSERT: Now skb->data is really the user data. */ /* - * if we are established, and we have used up our receive - * buffer memory, drop the frame - */ - if (asoc->state == SCTP_STATE_ESTABLISHED) { + * If we are established, and we have used up our receive buffer + * memory, think about droping the frame. + * Note that we have an opportunity to improve performance here. + * If we accept one chunk from an skbuff, we have to keep all the + * memory of that skbuff around until the chunk is read into user + * space. Therefore, once we accept 1 chunk we may as well accept all + * remaining chunks in the skbuff. The data_accepted flag helps us do + * that. + */ + if ((asoc->state == SCTP_STATE_ESTABLISHED) && (!chunk->data_accepted)) { /* * If the receive buffer policy is 1, then each * association can allocate up to sk_rcvbuf bytes @@ -5176,9 +5184,25 @@ static int sctp_eat_data(const struct sctp_association *asoc, account_value = atomic_read(&asoc->rmem_alloc); else account_value = atomic_read(&sk->sk_rmem_alloc); - - if (account_value > sk->sk_rcvbuf) - return SCTP_IERROR_IGNORE_TSN; + if (account_value > sk->sk_rcvbuf) { + /* + * We need to make forward progress, even when we are + * under memory pressure, so we always allow the + * next tsn after the ctsn ack point to be accepted. + * This lets us avoid deadlocks in which we have to + * drop frames that would otherwise let us drain the + * receive queue. + */ + if ((sctp_tsnmap_get_ctsn(map) + 1) != tsn) + return SCTP_IERROR_IGNORE_TSN; + + /* + * We're going to accept the frame but we should renege + * to make space for it. This will send us down that + * path later in this function. + */ + rcvbuf_over = 1; + } } /* Process ECN based congestion. @@ -5226,6 +5250,7 @@ static int sctp_eat_data(const struct sctp_association *asoc, datalen -= sizeof(sctp_data_chunk_t); deliver = SCTP_CMD_CHUNK_ULP; + chunk->data_accepted = 1; /* Think about partial delivery. */ if ((datalen >= asoc->rwnd) && (!asoc->ulpq.pd_mode)) { @@ -5242,7 +5267,8 @@ static int sctp_eat_data(const struct sctp_association *asoc, * large spill over. */ if (!asoc->rwnd || asoc->rwnd_over || - (datalen > asoc->rwnd + asoc->frag_point)) { + (datalen > asoc->rwnd + asoc->frag_point) || + rcvbuf_over) { /* If this is the next TSN, consider reneging to make * room. Note: Playing nice with a confused sender. A @@ -5250,8 +5276,8 @@ static int sctp_eat_data(const struct sctp_association *asoc, * space and in the future we may want to detect and * do more drastic reneging. */ - if (sctp_tsnmap_has_gap(&asoc->peer.tsn_map) && - (sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + 1) == tsn) { + if (sctp_tsnmap_has_gap(map) && + (sctp_tsnmap_get_ctsn(map) + 1) == tsn) { SCTP_DEBUG_PRINTK("Reneging for tsn:%u\n", tsn); deliver = SCTP_CMD_RENEGE; } else { -- cgit v1.2.3-70-g09d2 From 672e7cca17ed6036a1756ed34cf20dbd72d5e5f6 Mon Sep 17 00:00:00 2001 From: Vladislav Yasevich Date: Fri, 5 May 2006 17:03:49 -0700 Subject: [SCTP]: Prevent possible infinite recursion with multiple bundled DATA. There is a rare situation that causes lksctp to go into infinite recursion and crash the system. The trigger is a packet that contains at least the first two DATA fragments of a message bundled together. The recursion is triggered when the user data buffer is smaller that the full data message. The problem is that we clone the skb for every fragment in the message. When reassembling the full message, we try to link skbs from the "first fragment" clone using the frag_list. However, since the frag_list is shared between two clones in this rare situation, we end up setting the frag_list pointer of the second fragment to point to itself. This causes sctp_skb_pull() to potentially recurse indefinitely. Proposed solution is to make a copy of the skb when attempting to link things using frag_list. Signed-off-by: Vladislav Yasevich Signed-off-by: Sridhar Samudrala Signed-off-by: David S. Miller --- net/sctp/ulpqueue.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c index 2080b2d28c98..575e556aeb3e 100644 --- a/net/sctp/ulpqueue.c +++ b/net/sctp/ulpqueue.c @@ -279,6 +279,7 @@ static inline void sctp_ulpq_store_reasm(struct sctp_ulpq *ulpq, static struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff_head *queue, struct sk_buff *f_frag, struct sk_buff *l_frag) { struct sk_buff *pos; + struct sk_buff *new = NULL; struct sctp_ulpevent *event; struct sk_buff *pnext, *last; struct sk_buff *list = skb_shinfo(f_frag)->frag_list; @@ -297,11 +298,33 @@ static struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff_head *qu */ if (last) last->next = pos; - else - skb_shinfo(f_frag)->frag_list = pos; + else { + if (skb_cloned(f_frag)) { + /* This is a cloned skb, we can't just modify + * the frag_list. We need a new skb to do that. + * Instead of calling skb_unshare(), we'll do it + * ourselves since we need to delay the free. + */ + new = skb_copy(f_frag, GFP_ATOMIC); + if (!new) + return NULL; /* try again later */ + + new->sk = f_frag->sk; + + skb_shinfo(new)->frag_list = pos; + } else + skb_shinfo(f_frag)->frag_list = pos; + } /* Remove the first fragment from the reassembly queue. */ __skb_unlink(f_frag, queue); + + /* if we did unshare, then free the old skb and re-assign */ + if (new) { + kfree_skb(f_frag); + f_frag = new; + } + while (pos) { pnext = pos->next; -- cgit v1.2.3-70-g09d2 From 62b08083ec3dbfd7e533c8d230dd1d8191a6e813 Mon Sep 17 00:00:00 2001 From: Sridhar Samudrala Date: Fri, 5 May 2006 17:04:43 -0700 Subject: [SCTP]: Fix panic's when receiving fragmented SCTP control chunks. Use pskb_pull() to handle incoming COOKIE_ECHO and HEARTBEAT chunks that are received as skb's with fragment list. Signed-off-by: Sridhar Samudrala Signed-off-by: David S. Miller --- net/sctp/sm_statefuns.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index f5d131f52a70..8cdba51ec076 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -636,8 +636,9 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep, */ chunk->subh.cookie_hdr = (struct sctp_signed_cookie *)chunk->skb->data; - skb_pull(chunk->skb, - ntohs(chunk->chunk_hdr->length) - sizeof(sctp_chunkhdr_t)); + if (!pskb_pull(chunk->skb, ntohs(chunk->chunk_hdr->length) - + sizeof(sctp_chunkhdr_t))) + goto nomem; /* 5.1 D) Upon reception of the COOKIE ECHO chunk, Endpoint * "Z" will reply with a COOKIE ACK chunk after building a TCB @@ -965,7 +966,8 @@ sctp_disposition_t sctp_sf_beat_8_3(const struct sctp_endpoint *ep, */ chunk->subh.hb_hdr = (sctp_heartbeathdr_t *) chunk->skb->data; paylen = ntohs(chunk->chunk_hdr->length) - sizeof(sctp_chunkhdr_t); - skb_pull(chunk->skb, paylen); + if (!pskb_pull(chunk->skb, paylen)) + goto nomem; reply = sctp_make_heartbeat_ack(asoc, chunk, chunk->subh.hb_hdr, paylen); @@ -1860,8 +1862,9 @@ sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const struct sctp_endpoint *ep, * are in good shape. */ chunk->subh.cookie_hdr = (struct sctp_signed_cookie *)chunk->skb->data; - skb_pull(chunk->skb, ntohs(chunk->chunk_hdr->length) - - sizeof(sctp_chunkhdr_t)); + if (!pskb_pull(chunk->skb, ntohs(chunk->chunk_hdr->length) - + sizeof(sctp_chunkhdr_t))) + goto nomem; /* In RFC 2960 5.2.4 3, if both Verification Tags in the State Cookie * of a duplicate COOKIE ECHO match the Verification Tags of the -- cgit v1.2.3-70-g09d2 From 35d63edb1c807bc5317e49592260e84637bc432e Mon Sep 17 00:00:00 2001 From: Sridhar Samudrala Date: Fri, 5 May 2006 17:05:23 -0700 Subject: [SCTP]: Fix state table entries for chunks received in CLOSED state. Discard an unexpected chunk in CLOSED state rather can calling BUG(). Signed-off-by: Sridhar Samudrala Signed-off-by: David S. Miller --- net/sctp/sm_statetable.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/net/sctp/sm_statetable.c b/net/sctp/sm_statetable.c index 75ef10408764..8bcca5676151 100644 --- a/net/sctp/sm_statetable.c +++ b/net/sctp/sm_statetable.c @@ -366,9 +366,9 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, /* SCTP_STATE_EMPTY */ \ {.fn = sctp_sf_ootb, .name = "sctp_sf_ootb"}, \ /* SCTP_STATE_CLOSED */ \ - {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \ + {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \ /* SCTP_STATE_COOKIE_WAIT */ \ - {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \ + {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \ /* SCTP_STATE_COOKIE_ECHOED */ \ {.fn = sctp_sf_do_ecne, .name = "sctp_sf_do_ecne"}, \ /* SCTP_STATE_ESTABLISHED */ \ @@ -380,7 +380,7 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ {.fn = sctp_sf_do_ecne, .name = "sctp_sf_do_ecne"}, \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \ + {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \ } /* TYPE_SCTP_ECN_ECNE */ #define TYPE_SCTP_ECN_CWR { \ @@ -401,7 +401,7 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \ + {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \ } /* TYPE_SCTP_ECN_CWR */ #define TYPE_SCTP_SHUTDOWN_COMPLETE { \ @@ -647,7 +647,7 @@ chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = { /* SCTP_STATE_EMPTY */ \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \ /* SCTP_STATE_CLOSED */ \ - {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \ + {.fn = sctp_sf_error_closed, .name = "sctp_sf_error_closed"}, \ /* SCTP_STATE_COOKIE_WAIT */ \ {.fn = sctp_sf_do_prm_requestheartbeat, \ .name = "sctp_sf_do_prm_requestheartbeat"}, \ -- cgit v1.2.3-70-g09d2 From 1c29fc4989bc2a3838b2837adc12b8aeb0feeede Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 5 May 2006 17:07:13 -0700 Subject: [BRIDGE]: keep track of received multicast packets It makes sense to add this simple statistic to keep track of received multicast packets. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/bridge/br_input.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index b0b7f55c1edd..bfa4d8c333f7 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c @@ -66,6 +66,7 @@ int br_handle_frame_finish(struct sk_buff *skb) } if (is_multicast_ether_addr(dest)) { + br->statistics.multicast++; br_flood_forward(br, skb, !passedup); if (!passedup) br_pass_frame_up(br, skb); -- cgit v1.2.3-70-g09d2 From 134af34632a7b3b0a98a79a2e56bf9cc927e0eac Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 5 May 2006 17:09:13 -0700 Subject: [DCCP]: Fix sock_orphan dead lock Calling sock_orphan inside bh_lock_sock in dccp_close can lead to dead locks. For example, the inet_diag code holds sk_callback_lock without disabling BH. If an inbound packet arrives during that admittedly tiny window, it will cause a dead lock on bh_lock_sock. Another possible path would be through sock_wfree if the network device driver frees the tx skb in process context with BH enabled. We can fix this by moving sock_orphan out of bh_lock_sock. The tricky bit is to work out when we need to destroy the socket ourselves and when it has already been destroyed by someone else. By moving sock_orphan before the release_sock we can solve this problem. This is because as long as we own the socket lock its state cannot change. So we simply record the socket state before the release_sock and then check the state again after we regain the socket lock. If the socket state has transitioned to DCCP_CLOSED in the time being, we know that the socket has been destroyed. Otherwise the socket is still ours to keep. This problem was discoverd by Ingo Molnar using his lock validator. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/dccp/proto.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/net/dccp/proto.c b/net/dccp/proto.c index 1ff7328b0e17..2e0ee8355c41 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -848,6 +848,7 @@ static int dccp_close_state(struct sock *sk) void dccp_close(struct sock *sk, long timeout) { struct sk_buff *skb; + int state; lock_sock(sk); @@ -882,6 +883,11 @@ void dccp_close(struct sock *sk, long timeout) sk_stream_wait_close(sk, timeout); adjudge_to_death: + state = sk->sk_state; + sock_hold(sk); + sock_orphan(sk); + atomic_inc(sk->sk_prot->orphan_count); + /* * It is the last release_sock in its life. It will remove backlog. */ @@ -894,8 +900,9 @@ adjudge_to_death: bh_lock_sock(sk); BUG_TRAP(!sock_owned_by_user(sk)); - sock_hold(sk); - sock_orphan(sk); + /* Have we already been destroyed by a softirq or backlog? */ + if (state != DCCP_CLOSED && sk->sk_state == DCCP_CLOSED) + goto out; /* * The last release_sock may have processed the CLOSE or RESET @@ -915,12 +922,12 @@ adjudge_to_death: #endif } - atomic_inc(sk->sk_prot->orphan_count); if (sk->sk_state == DCCP_CLOSED) inet_csk_destroy_sock(sk); /* Otherwise, socket is reprieved until protocol close. */ +out: bh_unlock_sock(sk); local_bh_enable(); sock_put(sk); -- cgit v1.2.3-70-g09d2 From f530937b2cccdb131cb459977943c98421ab09b3 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Fri, 5 May 2006 17:19:26 -0700 Subject: [NETROM/ROSE]: Kill module init version kernel log messages. There are out of date and don't tell the user anything useful. The similar messages which IPV4 and the core networking used to output were killed a long time ago. Signed-off-by: Ralf Baechle Signed-off-by: David S. Miller --- net/netrom/af_netrom.c | 3 --- net/rose/af_rose.c | 3 --- 2 files changed, 6 deletions(-) diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index ecd288beca7c..3669cb953e6e 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c @@ -1370,8 +1370,6 @@ static struct notifier_block nr_dev_notifier = { static struct net_device **dev_nr; -static char banner[] __initdata = KERN_INFO "G4KLX NET/ROM for Linux. Version 0.7 for AX25.037 Linux 2.4\n"; - static int __init nr_proto_init(void) { int i; @@ -1419,7 +1417,6 @@ static int __init nr_proto_init(void) } register_netdevice_notifier(&nr_dev_notifier); - printk(banner); ax25_protocol_register(AX25_P_NETROM, nr_route_frame); ax25_linkfail_register(nr_link_failed); diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index ef4538ac84f0..55564efccf11 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -1469,8 +1469,6 @@ static struct notifier_block rose_dev_notifier = { static struct net_device **dev_rose; -static const char banner[] = KERN_INFO "F6FBB/G4KLX ROSE for Linux. Version 0.62 for AX25.037 Linux 2.4\n"; - static int __init rose_proto_init(void) { int i; @@ -1519,7 +1517,6 @@ static int __init rose_proto_init(void) sock_register(&rose_family_ops); register_netdevice_notifier(&rose_dev_notifier); - printk(banner); ax25_protocol_register(AX25_P_ROSE, rose_route_frame); ax25_linkfail_register(rose_link_failed); -- cgit v1.2.3-70-g09d2 From 5528e568a760442e0ec8fd2dea1f0791875a066b Mon Sep 17 00:00:00 2001 From: John Heffner Date: Fri, 5 May 2006 17:41:44 -0700 Subject: [TCP]: Fix snd_cwnd adjustments in tcp_highspeed.c Xiaoliang (David) Wei wrote: > Hi gurus, > > I am reading the code of tcp_highspeed.c in the kernel and have a > question on the hstcp_cong_avoid function, specifically the following > AI part (line 136~143 in net/ipv4/tcp_highspeed.c ): > > /* Do additive increase */ > if (tp->snd_cwnd < tp->snd_cwnd_clamp) { > tp->snd_cwnd_cnt += ca->ai; > if (tp->snd_cwnd_cnt >= tp->snd_cwnd) { > tp->snd_cwnd++; > tp->snd_cwnd_cnt -= tp->snd_cwnd; > } > } > > In this part, when (tp->snd_cwnd_cnt == tp->snd_cwnd), > snd_cwnd_cnt will be -1... snd_cwnd_cnt is defined as u16, will this > small chance of getting -1 becomes a problem? > Shall we change it by reversing the order of the cwnd++ and cwnd_cnt -= > cwnd? Absolutely correct. Thanks. Signed-off-by: John Heffner Signed-off-by: David S. Miller --- net/ipv4/tcp_highspeed.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/tcp_highspeed.c b/net/ipv4/tcp_highspeed.c index e0e9d1383c7c..b72fa55dfb84 100644 --- a/net/ipv4/tcp_highspeed.c +++ b/net/ipv4/tcp_highspeed.c @@ -137,8 +137,8 @@ static void hstcp_cong_avoid(struct sock *sk, u32 adk, u32 rtt, if (tp->snd_cwnd < tp->snd_cwnd_clamp) { tp->snd_cwnd_cnt += ca->ai; if (tp->snd_cwnd_cnt >= tp->snd_cwnd) { - tp->snd_cwnd++; tp->snd_cwnd_cnt -= tp->snd_cwnd; + tp->snd_cwnd++; } } } -- cgit v1.2.3-70-g09d2 From 19ca5d27e15c10d8529984ecd98dcba2637edcd2 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 6 May 2006 11:26:30 +0100 Subject: [ARM] Allow SA1100 RTC alarm to be configured for wakeup The SA1100 RTC alarm can be configured to wake up the CPU from sleep mode, and the RTC driver has been using the API to configure this mode. Unfortunately, the code was which sets the required bit in the hardware was missing. Signed-off-by: Russell King --- arch/arm/mach-sa1100/irq.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/arch/arm/mach-sa1100/irq.c b/arch/arm/mach-sa1100/irq.c index c131a5201b5b..b3a56024182e 100644 --- a/arch/arm/mach-sa1100/irq.c +++ b/arch/arm/mach-sa1100/irq.c @@ -199,10 +199,26 @@ static void sa1100_unmask_irq(unsigned int irq) ICMR |= (1 << irq); } +/* + * Apart form GPIOs, only the RTC alarm can be a wakeup event. + */ +static int sa1100_set_wake(unsigned int irq, unsigned int on) +{ + if (irq == IRQ_RTCAlrm) { + if (on) + PWER |= PWER_RTC; + else + PWER &= ~PWER_RTC; + return 0; + } + return -EINVAL; +} + static struct irqchip sa1100_normal_chip = { .ack = sa1100_mask_irq, .mask = sa1100_mask_irq, .unmask = sa1100_unmask_irq, + .set_wake = sa1100_set_wake, }; static struct resource irq_resource = { -- cgit v1.2.3-70-g09d2 From f12267011d16b1722e71aa12cd3e89eb70a9edd6 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 6 May 2006 11:29:21 +0100 Subject: [ARM] rtc-sa1100: fix compiler warnings and error cleanup Fix: drivers/rtc/rtc-sa1100.c: In function `sa1100_rtc_proc': drivers/rtc/rtc-sa1100.c:298: warning: unsigned int format, long unsigned int arg (arg 3) and arrange for sa1100_rtc_open() to pass the devid to free_irq() rather than NULL. Signed-off-by: Russell King --- drivers/rtc/rtc-sa1100.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index a23ec54989f6..2bc8aad47219 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -178,9 +178,9 @@ static int sa1100_rtc_open(struct device *dev) return 0; fail_pi: - free_irq(IRQ_RTCAlrm, NULL); + free_irq(IRQ_RTCAlrm, dev); fail_ai: - free_irq(IRQ_RTC1Hz, NULL); + free_irq(IRQ_RTC1Hz, dev); fail_ui: return ret; } @@ -295,7 +295,7 @@ static int sa1100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) static int sa1100_rtc_proc(struct device *dev, struct seq_file *seq) { - seq_printf(seq, "trim/divider\t: 0x%08x\n", RTTR); + seq_printf(seq, "trim/divider\t: 0x%08lx\n", RTTR); seq_printf(seq, "alarm_IRQ\t: %s\n", (RTSR & RTSR_ALE) ? "yes" : "no" ); seq_printf(seq, "update_IRQ\t: %s\n", -- cgit v1.2.3-70-g09d2 From 1498221d51a43d5fa1a580618591497d90f957d9 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sat, 6 May 2006 17:55:11 -0700 Subject: [CLASS DEVICE]: add attribute_group creation Extend the support of attribute groups in class_device's to allow groups to be created as part of the registration process. This allows network device's to avoid race between registration and creating groups. Note that unlike attributes that are a property of the class object, the groups are a property of the class_device object. This is done because there are different types of network devices (wireless for example). Signed-off-by: Stephen Hemminger Signed-off-by: Greg Kroah-Hartman Signed-off-by: David S. Miller --- drivers/base/class.c | 32 ++++++++++++++++++++++++++++++++ include/linux/device.h | 2 ++ 2 files changed, 34 insertions(+) diff --git a/drivers/base/class.c b/drivers/base/class.c index 0e71dff327cd..b1ea4df85c7d 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -456,6 +456,35 @@ static void class_device_remove_attrs(struct class_device * cd) } } +static int class_device_add_groups(struct class_device * cd) +{ + int i; + int error = 0; + + if (cd->groups) { + for (i = 0; cd->groups[i]; i++) { + error = sysfs_create_group(&cd->kobj, cd->groups[i]); + if (error) { + while (--i >= 0) + sysfs_remove_group(&cd->kobj, cd->groups[i]); + goto out; + } + } + } +out: + return error; +} + +static void class_device_remove_groups(struct class_device * cd) +{ + int i; + if (cd->groups) { + for (i = 0; cd->groups[i]; i++) { + sysfs_remove_group(&cd->kobj, cd->groups[i]); + } + } +} + static ssize_t show_dev(struct class_device *class_dev, char *buf) { return print_dev_t(buf, class_dev->devt); @@ -559,6 +588,8 @@ int class_device_add(struct class_device *class_dev) class_name); } + class_device_add_groups(class_dev); + kobject_uevent(&class_dev->kobj, KOBJ_ADD); /* notify any interfaces this device is now here */ @@ -672,6 +703,7 @@ void class_device_del(struct class_device *class_dev) if (class_dev->devt_attr) class_device_remove_file(class_dev, class_dev->devt_attr); class_device_remove_attrs(class_dev); + class_device_remove_groups(class_dev); kobject_uevent(&class_dev->kobj, KOBJ_REMOVE); kobject_del(&class_dev->kobj); diff --git a/include/linux/device.h b/include/linux/device.h index f6e72a65a3f2..e8e53b9accc6 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -200,6 +200,7 @@ extern int class_device_create_file(struct class_device *, * @node: for internal use by the driver core only. * @kobj: for internal use by the driver core only. * @devt_attr: for internal use by the driver core only. + * @groups: optional additional groups to be created * @dev: if set, a symlink to the struct device is created in the sysfs * directory for this struct class device. * @class_data: pointer to whatever you want to store here for this struct @@ -228,6 +229,7 @@ struct class_device { struct device * dev; /* not necessary, but nice to have */ void * class_data; /* class-specific data */ struct class_device *parent; /* parent of this child device, if there is one */ + struct attribute_group ** groups; /* optional groups */ void (*release)(struct class_device *dev); int (*uevent)(struct class_device *dev, char **envp, -- cgit v1.2.3-70-g09d2 From fe9925b551a95fae6ec61470c79f8b701a2fe928 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sat, 6 May 2006 17:56:03 -0700 Subject: [NET]: Create netdev attribute_groups with class_device_add Atomically create attributes when class device is added. This avoids the race between registering class_device (which generates hotplug event), and the creation of attribute groups. Signed-off-by: Stephen Hemminger Signed-off-by: Greg Kroah-Hartman Signed-off-by: David S. Miller --- include/linux/netdevice.h | 2 ++ net/core/dev.c | 2 +- net/core/net-sysfs.c | 49 ++++++++++++----------------------------------- 3 files changed, 15 insertions(+), 38 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 01db7b88a2b1..309f9190a922 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -506,6 +506,8 @@ struct net_device /* class/net/name entry */ struct class_device class_dev; + /* space for optional statistics and wireless sysfs groups */ + struct attribute_group *sysfs_groups[3]; }; #define NETDEV_ALIGN 32 diff --git a/net/core/dev.c b/net/core/dev.c index 3bad1afc89fa..9ab3cfa58466 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3043,11 +3043,11 @@ void netdev_run_todo(void) switch(dev->reg_state) { case NETREG_REGISTERING: - dev->reg_state = NETREG_REGISTERED; err = netdev_register_sysfs(dev); if (err) printk(KERN_ERR "%s: failed sysfs registration (%d)\n", dev->name, err); + dev->reg_state = NETREG_REGISTERED; break; case NETREG_UNREGISTERING: diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index c12990c9c603..47a6fceb6771 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -29,7 +29,7 @@ static const char fmt_ulong[] = "%lu\n"; static inline int dev_isalive(const struct net_device *dev) { - return dev->reg_state == NETREG_REGISTERED; + return dev->reg_state <= NETREG_REGISTERED; } /* use same locking rules as GIF* ioctl's */ @@ -445,58 +445,33 @@ static struct class net_class = { void netdev_unregister_sysfs(struct net_device * net) { - struct class_device * class_dev = &(net->class_dev); - - if (net->get_stats) - sysfs_remove_group(&class_dev->kobj, &netstat_group); - -#ifdef WIRELESS_EXT - if (net->get_wireless_stats || (net->wireless_handlers && - net->wireless_handlers->get_wireless_stats)) - sysfs_remove_group(&class_dev->kobj, &wireless_group); -#endif - class_device_del(class_dev); - + class_device_del(&(net->class_dev)); } /* Create sysfs entries for network device. */ int netdev_register_sysfs(struct net_device *net) { struct class_device *class_dev = &(net->class_dev); - int ret; + struct attribute_group **groups = net->sysfs_groups; + class_device_initialize(class_dev); class_dev->class = &net_class; class_dev->class_data = net; + class_dev->groups = groups; + BUILD_BUG_ON(BUS_ID_SIZE < IFNAMSIZ); strlcpy(class_dev->class_id, net->name, BUS_ID_SIZE); - if ((ret = class_device_register(class_dev))) - goto out; - if (net->get_stats && - (ret = sysfs_create_group(&class_dev->kobj, &netstat_group))) - goto out_unreg; + if (net->get_stats) + *groups++ = &netstat_group; #ifdef WIRELESS_EXT - if (net->get_wireless_stats || (net->wireless_handlers && - net->wireless_handlers->get_wireless_stats)) { - ret = sysfs_create_group(&class_dev->kobj, &wireless_group); - if (ret) - goto out_cleanup; - } - return 0; -out_cleanup: - if (net->get_stats) - sysfs_remove_group(&class_dev->kobj, &netstat_group); -#else - return 0; + if (net->get_wireless_stats + || (net->wireless_handlers && net->wireless_handlers->get_wireless_stats)) + *groups++ = &wireless_group; #endif -out_unreg: - printk(KERN_WARNING "%s: sysfs attribute registration failed %d\n", - net->name, ret); - class_device_unregister(class_dev); -out: - return ret; + return class_device_add(class_dev); } int netdev_sysfs_init(void) -- cgit v1.2.3-70-g09d2 From 0182bd2b1e2fb45a55f110795bfdb9aa5f6c6b0b Mon Sep 17 00:00:00 2001 From: Hua Zhong Date: Sat, 6 May 2006 18:11:39 -0700 Subject: [IPV4]: Remove likely in ip_rcv_finish() This is another result from my likely profiling tool (dwalker@mvista.com just sent the patch of the profiling tool to linux-kernel mailing list, which is similar to what I use). On my system (not very busy, normal development machine within a VMWare workstation), I see a 6/5 miss/hit ratio for this "likely". Signed-off-by: Hua Zhong Signed-off-by: David S. Miller --- net/ipv4/ip_input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index 18d7fad474d7..c9026dbf4c93 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -337,7 +337,7 @@ static inline int ip_rcv_finish(struct sk_buff *skb) * Initialise the virtual path cache for the packet. It describes * how the packet travels inside Linux networking. */ - if (likely(skb->dst == NULL)) { + if (skb->dst == NULL) { int err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, skb->dev); if (unlikely(err)) { -- cgit v1.2.3-70-g09d2 From 0eb1bd210d94e9f2c87551d794bb2755e5e24eed Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 6 May 2006 18:34:10 -0700 Subject: [IRDA] irda-usb: use NULL instead of 0 Use NULL instead of 0 for a null pointer value (sparse warning): drivers/net/irda/irda-usb.c:1781:30: warning: Using plain integer as NULL pointer Also, correct timeout argument to use milliseconds instead of jiffies. Signed-off-by: Randy Dunlap Signed-off-by: David S. Miller --- drivers/net/irda/irda-usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c index 96bdb73c2283..cd87593e4e8a 100644 --- a/drivers/net/irda/irda-usb.c +++ b/drivers/net/irda/irda-usb.c @@ -1778,7 +1778,7 @@ static int irda_usb_probe(struct usb_interface *intf, if (self->needspatch) { ret = usb_control_msg (self->usbdev, usb_sndctrlpipe (self->usbdev, 0), - 0x02, 0x40, 0, 0, 0, 0, msecs_to_jiffies(500)); + 0x02, 0x40, 0, 0, NULL, 0, 500); if (ret < 0) { IRDA_DEBUG (0, "usb_control_msg failed %d\n", ret); goto err_out_3; -- cgit v1.2.3-70-g09d2 From f5b40e363ad6041a96e3da32281d8faa191597b9 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 7 May 2006 10:49:33 -0700 Subject: Fix ptrace_attach()/ptrace_traceme()/de_thread() race This holds the task lock (and, for ptrace_attach, the tasklist_lock) over the actual attach event, which closes a race between attacking to a thread that is either doing a PTRACE_TRACEME or getting de-threaded. Thanks to Oleg Nesterov for reminding me about this, and Chris Wright for noticing a lost return value in my first version. Signed-off-by: Linus Torvalds --- kernel/ptrace.c | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 4e0f0ec003f7..b0f8da80d7d4 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -148,12 +148,16 @@ int ptrace_may_attach(struct task_struct *task) int ptrace_attach(struct task_struct *task) { int retval; - task_lock(task); + retval = -EPERM; if (task->pid <= 1) - goto bad; + goto out; if (task->tgid == current->tgid) - goto bad; + goto out; + + write_lock_irq(&tasklist_lock); + task_lock(task); + /* the same process cannot be attached many times */ if (task->ptrace & PT_PTRACED) goto bad; @@ -166,17 +170,15 @@ int ptrace_attach(struct task_struct *task) ? PT_ATTACHED : 0); if (capable(CAP_SYS_PTRACE)) task->ptrace |= PT_PTRACE_CAP; - task_unlock(task); - write_lock_irq(&tasklist_lock); __ptrace_link(task, current); - write_unlock_irq(&tasklist_lock); force_sig_specific(SIGSTOP, task); - return 0; bad: + write_unlock_irq(&tasklist_lock); task_unlock(task); +out: return retval; } @@ -417,21 +419,22 @@ int ptrace_request(struct task_struct *child, long request, */ int ptrace_traceme(void) { - int ret; + int ret = -EPERM; /* * Are we already being traced? */ - if (current->ptrace & PT_PTRACED) - return -EPERM; - ret = security_ptrace(current->parent, current); - if (ret) - return -EPERM; - /* - * Set the ptrace bit in the process ptrace flags. - */ - current->ptrace |= PT_PTRACED; - return 0; + task_lock(current); + if (!(current->ptrace & PT_PTRACED)) { + ret = security_ptrace(current->parent, current); + /* + * Set the ptrace bit in the process ptrace flags. + */ + if (!ret) + current->ptrace |= PT_PTRACED; + } + task_unlock(current); + return ret; } /** -- cgit v1.2.3-70-g09d2 From 216251cff98838f2b79c53fc8a9e76884944be7d Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Sun, 7 May 2006 18:56:27 +0100 Subject: [ARM] 3501/1: i.MX: fix lowlevel debug macros Patch from Sascha Hauer This patch fixes the addruart macro to work with both mmu enabled and disabled. Signed-off-by: Sascha Hauer Signed-off-by: Russell King --- arch/arm/mach-imx/mx1ads.c | 2 +- include/asm-arm/arch-imx/debug-macro.S | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-imx/mx1ads.c b/arch/arm/mach-imx/mx1ads.c index e1f6c0bbe1e7..da893c80d471 100644 --- a/arch/arm/mach-imx/mx1ads.c +++ b/arch/arm/mach-imx/mx1ads.c @@ -161,7 +161,7 @@ mx1ads_map_io(void) MACHINE_START(MX1ADS, "Motorola MX1ADS") /* Maintainer: Sascha Hauer, Pengutronix */ .phys_io = 0x00200000, - .io_pg_offst = ((0xe0200000) >> 18) & 0xfffc, + .io_pg_offst = ((0xe0000000) >> 18) & 0xfffc, .boot_params = 0x08000100, .map_io = mx1ads_map_io, .init_irq = imx_init_irq, diff --git a/include/asm-arm/arch-imx/debug-macro.S b/include/asm-arm/arch-imx/debug-macro.S index 83f552f7bcc1..c611871643a2 100644 --- a/include/asm-arm/arch-imx/debug-macro.S +++ b/include/asm-arm/arch-imx/debug-macro.S @@ -16,7 +16,7 @@ tst \rx, #1 @ MMU enabled? moveq \rx, #0x00000000 @ physical movne \rx, #0xe0000000 @ virtual - orr \rx, \rx, #0x00200000 + orreq \rx, \rx, #0x00200000 @ physical orr \rx, \rx, #0x00006000 @ UART1 offset .endm -- cgit v1.2.3-70-g09d2 From 16b6dd4419cdef637a907cfc26594e4ebe688975 Mon Sep 17 00:00:00 2001 From: Bellido Nicolas Date: Sun, 7 May 2006 22:49:21 +0100 Subject: [ARM] 3503/1: Fix map_desc structure for aaec2000 Patch from Bellido Nicolas Patch: [ARM] 2982/1: Replace map_desc.physical with map_desc.pfn: aaec2000 incorrectly expanded the struct map_desc for aaec2000. Signed-off-by: Nicolas Bellido Signed-off-by: Russell King --- arch/arm/mach-aaec2000/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-aaec2000/core.c b/arch/arm/mach-aaec2000/core.c index dce4815cf53c..3be05c430619 100644 --- a/arch/arm/mach-aaec2000/core.c +++ b/arch/arm/mach-aaec2000/core.c @@ -50,12 +50,12 @@ static struct map_desc standard_io_desc[] __initdata = { { .virtual = VIO_APB_BASE, - .physical = __phys_to_pfn(PIO_APB_BASE), + .pfn = __phys_to_pfn(PIO_APB_BASE), .length = IO_APB_LENGTH, .type = MT_DEVICE }, { .virtual = VIO_AHB_BASE, - .physical = __phys_to_pfn(PIO_AHB_BASE), + .pfn = __phys_to_pfn(PIO_AHB_BASE), .length = IO_AHB_LENGTH, .type = MT_DEVICE } -- cgit v1.2.3-70-g09d2 From 8a33b224ecb576e27695ff8922c8e579dbf7070e Mon Sep 17 00:00:00 2001 From: Bellido Nicolas Date: Sun, 7 May 2006 22:49:21 +0100 Subject: [ARM] 3504/1: Fix clcd includes for aaec2000 Patch from Bellido Nicolas Since this patch: [ARM] 3366/1: Allow the 16bpp mode configuration in the CLCD control register linux/amba/bus.h needs to be included before linux/amba/clcd.h Signed-off-by: Nicolas Bellido Signed-off-by: Russell King --- arch/arm/mach-aaec2000/core.c | 1 - arch/arm/mach-aaec2000/core.h | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-aaec2000/core.c b/arch/arm/mach-aaec2000/core.c index 3be05c430619..65be5efd633c 100644 --- a/arch/arm/mach-aaec2000/core.c +++ b/arch/arm/mach-aaec2000/core.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include diff --git a/arch/arm/mach-aaec2000/core.h b/arch/arm/mach-aaec2000/core.h index b6029a95f19c..59501b573167 100644 --- a/arch/arm/mach-aaec2000/core.h +++ b/arch/arm/mach-aaec2000/core.h @@ -9,6 +9,7 @@ * */ +#include #include struct sys_timer; -- cgit v1.2.3-70-g09d2 From 201be92a4243e58bcc6c0878489bcc2aaaf51c80 Mon Sep 17 00:00:00 2001 From: Bellido Nicolas Date: Sun, 7 May 2006 22:49:22 +0100 Subject: [ARM] 3505/1: aaec2000: entry-macro.S needs asm/arch/irqs.h Patch from Bellido Nicolas Since git commit 2b78838842346da390e8547cd37035184376d506, entry-macro.S needs to include asm/arch/irqs.h Signed-off-by: Nicolas Bellido Signed-off-by: Russell King --- include/asm-arm/arch-aaec2000/entry-macro.S | 1 + 1 file changed, 1 insertion(+) diff --git a/include/asm-arm/arch-aaec2000/entry-macro.S b/include/asm-arm/arch-aaec2000/entry-macro.S index df31313ab07e..1eb3503bd16e 100644 --- a/include/asm-arm/arch-aaec2000/entry-macro.S +++ b/include/asm-arm/arch-aaec2000/entry-macro.S @@ -10,6 +10,7 @@ * published by the Free Software Foundation. * */ +#include .macro disable_fiq .endm -- cgit v1.2.3-70-g09d2 From 9a708becafe99fa32211e8c53dbacefdb4b11718 Mon Sep 17 00:00:00 2001 From: Bellido Nicolas Date: Sun, 7 May 2006 22:49:23 +0100 Subject: [ARM] 3506/1: aaec2000: debug-macro.S needs hardware.h Patch from Bellido Nicolas Include hardware.h in debug-macro.S, otherwise io_p2v is undefined. Signed-off-by: Nicolas Bellido Signed-off-by: Russell King --- include/asm-arm/arch-aaec2000/debug-macro.S | 1 + 1 file changed, 1 insertion(+) diff --git a/include/asm-arm/arch-aaec2000/debug-macro.S b/include/asm-arm/arch-aaec2000/debug-macro.S index e4f1fa539a74..7b1fce021d8a 100644 --- a/include/asm-arm/arch-aaec2000/debug-macro.S +++ b/include/asm-arm/arch-aaec2000/debug-macro.S @@ -9,6 +9,7 @@ * published by the Free Software Foundation. */ +#include "hardware.h" .macro addruart,rx mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? -- cgit v1.2.3-70-g09d2 From 74fae122eb9f0db8b8718b9851c31c2f374fb134 Mon Sep 17 00:00:00 2001 From: Bellido Nicolas Date: Sun, 7 May 2006 22:49:24 +0100 Subject: [ARM] 3507/1: Replace map_desc.physical with map_desc.pfn: aaed2000 Patch from Bellido Nicolas aaed2000 map_desc.pfn conversion Signed-off-by: Nicolas Bellido Signed-off-by: Russell King --- arch/arm/mach-aaec2000/aaed2000.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-aaec2000/aaed2000.c b/arch/arm/mach-aaec2000/aaed2000.c index dc5fa8e5ebef..83f57da3184c 100644 --- a/arch/arm/mach-aaec2000/aaed2000.c +++ b/arch/arm/mach-aaec2000/aaed2000.c @@ -79,7 +79,12 @@ static void __init aaed2000_init(void) } static struct map_desc aaed2000_io_desc[] __initdata = { - { EXT_GPIO_VBASE, EXT_GPIO_PBASE, EXT_GPIO_LENGTH, MT_DEVICE }, /* Ext GPIO */ + { + .virtual = EXT_GPIO_VBASE, + .pfn = __phys_to_pfn(EXT_GPIO_PBASE), + .length = EXT_GPIO_LENGTH, + .type = MT_DEVICE + }, }; static void __init aaed2000_map_io(void) -- cgit v1.2.3-70-g09d2 From fd5f0cd6b0cef59ba18e5ac13be5b2775fa6ec28 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Tue, 2 May 2006 12:33:20 +0200 Subject: kbuild: Do not overwrite makefile as anohter user Change the conditional of the outputmakefile rule to be evaluated entirely in make, and add a conditional to not touch the generated makefile when e.g. running 'make install' as root while the build was done as non-root. Also adjust the comment describing this, and move the message printing and redirection to mkmakefile. Signed-off-by: Jan Beulich Signed-off-by: Sam Ravnborg --- Makefile | 16 +++++++--------- scripts/mkmakefile | 5 ++++- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index 8517f7ba2473..9e4c5692a32f 100644 --- a/Makefile +++ b/Makefile @@ -344,16 +344,14 @@ scripts_basic: scripts/basic/%: scripts_basic ; PHONY += outputmakefile -# outputmakefile generate a Makefile to be placed in output directory, if -# using a seperate output directory. This allows convinient use -# of make in output directory +# outputmakefile generates a Makefile in the output directory, if using a +# separate output directory. This allows convenient use of make in the +# output directory. outputmakefile: - $(Q)if test ! $(srctree) -ef $(objtree); then \ - $(CONFIG_SHELL) $(srctree)/scripts/mkmakefile \ - $(srctree) $(objtree) $(VERSION) $(PATCHLEVEL) \ - > $(objtree)/Makefile; \ - echo ' GEN $(objtree)/Makefile'; \ - fi +ifneq ($(KBUILD_SRC),) + $(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkmakefile \ + $(srctree) $(objtree) $(VERSION) $(PATCHLEVEL) +endif # To make sure we do not include .config for any of the *config targets # catch them early, and hand them over to scripts/kconfig/Makefile diff --git a/scripts/mkmakefile b/scripts/mkmakefile index a22cbedd3b3e..7f9d544f9b6c 100644 --- a/scripts/mkmakefile +++ b/scripts/mkmakefile @@ -10,7 +10,10 @@ # $4 - patchlevel -cat << EOF +test ! -r $2/Makefile -o -O $2/Makefile || exit 0 +echo " GEN $2/Makefile" + +cat << EOF > $2/Makefile # Automatically generated by $0: don't edit VERSION = $3 -- cgit v1.2.3-70-g09d2 From bb3426ad6659282d9244d4909e69aa639d0360d0 Mon Sep 17 00:00:00 2001 From: Martin Habets Date: Sun, 7 May 2006 23:04:06 -0700 Subject: [SPARC]: Remove duplicate symbol exports This patch resolves the following build warnings seen in 2.6.17-rc3: WARNING: vmlinux: 'sys_close' exported twice. Previous export was in vmlinux WARNING: vmlinux: 'memchr' exported twice. Previous export was in vmlinux WARNING: vmlinux: 'strstr' exported twice. Previous export was in vmlinux WARNING: vmlinux: 'strnlen' exported twice. Previous export was in vmlinux WARNING: vmlinux: 'strrchr' exported twice. Previous export was in vmlinux WARNING: vmlinux: 'strchr' exported twice. Previous export was in vmlinux WARNING: vmlinux: 'strcmp' exported twice. Previous export was in vmlinux WARNING: vmlinux: 'strncat' exported twice. Previous export was in vmlinux WARNING: vmlinux: 'strcat' exported twice. Previous export was in vmlinux WARNING: vmlinux: 'strncpy' exported twice. Previous export was in vmlinux WARNING: vmlinux: 'strcpy' exported twice. Previous export was in vmlinux Signed-off-by: Martin Habets Signed-off-by: David S. Miller --- arch/sparc/kernel/sparc_ksyms.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c index ec1c9687d679..4b376fae752c 100644 --- a/arch/sparc/kernel/sparc_ksyms.c +++ b/arch/sparc/kernel/sparc_ksyms.c @@ -251,19 +251,9 @@ EXPORT_SYMBOL(__prom_getchild); EXPORT_SYMBOL(__prom_getsibling); /* sparc library symbols */ -EXPORT_SYMBOL(memchr); EXPORT_SYMBOL(memscan); EXPORT_SYMBOL(strlen); -EXPORT_SYMBOL(strnlen); -EXPORT_SYMBOL(strcpy); -EXPORT_SYMBOL(strncpy); -EXPORT_SYMBOL(strcat); -EXPORT_SYMBOL(strncat); -EXPORT_SYMBOL(strcmp); EXPORT_SYMBOL(strncmp); -EXPORT_SYMBOL(strchr); -EXPORT_SYMBOL(strrchr); -EXPORT_SYMBOL(strstr); EXPORT_SYMBOL(page_kernel); /* Special internal versions of library functions. */ @@ -317,6 +307,3 @@ EXPORT_SYMBOL(do_BUG); /* Sun Power Management Idle Handler */ EXPORT_SYMBOL(pm_idle); - -/* Binfmt_misc needs this */ -EXPORT_SYMBOL(sys_close); -- cgit v1.2.3-70-g09d2 From 4cfbd7eb24975e942c3b6c0119c953c3a7a5f787 Mon Sep 17 00:00:00 2001 From: Martin Habets Date: Sun, 7 May 2006 23:43:19 -0700 Subject: [SPARC]: show device name in /proc/dvma_map This patch will set the device name in a resource, which will be shown in /proc/dvma_map. Signed-off-by: Martin Habets Signed-off-by: David S. Miller --- arch/sparc/kernel/ioport.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c index 460f72e640e6..f9ff29734848 100644 --- a/arch/sparc/kernel/ioport.c +++ b/arch/sparc/kernel/ioport.c @@ -274,6 +274,11 @@ void *sbus_alloc_consistent(struct sbus_dev *sdev, long len, u32 *dma_addrp) if (mmu_map_dma_area(dma_addrp, va, res->start, len_total) != 0) goto err_noiommu; + /* Set the resource name, if known. */ + if (sdev) { + res->name = sdev->prom_name; + } + return (void *)res->start; err_noiommu: -- cgit v1.2.3-70-g09d2 From d08d389d5aef0509edba7ee42cd6c6a3998fee22 Mon Sep 17 00:00:00 2001 From: Nathan Scott Date: Mon, 8 May 2006 19:51:28 +1000 Subject: [XFS] Fix a possible forced shutdown due to mishandling write barriers with remount,ro. SGI-PV: 951944 SGI-Modid: xfs-linux-melb:xfs-kern:25742a Signed-off-by: Nathan Scott --- fs/xfs/xfs_vfsops.c | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/fs/xfs/xfs_vfsops.c b/fs/xfs/xfs_vfsops.c index f0e09ca14139..36ea1b2094f2 100644 --- a/fs/xfs/xfs_vfsops.c +++ b/fs/xfs/xfs_vfsops.c @@ -669,31 +669,22 @@ xfs_mntupdate( xfs_mount_t *mp = XFS_BHVTOM(bdp); int error; - if (args->flags & XFSMNT_BARRIER) - mp->m_flags |= XFS_MOUNT_BARRIER; - else - mp->m_flags &= ~XFS_MOUNT_BARRIER; - - if ((vfsp->vfs_flag & VFS_RDONLY) && - !(*flags & MS_RDONLY)) { - vfsp->vfs_flag &= ~VFS_RDONLY; - - if (args->flags & XFSMNT_BARRIER) + if (!(*flags & MS_RDONLY)) { /* rw/ro -> rw */ + if (vfsp->vfs_flag & VFS_RDONLY) + vfsp->vfs_flag &= ~VFS_RDONLY; + if (args->flags & XFSMNT_BARRIER) { + mp->m_flags |= XFS_MOUNT_BARRIER; xfs_mountfs_check_barriers(mp); - } - - if (!(vfsp->vfs_flag & VFS_RDONLY) && - (*flags & MS_RDONLY)) { + } else { + mp->m_flags &= ~XFS_MOUNT_BARRIER; + } + } else if (!(vfsp->vfs_flag & VFS_RDONLY)) { /* rw -> ro */ VFS_SYNC(vfsp, SYNC_FSDATA|SYNC_BDFLUSH|SYNC_ATTR, NULL, error); - xfs_quiesce_fs(mp); - - /* Ok now write out an unmount record */ xfs_log_unmount_write(mp); xfs_unmountfs_writesb(mp); vfsp->vfs_flag |= VFS_RDONLY; } - return 0; } -- cgit v1.2.3-70-g09d2 From b1ecdda9313ec5d2f971993f44f6b657acf70cff Mon Sep 17 00:00:00 2001 From: Nathan Scott Date: Mon, 8 May 2006 19:51:42 +1000 Subject: [XFS] Fix a project quota space accounting leak on rename. SGI-PV: 951636 SGI-Modid: xfs-linux-melb:xfs-kern:25811a Signed-off-by: Nathan Scott --- fs/xfs/xfs_rename.c | 12 ++++++++++++ fs/xfs/xfs_vnodeops.c | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/fs/xfs/xfs_rename.c b/fs/xfs/xfs_rename.c index 81a05cfd77d2..1f148762eb28 100644 --- a/fs/xfs/xfs_rename.c +++ b/fs/xfs/xfs_rename.c @@ -316,6 +316,18 @@ xfs_rename( } } + /* + * If we are using project inheritance, we only allow renames + * into our tree when the project IDs are the same; else the + * tree quota mechanism would be circumvented. + */ + if (unlikely((target_dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) && + (target_dp->i_d.di_projid != src_ip->i_d.di_projid))) { + error = XFS_ERROR(EXDEV); + xfs_rename_unlock4(inodes, XFS_ILOCK_SHARED); + goto rele_return; + } + new_parent = (src_dp != target_dp); src_is_directory = ((src_ip->i_d.di_mode & S_IFMT) == S_IFDIR); diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index fa71b305ba5c..7027ae68ee38 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c @@ -2663,7 +2663,7 @@ xfs_link( */ if (unlikely((tdp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) && (tdp->i_d.di_projid != sip->i_d.di_projid))) { - error = XFS_ERROR(EPERM); + error = XFS_ERROR(EXDEV); goto error_return; } -- cgit v1.2.3-70-g09d2 From e63a3690013a475746ad2cea998ebb534d825704 Mon Sep 17 00:00:00 2001 From: Nathan Scott Date: Mon, 8 May 2006 19:51:58 +1000 Subject: [XFS] Fix a possible metadata buffer (AGFL) refcount leak when fixing an AG freelist. SGI-PV: 952681 SGI-Modid: xfs-linux-melb:xfs-kern:25902a Signed-off-by: Nathan Scott --- fs/xfs/xfs_alloc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c index 64ee07db0d5e..8558226281c4 100644 --- a/fs/xfs/xfs_alloc.c +++ b/fs/xfs/xfs_alloc.c @@ -1942,8 +1942,10 @@ xfs_alloc_fix_freelist( /* * Allocate as many blocks as possible at once. */ - if ((error = xfs_alloc_ag_vextent(&targs))) + if ((error = xfs_alloc_ag_vextent(&targs))) { + xfs_trans_brelse(tp, agflbp); return error; + } /* * Stop if we run out. Won't happen if callers are obeying * the restrictions correctly. Can happen for free calls @@ -1960,6 +1962,7 @@ xfs_alloc_fix_freelist( return error; } } + xfs_trans_brelse(tp, agflbp); args->agbp = agbp; return 0; } -- cgit v1.2.3-70-g09d2 From 75dff55af9a989293e9f9bacf049858f4262bc08 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 7 May 2006 23:02:42 -0400 Subject: [PATCH] fs/locks.c: Fix lease_init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is insane to be giving lease_init() the task of freeing the lock it is supposed to initialise, given that the lock is not guaranteed to be allocated on the stack. This causes lockups in fcntl_setlease(). Problem diagnosed by Daniel Hokka Zakrisson Also fix a slab leak in __setlease() due to an uninitialised return value. Problem diagnosed by Björn Steinbrink. Signed-off-by: Trond Myklebust Tested-by: Daniel Hokka Zakrisson Signed-off-by: Linus Torvalds --- fs/locks.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/fs/locks.c b/fs/locks.c index efad798824dc..6f99c0a6f836 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -446,15 +446,14 @@ static struct lock_manager_operations lease_manager_ops = { */ static int lease_init(struct file *filp, int type, struct file_lock *fl) { + if (assign_type(fl, type) != 0) + return -EINVAL; + fl->fl_owner = current->files; fl->fl_pid = current->tgid; fl->fl_file = filp; fl->fl_flags = FL_LEASE; - if (assign_type(fl, type) != 0) { - locks_free_lock(fl); - return -EINVAL; - } fl->fl_start = 0; fl->fl_end = OFFSET_MAX; fl->fl_ops = NULL; @@ -466,16 +465,19 @@ static int lease_init(struct file *filp, int type, struct file_lock *fl) static int lease_alloc(struct file *filp, int type, struct file_lock **flp) { struct file_lock *fl = locks_alloc_lock(); - int error; + int error = -ENOMEM; if (fl == NULL) - return -ENOMEM; + goto out; error = lease_init(filp, type, fl); - if (error) - return error; + if (error) { + locks_free_lock(fl); + fl = NULL; + } +out: *flp = fl; - return 0; + return error; } /* Check if two locks overlap each other. @@ -1372,6 +1374,7 @@ static int __setlease(struct file *filp, long arg, struct file_lock **flp) goto out; if (my_before != NULL) { + *flp = *my_before; error = lease->fl_lmops->fl_change(my_before, arg); goto out; } -- cgit v1.2.3-70-g09d2 From e0c1e9bf81badc7ba59e120d6218101903d5d103 Mon Sep 17 00:00:00 2001 From: Kimball Murray Date: Mon, 8 May 2006 15:17:16 +0200 Subject: [PATCH] x86_64: avoid IRQ0 ioapic pin collision The patch addresses a problem with ACPI SCI interrupt entry, which gets re-used, and the IRQ is assigned to another unrelated device. The patch corrects the code such that SCI IRQ is skipped and duplicate entry is avoided. Second issue came up with VIA chipset, the problem was caused by original patch assigning IRQs starting 16 and up. The VIA chipset uses 4-bit IRQ register for internal interrupt routing, and therefore cannot handle IRQ numbers assigned to its devices. The patch corrects this problem by allowing PCI IRQs below 16. Cc: len.brown@intel.com Signed-off by: Natalie Protasevich Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/io_apic.c | 5 +++++ arch/i386/kernel/mpparse.c | 12 +++++++++++- arch/x86_64/kernel/io_apic.c | 5 +++++ arch/x86_64/kernel/mpparse.c | 12 +++++++++++- include/asm-i386/io_apic.h | 1 + include/asm-x86_64/io_apic.h | 1 + 6 files changed, 34 insertions(+), 2 deletions(-) diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index f8f132aa5472..d70f2ade5cde 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c @@ -2238,6 +2238,8 @@ static inline void unlock_ExtINT_logic(void) spin_unlock_irqrestore(&ioapic_lock, flags); } +int timer_uses_ioapic_pin_0; + /* * This code may look a bit paranoid, but it's supposed to cooperate with * a wide range of boards and BIOS bugs. Fortunately only the timer IRQ @@ -2274,6 +2276,9 @@ static inline void check_timer(void) pin2 = ioapic_i8259.pin; apic2 = ioapic_i8259.apic; + if (pin1 == 0) + timer_uses_ioapic_pin_0 = 1; + printk(KERN_INFO "..TIMER: vector=0x%02X apic1=%d pin1=%d apic2=%d pin2=%d\n", vector, apic1, pin1, apic2, pin2); diff --git a/arch/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse.c index 34d21e21e012..6b1392d33ed5 100644 --- a/arch/i386/kernel/mpparse.c +++ b/arch/i386/kernel/mpparse.c @@ -1130,7 +1130,17 @@ int mp_register_gsi (u32 gsi, int triggering, int polarity) */ int irq = gsi; if (gsi < MAX_GSI_NUM) { - if (gsi > 15) + /* + * Retain the VIA chipset work-around (gsi > 15), but + * avoid a problem where the 8254 timer (IRQ0) is setup + * via an override (so it's not on pin 0 of the ioapic), + * and at the same time, the pin 0 interrupt is a PCI + * type. The gsi > 15 test could cause these two pins + * to be shared as IRQ0, and they are not shareable. + * So test for this condition, and if necessary, avoid + * the pin collision. + */ + if (gsi > 15 || (gsi == 0 && !timer_uses_ioapic_pin_0)) gsi = pci_irq++; /* * Don't assign IRQ used by ACPI SCI diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index 77b4c608cca0..0de3ea938830 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c @@ -1777,6 +1777,8 @@ static inline void unlock_ExtINT_logic(void) spin_unlock_irqrestore(&ioapic_lock, flags); } +int timer_uses_ioapic_pin_0; + /* * This code may look a bit paranoid, but it's supposed to cooperate with * a wide range of boards and BIOS bugs. Fortunately only the timer IRQ @@ -1814,6 +1816,9 @@ static inline void check_timer(void) pin2 = ioapic_i8259.pin; apic2 = ioapic_i8259.apic; + if (pin1 == 0) + timer_uses_ioapic_pin_0 = 1; + apic_printk(APIC_VERBOSE,KERN_INFO "..TIMER: vector=0x%02X apic1=%d pin1=%d apic2=%d pin2=%d\n", vector, apic1, pin1, apic2, pin2); diff --git a/arch/x86_64/kernel/mpparse.c b/arch/x86_64/kernel/mpparse.c index b17cf3eba359..083da7e606b1 100644 --- a/arch/x86_64/kernel/mpparse.c +++ b/arch/x86_64/kernel/mpparse.c @@ -968,7 +968,17 @@ int mp_register_gsi(u32 gsi, int triggering, int polarity) */ int irq = gsi; if (gsi < MAX_GSI_NUM) { - if (gsi > 15) + /* + * Retain the VIA chipset work-around (gsi > 15), but + * avoid a problem where the 8254 timer (IRQ0) is setup + * via an override (so it's not on pin 0 of the ioapic), + * and at the same time, the pin 0 interrupt is a PCI + * type. The gsi > 15 test could cause these two pins + * to be shared as IRQ0, and they are not shareable. + * So test for this condition, and if necessary, avoid + * the pin collision. + */ + if (gsi > 15 || (gsi == 0 && !timer_uses_ioapic_pin_0)) gsi = pci_irq++; /* * Don't assign IRQ used by ACPI SCI diff --git a/include/asm-i386/io_apic.h b/include/asm-i386/io_apic.h index 51c4e5fe6062..d92e253f7f6f 100644 --- a/include/asm-i386/io_apic.h +++ b/include/asm-i386/io_apic.h @@ -200,6 +200,7 @@ extern int io_apic_get_unique_id (int ioapic, int apic_id); extern int io_apic_get_version (int ioapic); extern int io_apic_get_redir_entries (int ioapic); extern int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int active_high_low); +extern int timer_uses_ioapic_pin_0; #endif /* CONFIG_ACPI */ extern int (*ioapic_renumber_irq)(int ioapic, int irq); diff --git a/include/asm-x86_64/io_apic.h b/include/asm-x86_64/io_apic.h index ee1bc69aec9c..52484e82c641 100644 --- a/include/asm-x86_64/io_apic.h +++ b/include/asm-x86_64/io_apic.h @@ -205,6 +205,7 @@ extern int skip_ioapic_setup; extern int io_apic_get_version (int ioapic); extern int io_apic_get_redir_entries (int ioapic); extern int io_apic_set_pci_routing (int ioapic, int pin, int irq, int, int); +extern int timer_uses_ioapic_pin_0; #endif extern int sis_apic_bug; /* dummy */ -- cgit v1.2.3-70-g09d2 From 5192d84e4c32cd335fd572e5ff0712041f45f7e7 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Mon, 8 May 2006 15:17:19 +0200 Subject: [PATCH] x86_64: Check for too many northbridges in IOMMU code The IOMMU code can only deal with 8 northbridges. Error out when more are found. Signed-off-by: Andi Kleen Signed-off-by: Linus Torvalds --- arch/x86_64/kernel/pci-gart.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/x86_64/kernel/pci-gart.c b/arch/x86_64/kernel/pci-gart.c index 9d3d76c85ae7..2480d3f08a47 100644 --- a/arch/x86_64/kernel/pci-gart.c +++ b/arch/x86_64/kernel/pci-gart.c @@ -639,6 +639,14 @@ static int __init pci_iommu_init(void) return -1; } + i = 0; + for_all_nb(dev) + i++; + if (i > MAX_NB) { + printk(KERN_ERR "PCI-GART: Too many northbridges (%ld). Disabled\n", i); + return -1; + } + printk(KERN_INFO "PCI-DMA: using GART IOMMU.\n"); aper_size = info.aper_size * 1024 * 1024; iommu_size = check_iommu_size(info.aper_base, aper_size); -- cgit v1.2.3-70-g09d2 From cdc60a4c8e71c4bcf67e83fac6c0cabd0ff19bfe Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Mon, 8 May 2006 15:17:22 +0200 Subject: [PATCH] x86_64: fix die_lock nesting I noticed this when poking around in this area. The oops_begin() function in x86_64 would only conditionally claim the die_lock if the call is nested, but oops_end() would always release the spinlock. This patch adds a nest count for the die lock so that the release of the lock is only done on the final oops_end(). Signed-off-by: Corey Minyard Signed-off-by: Andi Kleen Signed-off-by: Linus Torvalds --- arch/x86_64/kernel/traps.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c index 2700b1375c1f..0ebb281aa178 100644 --- a/arch/x86_64/kernel/traps.c +++ b/arch/x86_64/kernel/traps.c @@ -385,6 +385,7 @@ void out_of_line_bug(void) static DEFINE_SPINLOCK(die_lock); static int die_owner = -1; +static unsigned int die_nest_count; unsigned __kprobes long oops_begin(void) { @@ -399,6 +400,7 @@ unsigned __kprobes long oops_begin(void) else spin_lock(&die_lock); } + die_nest_count++; die_owner = cpu; console_verbose(); bust_spinlocks(1); @@ -409,7 +411,13 @@ void __kprobes oops_end(unsigned long flags) { die_owner = -1; bust_spinlocks(0); - spin_unlock_irqrestore(&die_lock, flags); + die_nest_count--; + if (die_nest_count) + /* We still own the lock */ + local_irq_restore(flags); + else + /* Nest count reaches zero, release the lock. */ + spin_unlock_irqrestore(&die_lock, flags); if (panic_on_oops) panic("Oops"); } -- cgit v1.2.3-70-g09d2 From 8b1ffe9550e71224c43d8c754245bd76f4ea9bb8 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Mon, 8 May 2006 15:17:25 +0200 Subject: [PATCH] x86_64: add nmi_exit to die_nmi Playing with NMI watchdog on x86_64, I discovered that it didn't do what I expected. It always panic-ed, even when it didn't happen from interrupt context. This patch solves that problem for me. Also, in this case, do_exit() will be called with interrupts disabled, I believe. Would it be wise to also call local_irq_enable() after nmi_exit()? [Yes I added it -AK] Currently, on x86_64, any NMI watchdog timeout will cause a panic because the irq count will always be set to be in an interrupt when do_exit() is called from die_nmi(). If we add nmi_exit() to the die_nmi() call (since the nmi will never exit "normally") it seems to solve this problem. The following small program can be used to trigger the NMI watchdog to reproduce this: main () { iopl(3); for (;;) asm("cli"); } Signed-off-by: Andi Kleen Signed-off-by: Linus Torvalds --- arch/x86_64/kernel/traps.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c index 0ebb281aa178..6b87268c5c2e 100644 --- a/arch/x86_64/kernel/traps.c +++ b/arch/x86_64/kernel/traps.c @@ -472,6 +472,8 @@ void __kprobes die_nmi(char *str, struct pt_regs *regs) panic("nmi watchdog"); printk("console shuts up ...\n"); oops_end(flags); + nmi_exit(); + local_irq_enable(); do_exit(SIGSEGV); } -- cgit v1.2.3-70-g09d2 From ac71d12c990526b01ef6cfe50907ef8530a30331 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Mon, 8 May 2006 15:17:28 +0200 Subject: [PATCH] x86_64: Avoid EBDA area in early boot allocator Based on analysis&patch from Robert Hentosch Observed on a Dell PE6850 with 16GB The problem occurs very early on, when the kernel allocates space for the temporary memory map called bootmap. The bootmap overlaps the EBDA region. EBDA region is not historically reserved in the e820 mapping. When the bootmap is freed it marks the EBDA region as usable. If you notice in setup.c there is already code to work around the EBDA in reserve_ebda_region(), this check however occurs after the bootmap is allocated and doesn't prevent the bootmap from using this range. AK: I redid the original patch. Thanks also to Jan Beulich for spotting some mistakes. Cc: Robert_Hentosch@dell.com Cc: jbeulich@novell.com Signed-off-by: Andi Kleen Signed-off-by: Linus Torvalds --- arch/x86_64/kernel/e820.c | 6 ++++++ arch/x86_64/kernel/setup.c | 30 ++++++++++++++++++++++-------- include/asm-x86_64/e820.h | 2 ++ 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/arch/x86_64/kernel/e820.c b/arch/x86_64/kernel/e820.c index 62776c07cff1..222b5b46d2b2 100644 --- a/arch/x86_64/kernel/e820.c +++ b/arch/x86_64/kernel/e820.c @@ -76,6 +76,12 @@ static inline int bad_addr(unsigned long *addrp, unsigned long size) *addrp = __pa_symbol(&_end); return 1; } + + if (last >= ebda_addr && addr < ebda_addr + ebda_size) { + *addrp = ebda_addr + ebda_size; + return 1; + } + /* XXX ramdisk image here? */ return 0; } diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c index ebc3c33b1c6c..f0870bef24d1 100644 --- a/arch/x86_64/kernel/setup.c +++ b/arch/x86_64/kernel/setup.c @@ -571,17 +571,28 @@ static inline void copy_edd(void) #endif #define EBDA_ADDR_POINTER 0x40E -static void __init reserve_ebda_region(void) + +unsigned __initdata ebda_addr; +unsigned __initdata ebda_size; + +static void discover_ebda(void) { - unsigned int addr; - /** + /* * there is a real-mode segmented pointer pointing to the * 4K EBDA area at 0x40E */ - addr = *(unsigned short *)phys_to_virt(EBDA_ADDR_POINTER); - addr <<= 4; - if (addr) - reserve_bootmem_generic(addr, PAGE_SIZE); + ebda_addr = *(unsigned short *)EBDA_ADDR_POINTER; + ebda_addr <<= 4; + + ebda_size = *(unsigned short *)(unsigned long)ebda_addr; + + /* Round EBDA up to pages */ + if (ebda_size == 0) + ebda_size = 1; + ebda_size <<= 10; + ebda_size = round_up(ebda_size + (ebda_addr & ~PAGE_MASK), PAGE_SIZE); + if (ebda_size > 64*1024) + ebda_size = 64*1024; } void __init setup_arch(char **cmdline_p) @@ -627,6 +638,8 @@ void __init setup_arch(char **cmdline_p) check_efer(); + discover_ebda(); + init_memory_mapping(0, (end_pfn_map << PAGE_SHIFT)); dmi_scan_machine(); @@ -669,7 +682,8 @@ void __init setup_arch(char **cmdline_p) reserve_bootmem_generic(0, PAGE_SIZE); /* reserve ebda region */ - reserve_ebda_region(); + if (ebda_addr) + reserve_bootmem_generic(ebda_addr, ebda_size); #ifdef CONFIG_SMP /* diff --git a/include/asm-x86_64/e820.h b/include/asm-x86_64/e820.h index 93b51df51687..670a3388e70a 100644 --- a/include/asm-x86_64/e820.h +++ b/include/asm-x86_64/e820.h @@ -59,6 +59,8 @@ extern void __init parse_memopt(char *p, char **end); extern void __init parse_memmapopt(char *p, char **end); extern struct e820map e820; + +extern unsigned ebda_addr, ebda_size; #endif/*!__ASSEMBLY__*/ #endif/*__E820_HEADER*/ -- cgit v1.2.3-70-g09d2 From 6810b548b25114607e0814612d84125abccc0a4f Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Mon, 8 May 2006 15:17:31 +0200 Subject: [PATCH] x86_64: Move ondemand timer into own work queue Taking the cpu hotplug semaphore in a normal events workqueue is unsafe because other tasks can wait for any workqueues with it hold. This results in a deadlock. Move the DBS timer into its own work queue which is not affected by other work queue flushes to avoid this. Has been acked by Venkatesh. Cc: venkatesh.pallipadi@intel.com Cc: cpufreq@lists.linux.org.uk Signed-off-by: Andi Kleen Signed-off-by: Linus Torvalds --- drivers/cpufreq/cpufreq_ondemand.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 956d121cb161..3e6ffcaa5af4 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -74,6 +74,8 @@ static unsigned int dbs_enable; /* number of CPUs using this policy */ static DEFINE_MUTEX (dbs_mutex); static DECLARE_WORK (dbs_work, do_dbs_timer, NULL); +static struct workqueue_struct *dbs_workq; + struct dbs_tuners { unsigned int sampling_rate; unsigned int sampling_down_factor; @@ -364,23 +366,29 @@ static void do_dbs_timer(void *data) mutex_lock(&dbs_mutex); for_each_online_cpu(i) dbs_check_cpu(i); - schedule_delayed_work(&dbs_work, - usecs_to_jiffies(dbs_tuners_ins.sampling_rate)); + queue_delayed_work(dbs_workq, &dbs_work, + usecs_to_jiffies(dbs_tuners_ins.sampling_rate)); mutex_unlock(&dbs_mutex); } static inline void dbs_timer_init(void) { INIT_WORK(&dbs_work, do_dbs_timer, NULL); - schedule_delayed_work(&dbs_work, - usecs_to_jiffies(dbs_tuners_ins.sampling_rate)); + if (!dbs_workq) + dbs_workq = create_singlethread_workqueue("ondemand"); + if (!dbs_workq) { + printk(KERN_ERR "ondemand: Cannot initialize kernel thread\n"); + return; + } + queue_delayed_work(dbs_workq, &dbs_work, + usecs_to_jiffies(dbs_tuners_ins.sampling_rate)); return; } static inline void dbs_timer_exit(void) { - cancel_delayed_work(&dbs_work); - return; + if (dbs_workq) + cancel_rearming_delayed_workqueue(dbs_workq, &dbs_work); } static int cpufreq_governor_dbs(struct cpufreq_policy *policy, @@ -489,8 +497,12 @@ static int __init cpufreq_gov_dbs_init(void) static void __exit cpufreq_gov_dbs_exit(void) { - /* Make sure that the scheduled work is indeed not running */ - flush_scheduled_work(); + /* Make sure that the scheduled work is indeed not running. + Assumes the timer has been cancelled first. */ + if (dbs_workq) { + flush_workqueue(dbs_workq); + destroy_workqueue(dbs_workq); + } cpufreq_unregister_governor(&cpufreq_gov_dbs); } -- cgit v1.2.3-70-g09d2 From 5eb204eb1fff7387d3ab3e6225c0099dc34e69db Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 8 May 2006 20:30:24 +0100 Subject: [ARM] Update versatile_defconfig Update versatile default configuration, enabling the AACI sound driver, VFP and Versatile AB support. Signed-off-by: Russell King --- arch/arm/configs/versatile_defconfig | 390 ++++++++++++++++++++++------------- 1 file changed, 246 insertions(+), 144 deletions(-) diff --git a/arch/arm/configs/versatile_defconfig b/arch/arm/configs/versatile_defconfig index 2687a225aa6a..96b7a7762426 100644 --- a/arch/arm/configs/versatile_defconfig +++ b/arch/arm/configs/versatile_defconfig @@ -1,50 +1,55 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.12-rc1-bk2 -# Mon Mar 28 00:20:50 2005 +# Linux kernel version: 2.6.17-rc3 +# Mon May 8 20:15:57 2006 # CONFIG_ARM=y CONFIG_MMU=y -CONFIG_UID16=y CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y -CONFIG_GENERIC_IOMAP=y +CONFIG_VECTORS_BASE=0xffff0000 # # Code maturity level options # CONFIG_EXPERIMENTAL=y -CONFIG_CLEAN_COMPILE=y CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 # # General setup # CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set CONFIG_SWAP=y CONFIG_SYSVIPC=y # CONFIG_POSIX_MQUEUE is not set # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y # CONFIG_AUDIT is not set -CONFIG_HOTPLUG=y -CONFIG_KOBJECT_UEVENT=y # CONFIG_IKCONFIG is not set +# CONFIG_RELAY is not set +CONFIG_INITRAMFS_SOURCE="" +CONFIG_UID16=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y # CONFIG_EMBEDDED is not set CONFIG_KALLSYMS=y # CONFIG_KALLSYMS_ALL is not set # CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y CONFIG_BASE_FULL=y CONFIG_FUTEX=y CONFIG_EPOLL=y -CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_SHMEM=y -CONFIG_CC_ALIGN_FUNCTIONS=0 -CONFIG_CC_ALIGN_LABELS=0 -CONFIG_CC_ALIGN_LOOPS=0 -CONFIG_CC_ALIGN_JUMPS=0 +CONFIG_SLAB=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 +# CONFIG_SLOB is not set +CONFIG_OBSOLETE_INTERMODULE=y # # Loadable module support @@ -52,11 +57,28 @@ CONFIG_BASE_SMALL=0 CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_MODULE_FORCE_UNLOAD is not set -CONFIG_OBSOLETE_MODPARM=y # CONFIG_MODVERSIONS is not set # CONFIG_MODULE_SRCVERSION_ALL is not set CONFIG_KMOD=y +# +# Block layer +# +# CONFIG_BLK_DEV_IO_TRACE is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" + # # System Type # @@ -64,11 +86,13 @@ CONFIG_KMOD=y # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set # CONFIG_ARCH_IXP4XX is not set # CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_IXP23XX is not set # CONFIG_ARCH_L7200 is not set # CONFIG_ARCH_PXA is not set # CONFIG_ARCH_RPC is not set @@ -78,14 +102,17 @@ CONFIG_KMOD=y # CONFIG_ARCH_LH7A40X is not set # CONFIG_ARCH_OMAP is not set CONFIG_ARCH_VERSATILE=y +# CONFIG_ARCH_REALVIEW is not set # CONFIG_ARCH_IMX is not set # CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_AAEC2000 is not set +# CONFIG_ARCH_AT91RM9200 is not set # # Versatile platform type # CONFIG_ARCH_VERSATILE_PB=y -# CONFIG_MACH_VERSATILE_AB is not set +CONFIG_MACH_VERSATILE_AB=y # # Processor Type @@ -106,12 +133,14 @@ CONFIG_ARM_THUMB=y # CONFIG_CPU_DCACHE_DISABLE is not set # CONFIG_CPU_DCACHE_WRITETHROUGH is not set # CONFIG_CPU_CACHE_ROUND_ROBIN is not set +CONFIG_ARM_VIC=y CONFIG_ICST307=y # # Bus support # CONFIG_ARM_AMBA=y +# CONFIG_PCI is not set # # PCCARD (PCMCIA/CardBus) support @@ -122,6 +151,18 @@ CONFIG_ARM_AMBA=y # Kernel Features # # CONFIG_PREEMPT is not set +# CONFIG_NO_IDLE_HZ is not set +CONFIG_HZ=100 +# CONFIG_AEABI is not set +# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4096 CONFIG_LEDS=y CONFIG_LEDS_TIMER=y CONFIG_LEDS_CPU=y @@ -145,7 +186,7 @@ CONFIG_CMDLINE="root=1f03 mem=32M" CONFIG_FPE_NWFPE=y # CONFIG_FPE_NWFPE_XP is not set # CONFIG_FPE_FASTFPE is not set -# CONFIG_VFP is not set +CONFIG_VFP=y # # Userspace binary formats @@ -159,8 +200,91 @@ CONFIG_BINFMT_ELF=y # Power management options # CONFIG_PM=y +CONFIG_PM_LEGACY=y +# CONFIG_PM_DEBUG is not set # CONFIG_APM is not set +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_NETDEBUG is not set +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_INET_DIAG is not set +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_BIC=y +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETFILTER is not set + +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set + +# +# TIPC Configuration (EXPERIMENTAL) +# +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_IEEE80211 is not set + # # Device Drivers # @@ -173,6 +297,11 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y # CONFIG_FW_LOADER is not set # CONFIG_DEBUG_DRIVER is not set +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set + # # Memory Technology Devices (MTD) # @@ -192,6 +321,7 @@ CONFIG_MTD_BLOCK=y # CONFIG_FTL is not set # CONFIG_NFTL is not set # CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set # # RAM/ROM/Flash chip drivers @@ -214,6 +344,7 @@ CONFIG_MTD_CFI_I1=y CONFIG_MTD_CFI_I2=y # CONFIG_MTD_CFI_I4 is not set # CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_OTP is not set CONFIG_MTD_CFI_INTELEXT=y # CONFIG_MTD_CFI_AMDSTD is not set # CONFIG_MTD_CFI_STAA is not set @@ -221,7 +352,7 @@ CONFIG_MTD_CFI_UTIL=y # CONFIG_MTD_RAM is not set # CONFIG_MTD_ROM is not set # CONFIG_MTD_ABSENT is not set -# CONFIG_MTD_XIP is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set # # Mapping drivers for chip access @@ -229,7 +360,7 @@ CONFIG_MTD_CFI_UTIL=y # CONFIG_MTD_COMPLEX_MAPPINGS is not set # CONFIG_MTD_PHYSMAP is not set CONFIG_MTD_ARM_INTEGRATOR=y -# CONFIG_MTD_EDB7312 is not set +# CONFIG_MTD_PLATRAM is not set # # Self-contained MTD device drivers @@ -237,7 +368,6 @@ CONFIG_MTD_ARM_INTEGRATOR=y # CONFIG_MTD_SLRAM is not set # CONFIG_MTD_PHRAM is not set # CONFIG_MTD_MTDRAM is not set -# CONFIG_MTD_BLKMTD is not set # CONFIG_MTD_BLOCK2MTD is not set # @@ -252,6 +382,11 @@ CONFIG_MTD_ARM_INTEGRATOR=y # # CONFIG_MTD_NAND is not set +# +# OneNAND Flash Device Drivers +# +# CONFIG_MTD_ONENAND is not set + # # Parallel port support # @@ -264,7 +399,6 @@ CONFIG_MTD_ARM_INTEGRATOR=y # # Block devices # -# CONFIG_BLK_DEV_FD is not set # CONFIG_BLK_DEV_COW_COMMON is not set # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set @@ -272,21 +406,13 @@ CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="" # CONFIG_CDROM_PKTCDVD is not set - -# -# IO Schedulers -# -CONFIG_IOSCHED_NOOP=y -CONFIG_IOSCHED_AS=y -CONFIG_IOSCHED_DEADLINE=y -CONFIG_IOSCHED_CFQ=y # CONFIG_ATA_OVER_ETH is not set # # SCSI device support # +# CONFIG_RAID_ATTRS is not set # CONFIG_SCSI is not set # @@ -297,6 +423,7 @@ CONFIG_IOSCHED_CFQ=y # # Fusion MPT device support # +# CONFIG_FUSION is not set # # IEEE 1394 (FireWire) support @@ -307,83 +434,26 @@ CONFIG_IOSCHED_CFQ=y # # -# Networking support -# -CONFIG_NET=y - -# -# Networking options -# -CONFIG_PACKET=y -CONFIG_PACKET_MMAP=y -# CONFIG_NETLINK_DEV is not set -CONFIG_UNIX=y -# CONFIG_NET_KEY is not set -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -# CONFIG_IP_ADVANCED_ROUTER is not set -CONFIG_IP_PNP=y -# CONFIG_IP_PNP_DHCP is not set -CONFIG_IP_PNP_BOOTP=y -# CONFIG_IP_PNP_RARP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_IP_MROUTE is not set -# CONFIG_ARPD is not set -# CONFIG_SYN_COOKIES is not set -# CONFIG_INET_AH is not set -# CONFIG_INET_ESP is not set -# CONFIG_INET_IPCOMP is not set -# CONFIG_INET_TUNNEL is not set -# CONFIG_IP_TCPDIAG is not set -# CONFIG_IP_TCPDIAG_IPV6 is not set -# CONFIG_IPV6 is not set -# CONFIG_NETFILTER is not set - -# -# SCTP Configuration (EXPERIMENTAL) -# -# CONFIG_IP_SCTP is not set -# CONFIG_ATM is not set -# CONFIG_BRIDGE is not set -# CONFIG_VLAN_8021Q is not set -# CONFIG_DECNET is not set -# CONFIG_LLC2 is not set -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_NET_DIVERT is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set -# CONFIG_NET_CLS_ROUTE is not set - -# -# Network testing +# Network device support # -# CONFIG_NET_PKTGEN is not set -# CONFIG_NETPOLL is not set -# CONFIG_NET_POLL_CONTROLLER is not set -# CONFIG_HAMRADIO is not set -# CONFIG_IRDA is not set -# CONFIG_BT is not set CONFIG_NETDEVICES=y # CONFIG_DUMMY is not set # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set +# +# PHY device support +# +# CONFIG_PHYLIB is not set + # # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y CONFIG_MII=y CONFIG_SMC91X=y +# CONFIG_DM9000 is not set # # Ethernet (1000 Mbit) @@ -410,6 +480,8 @@ CONFIG_SMC91X=y # CONFIG_SLIP is not set # CONFIG_SHAPER is not set # CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set # # ISDN subsystem @@ -459,7 +531,6 @@ CONFIG_SERIO_AMBAKMI=y CONFIG_SERIO_LIBPS2=y # CONFIG_SERIO_RAW is not set # CONFIG_GAMEPORT is not set -CONFIG_SOUND_GAMEPORT=y # # Character devices @@ -474,17 +545,16 @@ CONFIG_HW_CONSOLE=y # CONFIG_SERIAL_8250=m CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 CONFIG_SERIAL_8250_EXTENDED=y CONFIG_SERIAL_8250_MANY_PORTS=y CONFIG_SERIAL_8250_SHARE_IRQ=y # CONFIG_SERIAL_8250_DETECT_IRQ is not set -CONFIG_SERIAL_8250_MULTIPORT=y CONFIG_SERIAL_8250_RSA=y # # Non-8250 serial port support # -# CONFIG_SERIAL_AMBA_PL010 is not set CONFIG_SERIAL_AMBA_PL011=y CONFIG_SERIAL_AMBA_PL011_CONSOLE=y CONFIG_SERIAL_CORE=y @@ -503,20 +573,19 @@ CONFIG_LEGACY_PTY_COUNT=16 # # CONFIG_WATCHDOG is not set # CONFIG_NVRAM is not set -# CONFIG_RTC is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # # Ftape, the floppy tape device driver # -# CONFIG_DRM is not set # CONFIG_RAW_DRIVER is not set # # TPM devices # # CONFIG_TCG_TPM is not set +# CONFIG_TELCLOCK is not set # # I2C support @@ -534,59 +603,59 @@ CONFIG_I2C_ALGOBIT=y # # I2C Hardware Bus support # -# CONFIG_I2C_ISA is not set # CONFIG_I2C_PARPORT_LIGHT is not set # CONFIG_I2C_STUB is not set # CONFIG_I2C_PCA_ISA is not set # -# Hardware Sensors Chip support -# -CONFIG_I2C_SENSOR=m -# CONFIG_SENSORS_ADM1021 is not set -# CONFIG_SENSORS_ADM1025 is not set -# CONFIG_SENSORS_ADM1026 is not set -# CONFIG_SENSORS_ADM1031 is not set -# CONFIG_SENSORS_ASB100 is not set -# CONFIG_SENSORS_DS1621 is not set -# CONFIG_SENSORS_FSCHER is not set -# CONFIG_SENSORS_FSCPOS is not set -# CONFIG_SENSORS_GL518SM is not set -# CONFIG_SENSORS_GL520SM is not set -# CONFIG_SENSORS_IT87 is not set -# CONFIG_SENSORS_LM63 is not set -# CONFIG_SENSORS_LM75 is not set -# CONFIG_SENSORS_LM77 is not set -# CONFIG_SENSORS_LM78 is not set -# CONFIG_SENSORS_LM80 is not set -# CONFIG_SENSORS_LM83 is not set -# CONFIG_SENSORS_LM85 is not set -# CONFIG_SENSORS_LM87 is not set -# CONFIG_SENSORS_LM90 is not set -# CONFIG_SENSORS_MAX1619 is not set -# CONFIG_SENSORS_PC87360 is not set -# CONFIG_SENSORS_SMSC47B397 is not set -# CONFIG_SENSORS_SMSC47M1 is not set -# CONFIG_SENSORS_W83781D is not set -# CONFIG_SENSORS_W83L785TS is not set -# CONFIG_SENSORS_W83627HF is not set - -# -# Other I2C Chip support +# Miscellaneous I2C Chip support # +# CONFIG_SENSORS_DS1337 is not set +# CONFIG_SENSORS_DS1374 is not set CONFIG_SENSORS_EEPROM=m # CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCA9539 is not set # CONFIG_SENSORS_PCF8591 is not set -# CONFIG_SENSORS_RTC8564 is not set +# CONFIG_SENSORS_MAX6875 is not set # CONFIG_I2C_DEBUG_CORE is not set # CONFIG_I2C_DEBUG_ALGO is not set # CONFIG_I2C_DEBUG_BUS is not set # CONFIG_I2C_DEBUG_CHIP is not set +# +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Hardware Monitoring support +# +# CONFIG_HWMON is not set +# CONFIG_HWMON_VID is not set + # # Misc devices # +# +# LED devices +# +# CONFIG_NEW_LEDS is not set + +# +# LED drivers +# + +# +# LED Triggers +# + # # Multimedia devices # @@ -604,27 +673,31 @@ CONFIG_FB=y CONFIG_FB_CFB_FILLRECT=y CONFIG_FB_CFB_COPYAREA=y CONFIG_FB_CFB_IMAGEBLIT=y -CONFIG_FB_SOFT_CURSOR=y +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_FIRMWARE_EDID is not set # CONFIG_FB_MODE_HELPERS is not set # CONFIG_FB_TILEBLITTING is not set CONFIG_FB_ARMCLCD=y +# CONFIG_FB_S1D13XXX is not set # CONFIG_FB_VIRTUAL is not set # # Console display driver support # -# CONFIG_VGA_CONSOLE is not set CONFIG_DUMMY_CONSOLE=y CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set CONFIG_FONTS=y # CONFIG_FONT_8x8 is not set # CONFIG_FONT_8x16 is not set # CONFIG_FONT_6x11 is not set +# CONFIG_FONT_7x14 is not set # CONFIG_FONT_PEARL_8x8 is not set CONFIG_FONT_ACORN_8x8=y # CONFIG_FONT_MINI_4x6 is not set # CONFIG_FONT_SUN8x16 is not set # CONFIG_FONT_SUN12x22 is not set +# CONFIG_FONT_10x18 is not set # # Logo configuration @@ -647,12 +720,18 @@ CONFIG_SND_PCM=m CONFIG_SND_OSSEMUL=y CONFIG_SND_MIXER_OSS=m CONFIG_SND_PCM_OSS=m +CONFIG_SND_PCM_OSS_PLUGINS=y +# CONFIG_SND_DYNAMIC_MINORS is not set +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_VERBOSE_PROCFS=y # CONFIG_SND_VERBOSE_PRINTK is not set # CONFIG_SND_DEBUG is not set # # Generic devices # +CONFIG_SND_AC97_CODEC=m +CONFIG_SND_AC97_BUS=m # CONFIG_SND_DUMMY is not set # CONFIG_SND_MTPAV is not set # CONFIG_SND_SERIAL_U16550 is not set @@ -661,6 +740,7 @@ CONFIG_SND_PCM_OSS=m # # ALSA ARM devices # +CONFIG_SND_ARMAACI=m # # Open Sound System @@ -672,8 +752,13 @@ CONFIG_SND_PCM_OSS=m # CONFIG_USB_ARCH_HAS_HCD=y # CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB_ARCH_HAS_EHCI is not set # CONFIG_USB is not set +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + # # USB Gadget Support # @@ -687,26 +772,32 @@ CONFIG_MMC=y CONFIG_MMC_BLOCK=y CONFIG_MMC_ARMMMCI=m +# +# Real Time Clock +# +CONFIG_RTC_LIB=y +# CONFIG_RTC_CLASS is not set + # # File systems # CONFIG_EXT2_FS=y # CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set # CONFIG_EXT3_FS is not set -# CONFIG_JBD is not set # CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set - -# -# XFS support -# +# CONFIG_FS_POSIX_ACL is not set # CONFIG_XFS_FS is not set +# CONFIG_OCFS2_FS is not set CONFIG_MINIX_FS=y CONFIG_ROMFS_FS=y +# CONFIG_INOTIFY is not set # CONFIG_QUOTA is not set CONFIG_DNOTIFY=y # CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set # # CD-ROM/DVD Filesystems @@ -729,11 +820,10 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" # CONFIG_PROC_FS=y CONFIG_SYSFS=y -# CONFIG_DEVFS_FS is not set -# CONFIG_DEVPTS_FS_XATTR is not set # CONFIG_TMPFS is not set # CONFIG_HUGETLB_PAGE is not set CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set # # Miscellaneous filesystems @@ -748,8 +838,8 @@ CONFIG_RAMFS=y # CONFIG_JFFS_FS is not set CONFIG_JFFS2_FS=y CONFIG_JFFS2_FS_DEBUG=0 -# CONFIG_JFFS2_FS_NAND is not set -# CONFIG_JFFS2_FS_NOR_ECC is not set +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_SUMMARY is not set # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set CONFIG_JFFS2_ZLIB=y CONFIG_JFFS2_RTIME=y @@ -766,16 +856,19 @@ CONFIG_CRAMFS=y # CONFIG_NFS_FS=y CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set # CONFIG_NFS_V4 is not set # CONFIG_NFS_DIRECTIO is not set CONFIG_NFSD=y CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set # CONFIG_NFSD_V4 is not set # CONFIG_NFSD_TCP is not set CONFIG_ROOT_NFS=y CONFIG_LOCKD=y CONFIG_LOCKD_V4=y CONFIG_EXPORTFS=y +CONFIG_NFS_COMMON=y CONFIG_SUNRPC=y # CONFIG_RPCSEC_GSS_KRB5 is not set # CONFIG_RPCSEC_GSS_SPKM3 is not set @@ -784,6 +877,7 @@ CONFIG_SUNRPC=y # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set # CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set # # Partition Types @@ -803,6 +897,7 @@ CONFIG_MSDOS_PARTITION=y # CONFIG_SGI_PARTITION is not set # CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set # CONFIG_EFI_PARTITION is not set # @@ -858,18 +953,24 @@ CONFIG_NLS_ISO8859_1=m # Kernel hacking # # CONFIG_PRINTK_TIME is not set -CONFIG_DEBUG_KERNEL=y CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_KERNEL=y CONFIG_LOG_BUF_SHIFT=14 +CONFIG_DETECT_SOFTLOCKUP=y # CONFIG_SCHEDSTATS is not set # CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_MUTEXES is not set # CONFIG_DEBUG_SPINLOCK is not set # CONFIG_DEBUG_SPINLOCK_SLEEP is not set # CONFIG_DEBUG_KOBJECT is not set CONFIG_DEBUG_BUGVERBOSE=y # CONFIG_DEBUG_INFO is not set # CONFIG_DEBUG_FS is not set +# CONFIG_DEBUG_VM is not set CONFIG_FRAME_POINTER=y +# CONFIG_UNWIND_INFO is not set +CONFIG_FORCED_INLINING=y +# CONFIG_RCU_TORTURE_TEST is not set CONFIG_DEBUG_USER=y # CONFIG_DEBUG_WAITQ is not set CONFIG_DEBUG_ERRORS=y @@ -895,6 +996,7 @@ CONFIG_DEBUG_LL=y # Library routines # # CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=y -- cgit v1.2.3-70-g09d2 From f9d8f063fee645a23776519fb5c910b9d9435270 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 8 May 2006 20:31:11 +0100 Subject: [ARM] Update mach-types Signed-off-by: Russell King --- arch/arm/tools/mach-types | 89 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 80 insertions(+), 9 deletions(-) diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types index 8ab5300dcb94..6d7de9c0412f 100644 --- a/arch/arm/tools/mach-types +++ b/arch/arm/tools/mach-types @@ -12,7 +12,7 @@ # # http://www.arm.linux.org.uk/developer/machines/?action=new # -# Last update: Mon Feb 20 10:18:02 2006 +# Last update: Mon May 8 20:11:05 2006 # # machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number # @@ -566,8 +566,8 @@ switchgrass MACH_SWITCHGRASS SWITCHGRASS 549 ens_cmu MACH_ENS_CMU ENS_CMU 550 mm6_sdb MACH_MM6_SDB MM6_SDB 551 saturn MACH_SATURN SATURN 552 -argonplusevb MACH_ARGONPLUSEVB ARGONPLUSEVB 553 -scma11evb MACH_SCMA11EVB SCMA11EVB 554 +i30030evb MACH_ARGONPLUSEVB ARGONPLUSEVB 553 +mxc27530evb MACH_SCMA11EVB SCMA11EVB 554 smdk2800 MACH_SMDK2800 SMDK2800 555 mtwilson MACH_MTWILSON MTWILSON 556 ziti MACH_ZITI ZITI 557 @@ -647,7 +647,7 @@ sendt MACH_SENDT SENDT 630 mx2jazz MACH_MX2JAZZ MX2JAZZ 631 multiio MACH_MULTIIO MULTIIO 632 hrdisplay MACH_HRDISPLAY HRDISPLAY 633 -scma11bb MACH_SCMA11BB SCMA11BB 634 +mxc27530ads MACH_SCMA11BB SCMA11BB 634 trizeps3 MACH_TRIZEPS3 TRIZEPS3 635 zefeerdza MACH_ZEFEERDZA ZEFEERDZA 636 zefeerdzb MACH_ZEFEERDZB ZEFEERDZB 637 @@ -721,7 +721,7 @@ gp32 MACH_GP32 GP32 706 gem MACH_GEM GEM 707 i858 MACH_I858 I858 708 hx2750 MACH_HX2750 HX2750 709 -zeusevb MACH_ZEUSEVB ZEUSEVB 710 +mxc91131evb MACH_ZEUSEVB ZEUSEVB 710 p700 MACH_P700 P700 711 cpe MACH_CPE CPE 712 spitz MACH_SPITZ SPITZ 713 @@ -802,7 +802,7 @@ cpuat91 MACH_CPUAT91 CPUAT91 787 rea9200 MACH_REA9200 REA9200 788 acts_pune_sa1110 MACH_ACTS_PUNE_SA1110 ACTS_PUNE_SA1110 789 ixp425 MACH_IXP425 IXP425 790 -argonplusodyssey MACH_ARGONPLUSODYSSEY ARGONPLUSODYSSEY 791 +i30030ads MACH_ARGONPLUSODYSSEY ARGONPLUSODYSSEY 791 perch MACH_PERCH PERCH 792 eis05r1 MACH_EIS05R1 EIS05R1 793 pepperpad MACH_PEPPERPAD PEPPERPAD 794 @@ -827,7 +827,7 @@ micro9l MACH_MICRO9L MICRO9L 812 uc5471dsp MACH_UC5471DSP UC5471DSP 813 sj5471eng MACH_SJ5471ENG SJ5471ENG 814 none MACH_CMPXA26X CMPXA26X 815 -nc MACH_NC NC 816 +nc1 MACH_NC NC 816 omap_palmte MACH_OMAP_PALMTE OMAP_PALMTE 817 ajax52x MACH_AJAX52X AJAX52X 818 siriustar MACH_SIRIUSTAR SIRIUSTAR 819 @@ -930,7 +930,7 @@ netclient MACH_NETCLIENT NETCLIENT 916 xscale_palmtt5 MACH_XSCALE_PALMTT5 XSCALE_PALMTT5 917 xscale_palmtc MACH_OMAP_PALMTC OMAP_PALMTC 918 omap_apollon MACH_OMAP_APOLLON OMAP_APOLLON 919 -argonlvevb MACH_ARGONLVEVB ARGONLVEVB 920 +mxc30030evb MACH_ARGONLVEVB ARGONLVEVB 920 rea_2d MACH_REA_2D REA_2D 921 eti3e524 MACH_TI3E524 TI3E524 922 ateb9200 MACH_ATEB9200 ATEB9200 923 @@ -965,7 +965,78 @@ sisteron MACH_SISTERON SISTERON 951 rx1950 MACH_RX1950 RX1950 952 tsc_venus MACH_TSC_VENUS TSC_VENUS 953 ds101j MACH_DS101J DS101J 954 -mxc300_30ads MACH_MXC30030ADS MXC30030ADS 955 +mxc30030ads MACH_MXC30030ADS MXC30030ADS 955 fujitsu_wimaxsoc MACH_FUJITSU_WIMAXSOC FUJITSU_WIMAXSOC 956 dualpcmodem MACH_DUALPCMODEM DUALPCMODEM 957 gesbc9312 MACH_GESBC9312 GESBC9312 958 +htcapache MACH_HTCAPACHE HTCAPACHE 959 +ixdp435 MACH_IXDP435 IXDP435 960 +catprovt100 MACH_CATPROVT100 CATPROVT100 961 +picotux1xx MACH_PICOTUX1XX PICOTUX1XX 962 +picotux2xx MACH_PICOTUX2XX PICOTUX2XX 963 +dsmg600 MACH_DSMG600 DSMG600 964 +empc2 MACH_EMPC2 EMPC2 965 +ventura MACH_VENTURA VENTURA 966 +phidget_sbc MACH_PHIDGET_SBC PHIDGET_SBC 967 +ij3k MACH_IJ3K IJ3K 968 +pisgah MACH_PISGAH PISGAH 969 +omap_fsample MACH_OMAP_FSAMPLE OMAP_FSAMPLE 970 +sg720 MACH_SG720 SG720 971 +redfox MACH_REDFOX REDFOX 972 +mysh_ep9315_1 MACH_MYSH_EP9315_1 MYSH_EP9315_1 973 +tpf106 MACH_TPF106 TPF106 974 +at91rm9200kg MACH_AT91RM9200KG AT91RM9200KG 975 +racemt2 MACH_SLEDB SLEDB 976 +ontrack MACH_ONTRACK ONTRACK 977 +pm1200 MACH_PM1200 PM1200 978 +ess24562 MACH_ESS24XXX ESS24XXX 979 +coremp7 MACH_COREMP7 COREMP7 980 +nexcoder_6446 MACH_NEXCODER_6446 NEXCODER_6446 981 +stvc8380 MACH_STVC8380 STVC8380 982 +teklynx MACH_TEKLYNX TEKLYNX 983 +carbonado MACH_CARBONADO CARBONADO 984 +sysmos_mp730 MACH_SYSMOS_MP730 SYSMOS_MP730 985 +snapper_cl15 MACH_SNAPPER_CL15 SNAPPER_CL15 986 +pgigim MACH_PGIGIM PGIGIM 987 +ptx9160p2 MACH_PTX9160P2 PTX9160P2 988 +dcore1 MACH_DCORE1 DCORE1 989 +victorpxa MACH_VICTORPXA VICTORPXA 990 +mx2dtb MACH_MX2DTB MX2DTB 991 +pxa_irex_er0100 MACH_PXA_IREX_ER0100 PXA_IREX_ER0100 992 +omap_palmz71 MACH_OMAP_PALMZ71 OMAP_PALMZ71 993 +bartec_deg MACH_BARTEC_DEG BARTEC_DEG 994 +hw50251 MACH_HW50251 HW50251 995 +ibox MACH_IBOX IBOX 996 +atlaslh7a404 MACH_ATLASLH7A404 ATLASLH7A404 997 +pt2026 MACH_PT2026 PT2026 998 +htcalpine MACH_HTCALPINE HTCALPINE 999 +bartec_vtu MACH_BARTEC_VTU BARTEC_VTU 1000 +vcoreii MACH_VCOREII VCOREII 1001 +pdnb3 MACH_PDNB3 PDNB3 1002 +htcbeetles MACH_HTCBEETLES HTCBEETLES 1003 +s3c6400 MACH_S3C6400 S3C6400 1004 +s3c2443 MACH_S3C2443 S3C2443 1005 +omap_ldk MACH_OMAP_LDK OMAP_LDK 1006 +smdk2460 MACH_SMDK2460 SMDK2460 1007 +smdk2440 MACH_SMDK2440 SMDK2440 1008 +smdk2412 MACH_SMDK2412 SMDK2412 1009 +webbox MACH_WEBBOX WEBBOX 1010 +cwwndp MACH_CWWNDP CWWNDP 1011 +dragon MACH_DRAGON DRAGON 1012 +opendo_cpu_board MACH_OPENDO_CPU_BOARD OPENDO_CPU_BOARD 1013 +ccm2200 MACH_CCM2200 CCM2200 1014 +etwarm MACH_ETWARM ETWARM 1015 +m93030 MACH_M93030 M93030 1016 +cc7u MACH_CC7U CC7U 1017 +mtt_ranger MACH_MTT_RANGER MTT_RANGER 1018 +nexus MACH_NEXUS NEXUS 1019 +desman MACH_DESMAN DESMAN 1020 +bkde303 MACH_BKDE303 BKDE303 1021 +smdk2413 MACH_SMDK2413 SMDK2413 1022 +aml_m7200 MACH_AML_M7200 AML_M7200 1023 +aml_m5900 MACH_AML_M5900 AML_M5900 1024 +sg640 MACH_SG640 SG640 1025 +edg79524 MACH_EDG79524 EDG79524 1026 +ai2410 MACH_AI2410 AI2410 1027 +ixp465 MACH_IXP465 IXP465 1028 +balloon3 MACH_BALLOON3 BALLOON3 1029 -- cgit v1.2.3-70-g09d2 From 601e7f024edbea8018de34c83a7398623214e636 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 8 May 2006 13:38:42 -0700 Subject: Revert "kbuild: fix modpost segfault for 64bit mipsel kernel" This reverts commit c8d8b837ebe4b4f11e1b0c4a2bdc358c697692ed, which caused problems for the x86 build. Quoth Sam: "It was discussed on mips list but apparently the fix was bogus. I will not have time to look into it so mips can carry this local fix until we get a proper fix in mainline." Signed-off-by: Linus Torvalds --- scripts/mod/modpost.c | 11 ++--------- scripts/mod/modpost.h | 19 ------------------- 2 files changed, 2 insertions(+), 28 deletions(-) diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index b36e884f5f96..6d04504b2fc1 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -709,17 +709,10 @@ static void check_sec_ref(struct module *mod, const char *modname, for (rela = start; rela < stop; rela++) { Elf_Rela r; const char *secname; - unsigned int r_sym; r.r_offset = TO_NATIVE(rela->r_offset); - if (hdr->e_ident[EI_CLASS] == ELFCLASS64 && - hdr->e_machine == EM_MIPS) { - r_sym = ELF64_MIPS_R_SYM(rela->r_info); - r_sym = TO_NATIVE(r_sym); - } else { - r_sym = ELF_R_SYM(TO_NATIVE(rela->r_info)); - } + r.r_info = TO_NATIVE(rela->r_info); r.r_addend = TO_NATIVE(rela->r_addend); - sym = elf->symtab_start + r_sym; + sym = elf->symtab_start + ELF_R_SYM(r.r_info); /* Skip special sections */ if (sym->st_shndx >= SHN_LORESERVE) continue; diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h index 89b96c6d8ef5..b14255c72a37 100644 --- a/scripts/mod/modpost.h +++ b/scripts/mod/modpost.h @@ -39,25 +39,6 @@ #define ELF_R_TYPE ELF64_R_TYPE #endif -/* The 64-bit MIPS ELF ABI uses an unusual reloc format. */ -typedef struct -{ - Elf32_Word r_sym; /* Symbol index */ - unsigned char r_ssym; /* Special symbol for 2nd relocation */ - unsigned char r_type3; /* 3rd relocation type */ - unsigned char r_type2; /* 2nd relocation type */ - unsigned char r_type1; /* 1st relocation type */ -} _Elf64_Mips_R_Info; - -typedef union -{ - Elf64_Xword r_info_number; - _Elf64_Mips_R_Info r_info_fields; -} _Elf64_Mips_R_Info_union; - -#define ELF64_MIPS_R_SYM(i) \ - ((__extension__ (_Elf64_Mips_R_Info_union)(i)).r_info_fields.r_sym) - #if KERNEL_ELFDATA != HOST_ELFDATA static inline void __endian(const void *src, void *dest, unsigned int size) -- cgit v1.2.3-70-g09d2 From 1f8aa2f66b7253d1a42ead0142c7a00d2df5ac89 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 8 May 2006 15:13:14 -0700 Subject: [SPARC64]: Update defconfig. Signed-off-by: David S. Miller --- arch/sparc64/defconfig | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig index 1317380fa937..22ca69fc865c 100644 --- a/arch/sparc64/defconfig +++ b/arch/sparc64/defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.16 -# Sun Apr 2 19:31:04 2006 +# Linux kernel version: 2.6.17-rc3 +# Mon May 8 15:12:53 2006 # CONFIG_SPARC=y CONFIG_SPARC64=y @@ -114,6 +114,7 @@ CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_HUGETLB_PAGE_SIZE_4MB=y # CONFIG_HUGETLB_PAGE_SIZE_512K is not set # CONFIG_HUGETLB_PAGE_SIZE_64K is not set +CONFIG_ARCH_SELECT_MEMORY_MODEL=y CONFIG_ARCH_SPARSEMEM_ENABLE=y CONFIG_ARCH_SPARSEMEM_DEFAULT=y CONFIG_LARGE_ALLOCS=y @@ -430,7 +431,6 @@ CONFIG_ISCSI_TCP=m # CONFIG_SCSI_INIA100 is not set # CONFIG_SCSI_SYM53C8XX_2 is not set # CONFIG_SCSI_IPR is not set -# CONFIG_SCSI_QLOGIC_FC is not set # CONFIG_SCSI_QLOGIC_1280 is not set # CONFIG_SCSI_QLOGICPTI is not set # CONFIG_SCSI_QLA_FC is not set @@ -1042,9 +1042,7 @@ CONFIG_USB_HIDDEV=y # CONFIG_USB_ACECAD is not set # CONFIG_USB_KBTAB is not set # CONFIG_USB_POWERMATE is not set -# CONFIG_USB_MTOUCH is not set -# CONFIG_USB_ITMTOUCH is not set -# CONFIG_USB_EGALAX is not set +# CONFIG_USB_TOUCHSCREEN is not set # CONFIG_USB_YEALINK is not set # CONFIG_USB_XPAD is not set # CONFIG_USB_ATI_REMOTE is not set @@ -1114,6 +1112,14 @@ CONFIG_USB_HIDDEV=y # # CONFIG_NEW_LEDS is not set +# +# LED drivers +# + +# +# LED Triggers +# + # # InfiniBand support # -- cgit v1.2.3-70-g09d2 From d324031245abbb54e4e0321004430826052b6c37 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 8 May 2006 15:11:26 -0700 Subject: sky2: backout NAPI reschedule This is a backout of earlier patch. The whole rescheduling hack was a bad idea. It doesn't really solve the problem and it makes the code more complicated for no good reason. Signed-off-by: Stephen Hemminger --- drivers/net/sky2.c | 20 ++++---------------- include/linux/netdevice.h | 18 ++++++++---------- 2 files changed, 12 insertions(+), 26 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 227df9876a2c..76da74fbe859 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -2105,7 +2105,6 @@ static int sky2_poll(struct net_device *dev0, int *budget) int work_done = 0; u32 status = sky2_read32(hw, B0_Y2_SP_EISR); - restart_poll: if (unlikely(status & ~Y2_IS_STAT_BMU)) { if (status & Y2_IS_HW_ERR) sky2_hw_intr(hw); @@ -2136,7 +2135,7 @@ static int sky2_poll(struct net_device *dev0, int *budget) } if (status & Y2_IS_STAT_BMU) { - work_done += sky2_status_intr(hw, work_limit - work_done); + work_done = sky2_status_intr(hw, work_limit); *budget -= work_done; dev0->quota -= work_done; @@ -2148,22 +2147,9 @@ static int sky2_poll(struct net_device *dev0, int *budget) mod_timer(&hw->idle_timer, jiffies + HZ); - local_irq_disable(); - __netif_rx_complete(dev0); + netif_rx_complete(dev0); status = sky2_read32(hw, B0_Y2_SP_LISR); - - if (unlikely(status)) { - /* More work pending, try and keep going */ - if (__netif_rx_schedule_prep(dev0)) { - __netif_rx_reschedule(dev0, work_done); - status = sky2_read32(hw, B0_Y2_SP_EISR); - local_irq_enable(); - goto restart_poll; - } - } - - local_irq_enable(); return 0; } @@ -2181,6 +2167,8 @@ static irqreturn_t sky2_intr(int irq, void *dev_id, struct pt_regs *regs) prefetch(&hw->st_le[hw->st_idx]); if (likely(__netif_rx_schedule_prep(dev0))) __netif_rx_schedule(dev0); + else + printk(KERN_DEBUG PFX "irq race detected\n"); return IRQ_HANDLED; } diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 309f9190a922..a461b51d6076 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -831,21 +831,19 @@ static inline void netif_rx_schedule(struct net_device *dev) __netif_rx_schedule(dev); } - -static inline void __netif_rx_reschedule(struct net_device *dev, int undo) -{ - dev->quota += undo; - list_add_tail(&dev->poll_list, &__get_cpu_var(softnet_data).poll_list); - __raise_softirq_irqoff(NET_RX_SOFTIRQ); -} - -/* Try to reschedule poll. Called by dev->poll() after netif_rx_complete(). */ +/* Try to reschedule poll. Called by dev->poll() after netif_rx_complete(). + * Do not inline this? + */ static inline int netif_rx_reschedule(struct net_device *dev, int undo) { if (netif_rx_schedule_prep(dev)) { unsigned long flags; + + dev->quota += undo; + local_irq_save(flags); - __netif_rx_reschedule(dev, undo); + list_add_tail(&dev->poll_list, &__get_cpu_var(softnet_data).poll_list); + __raise_softirq_irqoff(NET_RX_SOFTIRQ); local_irq_restore(flags); return 1; } -- cgit v1.2.3-70-g09d2 From 1e5f1283a2aed429f4457e2eb875b1928a6643df Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 8 May 2006 15:11:27 -0700 Subject: sky2: status irq hang fix The status interrupt flag should be cleared before processing, not afterwards to avoid race. Need to process in poll routine even if no new interrupt status. This is a normal occurrence when more than 64 frames (NAPI weight) are processed in one poll routine. Signed-off-by: Stephen Hemminger --- drivers/net/sky2.c | 53 +++++++++++++++++++++++++---------------------------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 76da74fbe859..552aca76b283 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -2105,45 +2105,42 @@ static int sky2_poll(struct net_device *dev0, int *budget) int work_done = 0; u32 status = sky2_read32(hw, B0_Y2_SP_EISR); - if (unlikely(status & ~Y2_IS_STAT_BMU)) { - if (status & Y2_IS_HW_ERR) - sky2_hw_intr(hw); + if (status & Y2_IS_HW_ERR) + sky2_hw_intr(hw); - if (status & Y2_IS_IRQ_PHY1) - sky2_phy_intr(hw, 0); + if (status & Y2_IS_IRQ_PHY1) + sky2_phy_intr(hw, 0); - if (status & Y2_IS_IRQ_PHY2) - sky2_phy_intr(hw, 1); + if (status & Y2_IS_IRQ_PHY2) + sky2_phy_intr(hw, 1); - if (status & Y2_IS_IRQ_MAC1) - sky2_mac_intr(hw, 0); + if (status & Y2_IS_IRQ_MAC1) + sky2_mac_intr(hw, 0); - if (status & Y2_IS_IRQ_MAC2) - sky2_mac_intr(hw, 1); + if (status & Y2_IS_IRQ_MAC2) + sky2_mac_intr(hw, 1); - if (status & Y2_IS_CHK_RX1) - sky2_descriptor_error(hw, 0, "receive", Y2_IS_CHK_RX1); + if (status & Y2_IS_CHK_RX1) + sky2_descriptor_error(hw, 0, "receive", Y2_IS_CHK_RX1); - if (status & Y2_IS_CHK_RX2) - sky2_descriptor_error(hw, 1, "receive", Y2_IS_CHK_RX2); + if (status & Y2_IS_CHK_RX2) + sky2_descriptor_error(hw, 1, "receive", Y2_IS_CHK_RX2); - if (status & Y2_IS_CHK_TXA1) - sky2_descriptor_error(hw, 0, "transmit", Y2_IS_CHK_TXA1); + if (status & Y2_IS_CHK_TXA1) + sky2_descriptor_error(hw, 0, "transmit", Y2_IS_CHK_TXA1); - if (status & Y2_IS_CHK_TXA2) - sky2_descriptor_error(hw, 1, "transmit", Y2_IS_CHK_TXA2); - } + if (status & Y2_IS_CHK_TXA2) + sky2_descriptor_error(hw, 1, "transmit", Y2_IS_CHK_TXA2); - if (status & Y2_IS_STAT_BMU) { - work_done = sky2_status_intr(hw, work_limit); - *budget -= work_done; - dev0->quota -= work_done; + if (status & Y2_IS_STAT_BMU) + sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ); - if (work_done >= work_limit) - return 1; + work_done = sky2_status_intr(hw, work_limit); + *budget -= work_done; + dev0->quota -= work_done; - sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ); - } + if (work_done >= work_limit) + return 1; mod_timer(&hw->idle_timer, jiffies + HZ); -- cgit v1.2.3-70-g09d2 From f55925d7eb04f936ab4c001f10e3e9c74c1297ae Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 8 May 2006 15:11:28 -0700 Subject: sky2: tx ring index mask fix Mask for transmit ring status was picking up bits from the unused sync ring. They were always zero, so far... Also, make sure to remind self not to make tx ring too big. Signed-off-by: Stephen Hemminger --- drivers/net/sky2.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 552aca76b283..4bb6ea13efdd 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1927,7 +1927,8 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do) case OP_TXINDEXLE: /* TX index reports status for both ports */ - sky2_tx_done(hw->dev[0], status & 0xffff); + BUILD_BUG_ON(TX_RING_SIZE > 0x1000); + sky2_tx_done(hw->dev[0], status & 0xfff); if (hw->dev[1]) sky2_tx_done(hw->dev[1], ((status >> 24) & 0xff) -- cgit v1.2.3-70-g09d2 From cb5d9547307f44f210f88c829bad4249eeb24bc3 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 8 May 2006 15:11:29 -0700 Subject: sky2: use mask instead of modulo operation Gcc isn't smart enough to know that it can do a modulo operation with power of 2 constant by doing a mask. So add macro to do it for us. Signed-off-by: Stephen Hemminger --- drivers/net/sky2.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 4bb6ea13efdd..d9cce50cffd1 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -79,6 +79,8 @@ #define NAPI_WEIGHT 64 #define PHY_RETRIES 1000 +#define RING_NEXT(x,s) (((x)+1) & ((s)-1)) + static const u32 default_msg = NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | NETIF_MSG_TIMER | NETIF_MSG_TX_ERR | NETIF_MSG_RX_ERR @@ -719,7 +721,7 @@ static inline struct sky2_tx_le *get_tx_le(struct sky2_port *sky2) { struct sky2_tx_le *le = sky2->tx_le + sky2->tx_prod; - sky2->tx_prod = (sky2->tx_prod + 1) % TX_RING_SIZE; + sky2->tx_prod = RING_NEXT(sky2->tx_prod, TX_RING_SIZE); return le; } @@ -735,7 +737,7 @@ static inline void sky2_put_idx(struct sky2_hw *hw, unsigned q, u16 idx) static inline struct sky2_rx_le *sky2_next_rx(struct sky2_port *sky2) { struct sky2_rx_le *le = sky2->rx_le + sky2->rx_put; - sky2->rx_put = (sky2->rx_put + 1) % RX_LE_SIZE; + sky2->rx_put = RING_NEXT(sky2->rx_put, RX_LE_SIZE); return le; } @@ -1078,7 +1080,7 @@ err_out: /* Modular subtraction in ring */ static inline int tx_dist(unsigned tail, unsigned head) { - return (head - tail) % TX_RING_SIZE; + return (head - tail) & (TX_RING_SIZE - 1); } /* Number of list elements available for next tx */ @@ -1255,7 +1257,7 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) le->opcode = OP_BUFFER | HW_OWNER; fre = sky2->tx_ring - + ((re - sky2->tx_ring) + i + 1) % TX_RING_SIZE; + + RING_NEXT((re - sky2->tx_ring) + i, TX_RING_SIZE); pci_unmap_addr_set(fre, mapaddr, mapping); } @@ -1315,7 +1317,7 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done) for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { struct tx_ring_info *fre; - fre = sky2->tx_ring + (put + i + 1) % TX_RING_SIZE; + fre = sky2->tx_ring + RING_NEXT(put + i, TX_RING_SIZE); pci_unmap_page(pdev, pci_unmap_addr(fre, mapaddr), skb_shinfo(skb)->frags[i].size, PCI_DMA_TODEVICE); @@ -1876,7 +1878,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do) break; opcode &= ~HW_OWNER; - hw->st_idx = (hw->st_idx + 1) % STATUS_RING_SIZE; + hw->st_idx = RING_NEXT(hw->st_idx, STATUS_RING_SIZE); le->opcode = 0; link = le->link; -- cgit v1.2.3-70-g09d2 From 01bd75645f94d49cb7ffd61022890166ce00ec2a Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 8 May 2006 15:11:30 -0700 Subject: sky2: edge triggered workaround enhancement Need to make the edge-triggered workaround timer faster to get marginally better peformance. The test_and_set_bit in schedule_prep() acts as a barrier already. Make it a module parameter so that laptops who are concerned about power can set it to 0; and user's stuck with broken BIOS's can turn the driver into pure polling. Signed-off-by: Stephen Hemminger --- drivers/net/sky2.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index d9cce50cffd1..940ed699a702 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -98,6 +98,10 @@ static int disable_msi = 0; module_param(disable_msi, int, 0); MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)"); +static int idle_timeout = 100; +module_param(idle_timeout, int, 0); +MODULE_PARM_DESC(idle_timeout, "Idle timeout workaround for lost interrupts (ms)"); + static const struct pci_device_id sky2_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9000) }, { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9E00) }, @@ -2092,12 +2096,13 @@ static void sky2_descriptor_error(struct sky2_hw *hw, unsigned port, */ static void sky2_idle(unsigned long arg) { - struct net_device *dev = (struct net_device *) arg; + struct sky2_hw *hw = (struct sky2_hw *) arg; + struct net_device *dev = hw->dev[0]; - local_irq_disable(); if (__netif_rx_schedule_prep(dev)) __netif_rx_schedule(dev); - local_irq_enable(); + + mod_timer(&hw->idle_timer, jiffies + msecs_to_jiffies(idle_timeout)); } @@ -2145,8 +2150,6 @@ static int sky2_poll(struct net_device *dev0, int *budget) if (work_done >= work_limit) return 1; - mod_timer(&hw->idle_timer, jiffies + HZ); - netif_rx_complete(dev0); status = sky2_read32(hw, B0_Y2_SP_LISR); @@ -2167,8 +2170,6 @@ static irqreturn_t sky2_intr(int irq, void *dev_id, struct pt_regs *regs) prefetch(&hw->st_le[hw->st_idx]); if (likely(__netif_rx_schedule_prep(dev0))) __netif_rx_schedule(dev0); - else - printk(KERN_DEBUG PFX "irq race detected\n"); return IRQ_HANDLED; } @@ -3290,7 +3291,10 @@ static int __devinit sky2_probe(struct pci_dev *pdev, sky2_write32(hw, B0_IMSK, Y2_IS_BASE); - setup_timer(&hw->idle_timer, sky2_idle, (unsigned long) dev); + setup_timer(&hw->idle_timer, sky2_idle, (unsigned long) hw); + if (idle_timeout > 0) + mod_timer(&hw->idle_timer, + jiffies + msecs_to_jiffies(idle_timeout)); pci_set_drvdata(pdev, hw); -- cgit v1.2.3-70-g09d2 From e71ebd73276cc21efc74aba4118ef037cd32e50a Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 8 May 2006 15:11:31 -0700 Subject: sky2: dont write status ring It is more efficient not to write the status ring from the processor and just read the active portion. Signed-off-by: Stephen Hemminger --- drivers/net/sky2.c | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 940ed699a702..ea23da53677b 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1865,35 +1865,28 @@ static inline void sky2_tx_done(struct net_device *dev, u16 last) static int sky2_status_intr(struct sky2_hw *hw, int to_do) { int work_done = 0; + u16 hwidx = sky2_read16(hw, STAT_PUT_IDX); rmb(); - for(;;) { + while (hw->st_idx != hwidx) { struct sky2_status_le *le = hw->st_le + hw->st_idx; struct net_device *dev; struct sky2_port *sky2; struct sk_buff *skb; u32 status; u16 length; - u8 link, opcode; - - opcode = le->opcode; - if (!opcode) - break; - opcode &= ~HW_OWNER; hw->st_idx = RING_NEXT(hw->st_idx, STATUS_RING_SIZE); - le->opcode = 0; - link = le->link; - BUG_ON(link >= 2); - dev = hw->dev[link]; + BUG_ON(le->link >= 2); + dev = hw->dev[le->link]; sky2 = netdev_priv(dev); length = le->length; status = le->status; - switch (opcode) { + switch (le->opcode & ~HW_OWNER) { case OP_RXSTAT: skb = sky2_receive(sky2, length, status); if (!skb) @@ -1944,8 +1937,8 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do) default: if (net_ratelimit()) printk(KERN_WARNING PFX - "unknown status opcode 0x%x\n", opcode); - break; + "unknown status opcode 0x%x\n", le->opcode); + goto exit_loop; } } -- cgit v1.2.3-70-g09d2 From 72cb8529208020484cecd69bbf87719b50ee6313 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 8 May 2006 15:11:32 -0700 Subject: sky2: synchronize irq on remove Need to make sure interrupt is not racing with unregister of network device. Signed-off-by: Stephen Hemminger --- drivers/net/sky2.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index ea23da53677b..9b16c2a899e0 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -3327,6 +3327,8 @@ static void __devexit sky2_remove(struct pci_dev *pdev) del_timer_sync(&hw->idle_timer); sky2_write32(hw, B0_IMSK, 0); + synchronize_irq(hw->pdev->irq); + dev0 = hw->dev[0]; dev1 = hw->dev[1]; if (dev1) -- cgit v1.2.3-70-g09d2 From ed6d32c7a927bfccf921d15a3e25160f4528c3eb Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 8 May 2006 15:11:33 -0700 Subject: Add more support for the Yukon Ultra chip found in dual core centino laptops. The newest Yukon Ultra chipset's require more special tweaks. They seem to be like the Yukon XL chipsets. This code is transliterated from the latest SysKonnect driver; I don't have any Ultra hardware. Signed-off-by: Stephe Hemminger Signed-off-by: Stephen Hemminger --- drivers/net/sky2.c | 88 ++++++++++++++++++++++++++++++++++++------------------ drivers/net/sky2.h | 3 ++ 2 files changed, 62 insertions(+), 29 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 9b16c2a899e0..16a99f1ed171 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -304,7 +304,8 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) struct sky2_port *sky2 = netdev_priv(hw->dev[port]); u16 ctrl, ct1000, adv, pg, ledctrl, ledover; - if (sky2->autoneg == AUTONEG_ENABLE && hw->chip_id != CHIP_ID_YUKON_XL) { + if (sky2->autoneg == AUTONEG_ENABLE && + (hw->chip_id != CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U)) { u16 ectrl = gm_phy_read(hw, port, PHY_MARV_EXT_CTRL); ectrl &= ~(PHY_M_EC_M_DSC_MSK | PHY_M_EC_S_DSC_MSK | @@ -332,7 +333,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) ctrl |= PHY_M_PC_MDI_XMODE(PHY_M_PC_ENA_AUTO); if (sky2->autoneg == AUTONEG_ENABLE && - hw->chip_id == CHIP_ID_YUKON_XL) { + (hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U)) { ctrl &= ~PHY_M_PC_DSC_MSK; ctrl |= PHY_M_PC_DSC(2) | PHY_M_PC_DOWN_S_ENA; } @@ -448,10 +449,11 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 3); /* set LED Function Control register */ - gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, (PHY_M_LEDC_LOS_CTRL(1) | /* LINK/ACT */ - PHY_M_LEDC_INIT_CTRL(7) | /* 10 Mbps */ - PHY_M_LEDC_STA1_CTRL(7) | /* 100 Mbps */ - PHY_M_LEDC_STA0_CTRL(7))); /* 1000 Mbps */ + gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, + (PHY_M_LEDC_LOS_CTRL(1) | /* LINK/ACT */ + PHY_M_LEDC_INIT_CTRL(7) | /* 10 Mbps */ + PHY_M_LEDC_STA1_CTRL(7) | /* 100 Mbps */ + PHY_M_LEDC_STA0_CTRL(7))); /* 1000 Mbps */ /* set Polarity Control register */ gm_phy_write(hw, port, PHY_MARV_PHY_STAT, @@ -465,6 +467,25 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) /* restore page register */ gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg); break; + case CHIP_ID_YUKON_EC_U: + pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR); + + /* select page 3 to access LED control register */ + gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 3); + + /* set LED Function Control register */ + gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, + (PHY_M_LEDC_LOS_CTRL(1) | /* LINK/ACT */ + PHY_M_LEDC_INIT_CTRL(8) | /* 10 Mbps */ + PHY_M_LEDC_STA1_CTRL(7) | /* 100 Mbps */ + PHY_M_LEDC_STA0_CTRL(7)));/* 1000 Mbps */ + + /* set Blink Rate in LED Timer Control Register */ + gm_phy_write(hw, port, PHY_MARV_INT_MASK, + ledctrl | PHY_M_LED_BLINK_RT(BLINK_84MS)); + /* restore page register */ + gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg); + break; default: /* set Tx LED (LED_TX) to blink mode on Rx OR Tx activity */ @@ -473,19 +494,21 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) ledover |= PHY_M_LED_MO_RX(MO_LED_OFF); } - if (hw->chip_id == CHIP_ID_YUKON_EC_U && hw->chip_rev >= 2) { + if (hw->chip_id == CHIP_ID_YUKON_EC_U && hw->chip_rev == CHIP_REV_YU_EC_A1) { /* apply fixes in PHY AFE */ - gm_phy_write(hw, port, 22, 255); + pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR); + gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 255); + /* increase differential signal amplitude in 10BASE-T */ - gm_phy_write(hw, port, 24, 0xaa99); - gm_phy_write(hw, port, 23, 0x2011); + gm_phy_write(hw, port, 0x18, 0xaa99); + gm_phy_write(hw, port, 0x17, 0x2011); /* fix for IEEE A/B Symmetry failure in 1000BASE-T */ - gm_phy_write(hw, port, 24, 0xa204); - gm_phy_write(hw, port, 23, 0x2002); + gm_phy_write(hw, port, 0x18, 0xa204); + gm_phy_write(hw, port, 0x17, 0x2002); /* set page register to 0 */ - gm_phy_write(hw, port, 22, 0); + gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg); } else { gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl); @@ -559,6 +582,11 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port) if (sky2->duplex == DUPLEX_FULL) reg |= GM_GPCR_DUP_FULL; + + /* turn off pause in 10/100mbps half duplex */ + else if (sky2->speed != SPEED_1000 && + hw->chip_id != CHIP_ID_YUKON_EC_U) + sky2->tx_pause = sky2->rx_pause = 0; } else reg = GM_GPCR_SPEED_1000 | GM_GPCR_SPEED_100 | GM_GPCR_DUP_FULL; @@ -1504,17 +1532,26 @@ static void sky2_link_up(struct sky2_port *sky2) sky2_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_ON | LINKLED_BLINK_OFF | LINKLED_LINKSYNC_OFF); - if (hw->chip_id == CHIP_ID_YUKON_XL) { + if (hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U) { u16 pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR); + u16 led = PHY_M_LEDC_LOS_CTRL(1); /* link active */ + + switch(sky2->speed) { + case SPEED_10: + led |= PHY_M_LEDC_INIT_CTRL(7); + break; + + case SPEED_100: + led |= PHY_M_LEDC_STA1_CTRL(7); + break; + + case SPEED_1000: + led |= PHY_M_LEDC_STA0_CTRL(7); + break; + } gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 3); - gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, PHY_M_LEDC_LOS_CTRL(1) | /* LINK/ACT */ - PHY_M_LEDC_INIT_CTRL(sky2->speed == - SPEED_10 ? 7 : 0) | - PHY_M_LEDC_STA1_CTRL(sky2->speed == - SPEED_100 ? 7 : 0) | - PHY_M_LEDC_STA0_CTRL(sky2->speed == - SPEED_1000 ? 7 : 0)); + gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, led); gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg); } @@ -1589,7 +1626,7 @@ static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux) sky2->speed = sky2_phy_speed(hw, aux); /* Pause bits are offset (9..8) */ - if (hw->chip_id == CHIP_ID_YUKON_XL) + if (hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U) aux >>= 6; sky2->rx_pause = (aux & PHY_M_PS_RX_P_EN) != 0; @@ -2226,13 +2263,6 @@ static int __devinit sky2_reset(struct sky2_hw *hw) return -EOPNOTSUPP; } - /* This chip is new and not tested yet */ - if (hw->chip_id == CHIP_ID_YUKON_EC_U) { - pr_info(PFX "%s: is a version of Yukon 2 chipset that has not been tested yet.\n", - pci_name(hw->pdev)); - pr_info("Please report success/failure to maintainer \n"); - } - /* disable ASF */ if (hw->chip_id <= CHIP_ID_YUKON_EC) { sky2_write8(hw, B28_Y2_ASF_STAT_CMD, Y2_ASF_RESET); diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index b026f5653f04..8012994c9b93 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -378,6 +378,9 @@ enum { CHIP_REV_YU_EC_A1 = 0, /* Chip Rev. for Yukon-EC A1/A0 */ CHIP_REV_YU_EC_A2 = 1, /* Chip Rev. for Yukon-EC A2 */ CHIP_REV_YU_EC_A3 = 2, /* Chip Rev. for Yukon-EC A3 */ + + CHIP_REV_YU_EC_U_A0 = 0, + CHIP_REV_YU_EC_U_A1 = 1, }; /* B2_Y2_CLK_GATE 8 bit Clock Gating (Yukon-2 only) */ -- cgit v1.2.3-70-g09d2 From 6d4b0f617d577975108ccc7e3b0c7dbe50144df6 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 8 May 2006 15:11:34 -0700 Subject: sky2: version 1.3 Update version number, to track changes. Signed-off-by: Stephen Hemminger --- drivers/net/sky2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 16a99f1ed171..60cdfcabe1fd 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -51,7 +51,7 @@ #include "sky2.h" #define DRV_NAME "sky2" -#define DRV_VERSION "1.2" +#define DRV_VERSION "1.3" #define PFX DRV_NAME " " /* -- cgit v1.2.3-70-g09d2 From 8cd35da094bed8a41eb722c1d03eab24d57bf706 Mon Sep 17 00:00:00 2001 From: Herbert Valerio Riedel Date: Mon, 1 May 2006 15:37:09 +0200 Subject: au1000_eth.c: use ether_crc() from since the au1000 driver already selects the CRC32 routines, simply replace the internal ether_crc() implementation with the semantically equivalent one from Signed-off-by: Herbert Valerio Riedel Signed-off-by: Stephen Hemminger --- drivers/net/au1000_eth.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c index 1363083b4d83..14dbad14afb6 100644 --- a/drivers/net/au1000_eth.c +++ b/drivers/net/au1000_eth.c @@ -52,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -2070,23 +2071,6 @@ static void au1000_tx_timeout(struct net_device *dev) netif_wake_queue(dev); } - -static unsigned const ethernet_polynomial = 0x04c11db7U; -static inline u32 ether_crc(int length, unsigned char *data) -{ - int crc = -1; - - while(--length >= 0) { - unsigned char current_octet = *data++; - int bit; - for (bit = 0; bit < 8; bit++, current_octet >>= 1) - crc = (crc << 1) ^ - ((crc < 0) ^ (current_octet & 1) ? - ethernet_polynomial : 0); - } - return crc; -} - static void set_rx_mode(struct net_device *dev) { struct au1000_private *aup = (struct au1000_private *) dev->priv; -- cgit v1.2.3-70-g09d2 From aedc0e520e5ae9ba1342c25c4604d18fb236c2bc Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Tue, 9 May 2006 00:58:28 +0400 Subject: Fix RTL8019AS init for Toshiba RBTX49xx boards Ensure that 8-bit mode is selected for the on-board Realtek RTL8019AS chip on Toshiba RBHMA4x00, get rid of the duplicate #ifdef's when setting ei_status.word16. The chip's datasheet says that the PSTOP register shouldn't exceed 0x60 in 8-bit mode -- ensure this too. Signed-off-by: Sergei Shtylyov Signed-off-by: Stephen Hemminger --- drivers/net/ne.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/drivers/net/ne.c b/drivers/net/ne.c index 93c494bcd18d..b32765215f75 100644 --- a/drivers/net/ne.c +++ b/drivers/net/ne.c @@ -139,8 +139,9 @@ bad_clone_list[] __initdata = { #if defined(CONFIG_PLAT_MAPPI) # define DCR_VAL 0x4b -#elif defined(CONFIG_PLAT_OAKS32R) -# define DCR_VAL 0x48 +#elif defined(CONFIG_PLAT_OAKS32R) || \ + defined(CONFIG_TOSHIBA_RBTX4927) || defined(CONFIG_TOSHIBA_RBTX4938) +# define DCR_VAL 0x48 /* 8-bit mode */ #else # define DCR_VAL 0x49 #endif @@ -396,10 +397,22 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr) /* We must set the 8390 for word mode. */ outb_p(DCR_VAL, ioaddr + EN0_DCFG); start_page = NESM_START_PG; - stop_page = NESM_STOP_PG; + + /* + * Realtek RTL8019AS datasheet says that the PSTOP register + * shouldn't exceed 0x60 in 8-bit mode. + * This chip can be identified by reading the signature from + * the remote byte count registers (otherwise write-only)... + */ + if ((DCR_VAL & 0x01) == 0 && /* 8-bit mode */ + inb(ioaddr + EN0_RCNTLO) == 0x50 && + inb(ioaddr + EN0_RCNTHI) == 0x70) + stop_page = 0x60; + else + stop_page = NESM_STOP_PG; } else { start_page = NE1SM_START_PG; - stop_page = NE1SM_STOP_PG; + stop_page = NE1SM_STOP_PG; } #if defined(CONFIG_PLAT_MAPPI) || defined(CONFIG_PLAT_OAKS32R) @@ -509,15 +522,9 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr) ei_status.name = name; ei_status.tx_start_page = start_page; ei_status.stop_page = stop_page; -#if defined(CONFIG_TOSHIBA_RBTX4927) || defined(CONFIG_TOSHIBA_RBTX4938) - wordlength = 1; -#endif -#ifdef CONFIG_PLAT_OAKS32R - ei_status.word16 = 0; -#else - ei_status.word16 = (wordlength == 2); -#endif + /* Use 16-bit mode only if this wasn't overridden by DCR_VAL */ + ei_status.word16 = (wordlength == 2 && (DCR_VAL & 0x01)); ei_status.rx_start_page = start_page + TX_PAGES; #ifdef PACKETBUF_MEMSIZE -- cgit v1.2.3-70-g09d2 From b636d17a3bee8ba988e78e4bc8262f0dc3fad8ab Mon Sep 17 00:00:00 2001 From: Jens Osterkamp Date: Thu, 4 May 2006 05:59:56 -0400 Subject: spidernet: introduce new setting We found a new chip setting that we need in order to make the driver work more reliable. Signed-off-by: Arnd Bergmann Signed-off-by: Stephen Hemminger --- drivers/net/spider_net.c | 2 ++ drivers/net/spider_net.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 43f5e86fc559..b36838bfb8dc 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -1652,6 +1652,8 @@ spider_net_enable_card(struct spider_net_card *card) { SPIDER_NET_GFTRESTRT, SPIDER_NET_RESTART_VALUE }, { SPIDER_NET_GMRWOLCTRL, 0 }, + { SPIDER_NET_GTESTMD, 0x10000000 }, + { SPIDER_NET_GTTQMSK, 0x00400040 }, { SPIDER_NET_GTESTMD, 0 }, { SPIDER_NET_GMACINTEN, 0 }, diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h index 5922b529a048..3b8d951cf73c 100644 --- a/drivers/net/spider_net.h +++ b/drivers/net/spider_net.h @@ -120,6 +120,8 @@ extern char spider_net_driver_name[]; #define SPIDER_NET_GMRUAFILnR 0x00000500 #define SPIDER_NET_GMRUA0FIL15R 0x00000578 +#define SPIDER_NET_GTTQMSK 0x00000934 + /* RX DMA controller registers, all 0x00000a.. are for DMA controller A, * 0x00000b.. for DMA controller B, etc. */ #define SPIDER_NET_GDADCHA 0x00000a00 -- cgit v1.2.3-70-g09d2 From 8ec93459655a3618dedec6360bb28d63f0010ef6 Mon Sep 17 00:00:00 2001 From: Jens Osterkamp Date: Thu, 4 May 2006 05:59:41 -0400 Subject: spidernet: enable support for bcm5461 ethernet phy A newer board revision changed the type of ethernet phy. Moreover, this generalizes the way that a phy gets switched into fiber mode when autodetection is not available. Signed-off-by: Jens Osterkamp Signed-off-by: Arnd Bergmann Signed-off-by: Stephen Hemminger --- drivers/net/spider_net.c | 10 +--------- drivers/net/sungem_phy.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ drivers/net/sungem_phy.h | 1 + 3 files changed, 47 insertions(+), 9 deletions(-) diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index b36838bfb8dc..394339d5e87c 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -1794,15 +1794,7 @@ spider_net_setup_phy(struct spider_net_card *card) if (phy->def->ops->setup_forced) phy->def->ops->setup_forced(phy, SPEED_1000, DUPLEX_FULL); - /* the following two writes could be moved to sungem_phy.c */ - /* enable fiber mode */ - spider_net_write_phy(card->netdev, 1, MII_NCONFIG, 0x9020); - /* LEDs active in both modes, autosense prio = fiber */ - spider_net_write_phy(card->netdev, 1, MII_NCONFIG, 0x945f); - - /* switch off fibre autoneg */ - spider_net_write_phy(card->netdev, 1, MII_NCONFIG, 0xfc01); - spider_net_write_phy(card->netdev, 1, 0x0b, 0x0004); + phy->def->ops->enable_fiber(phy); phy->def->ops->read_link(phy); pr_info("Found %s with %i Mbps, %s-duplex.\n", phy->def->name, diff --git a/drivers/net/sungem_phy.c b/drivers/net/sungem_phy.c index 046371ee5bbe..b2ddd5e79303 100644 --- a/drivers/net/sungem_phy.c +++ b/drivers/net/sungem_phy.c @@ -329,6 +329,30 @@ static int bcm5421_init(struct mii_phy* phy) return 0; } +static int bcm5421_enable_fiber(struct mii_phy* phy) +{ + /* enable fiber mode */ + phy_write(phy, MII_NCONFIG, 0x9020); + /* LEDs active in both modes, autosense prio = fiber */ + phy_write(phy, MII_NCONFIG, 0x945f); + + /* switch off fibre autoneg */ + phy_write(phy, MII_NCONFIG, 0xfc01); + phy_write(phy, 0x0b, 0x0004); + + return 0; +} + +static int bcm5461_enable_fiber(struct mii_phy* phy) +{ + phy_write(phy, MII_NCONFIG, 0xfc0c); + phy_write(phy, MII_BMCR, 0x4140); + phy_write(phy, MII_NCONFIG, 0xfc0b); + phy_write(phy, MII_BMCR, 0x0140); + + return 0; +} + static int bcm54xx_setup_aneg(struct mii_phy *phy, u32 advertise) { u16 ctl, adv; @@ -762,6 +786,7 @@ static struct mii_phy_ops bcm5421_phy_ops = { .setup_forced = bcm54xx_setup_forced, .poll_link = genmii_poll_link, .read_link = bcm54xx_read_link, + .enable_fiber = bcm5421_enable_fiber, }; static struct mii_phy_def bcm5421_phy_def = { @@ -792,6 +817,25 @@ static struct mii_phy_def bcm5421k2_phy_def = { .ops = &bcm5421k2_phy_ops }; +static struct mii_phy_ops bcm5461_phy_ops = { + .init = bcm5421_init, + .suspend = generic_suspend, + .setup_aneg = bcm54xx_setup_aneg, + .setup_forced = bcm54xx_setup_forced, + .poll_link = genmii_poll_link, + .read_link = bcm54xx_read_link, + .enable_fiber = bcm5461_enable_fiber, +}; + +static struct mii_phy_def bcm5461_phy_def = { + .phy_id = 0x002060c0, + .phy_id_mask = 0xfffffff0, + .name = "BCM5461", + .features = MII_GBIT_FEATURES, + .magic_aneg = 1, + .ops = &bcm5461_phy_ops +}; + /* Broadcom BCM 5462 built-in Vesta */ static struct mii_phy_ops bcm5462V_phy_ops = { .init = bcm5421_init, @@ -857,6 +901,7 @@ static struct mii_phy_def* mii_phy_table[] = { &bcm5411_phy_def, &bcm5421_phy_def, &bcm5421k2_phy_def, + &bcm5461_phy_def, &bcm5462V_phy_def, &marvell_phy_def, &genmii_phy_def, diff --git a/drivers/net/sungem_phy.h b/drivers/net/sungem_phy.h index 430544496c52..69e125197fcf 100644 --- a/drivers/net/sungem_phy.h +++ b/drivers/net/sungem_phy.h @@ -12,6 +12,7 @@ struct mii_phy_ops int (*setup_forced)(struct mii_phy *phy, int speed, int fd); int (*poll_link)(struct mii_phy *phy); int (*read_link)(struct mii_phy *phy); + int (*enable_fiber)(struct mii_phy *phy); }; /* Structure used to statically define an mii/gii based PHY */ -- cgit v1.2.3-70-g09d2 From e4de00215c3af02116db3d486bf53700dfe10619 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 9 May 2006 16:00:59 +1000 Subject: powerpc/32: Define an is_kernel_addr() to fix ARCH=ppc compilation My commit 6bfd93c32a5065d0e858780b3beb0b667081601c broke the ARCH=ppc compilation by using the is_kernel_addr() macro in asm/uaccess.h. This fixes it by defining a suitable is_kernel_addr() for ARCH=ppc. Signed-off-by: Paul Mackerras --- include/asm-ppc/page.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/asm-ppc/page.h b/include/asm-ppc/page.h index a70ba2ee552d..0fb68a0b0181 100644 --- a/include/asm-ppc/page.h +++ b/include/asm-ppc/page.h @@ -20,6 +20,7 @@ /* This must match what is in arch/ppc/Makefile */ #define PAGE_OFFSET CONFIG_KERNEL_START #define KERNELBASE PAGE_OFFSET +#define is_kernel_addr(x) ((x) >= PAGE_OFFSET) #ifndef __ASSEMBLY__ -- cgit v1.2.3-70-g09d2 From c51e078f82096a7d35ac8ec2416272e843a0e1c4 Mon Sep 17 00:00:00 2001 From: Marcelo Tosatti Date: Fri, 5 May 2006 17:09:29 -0300 Subject: [PATCH] ppc32/8xx: Fix r3 trashing due to 8MB TLB page instantiation Instantiation of 8MB pages on the TLB cache for the kernel static mapping trashes r3 register on !CONFIG_8xx_CPU6 configurations. This ensures r3 gets saved and restored. Signed-off-by: Marcelo Tosatti Signed-off-by: Paul Mackerras --- arch/ppc/kernel/head_8xx.S | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/ppc/kernel/head_8xx.S b/arch/ppc/kernel/head_8xx.S index ec53c7d65f2b..7a2f20583be4 100644 --- a/arch/ppc/kernel/head_8xx.S +++ b/arch/ppc/kernel/head_8xx.S @@ -355,9 +355,7 @@ InstructionTLBMiss: . = 0x1200 DataStoreTLBMiss: -#ifdef CONFIG_8xx_CPU6 stw r3, 8(r0) -#endif DO_8xx_CPU6(0x3f80, r3) mtspr SPRN_M_TW, r10 /* Save a couple of working registers */ mfcr r10 @@ -417,9 +415,7 @@ DataStoreTLBMiss: lwz r11, 0(r0) mtcr r11 lwz r11, 4(r0) -#ifdef CONFIG_8xx_CPU6 lwz r3, 8(r0) -#endif rfi /* This is an instruction TLB error on the MPC8xx. This could be due -- cgit v1.2.3-70-g09d2 From 839ab1d4ce4dfd7e6c189391a82c584292488b41 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Wed, 26 Apr 2006 14:39:11 -0700 Subject: [PATCH] USB: fix bug in ohci-hcd.c ohci_restart() A loop on a power-lost resume path used the wrong index. I suspect khubd has been working around such bugs. Noticed by Andreas Mohr . Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-hcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 544f7589912f..73f5a379d9b3 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -863,7 +863,7 @@ static int ohci_restart (struct ohci_hcd *ohci) i = ohci->num_ports; while (i--) ohci_writel (ohci, RH_PS_PSS, - &ohci->regs->roothub.portstatus [temp]); + &ohci->regs->roothub.portstatus [i]); ohci_dbg (ohci, "restart complete\n"); } return 0; -- cgit v1.2.3-70-g09d2 From 67c752b41a4238c1a2d7eebcd061ff8c1127d3e9 Mon Sep 17 00:00:00 2001 From: Duncan Sands Date: Fri, 28 Apr 2006 18:44:06 +0200 Subject: [PATCH] USBATM: change the default speedtouch iso altsetting The maximum possible bandwidth for a speedtouch modem is about 7Mbaud. You can only get this by using isochronous urbs (enable_isoc=1) and altsetting 3. With the current default altsetting of 2, the modem maxes out at about 4Mbaud. So change the default altsetting to 3 when using isochronous urbs. It would be nice to base the altsetting on the detected line speed, but that's hard given the current design. Signed-off-by: Duncan Sands Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/speedtch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c index 7860c8a5800d..956b7a1e8af9 100644 --- a/drivers/usb/atm/speedtch.c +++ b/drivers/usb/atm/speedtch.c @@ -69,7 +69,7 @@ static const char speedtch_driver_name[] = "speedtch"; #define RESUBMIT_DELAY 1000 /* milliseconds */ #define DEFAULT_BULK_ALTSETTING 1 -#define DEFAULT_ISOC_ALTSETTING 2 +#define DEFAULT_ISOC_ALTSETTING 3 #define DEFAULT_DL_512_FIRST 0 #define DEFAULT_ENABLE_ISOC 0 #define DEFAULT_SW_BUFFERING 0 -- cgit v1.2.3-70-g09d2 From 6275cdfa0fe032208937a3567ebb8bcfd42d20b1 Mon Sep 17 00:00:00 2001 From: Duncan Sands Date: Fri, 28 Apr 2006 18:52:16 +0200 Subject: [PATCH] USBATM: fix modinfo output Because of the way stringify works, using an expression like 64 * 1024 for UDSL_MAX_BUF_SIZE results in 64 * 1024 turning up in the modinfo output instead of 65536. So use 65536 directly (this was the only way I found of fixing this). Signed-off-by: Duncan Sands Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/usbatm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c index c1211fc037d9..546249843b8e 100644 --- a/drivers/usb/atm/usbatm.c +++ b/drivers/usb/atm/usbatm.c @@ -99,11 +99,11 @@ static const char usbatm_driver_name[] = "usbatm"; #define UDSL_MAX_RCV_URBS 16 #define UDSL_MAX_SND_URBS 16 -#define UDSL_MAX_BUF_SIZE 64 * 1024 /* bytes */ +#define UDSL_MAX_BUF_SIZE 65536 #define UDSL_DEFAULT_RCV_URBS 4 #define UDSL_DEFAULT_SND_URBS 4 -#define UDSL_DEFAULT_RCV_BUF_SIZE 64 * ATM_CELL_SIZE /* bytes */ -#define UDSL_DEFAULT_SND_BUF_SIZE 64 * ATM_CELL_SIZE /* bytes */ +#define UDSL_DEFAULT_RCV_BUF_SIZE 3392 /* 64 * ATM_CELL_SIZE */ +#define UDSL_DEFAULT_SND_BUF_SIZE 3392 /* 64 * ATM_CELL_SIZE */ #define ATM_CELL_HEADER (ATM_CELL_SIZE - ATM_CELL_PAYLOAD) @@ -135,7 +135,7 @@ MODULE_PARM_DESC(rcv_buf_bytes, module_param(snd_buf_bytes, uint, S_IRUGO); MODULE_PARM_DESC(snd_buf_bytes, "Size of the buffers used for transmission, in bytes (range: 1-" - __MODULE_STRING(UDSL_MAX_SND_BUF_SIZE) ", default: " + __MODULE_STRING(UDSL_MAX_BUF_SIZE) ", default: " __MODULE_STRING(UDSL_DEFAULT_SND_BUF_SIZE) ")"); -- cgit v1.2.3-70-g09d2 From 7e713b825610de9a9584c189c72e2d9f2326359c Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 1 May 2006 14:02:45 -0700 Subject: [PATCH] USB: pegasus fixes (logstorm, suspend) Teach "pegasus" to handle a few of the disconnect fault paths without hundreds of usless syslog messages. Handle the carrier check workqueue entry even if the driver has not been opened. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/net/pegasus.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c index 2deb4c01539e..7683926a1b6f 100644 --- a/drivers/usb/net/pegasus.c +++ b/drivers/usb/net/pegasus.c @@ -318,6 +318,8 @@ static int read_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 * regd) set_register(pegasus, PhyCtrl, (indx | PHY_READ)); for (i = 0; i < REG_TIMEOUT; i++) { ret = get_registers(pegasus, PhyCtrl, 1, data); + if (ret == -ESHUTDOWN) + goto fail; if (data[0] & PHY_DONE) break; } @@ -326,6 +328,7 @@ static int read_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 * regd) *regd = le16_to_cpu(regdi); return ret; } +fail: if (netif_msg_drv(pegasus)) dev_warn(&pegasus->intf->dev, "fail %s\n", __FUNCTION__); @@ -354,12 +357,15 @@ static int write_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 regd) set_register(pegasus, PhyCtrl, (indx | PHY_WRITE)); for (i = 0; i < REG_TIMEOUT; i++) { ret = get_registers(pegasus, PhyCtrl, 1, data); + if (ret == -ESHUTDOWN) + goto fail; if (data[0] & PHY_DONE) break; } if (i < REG_TIMEOUT) return ret; +fail: if (netif_msg_drv(pegasus)) dev_warn(&pegasus->intf->dev, "fail %s\n", __FUNCTION__); return -ETIMEDOUT; @@ -387,6 +393,8 @@ static int read_eprom_word(pegasus_t * pegasus, __u8 index, __u16 * retdata) ret = get_registers(pegasus, EpromCtrl, 1, &tmp); if (tmp & EPROM_DONE) break; + if (ret == -ESHUTDOWN) + goto fail; } if (i < REG_TIMEOUT) { ret = get_registers(pegasus, EpromData, 2, &retdatai); @@ -394,6 +402,7 @@ static int read_eprom_word(pegasus_t * pegasus, __u8 index, __u16 * retdata) return ret; } +fail: if (netif_msg_drv(pegasus)) dev_warn(&pegasus->intf->dev, "fail %s\n", __FUNCTION__); return -ETIMEDOUT; @@ -433,12 +442,15 @@ static int write_eprom_word(pegasus_t * pegasus, __u8 index, __u16 data) for (i = 0; i < REG_TIMEOUT; i++) { ret = get_registers(pegasus, EpromCtrl, 1, &tmp); + if (ret == -ESHUTDOWN) + goto fail; if (tmp & EPROM_DONE) break; } disable_eprom_write(pegasus); if (i < REG_TIMEOUT) return ret; +fail: if (netif_msg_drv(pegasus)) dev_warn(&pegasus->intf->dev, "fail %s\n", __FUNCTION__); return -ETIMEDOUT; @@ -1378,9 +1390,8 @@ static int pegasus_suspend (struct usb_interface *intf, pm_message_t message) struct pegasus *pegasus = usb_get_intfdata(intf); netif_device_detach (pegasus->net); + cancel_delayed_work(&pegasus->carrier_check); if (netif_running(pegasus->net)) { - cancel_delayed_work(&pegasus->carrier_check); - usb_kill_urb(pegasus->rx_urb); usb_kill_urb(pegasus->intr_urb); } @@ -1400,10 +1411,9 @@ static int pegasus_resume (struct usb_interface *intf) pegasus->intr_urb->status = 0; pegasus->intr_urb->actual_length = 0; intr_callback(pegasus->intr_urb, NULL); - - queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check, - CARRIER_CHECK_DELAY); } + queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check, + CARRIER_CHECK_DELAY); return 0; } -- cgit v1.2.3-70-g09d2 From db4cefaaea4c6d67cdaebfd315abc791c5c9d22f Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 1 May 2006 22:07:13 -0700 Subject: [PATCH] USB: fix OHCI PM regression This fixes a small regression in USB controller power usage for many OHCI controllers, notably including every non-PCI version of OHCI: on those systems, the runtime autosuspend mechanism is no longer enabled. The change moves to saner defaults. All root hubs are expected to handle remote wakeup (and hence autosuspend), although drivers for buggy silicon may override that default. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index fbd938d4ea58..e2e00ba4e1e6 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1805,6 +1805,12 @@ int usb_add_hcd(struct usb_hcd *hcd, USB_SPEED_FULL; hcd->self.root_hub = rhdev; + /* wakeup flag init defaults to "everything works" for root hubs, + * but drivers can override it in reset() if needed, along with + * recording the overall controller's system wakeup capability. + */ + device_init_wakeup(&rhdev->dev, 1); + /* "reset" is misnamed; its role is now one-time init. the controller * should already have been reset (and boot firmware kicked off etc). */ @@ -1813,13 +1819,6 @@ int usb_add_hcd(struct usb_hcd *hcd, goto err_hcd_driver_setup; } - /* wakeup flag init is in transition; for now we can't rely on PCI to - * initialize these bits properly, so we let reset() override it. - * This init should _precede_ the reset() once PCI behaves. - */ - device_init_wakeup(&rhdev->dev, - device_can_wakeup(hcd->self.controller)); - /* NOTE: root hub and controller capabilities may not be the same */ if (device_can_wakeup(hcd->self.controller) && device_can_wakeup(&hcd->self.root_hub->dev)) -- cgit v1.2.3-70-g09d2 From 436f5762bcd4929825a0725d4bc78337e6fc0d8f Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 2 May 2006 15:22:41 -0400 Subject: [PATCH] USB: usbcore: don't check the device's power source The choose_configuration() routine contains code the determine the device's power source, so that configurations requiring external power can be ruled out if the device is running on bus power. Unfortunately it turns out that some devices have errors in their config descriptors and other devices don't like the GET_DEVICE_STATUS request. Since that information wasn't used for anything else, this patch (as673) removes the code, leaving only a comment. It fixes bugzilla entry #6448. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 0c87f73f2933..90b8d43c6b33 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1168,19 +1168,9 @@ static inline const char *plural(int n) static int choose_configuration(struct usb_device *udev) { int i; - u16 devstatus; - int bus_powered; int num_configs; struct usb_host_config *c, *best; - /* If this fails, assume the device is bus-powered */ - devstatus = 0; - usb_get_status(udev, USB_RECIP_DEVICE, 0, &devstatus); - le16_to_cpus(&devstatus); - bus_powered = ((devstatus & (1 << USB_DEVICE_SELF_POWERED)) == 0); - dev_dbg(&udev->dev, "device is %s-powered\n", - bus_powered ? "bus" : "self"); - best = NULL; c = udev->config; num_configs = udev->descriptor.bNumConfigurations; @@ -1197,6 +1187,19 @@ static int choose_configuration(struct usb_device *udev) * similar errors in their descriptors. If the next test * were allowed to execute, such configurations would always * be rejected and the devices would not work as expected. + * In the meantime, we run the risk of selecting a config + * that requires external power at a time when that power + * isn't available. It seems to be the lesser of two evils. + * + * Bugzilla #6448 reports a device that appears to crash + * when it receives a GET_DEVICE_STATUS request! We don't + * have any other way to tell whether a device is self-powered, + * but since we don't use that information anywhere but here, + * the call has been removed. + * + * Maybe the GET_DEVICE_STATUS call and the test below can + * be reinstated when device firmwares become more reliable. + * Don't hold your breath. */ #if 0 /* Rule out self-powered configs for a bus-powered device */ -- cgit v1.2.3-70-g09d2 From 77ef6c4d6e23653a79eedacdd6d1d0da7083e59c Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Wed, 3 May 2006 00:16:00 -0700 Subject: [PATCH] USB: ub oops in block_uevent In kernel 2.6.16, if a mounted storage device is removed, an oops happens because ub supplies an interface device (and kobject) to the block layer, but neglects to pin it. And apparently, the block layer expects its users to pin device structures. The code in ub was broken this way for years. But the bug was exposed only by 2.6.16 when it started to call block_uevent on close, which traverses device structures (kobjects actually). Signed-off-by: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- drivers/block/ub.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/block/ub.c b/drivers/block/ub.c index f73446f580df..c688c25992e4 100644 --- a/drivers/block/ub.c +++ b/drivers/block/ub.c @@ -536,6 +536,9 @@ static void ub_cleanup(struct ub_dev *sc) kfree(lun); } + usb_set_intfdata(sc->intf, NULL); + usb_put_intf(sc->intf); + usb_put_dev(sc->dev); kfree(sc); } @@ -2221,7 +2224,12 @@ static int ub_probe(struct usb_interface *intf, // sc->ifnum = intf->cur_altsetting->desc.bInterfaceNumber; usb_set_intfdata(intf, sc); usb_get_dev(sc->dev); - // usb_get_intf(sc->intf); /* Do we need this? */ + /* + * Since we give the interface struct to the block level through + * disk->driverfs_dev, we have to pin it. Otherwise, block_uevent + * oopses on close after a disconnect (kernels 2.6.16 and up). + */ + usb_get_intf(sc->intf); snprintf(sc->name, 12, DRV_NAME "(%d.%d)", sc->dev->bus->busnum, sc->dev->devnum); @@ -2286,7 +2294,7 @@ static int ub_probe(struct usb_interface *intf, err_dev_desc: usb_set_intfdata(intf, NULL); - // usb_put_intf(sc->intf); + usb_put_intf(sc->intf); usb_put_dev(sc->dev); kfree(sc); err_core: @@ -2461,12 +2469,6 @@ static void ub_disconnect(struct usb_interface *intf) * and no URBs left in transit. */ - usb_set_intfdata(intf, NULL); - // usb_put_intf(sc->intf); - sc->intf = NULL; - usb_put_dev(sc->dev); - sc->dev = NULL; - ub_put(sc); } -- cgit v1.2.3-70-g09d2 From 20a0f47e18c646bcc772282512fc59e56b2fc968 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Thu, 4 May 2006 11:34:25 +0100 Subject: [PATCH] USB: ftdi_sio: Add support for HCG HF Dual ISO RFID Reader This patch adds support for ACG Identification Technologies GmbH's HF Dual ISO Reader (an RFID tag reader) to the ftdi_sio driver's device ID table. The product ID was supplied by anotonios (anton at goto10 dot org) on the ftdi-usb-sio-devel list and subsequently verified by myself (Ian Abbott). Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 1 + drivers/usb/serial/ftdi_sio.h | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 82151207d814..9498da461036 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -498,6 +498,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_ASK_RDR400_PID) }, { USB_DEVICE(ICOM_ID1_VID, ICOM_ID1_PID) }, { USB_DEVICE(PAPOUCH_VID, PAPOUCH_TMU_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ACG_HFDUAL_PID) }, { }, /* Optional parameter entry */ { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index 2c55a5ea9c99..3e4123f09e0d 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -426,6 +426,11 @@ #define PAPOUCH_VID 0x5050 /* Vendor ID */ #define PAPOUCH_TMU_PID 0x0400 /* TMU USB Thermometer */ +/* + * ACG Identification Technologies GmbH products (http://www.acg.de/). + * Submitted by anton -at- goto10 -dot- org. + */ +#define FTDI_ACG_HFDUAL_PID 0xDD20 /* HF Dual ISO Reader (RFID) */ /* Commands */ #define FTDI_SIO_RESET 0 /* Reset the port */ -- cgit v1.2.3-70-g09d2 From 72a9f958421a519e69b3e7b409948c3a294f4a32 Mon Sep 17 00:00:00 2001 From: Razvan Gavril Date: Thu, 4 May 2006 11:35:49 +0300 Subject: [PATCH] USB: ftdi_sio: add device id for ACT Solutions HomePro ZWave interface Signed-off-by: Razvan Gavril Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 1 + drivers/usb/serial/ftdi_sio.h | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 9498da461036..986d7622273d 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -307,6 +307,7 @@ static struct ftdi_sio_quirk ftdi_HE_TIRA1_quirk = { static struct usb_device_id id_table_combined [] = { + { USB_DEVICE(FTDI_VID, FTDI_ACTZWAVE_PID) }, { USB_DEVICE(FTDI_VID, FTDI_IRTRANS_PID) }, { USB_DEVICE(FTDI_VID, FTDI_IPLUS_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SIO_PID) }, diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index 3e4123f09e0d..d69a917e768f 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -32,6 +32,10 @@ #define FTDI_NF_RIC_PID 0x0001 /* Product Id */ +/* ACT Solutions HomePro ZWave interface (http://www.act-solutions.com/HomePro.htm) */ +#define FTDI_ACTZWAVE_PID 0xF2D0 + + /* www.irtrans.de device */ #define FTDI_IRTRANS_PID 0xFC60 /* Product Id */ -- cgit v1.2.3-70-g09d2 From d8b9f23b23e080d820e3c0aa5ccd7834c26ebf96 Mon Sep 17 00:00:00 2001 From: Ralph Campbell Date: Tue, 9 May 2006 10:50:28 -0700 Subject: IB: Fix display of 4-bit port counters in sysfs The code to display local_link_integrity_errors and excessive_buffer_overrun_errors in /sys/class/infiniband//ports//counters/ uses the wrong shift to extract the 4 bit values. Signed-off-by: Ralph Campbell Signed-off-by: Roland Dreier --- drivers/infiniband/core/sysfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c index 15121cb5a1f6..21f9282c1b25 100644 --- a/drivers/infiniband/core/sysfs.c +++ b/drivers/infiniband/core/sysfs.c @@ -336,7 +336,7 @@ static ssize_t show_pma_counter(struct ib_port *p, struct port_attribute *attr, switch (width) { case 4: ret = sprintf(buf, "%u\n", (out_mad->data[40 + offset / 8] >> - (offset % 4)) & 0xf); + (4 - (offset % 8))) & 0xf); break; case 8: ret = sprintf(buf, "%u\n", out_mad->data[40 + offset / 8]); -- cgit v1.2.3-70-g09d2 From d945e1df28ca07642b3e1a9b9d07074ba5f76be0 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 May 2006 10:50:28 -0700 Subject: IB/srp: Fix tracking of pending requests during error handling If a SCSI abort completes, or the command completes successfully, then the driver must remove the command from its queue of pending commands. Similarly, if a device reset succeeds, then all commands queued for the given device must be removed from the queue. Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/srp/ib_srp.c | 195 +++++++++++++++++++++--------------- drivers/infiniband/ulp/srp/ib_srp.h | 4 +- 2 files changed, 115 insertions(+), 84 deletions(-) diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 5bb55742ada6..c32ce4348e1b 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -409,6 +409,34 @@ static int srp_connect_target(struct srp_target_port *target) } } +static void srp_unmap_data(struct scsi_cmnd *scmnd, + struct srp_target_port *target, + struct srp_request *req) +{ + struct scatterlist *scat; + int nents; + + if (!scmnd->request_buffer || + (scmnd->sc_data_direction != DMA_TO_DEVICE && + scmnd->sc_data_direction != DMA_FROM_DEVICE)) + return; + + /* + * This handling of non-SG commands can be killed when the + * SCSI midlayer no longer generates non-SG commands. + */ + if (likely(scmnd->use_sg)) { + nents = scmnd->use_sg; + scat = scmnd->request_buffer; + } else { + nents = 1; + scat = &req->fake_sg; + } + + dma_unmap_sg(target->srp_host->dev->dma_device, scat, nents, + scmnd->sc_data_direction); +} + static int srp_reconnect_target(struct srp_target_port *target) { struct ib_cm_id *new_cm_id; @@ -455,16 +483,16 @@ static int srp_reconnect_target(struct srp_target_port *target) list_for_each_entry(req, &target->req_queue, list) { req->scmnd->result = DID_RESET << 16; req->scmnd->scsi_done(req->scmnd); + srp_unmap_data(req->scmnd, target, req); } target->rx_head = 0; target->tx_head = 0; target->tx_tail = 0; - target->req_head = 0; - for (i = 0; i < SRP_SQ_SIZE - 1; ++i) - target->req_ring[i].next = i + 1; - target->req_ring[SRP_SQ_SIZE - 1].next = -1; + INIT_LIST_HEAD(&target->free_reqs); INIT_LIST_HEAD(&target->req_queue); + for (i = 0; i < SRP_SQ_SIZE; ++i) + list_add_tail(&target->req_ring[i].list, &target->free_reqs); ret = srp_connect_target(target); if (ret) @@ -589,40 +617,10 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target, return len; } -static void srp_unmap_data(struct scsi_cmnd *scmnd, - struct srp_target_port *target, - struct srp_request *req) -{ - struct scatterlist *scat; - int nents; - - if (!scmnd->request_buffer || - (scmnd->sc_data_direction != DMA_TO_DEVICE && - scmnd->sc_data_direction != DMA_FROM_DEVICE)) - return; - - /* - * This handling of non-SG commands can be killed when the - * SCSI midlayer no longer generates non-SG commands. - */ - if (likely(scmnd->use_sg)) { - nents = scmnd->use_sg; - scat = scmnd->request_buffer; - } else { - nents = 1; - scat = &req->fake_sg; - } - - dma_unmap_sg(target->srp_host->dev->dma_device, scat, nents, - scmnd->sc_data_direction); -} - -static void srp_remove_req(struct srp_target_port *target, struct srp_request *req, - int index) +static void srp_remove_req(struct srp_target_port *target, struct srp_request *req) { - list_del(&req->list); - req->next = target->req_head; - target->req_head = index; + srp_unmap_data(req->scmnd, target, req); + list_move_tail(&req->list, &target->free_reqs); } static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp) @@ -647,7 +645,7 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp) req->tsk_status = rsp->data[3]; complete(&req->done); } else { - scmnd = req->scmnd; + scmnd = req->scmnd; if (!scmnd) printk(KERN_ERR "Null scmnd for RSP w/tag %016llx\n", (unsigned long long) rsp->tag); @@ -665,14 +663,11 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp) else if (rsp->flags & (SRP_RSP_FLAG_DIOVER | SRP_RSP_FLAG_DIUNDER)) scmnd->resid = be32_to_cpu(rsp->data_in_res_cnt); - srp_unmap_data(scmnd, target, req); - if (!req->tsk_mgmt) { - req->scmnd = NULL; scmnd->host_scribble = (void *) -1L; scmnd->scsi_done(scmnd); - srp_remove_req(target, req, rsp->tag & ~SRP_TAG_TSK_MGMT); + srp_remove_req(target, req); } else req->cmd_done = 1; } @@ -859,7 +854,6 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd, struct srp_request *req; struct srp_iu *iu; struct srp_cmd *cmd; - long req_index; int len; if (target->state == SRP_TARGET_CONNECTING) @@ -879,22 +873,20 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd, dma_sync_single_for_cpu(target->srp_host->dev->dma_device, iu->dma, SRP_MAX_IU_LEN, DMA_TO_DEVICE); - req_index = target->req_head; + req = list_entry(target->free_reqs.next, struct srp_request, list); scmnd->scsi_done = done; scmnd->result = 0; - scmnd->host_scribble = (void *) req_index; + scmnd->host_scribble = (void *) (long) req->index; cmd = iu->buf; memset(cmd, 0, sizeof *cmd); cmd->opcode = SRP_CMD; cmd->lun = cpu_to_be64((u64) scmnd->device->lun << 48); - cmd->tag = req_index; + cmd->tag = req->index; memcpy(cmd->cdb, scmnd->cmnd, scmnd->cmd_len); - req = &target->req_ring[req_index]; - req->scmnd = scmnd; req->cmd = iu; req->cmd_done = 0; @@ -919,8 +911,7 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd, goto err_unmap; } - target->req_head = req->next; - list_add_tail(&req->list, &target->req_queue); + list_move_tail(&req->list, &target->req_queue); return 0; @@ -1143,30 +1134,20 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event) return 0; } -static int srp_send_tsk_mgmt(struct scsi_cmnd *scmnd, u8 func) +static int srp_send_tsk_mgmt(struct srp_target_port *target, + struct srp_request *req, u8 func) { - struct srp_target_port *target = host_to_target(scmnd->device->host); - struct srp_request *req; struct srp_iu *iu; struct srp_tsk_mgmt *tsk_mgmt; - int req_index; - int ret = FAILED; spin_lock_irq(target->scsi_host->host_lock); if (target->state == SRP_TARGET_DEAD || target->state == SRP_TARGET_REMOVED) { - scmnd->result = DID_BAD_TARGET << 16; + req->scmnd->result = DID_BAD_TARGET << 16; goto out; } - if (scmnd->host_scribble == (void *) -1L) - goto out; - - req_index = (long) scmnd->host_scribble; - printk(KERN_ERR "Abort for req_index %d\n", req_index); - - req = &target->req_ring[req_index]; init_completion(&req->done); iu = __srp_get_tx_iu(target); @@ -1177,10 +1158,10 @@ static int srp_send_tsk_mgmt(struct scsi_cmnd *scmnd, u8 func) memset(tsk_mgmt, 0, sizeof *tsk_mgmt); tsk_mgmt->opcode = SRP_TSK_MGMT; - tsk_mgmt->lun = cpu_to_be64((u64) scmnd->device->lun << 48); - tsk_mgmt->tag = req_index | SRP_TAG_TSK_MGMT; + tsk_mgmt->lun = cpu_to_be64((u64) req->scmnd->device->lun << 48); + tsk_mgmt->tag = req->index | SRP_TAG_TSK_MGMT; tsk_mgmt->tsk_mgmt_func = func; - tsk_mgmt->task_tag = req_index; + tsk_mgmt->task_tag = req->index; if (__srp_post_send(target, iu, sizeof *tsk_mgmt)) goto out; @@ -1188,37 +1169,85 @@ static int srp_send_tsk_mgmt(struct scsi_cmnd *scmnd, u8 func) req->tsk_mgmt = iu; spin_unlock_irq(target->scsi_host->host_lock); + if (!wait_for_completion_timeout(&req->done, msecs_to_jiffies(SRP_ABORT_TIMEOUT_MS))) - return FAILED; - spin_lock_irq(target->scsi_host->host_lock); + return -1; - if (req->cmd_done) { - srp_remove_req(target, req, req_index); - scmnd->scsi_done(scmnd); - } else if (!req->tsk_status) { - srp_remove_req(target, req, req_index); - scmnd->result = DID_ABORT << 16; - ret = SUCCESS; - } + return 0; out: spin_unlock_irq(target->scsi_host->host_lock); - return ret; + return -1; +} + +static int srp_find_req(struct srp_target_port *target, + struct scsi_cmnd *scmnd, + struct srp_request **req) +{ + if (scmnd->host_scribble == (void *) -1L) + return -1; + + *req = &target->req_ring[(long) scmnd->host_scribble]; + + return 0; } static int srp_abort(struct scsi_cmnd *scmnd) { + struct srp_target_port *target = host_to_target(scmnd->device->host); + struct srp_request *req; + int ret = SUCCESS; + printk(KERN_ERR "SRP abort called\n"); - return srp_send_tsk_mgmt(scmnd, SRP_TSK_ABORT_TASK); + if (srp_find_req(target, scmnd, &req)) + return FAILED; + if (srp_send_tsk_mgmt(target, req, SRP_TSK_ABORT_TASK)) + return FAILED; + + spin_lock_irq(target->scsi_host->host_lock); + + if (req->cmd_done) { + srp_remove_req(target, req); + scmnd->scsi_done(scmnd); + } else if (!req->tsk_status) { + srp_remove_req(target, req); + scmnd->result = DID_ABORT << 16; + } else + ret = FAILED; + + spin_unlock_irq(target->scsi_host->host_lock); + + return ret; } static int srp_reset_device(struct scsi_cmnd *scmnd) { + struct srp_target_port *target = host_to_target(scmnd->device->host); + struct srp_request *req, *tmp; + printk(KERN_ERR "SRP reset_device called\n"); - return srp_send_tsk_mgmt(scmnd, SRP_TSK_LUN_RESET); + if (srp_find_req(target, scmnd, &req)) + return FAILED; + if (srp_send_tsk_mgmt(target, req, SRP_TSK_LUN_RESET)) + return FAILED; + if (req->tsk_status) + return FAILED; + + spin_lock_irq(target->scsi_host->host_lock); + + list_for_each_entry_safe(req, tmp, &target->req_queue, list) + if (req->scmnd->device == scmnd->device) { + req->scmnd->result = DID_RESET << 16; + scmnd->scsi_done(scmnd); + srp_remove_req(target, req); + } + + spin_unlock_irq(target->scsi_host->host_lock); + + return SUCCESS; } static int srp_reset_host(struct scsi_cmnd *scmnd) @@ -1518,10 +1547,12 @@ static ssize_t srp_create_target(struct class_device *class_dev, INIT_WORK(&target->work, srp_reconnect_work, target); - for (i = 0; i < SRP_SQ_SIZE - 1; ++i) - target->req_ring[i].next = i + 1; - target->req_ring[SRP_SQ_SIZE - 1].next = -1; + INIT_LIST_HEAD(&target->free_reqs); INIT_LIST_HEAD(&target->req_queue); + for (i = 0; i < SRP_SQ_SIZE; ++i) { + target->req_ring[i].index = i; + list_add_tail(&target->req_ring[i].list, &target->free_reqs); + } ret = srp_parse_options(buf, target); if (ret) diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h index bd7f7c3115de..c5cd43aae860 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.h +++ b/drivers/infiniband/ulp/srp/ib_srp.h @@ -101,7 +101,7 @@ struct srp_request { */ struct scatterlist fake_sg; struct completion done; - short next; + short index; u8 cmd_done; u8 tsk_status; }; @@ -133,7 +133,7 @@ struct srp_target_port { unsigned tx_tail; struct srp_iu *tx_ring[SRP_SQ_SIZE + 1]; - int req_head; + struct list_head free_reqs; struct list_head req_queue; struct srp_request req_ring[SRP_SQ_SIZE]; -- cgit v1.2.3-70-g09d2 From a3285aa4eecd722508dab01c4932b11b4ba80134 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 May 2006 10:50:29 -0700 Subject: IB/mthca: Fix race in reference counting Fix races in in destroying various objects. If a destroy routine waits for an object to become free by doing wait_event(&obj->wait, !atomic_read(&obj->refcount)); /* now clean up and destroy the object */ and another place drops a reference to the object by doing if (atomic_dec_and_test(&obj->refcount)) wake_up(&obj->wait); then this is susceptible to a race where the wait_event() and final freeing of the object occur between the atomic_dec_and_test() and the wake_up(). And this is a use-after-free, since wake_up() will be called on part of the already-freed object. Fix this in mthca by replacing the atomic_t refcounts with plain old integers protected by a spinlock. This makes it possible to do the decrement of the reference count and the wake_up() so that it appears as a single atomic operation to the code waiting on the wait queue. While touching this code, also simplify mthca_cq_clean(): the CQ being cleaned cannot go away, because it still has a QP attached to it. So there's no reason to be paranoid and look up the CQ by number; it's perfectly safe to use the pointer that the callers already have. Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_cq.c | 41 ++++++++++++++-------------- drivers/infiniband/hw/mthca/mthca_dev.h | 2 +- drivers/infiniband/hw/mthca/mthca_provider.h | 22 ++++++++------- drivers/infiniband/hw/mthca/mthca_qp.c | 31 +++++++++++++++------ drivers/infiniband/hw/mthca/mthca_srq.c | 23 ++++++++++++---- 5 files changed, 74 insertions(+), 45 deletions(-) diff --git a/drivers/infiniband/hw/mthca/mthca_cq.c b/drivers/infiniband/hw/mthca/mthca_cq.c index 312cf90731ea..205854e9c662 100644 --- a/drivers/infiniband/hw/mthca/mthca_cq.c +++ b/drivers/infiniband/hw/mthca/mthca_cq.c @@ -238,9 +238,9 @@ void mthca_cq_event(struct mthca_dev *dev, u32 cqn, spin_lock(&dev->cq_table.lock); cq = mthca_array_get(&dev->cq_table.cq, cqn & (dev->limits.num_cqs - 1)); - if (cq) - atomic_inc(&cq->refcount); + ++cq->refcount; + spin_unlock(&dev->cq_table.lock); if (!cq) { @@ -254,8 +254,10 @@ void mthca_cq_event(struct mthca_dev *dev, u32 cqn, if (cq->ibcq.event_handler) cq->ibcq.event_handler(&event, cq->ibcq.cq_context); - if (atomic_dec_and_test(&cq->refcount)) + spin_lock(&dev->cq_table.lock); + if (!--cq->refcount) wake_up(&cq->wait); + spin_unlock(&dev->cq_table.lock); } static inline int is_recv_cqe(struct mthca_cqe *cqe) @@ -267,23 +269,13 @@ static inline int is_recv_cqe(struct mthca_cqe *cqe) return !(cqe->is_send & 0x80); } -void mthca_cq_clean(struct mthca_dev *dev, u32 cqn, u32 qpn, +void mthca_cq_clean(struct mthca_dev *dev, struct mthca_cq *cq, u32 qpn, struct mthca_srq *srq) { - struct mthca_cq *cq; struct mthca_cqe *cqe; u32 prod_index; int nfreed = 0; - spin_lock_irq(&dev->cq_table.lock); - cq = mthca_array_get(&dev->cq_table.cq, cqn & (dev->limits.num_cqs - 1)); - if (cq) - atomic_inc(&cq->refcount); - spin_unlock_irq(&dev->cq_table.lock); - - if (!cq) - return; - spin_lock_irq(&cq->lock); /* @@ -301,7 +293,7 @@ void mthca_cq_clean(struct mthca_dev *dev, u32 cqn, u32 qpn, if (0) mthca_dbg(dev, "Cleaning QPN %06x from CQN %06x; ci %d, pi %d\n", - qpn, cqn, cq->cons_index, prod_index); + qpn, cq->cqn, cq->cons_index, prod_index); /* * Now sweep backwards through the CQ, removing CQ entries @@ -325,8 +317,6 @@ void mthca_cq_clean(struct mthca_dev *dev, u32 cqn, u32 qpn, } spin_unlock_irq(&cq->lock); - if (atomic_dec_and_test(&cq->refcount)) - wake_up(&cq->wait); } void mthca_cq_resize_copy_cqes(struct mthca_cq *cq) @@ -821,7 +811,7 @@ int mthca_init_cq(struct mthca_dev *dev, int nent, } spin_lock_init(&cq->lock); - atomic_set(&cq->refcount, 1); + cq->refcount = 1; init_waitqueue_head(&cq->wait); memset(cq_context, 0, sizeof *cq_context); @@ -896,6 +886,17 @@ err_out: return err; } +static inline int get_cq_refcount(struct mthca_dev *dev, struct mthca_cq *cq) +{ + int c; + + spin_lock_irq(&dev->cq_table.lock); + c = cq->refcount; + spin_unlock_irq(&dev->cq_table.lock); + + return c; +} + void mthca_free_cq(struct mthca_dev *dev, struct mthca_cq *cq) { @@ -929,6 +930,7 @@ void mthca_free_cq(struct mthca_dev *dev, spin_lock_irq(&dev->cq_table.lock); mthca_array_clear(&dev->cq_table.cq, cq->cqn & (dev->limits.num_cqs - 1)); + --cq->refcount; spin_unlock_irq(&dev->cq_table.lock); if (dev->mthca_flags & MTHCA_FLAG_MSI_X) @@ -936,8 +938,7 @@ void mthca_free_cq(struct mthca_dev *dev, else synchronize_irq(dev->pdev->irq); - atomic_dec(&cq->refcount); - wait_event(cq->wait, !atomic_read(&cq->refcount)); + wait_event(cq->wait, !get_cq_refcount(dev, cq)); if (cq->is_kernel) { mthca_free_cq_buf(dev, &cq->buf, cq->ibcq.cqe); diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h index 4c1dcb4c1822..f8160b8de090 100644 --- a/drivers/infiniband/hw/mthca/mthca_dev.h +++ b/drivers/infiniband/hw/mthca/mthca_dev.h @@ -496,7 +496,7 @@ void mthca_free_cq(struct mthca_dev *dev, void mthca_cq_completion(struct mthca_dev *dev, u32 cqn); void mthca_cq_event(struct mthca_dev *dev, u32 cqn, enum ib_event_type event_type); -void mthca_cq_clean(struct mthca_dev *dev, u32 cqn, u32 qpn, +void mthca_cq_clean(struct mthca_dev *dev, struct mthca_cq *cq, u32 qpn, struct mthca_srq *srq); void mthca_cq_resize_copy_cqes(struct mthca_cq *cq); int mthca_alloc_cq_buf(struct mthca_dev *dev, struct mthca_cq_buf *buf, int nent); diff --git a/drivers/infiniband/hw/mthca/mthca_provider.h b/drivers/infiniband/hw/mthca/mthca_provider.h index 6676a786d690..179a8f610d0f 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.h +++ b/drivers/infiniband/hw/mthca/mthca_provider.h @@ -139,11 +139,12 @@ struct mthca_ah { * a qp may be locked, with the send cq locked first. No other * nesting should be done. * - * Each struct mthca_cq/qp also has an atomic_t ref count. The - * pointer from the cq/qp_table to the struct counts as one reference. - * This reference also is good for access through the consumer API, so - * modifying the CQ/QP etc doesn't need to take another reference. - * Access because of a completion being polled does need a reference. + * Each struct mthca_cq/qp also has an ref count, protected by the + * corresponding table lock. The pointer from the cq/qp_table to the + * struct counts as one reference. This reference also is good for + * access through the consumer API, so modifying the CQ/QP etc doesn't + * need to take another reference. Access to a QP because of a + * completion being polled does not need a reference either. * * Finally, each struct mthca_cq/qp has a wait_queue_head_t for the * destroy function to sleep on. @@ -159,8 +160,9 @@ struct mthca_ah { * - decrement ref count; if zero, wake up waiters * * To destroy a CQ/QP, we can do the following: - * - lock cq/qp_table, remove pointer, unlock cq/qp_table lock - * - decrement ref count + * - lock cq/qp_table + * - remove pointer and decrement ref count + * - unlock cq/qp_table lock * - wait_event until ref count is zero * * It is the consumer's responsibilty to make sure that no QP @@ -197,7 +199,7 @@ struct mthca_cq_resize { struct mthca_cq { struct ib_cq ibcq; spinlock_t lock; - atomic_t refcount; + int refcount; int cqn; u32 cons_index; struct mthca_cq_buf buf; @@ -217,7 +219,7 @@ struct mthca_cq { struct mthca_srq { struct ib_srq ibsrq; spinlock_t lock; - atomic_t refcount; + int refcount; int srqn; int max; int max_gs; @@ -254,7 +256,7 @@ struct mthca_wq { struct mthca_qp { struct ib_qp ibqp; - atomic_t refcount; + int refcount; u32 qpn; int is_direct; u8 port; /* for SQP and memfree use only */ diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c index f37b0e367323..19765f6f8d58 100644 --- a/drivers/infiniband/hw/mthca/mthca_qp.c +++ b/drivers/infiniband/hw/mthca/mthca_qp.c @@ -240,7 +240,7 @@ void mthca_qp_event(struct mthca_dev *dev, u32 qpn, spin_lock(&dev->qp_table.lock); qp = mthca_array_get(&dev->qp_table.qp, qpn & (dev->limits.num_qps - 1)); if (qp) - atomic_inc(&qp->refcount); + ++qp->refcount; spin_unlock(&dev->qp_table.lock); if (!qp) { @@ -257,8 +257,10 @@ void mthca_qp_event(struct mthca_dev *dev, u32 qpn, if (qp->ibqp.event_handler) qp->ibqp.event_handler(&event, qp->ibqp.qp_context); - if (atomic_dec_and_test(&qp->refcount)) + spin_lock(&dev->qp_table.lock); + if (!--qp->refcount) wake_up(&qp->wait); + spin_unlock(&dev->qp_table.lock); } static int to_mthca_state(enum ib_qp_state ib_state) @@ -833,10 +835,10 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) * entries and reinitialize the QP. */ if (new_state == IB_QPS_RESET && !qp->ibqp.uobject) { - mthca_cq_clean(dev, to_mcq(qp->ibqp.send_cq)->cqn, qp->qpn, + mthca_cq_clean(dev, to_mcq(qp->ibqp.send_cq), qp->qpn, qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL); if (qp->ibqp.send_cq != qp->ibqp.recv_cq) - mthca_cq_clean(dev, to_mcq(qp->ibqp.recv_cq)->cqn, qp->qpn, + mthca_cq_clean(dev, to_mcq(qp->ibqp.recv_cq), qp->qpn, qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL); mthca_wq_init(&qp->sq); @@ -1096,7 +1098,7 @@ static int mthca_alloc_qp_common(struct mthca_dev *dev, int ret; int i; - atomic_set(&qp->refcount, 1); + qp->refcount = 1; init_waitqueue_head(&qp->wait); qp->state = IB_QPS_RESET; qp->atomic_rd_en = 0; @@ -1318,6 +1320,17 @@ int mthca_alloc_sqp(struct mthca_dev *dev, return err; } +static inline int get_qp_refcount(struct mthca_dev *dev, struct mthca_qp *qp) +{ + int c; + + spin_lock_irq(&dev->qp_table.lock); + c = qp->refcount; + spin_unlock_irq(&dev->qp_table.lock); + + return c; +} + void mthca_free_qp(struct mthca_dev *dev, struct mthca_qp *qp) { @@ -1339,14 +1352,14 @@ void mthca_free_qp(struct mthca_dev *dev, spin_lock(&dev->qp_table.lock); mthca_array_clear(&dev->qp_table.qp, qp->qpn & (dev->limits.num_qps - 1)); + --qp->refcount; spin_unlock(&dev->qp_table.lock); if (send_cq != recv_cq) spin_unlock(&recv_cq->lock); spin_unlock_irq(&send_cq->lock); - atomic_dec(&qp->refcount); - wait_event(qp->wait, !atomic_read(&qp->refcount)); + wait_event(qp->wait, !get_qp_refcount(dev, qp)); if (qp->state != IB_QPS_RESET) mthca_MODIFY_QP(dev, qp->state, IB_QPS_RESET, qp->qpn, 0, @@ -1358,10 +1371,10 @@ void mthca_free_qp(struct mthca_dev *dev, * unref the mem-free tables and free the QPN in our table. */ if (!qp->ibqp.uobject) { - mthca_cq_clean(dev, to_mcq(qp->ibqp.send_cq)->cqn, qp->qpn, + mthca_cq_clean(dev, to_mcq(qp->ibqp.send_cq), qp->qpn, qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL); if (qp->ibqp.send_cq != qp->ibqp.recv_cq) - mthca_cq_clean(dev, to_mcq(qp->ibqp.recv_cq)->cqn, qp->qpn, + mthca_cq_clean(dev, to_mcq(qp->ibqp.recv_cq), qp->qpn, qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL); mthca_free_memfree(dev, qp); diff --git a/drivers/infiniband/hw/mthca/mthca_srq.c b/drivers/infiniband/hw/mthca/mthca_srq.c index adcaf85355ae..1ea433291fa7 100644 --- a/drivers/infiniband/hw/mthca/mthca_srq.c +++ b/drivers/infiniband/hw/mthca/mthca_srq.c @@ -241,7 +241,7 @@ int mthca_alloc_srq(struct mthca_dev *dev, struct mthca_pd *pd, goto err_out_mailbox; spin_lock_init(&srq->lock); - atomic_set(&srq->refcount, 1); + srq->refcount = 1; init_waitqueue_head(&srq->wait); if (mthca_is_memfree(dev)) @@ -308,6 +308,17 @@ err_out: return err; } +static inline int get_srq_refcount(struct mthca_dev *dev, struct mthca_srq *srq) +{ + int c; + + spin_lock_irq(&dev->srq_table.lock); + c = srq->refcount; + spin_unlock_irq(&dev->srq_table.lock); + + return c; +} + void mthca_free_srq(struct mthca_dev *dev, struct mthca_srq *srq) { struct mthca_mailbox *mailbox; @@ -329,10 +340,10 @@ void mthca_free_srq(struct mthca_dev *dev, struct mthca_srq *srq) spin_lock_irq(&dev->srq_table.lock); mthca_array_clear(&dev->srq_table.srq, srq->srqn & (dev->limits.num_srqs - 1)); + --srq->refcount; spin_unlock_irq(&dev->srq_table.lock); - atomic_dec(&srq->refcount); - wait_event(srq->wait, !atomic_read(&srq->refcount)); + wait_event(srq->wait, !get_srq_refcount(dev, srq)); if (!srq->ibsrq.uobject) { mthca_free_srq_buf(dev, srq); @@ -414,7 +425,7 @@ void mthca_srq_event(struct mthca_dev *dev, u32 srqn, spin_lock(&dev->srq_table.lock); srq = mthca_array_get(&dev->srq_table.srq, srqn & (dev->limits.num_srqs - 1)); if (srq) - atomic_inc(&srq->refcount); + ++srq->refcount; spin_unlock(&dev->srq_table.lock); if (!srq) { @@ -431,8 +442,10 @@ void mthca_srq_event(struct mthca_dev *dev, u32 srqn, srq->ibsrq.event_handler(&event, srq->ibsrq.srq_context); out: - if (atomic_dec_and_test(&srq->refcount)) + spin_lock(&dev->srq_table.lock); + if (!--srq->refcount) wake_up(&srq->wait); + spin_unlock(&dev->srq_table.lock); } /* -- cgit v1.2.3-70-g09d2 From 6f9c2963888e60e46a9e0bd09a25740abce29262 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 26 Apr 2006 22:50:32 +0200 Subject: [PATCH] scx200_acb: Fix return on init error The scx200_acb driver shouldn't return failure after initialization if it successfully registered at least one i2c_adapter, else we are leaking resources. The driver was OK in that respect up to 2.6.16, a recent change broke it. This is part of the fix to bug #6445. Signed-off-by: Jean Delvare Cc: Ben Gardner Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/scx200_acb.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c index 8bd305e47f0d..f2dae6831142 100644 --- a/drivers/i2c/busses/scx200_acb.c +++ b/drivers/i2c/busses/scx200_acb.c @@ -524,6 +524,9 @@ static int __init scx200_acb_init(void) } else if (pci_dev_present(divil_pci)) rc = scx200_add_cs553x(); + /* If at least one bus was created, init must succeed */ + if (scx200_acb_list) + return 0; return rc; } -- cgit v1.2.3-70-g09d2 From b33d0798e6cfae1fcee75afc808fe5690a48a814 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 26 Apr 2006 23:00:16 +0200 Subject: [PATCH] scx200_acb: Fix resource name use after free We can't pass a string on the stack to request_region. As soon as we leave the function that stack is gone and the string is lost. Let's use the same string we identify the i2c_adapter with instead, it's more simple, more consistent, and just works. This is the second half of fix to bug #6445. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/scx200_acb.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c index f2dae6831142..42e4e00d6c32 100644 --- a/drivers/i2c/busses/scx200_acb.c +++ b/drivers/i2c/busses/scx200_acb.c @@ -415,7 +415,6 @@ static int __init scx200_acb_create(const char *text, int base, int index) struct scx200_acb_iface *iface; struct i2c_adapter *adapter; int rc; - char description[64]; iface = kzalloc(sizeof(*iface), GFP_KERNEL); if (!iface) { @@ -434,10 +433,7 @@ static int __init scx200_acb_create(const char *text, int base, int index) mutex_init(&iface->mutex); - snprintf(description, sizeof(description), "%s ACCESS.bus [%s]", - text, adapter->name); - - if (request_region(base, 8, description) == 0) { + if (!request_region(base, 8, adapter->name)) { printk(KERN_ERR NAME ": can't allocate io 0x%x-0x%x\n", base, base + 8-1); rc = -EBUSY; -- cgit v1.2.3-70-g09d2 From 95563d343fec8d3e2f667c95230ac4ab7674b757 Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Fri, 28 Apr 2006 22:53:30 +0200 Subject: [PATCH] scx200_acb: Fix for the CS5535 errata This is a fix for the CS5535 errata 111: When the SMBus controller tries to access a non-existing device, it sets the NEGACK bit, SMBus I/O offset 01h[4], to 1 after it detects no acknowledge at the ninth clock. The specification states that the bit can be cleared by writing a 1 to it, but under certain circumstances it is possible for this bit to not clear. Writing a 0 to the bit resets the internal state machine and clears the issue. Since all writable bits in ACBST are W1C bits (write-one-to-clear) the second write doesn't affect any other logic except the buggy NEGACK state machine. The second write clears an internal register which is responsible for "overwriting" the NEGACK bit in ACBST. Signed-off-by: Jordan Crouse Signed-off-by: Andrew Morton Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/scx200_acb.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c index 42e4e00d6c32..a140e4536a4e 100644 --- a/drivers/i2c/busses/scx200_acb.c +++ b/drivers/i2c/busses/scx200_acb.c @@ -133,6 +133,9 @@ static void scx200_acb_machine(struct scx200_acb_iface *iface, u8 status) outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1); outb(ACBST_STASTR | ACBST_NEGACK, ACBST); + + /* Reset the status register */ + outb(0, ACBST); return; } @@ -228,6 +231,10 @@ static void scx200_acb_poll(struct scx200_acb_iface *iface) timeout = jiffies + POLL_TIMEOUT; while (time_before(jiffies, timeout)) { status = inb(ACBST); + + /* Reset the status register to avoid the hang */ + outb(0, ACBST); + if ((status & (ACBST_SDAST|ACBST_BER|ACBST_NEGACK)) != 0) { scx200_acb_machine(iface, status); return; -- cgit v1.2.3-70-g09d2 From 1929ab8c6860a4a94109eed038b0fa9d12c81721 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 9 May 2006 22:14:28 +0100 Subject: [ARM] Fix thread struct allocator for SMP case The ARM thread struct allocator is racy on SMP systems. Fix it by turning it into a per-cpu based allocator. This also allows keeps the cache cache warm for thread structs and kernel stacks. Signed-off-by: Russell King --- arch/arm/kernel/process.c | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 1ff75cee4b0d..1a1539e3a946 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -264,8 +264,12 @@ void show_fpregs(struct user_fp *regs) /* * Task structure and kernel stack allocation. */ -static unsigned long *thread_info_head; -static unsigned int nr_thread_info; +struct thread_info_list { + unsigned long *head; + unsigned int nr; +}; + +static DEFINE_PER_CPU(struct thread_info_list, thread_info_list) = { NULL, 0 }; #define EXTRA_TASK_STRUCT 4 @@ -274,12 +278,15 @@ struct thread_info *alloc_thread_info(struct task_struct *task) struct thread_info *thread = NULL; if (EXTRA_TASK_STRUCT) { - unsigned long *p = thread_info_head; + struct thread_info_list *th = &get_cpu_var(thread_info_list); + unsigned long *p = th->head; if (p) { - thread_info_head = (unsigned long *)p[0]; - nr_thread_info -= 1; + th->head = (unsigned long *)p[0]; + th->nr -= 1; } + put_cpu_var(thread_info_list); + thread = (struct thread_info *)p; } @@ -300,13 +307,19 @@ struct thread_info *alloc_thread_info(struct task_struct *task) void free_thread_info(struct thread_info *thread) { - if (EXTRA_TASK_STRUCT && nr_thread_info < EXTRA_TASK_STRUCT) { - unsigned long *p = (unsigned long *)thread; - p[0] = (unsigned long)thread_info_head; - thread_info_head = p; - nr_thread_info += 1; - } else - free_pages((unsigned long)thread, THREAD_SIZE_ORDER); + if (EXTRA_TASK_STRUCT) { + struct thread_info_list *th = &get_cpu_var(thread_info_list); + if (th->nr < EXTRA_TASK_STRUCT) { + unsigned long *p = (unsigned long *)thread; + p[0] = th->head; + th->head = p; + th->nr += 1; + put_cpu_var(thread_info_list); + return; + } + put_cpu_var(thread_info_list); + } + free_pages((unsigned long)thread, THREAD_SIZE_ORDER); } /* -- cgit v1.2.3-70-g09d2 From 41b11afb048d67cc0e221191191ba0b2012dce47 Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Tue, 9 May 2006 22:27:51 +0100 Subject: [ARM] 3508/1: Update collie defconfig Patch from Pavel Machek Update collie defconfig to something that can bring closer-to-working system to its user. Signed-off-by: Pavel Machek Signed-off-by: Russell King --- arch/arm/configs/collie_defconfig | 430 +++++++++++++++++++++++--------------- 1 file changed, 256 insertions(+), 174 deletions(-) diff --git a/arch/arm/configs/collie_defconfig b/arch/arm/configs/collie_defconfig index c9aa878e610a..074c47a4fb2e 100644 --- a/arch/arm/configs/collie_defconfig +++ b/arch/arm/configs/collie_defconfig @@ -1,21 +1,21 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.14-rc3 -# Sun Oct 9 16:55:14 2005 +# Linux kernel version: 2.6.17-rc1 +# Fri Apr 14 19:09:52 2006 # CONFIG_ARM=y CONFIG_MMU=y -CONFIG_UID16=y CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_ARCH_MTD_XIP=y +CONFIG_VECTORS_BASE=0xffff0000 # # Code maturity level options # CONFIG_EXPERIMENTAL=y -CONFIG_CLEAN_COMPILE=y CONFIG_BROKEN_ON_SMP=y -CONFIG_LOCK_KERNEL=y CONFIG_INIT_ENV_ARG_LIMIT=32 # @@ -23,45 +23,58 @@ CONFIG_INIT_ENV_ARG_LIMIT=32 # CONFIG_LOCALVERSION="" CONFIG_LOCALVERSION_AUTO=y -CONFIG_SWAP=y +# CONFIG_SWAP is not set CONFIG_SYSVIPC=y # CONFIG_POSIX_MQUEUE is not set -CONFIG_BSD_PROCESS_ACCT=y -# CONFIG_BSD_PROCESS_ACCT_V3 is not set +# CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y # CONFIG_AUDIT is not set -CONFIG_HOTPLUG=y -CONFIG_KOBJECT_UEVENT=y # CONFIG_IKCONFIG is not set +# CONFIG_RELAY is not set CONFIG_INITRAMFS_SOURCE="" +CONFIG_UID16=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EMBEDDED=y CONFIG_KALLSYMS=y # CONFIG_KALLSYMS_ALL is not set # CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y CONFIG_PRINTK=y CONFIG_BUG=y -CONFIG_BASE_FULL=y +CONFIG_ELF_CORE=y +# CONFIG_BASE_FULL is not set CONFIG_FUTEX=y -CONFIG_EPOLL=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +# CONFIG_EPOLL is not set CONFIG_SHMEM=y -CONFIG_CC_ALIGN_FUNCTIONS=0 -CONFIG_CC_ALIGN_LABELS=0 -CONFIG_CC_ALIGN_LOOPS=0 -CONFIG_CC_ALIGN_JUMPS=0 +# CONFIG_SLAB is not set +CONFIG_DOUBLEFAULT=y # CONFIG_TINY_SHMEM is not set -CONFIG_BASE_SMALL=0 +CONFIG_BASE_SMALL=1 +CONFIG_SLOB=y +CONFIG_OBSOLETE_INTERMODULE=y # # Loadable module support # -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -CONFIG_MODULE_FORCE_UNLOAD=y -CONFIG_OBSOLETE_MODPARM=y -CONFIG_MODVERSIONS=y -# CONFIG_MODULE_SRCVERSION_ALL is not set -CONFIG_KMOD=y +# CONFIG_MODULES is not set + +# +# Block layer +# +# CONFIG_BLK_DEV_IO_TRACE is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +# CONFIG_IOSCHED_DEADLINE is not set +# CONFIG_IOSCHED_CFQ is not set +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" # # System Type @@ -70,11 +83,13 @@ CONFIG_KMOD=y # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set # CONFIG_ARCH_IXP4XX is not set # CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_IXP23XX is not set # CONFIG_ARCH_L7200 is not set # CONFIG_ARCH_PXA is not set # CONFIG_ARCH_RPC is not set @@ -84,9 +99,11 @@ CONFIG_ARCH_SA1100=y # CONFIG_ARCH_LH7A40X is not set # CONFIG_ARCH_OMAP is not set # CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_REALVIEW is not set # CONFIG_ARCH_IMX is not set # CONFIG_ARCH_H720X is not set # CONFIG_ARCH_AAEC2000 is not set +# CONFIG_ARCH_AT91RM9200 is not set # # SA11x0 Implementations @@ -128,20 +145,32 @@ CONFIG_SHARP_SCOOP=y # Bus support # CONFIG_ISA=y -CONFIG_ISA_DMA_API=y # # PCCARD (PCMCIA/CardBus) support # -# CONFIG_PCCARD is not set +CONFIG_PCCARD=y +CONFIG_PCMCIA_DEBUG=y +CONFIG_PCMCIA=y +CONFIG_PCMCIA_LOAD_CIS=y +CONFIG_PCMCIA_IOCTL=y + +# +# PC-card bridges +# +# CONFIG_I82365 is not set +# CONFIG_TCIC is not set +CONFIG_PCMCIA_SA1100=y # # Kernel Features # -# CONFIG_SMP is not set -CONFIG_PREEMPT=y +# CONFIG_PREEMPT is not set # CONFIG_NO_IDLE_HZ is not set +CONFIG_HZ=100 +# CONFIG_AEABI is not set CONFIG_ARCH_DISCONTIGMEM_ENABLE=y +CONFIG_NODES_SHIFT=2 CONFIG_SELECT_MEMORY_MODEL=y # CONFIG_FLATMEM_MANUAL is not set CONFIG_DISCONTIGMEM_MANUAL=y @@ -150,6 +179,7 @@ CONFIG_DISCONTIGMEM=y CONFIG_FLAT_NODE_MEM_MAP=y CONFIG_NEED_MULTIPLE_NODES=y # CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4096 # CONFIG_LEDS is not set CONFIG_ALIGNMENT_TRAP=y @@ -158,7 +188,7 @@ CONFIG_ALIGNMENT_TRAP=y # CONFIG_ZBOOT_ROM_TEXT=0x0 CONFIG_ZBOOT_ROM_BSS=0x0 -CONFIG_CMDLINE="console=ttyS0,115200n8 console=tty1 noinitrd root=/dev/mtdblock2 rootfstype=jffs2 debug" +CONFIG_CMDLINE="noinitrd root=/dev/mtdblock2 rootfstype=jffs2 fbcon=rotate:1" # CONFIG_XIP_KERNEL is not set # @@ -181,14 +211,16 @@ CONFIG_FPE_NWFPE=y # Userspace binary formats # CONFIG_BINFMT_ELF=y -CONFIG_BINFMT_AOUT=m -CONFIG_BINFMT_MISC=m +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set # CONFIG_ARTHUR is not set # # Power management options # CONFIG_PM=y +CONFIG_PM_LEGACY=y +# CONFIG_PM_DEBUG is not set CONFIG_APM=y # @@ -199,6 +231,7 @@ CONFIG_NET=y # # Networking options # +# CONFIG_NETDEBUG is not set CONFIG_PACKET=y CONFIG_PACKET_MMAP=y CONFIG_UNIX=y @@ -211,16 +244,19 @@ CONFIG_IP_FIB_HASH=y # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set # CONFIG_ARPD is not set -CONFIG_SYN_COOKIES=y +# CONFIG_SYN_COOKIES is not set # CONFIG_INET_AH is not set # CONFIG_INET_ESP is not set # CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set # CONFIG_INET_TUNNEL is not set CONFIG_INET_DIAG=y CONFIG_INET_TCP_DIAG=y # CONFIG_TCP_CONG_ADVANCED is not set CONFIG_TCP_CONG_BIC=y # CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set # CONFIG_NETFILTER is not set # @@ -232,6 +268,11 @@ CONFIG_TCP_CONG_BIC=y # SCTP Configuration (EXPERIMENTAL) # # CONFIG_IP_SCTP is not set + +# +# TIPC Configuration (EXPERIMENTAL) +# +# CONFIG_TIPC is not set # CONFIG_ATM is not set # CONFIG_BRIDGE is not set # CONFIG_VLAN_8021Q is not set @@ -244,8 +285,11 @@ CONFIG_TCP_CONG_BIC=y # CONFIG_NET_DIVERT is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# # CONFIG_NET_SCHED is not set -# CONFIG_NET_CLS_ROUTE is not set # # Network testing @@ -265,9 +309,14 @@ CONFIG_TCP_CONG_BIC=y # CONFIG_STANDALONE=y CONFIG_PREVENT_FIRMWARE_BUILD=y -CONFIG_FW_LOADER=m +CONFIG_FW_LOADER=y # CONFIG_DEBUG_DRIVER is not set +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set + # # Memory Technology Devices (MTD) # @@ -287,32 +336,49 @@ CONFIG_MTD_BLOCK=y # CONFIG_FTL is not set # CONFIG_NFTL is not set # CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set # # RAM/ROM/Flash chip drivers # -# CONFIG_MTD_CFI is not set -# CONFIG_MTD_JEDECPROBE is not set -CONFIG_MTD_MAP_BANK_WIDTH_1=y -CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_CFI=y +CONFIG_MTD_JEDECPROBE=y +CONFIG_MTD_GEN_PROBE=y +CONFIG_MTD_CFI_ADV_OPTIONS=y +CONFIG_MTD_CFI_NOSWAP=y +# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set +# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set +CONFIG_MTD_CFI_GEOMETRY=y +# CONFIG_MTD_MAP_BANK_WIDTH_1 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_2 is not set CONFIG_MTD_MAP_BANK_WIDTH_4=y # CONFIG_MTD_MAP_BANK_WIDTH_8 is not set # CONFIG_MTD_MAP_BANK_WIDTH_16 is not set # CONFIG_MTD_MAP_BANK_WIDTH_32 is not set -CONFIG_MTD_CFI_I1=y -CONFIG_MTD_CFI_I2=y -# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I1 is not set +# CONFIG_MTD_CFI_I2 is not set +CONFIG_MTD_CFI_I4=y # CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_OTP is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y # CONFIG_MTD_RAM is not set # CONFIG_MTD_ROM is not set # CONFIG_MTD_ABSENT is not set CONFIG_MTD_OBSOLETE_CHIPS=y CONFIG_MTD_SHARP=y +# CONFIG_MTD_XIP is not set # # Mapping drivers for chip access # # CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +CONFIG_MTD_SA1100=y +# CONFIG_MTD_IMPA7 is not set # CONFIG_MTD_PLATRAM is not set # @@ -321,7 +387,6 @@ CONFIG_MTD_SHARP=y # CONFIG_MTD_SLRAM is not set # CONFIG_MTD_PHRAM is not set # CONFIG_MTD_MTDRAM is not set -# CONFIG_MTD_BLKMTD is not set # CONFIG_MTD_BLOCK2MTD is not set # @@ -336,6 +401,11 @@ CONFIG_MTD_SHARP=y # # CONFIG_MTD_NAND is not set +# +# OneNAND Flash Device Drivers +# +# CONFIG_MTD_ONENAND is not set + # # Parallel port support # @@ -349,7 +419,6 @@ CONFIG_MTD_SHARP=y # # Block devices # -# CONFIG_BLK_DEV_XD is not set # CONFIG_BLK_DEV_COW_COMMON is not set CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_CRYPTOLOOP is not set @@ -359,20 +428,35 @@ CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=1024 CONFIG_BLK_DEV_INITRD=y # CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set # -# IO Schedulers +# ATA/ATAPI/MFM/RLL support # -CONFIG_IOSCHED_NOOP=y -CONFIG_IOSCHED_AS=y -CONFIG_IOSCHED_DEADLINE=y -CONFIG_IOSCHED_CFQ=y -CONFIG_ATA_OVER_ETH=m +CONFIG_IDE=y +CONFIG_BLK_DEV_IDE=y # -# ATA/ATAPI/MFM/RLL support +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_IDEDISK=y +CONFIG_IDEDISK_MULTI_MODE=y +CONFIG_BLK_DEV_IDECS=y +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes # -# CONFIG_IDE is not set +CONFIG_IDE_GENERIC=y +# CONFIG_IDE_ARM is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_BLK_DEV_IDEDMA is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_BLK_DEV_HD is not set # # SCSI device support @@ -402,6 +486,39 @@ CONFIG_ATA_OVER_ETH=m # Network device support # # CONFIG_NETDEVICES is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# PHY device support +# + +# +# Ethernet (10 or 100Mbit) +# +# CONFIG_NET_ETHERNET is not set + +# +# Ethernet (1000 Mbit) +# + +# +# Ethernet (10000 Mbit) +# +CONFIG_PPP=y +# CONFIG_PPP_MULTILINK is not set +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_ASYNC=y +# CONFIG_PPP_SYNC_TTY is not set +# CONFIG_PPP_DEFLATE is not set +# CONFIG_PPP_BSDCOMP is not set +# CONFIG_PPP_MPPE is not set +# CONFIG_PPPOE is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set # CONFIG_NETPOLL is not set # CONFIG_NET_POLL_CONTROLLER is not set @@ -424,7 +541,7 @@ CONFIG_INPUT_TSDEV=y CONFIG_INPUT_TSDEV_SCREEN_X=240 CONFIG_INPUT_TSDEV_SCREEN_Y=320 CONFIG_INPUT_EVDEV=y -CONFIG_INPUT_EVBUG=y +# CONFIG_INPUT_EVBUG is not set # # Input Device Drivers @@ -438,7 +555,11 @@ CONFIG_KEYBOARD_LOCOMO=y # CONFIG_KEYBOARD_NEWTON is not set # CONFIG_INPUT_MOUSE is not set # CONFIG_INPUT_JOYSTICK is not set -# CONFIG_INPUT_TOUCHSCREEN is not set +CONFIG_INPUT_TOUCHSCREEN=y +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_TOUCHSCREEN_ELO is not set +# CONFIG_TOUCHSCREEN_MTOUCH is not set +# CONFIG_TOUCHSCREEN_MK712 is not set # CONFIG_INPUT_MISC is not set # @@ -461,7 +582,16 @@ CONFIG_HW_CONSOLE=y # # Serial drivers # -# CONFIG_SERIAL_8250 is not set +CONFIG_SERIAL_8250=y +# CONFIG_SERIAL_8250_CONSOLE is not set +CONFIG_SERIAL_8250_CS=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +# CONFIG_SERIAL_8250_MANY_PORTS is not set +# CONFIG_SERIAL_8250_SHARE_IRQ is not set +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_RSA is not set # # Non-8250 serial port support @@ -483,94 +613,48 @@ CONFIG_UNIX98_PTYS=y # # CONFIG_WATCHDOG is not set # CONFIG_NVRAM is not set -# CONFIG_RTC is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # # Ftape, the floppy tape device driver # -# CONFIG_RAW_DRIVER is not set # -# TPM devices +# PCMCIA character devices # +# CONFIG_SYNCLINK_CS is not set +# CONFIG_CARDMAN_4000 is not set +# CONFIG_CARDMAN_4040 is not set +# CONFIG_RAW_DRIVER is not set # -# I2C support +# TPM devices # -CONFIG_I2C=m -# CONFIG_I2C_CHARDEV is not set +# CONFIG_TCG_TPM is not set +# CONFIG_TELCLOCK is not set # -# I2C Algorithms +# I2C support # -CONFIG_I2C_ALGOBIT=m -# CONFIG_I2C_ALGOPCF is not set -# CONFIG_I2C_ALGOPCA is not set +# CONFIG_I2C is not set # -# I2C Hardware Bus support +# SPI support # -# CONFIG_I2C_ELEKTOR is not set -# CONFIG_I2C_PARPORT_LIGHT is not set -# CONFIG_I2C_STUB is not set -# CONFIG_I2C_PCA_ISA is not set +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set # -# Miscellaneous I2C Chip support +# Dallas's 1-wire bus # -# CONFIG_SENSORS_DS1337 is not set -# CONFIG_SENSORS_DS1374 is not set -# CONFIG_SENSORS_EEPROM is not set -# CONFIG_SENSORS_PCF8574 is not set -# CONFIG_SENSORS_PCA9539 is not set -# CONFIG_SENSORS_PCF8591 is not set -# CONFIG_SENSORS_RTC8564 is not set -# CONFIG_SENSORS_MAX6875 is not set -# CONFIG_I2C_DEBUG_CORE is not set -# CONFIG_I2C_DEBUG_ALGO is not set -# CONFIG_I2C_DEBUG_BUS is not set -# CONFIG_I2C_DEBUG_CHIP is not set +# CONFIG_W1 is not set # # Hardware Monitoring support # -CONFIG_HWMON=y +# CONFIG_HWMON is not set # CONFIG_HWMON_VID is not set -# CONFIG_SENSORS_ADM1021 is not set -# CONFIG_SENSORS_ADM1025 is not set -# CONFIG_SENSORS_ADM1026 is not set -# CONFIG_SENSORS_ADM1031 is not set -# CONFIG_SENSORS_ADM9240 is not set -# CONFIG_SENSORS_ASB100 is not set -# CONFIG_SENSORS_ATXP1 is not set -# CONFIG_SENSORS_DS1621 is not set -# CONFIG_SENSORS_FSCHER is not set -# CONFIG_SENSORS_FSCPOS is not set -# CONFIG_SENSORS_GL518SM is not set -# CONFIG_SENSORS_GL520SM is not set -# CONFIG_SENSORS_IT87 is not set -# CONFIG_SENSORS_LM63 is not set -# CONFIG_SENSORS_LM75 is not set -# CONFIG_SENSORS_LM77 is not set -# CONFIG_SENSORS_LM78 is not set -# CONFIG_SENSORS_LM80 is not set -# CONFIG_SENSORS_LM83 is not set -# CONFIG_SENSORS_LM85 is not set -# CONFIG_SENSORS_LM87 is not set -# CONFIG_SENSORS_LM90 is not set -# CONFIG_SENSORS_LM92 is not set -# CONFIG_SENSORS_MAX1619 is not set -# CONFIG_SENSORS_PC87360 is not set -# CONFIG_SENSORS_SMSC47M1 is not set -# CONFIG_SENSORS_SMSC47B397 is not set -# CONFIG_SENSORS_W83781D is not set -# CONFIG_SENSORS_W83792D is not set -# CONFIG_SENSORS_W83L785TS is not set -# CONFIG_SENSORS_W83627HF is not set -# CONFIG_SENSORS_W83627EHF is not set -# CONFIG_HWMON_DEBUG_CHIP is not set # # Misc devices @@ -579,42 +663,33 @@ CONFIG_HWMON=y # # Multimedia Capabilities Port drivers # -# CONFIG_MCP_SA11X0 is not set +CONFIG_MCP=y +CONFIG_MCP_SA11X0=y +CONFIG_MCP_UCB1200=y +CONFIG_MCP_UCB1200_TS=y # -# Multimedia devices +# LED devices # -CONFIG_VIDEO_DEV=m +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y # -# Video For Linux +# LED drivers # +CONFIG_LEDS_LOCOMO=y # -# Video Adapters +# LED Triggers # -# CONFIG_VIDEO_PMS is not set -# CONFIG_VIDEO_CPIA is not set -# CONFIG_VIDEO_SAA5246A is not set -# CONFIG_VIDEO_SAA5249 is not set -# CONFIG_TUNER_3036 is not set -# CONFIG_VIDEO_OVCAMCHIP is not set +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_LEDS_TRIGGER_IDE_DISK=y # -# Radio Adapters +# Multimedia devices # -# CONFIG_RADIO_CADET is not set -# CONFIG_RADIO_RTRACK is not set -# CONFIG_RADIO_RTRACK2 is not set -# CONFIG_RADIO_AZTECH is not set -# CONFIG_RADIO_GEMTEK is not set -# CONFIG_RADIO_MAESTRO is not set -# CONFIG_RADIO_SF16FMI is not set -# CONFIG_RADIO_SF16FMR2 is not set -# CONFIG_RADIO_TERRATEC is not set -# CONFIG_RADIO_TRUST is not set -# CONFIG_RADIO_TYPHOON is not set -# CONFIG_RADIO_ZOLTRIX is not set +# CONFIG_VIDEO_DEV is not set # # Digital Video Broadcasting Devices @@ -628,8 +703,8 @@ CONFIG_FB=y CONFIG_FB_CFB_FILLRECT=y CONFIG_FB_CFB_COPYAREA=y CONFIG_FB_CFB_IMAGEBLIT=y -CONFIG_FB_SOFT_CURSOR=y # CONFIG_FB_MACMODES is not set +# CONFIG_FB_FIRMWARE_EDID is not set CONFIG_FB_MODE_HELPERS=y # CONFIG_FB_TILEBLITTING is not set CONFIG_FB_SA1100=y @@ -643,14 +718,15 @@ CONFIG_FB_SA1100=y # CONFIG_MDA_CONSOLE is not set CONFIG_DUMMY_CONSOLE=y CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y CONFIG_FONTS=y -CONFIG_FONT_8x8=y +# CONFIG_FONT_8x8 is not set # CONFIG_FONT_8x16 is not set # CONFIG_FONT_6x11 is not set # CONFIG_FONT_7x14 is not set # CONFIG_FONT_PEARL_8x8 is not set # CONFIG_FONT_ACORN_8x8 is not set -# CONFIG_FONT_MINI_4x6 is not set +CONFIG_FONT_MINI_4x6=y # CONFIG_FONT_SUN8x16 is not set # CONFIG_FONT_SUN12x22 is not set # CONFIG_FONT_10x18 is not set @@ -659,7 +735,11 @@ CONFIG_FONT_8x8=y # Logo configuration # # CONFIG_LOGO is not set -# CONFIG_BACKLIGHT_LCD_SUPPORT is not set +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_DEVICE=y +CONFIG_LCD_CLASS_DEVICE=y +CONFIG_LCD_DEVICE=y # # Sound @@ -671,44 +751,42 @@ CONFIG_FONT_8x8=y # CONFIG_USB_ARCH_HAS_HCD=y # CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB_ARCH_HAS_EHCI is not set # CONFIG_USB is not set +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + # # USB Gadget Support # -CONFIG_USB_GADGET=y -# CONFIG_USB_GADGET_DEBUG_FILES is not set -# CONFIG_USB_GADGET_NET2280 is not set -# CONFIG_USB_GADGET_PXA2XX is not set -# CONFIG_USB_GADGET_GOKU is not set -# CONFIG_USB_GADGET_LH7A40X is not set -# CONFIG_USB_GADGET_OMAP is not set -# CONFIG_USB_GADGET_DUMMY_HCD is not set -# CONFIG_USB_GADGET_DUALSPEED is not set +# CONFIG_USB_GADGET is not set # # MMC/SD Card support # # CONFIG_MMC is not set +# +# Real Time Clock +# +CONFIG_RTC_LIB=y +# CONFIG_RTC_CLASS is not set + # # File systems # -CONFIG_EXT2_FS=y -CONFIG_EXT2_FS_XATTR=y -CONFIG_EXT2_FS_POSIX_ACL=y -CONFIG_EXT2_FS_SECURITY=y -# CONFIG_EXT2_FS_XIP is not set +# CONFIG_EXT2_FS is not set # CONFIG_EXT3_FS is not set -# CONFIG_JBD is not set -CONFIG_FS_MBCACHE=y # CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set -CONFIG_FS_POSIX_ACL=y +# CONFIG_FS_POSIX_ACL is not set # CONFIG_XFS_FS is not set +# CONFIG_OCFS2_FS is not set # CONFIG_MINIX_FS is not set CONFIG_ROMFS_FS=y -CONFIG_INOTIFY=y +# CONFIG_INOTIFY is not set # CONFIG_QUOTA is not set # CONFIG_DNOTIFY is not set # CONFIG_AUTOFS_FS is not set @@ -725,7 +803,7 @@ CONFIG_INOTIFY=y # DOS/FAT/NT Filesystems # CONFIG_FAT_FS=y -CONFIG_MSDOS_FS=y +# CONFIG_MSDOS_FS is not set CONFIG_VFAT_FS=y CONFIG_FAT_DEFAULT_CODEPAGE=437 CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" @@ -739,7 +817,7 @@ CONFIG_SYSFS=y CONFIG_TMPFS=y # CONFIG_HUGETLB_PAGE is not set CONFIG_RAMFS=y -# CONFIG_RELAYFS_FS is not set +# CONFIG_CONFIGFS_FS is not set # # Miscellaneous filesystems @@ -755,11 +833,12 @@ CONFIG_RAMFS=y CONFIG_JFFS2_FS=y CONFIG_JFFS2_FS_DEBUG=0 CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_SUMMARY is not set # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set CONFIG_JFFS2_ZLIB=y CONFIG_JFFS2_RTIME=y # CONFIG_JFFS2_RUBIN is not set -CONFIG_CRAMFS=y +# CONFIG_CRAMFS is not set # CONFIG_VXFS_FS is not set # CONFIG_HPFS_FS is not set # CONFIG_QNX4FS_FS is not set @@ -789,7 +868,7 @@ CONFIG_MSDOS_PARTITION=y # CONFIG_NLS=y CONFIG_NLS_DEFAULT="cp437" -CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_437=y # CONFIG_NLS_CODEPAGE_737 is not set # CONFIG_NLS_CODEPAGE_775 is not set # CONFIG_NLS_CODEPAGE_850 is not set @@ -813,7 +892,7 @@ CONFIG_NLS_CODEPAGE_437=m # CONFIG_NLS_CODEPAGE_1250 is not set # CONFIG_NLS_CODEPAGE_1251 is not set # CONFIG_NLS_ASCII is not set -CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_1=y # CONFIG_NLS_ISO8859_2 is not set # CONFIG_NLS_ISO8859_3 is not set # CONFIG_NLS_ISO8859_4 is not set @@ -826,7 +905,7 @@ CONFIG_NLS_ISO8859_1=m # CONFIG_NLS_ISO8859_15 is not set # CONFIG_NLS_KOI8_R is not set # CONFIG_NLS_KOI8_U is not set -CONFIG_NLS_UTF8=m +# CONFIG_NLS_UTF8 is not set # # Profiling support @@ -837,20 +916,23 @@ CONFIG_NLS_UTF8=m # Kernel hacking # # CONFIG_PRINTK_TIME is not set -CONFIG_DEBUG_KERNEL=y CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_KERNEL=y CONFIG_LOG_BUF_SHIFT=14 -CONFIG_DETECT_SOFTLOCKUP=y +# CONFIG_DETECT_SOFTLOCKUP is not set # CONFIG_SCHEDSTATS is not set -# CONFIG_DEBUG_SLAB is not set -CONFIG_DEBUG_PREEMPT=y +CONFIG_DEBUG_MUTEXES=y # CONFIG_DEBUG_SPINLOCK is not set # CONFIG_DEBUG_SPINLOCK_SLEEP is not set # CONFIG_DEBUG_KOBJECT is not set # CONFIG_DEBUG_BUGVERBOSE is not set # CONFIG_DEBUG_INFO is not set # CONFIG_DEBUG_FS is not set +# CONFIG_DEBUG_VM is not set CONFIG_FRAME_POINTER=y +# CONFIG_UNWIND_INFO is not set +CONFIG_FORCED_INLINING=y +# CONFIG_RCU_TORTURE_TEST is not set # CONFIG_DEBUG_USER is not set # CONFIG_DEBUG_WAITQ is not set CONFIG_DEBUG_ERRORS=y @@ -874,7 +956,7 @@ CONFIG_DEBUG_ERRORS=y # # Library routines # -# CONFIG_CRC_CCITT is not set +CONFIG_CRC_CCITT=y # CONFIG_CRC16 is not set CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set -- cgit v1.2.3-70-g09d2 From 3a01c1ef75e1d84752ddef607c389bbde9c2576e Mon Sep 17 00:00:00 2001 From: Stefan Rompf Date: Tue, 9 May 2006 15:15:35 -0700 Subject: [NET]: Add missing operstates documentation. Signed-off-by: Stefan Rompf Signed-off-by: David S. Miller --- Documentation/networking/operstates.txt | 161 ++++++++++++++++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 Documentation/networking/operstates.txt diff --git a/Documentation/networking/operstates.txt b/Documentation/networking/operstates.txt new file mode 100644 index 000000000000..4a21d9bb836b --- /dev/null +++ b/Documentation/networking/operstates.txt @@ -0,0 +1,161 @@ + +1. Introduction + +Linux distinguishes between administrative and operational state of an +interface. Admininstrative state is the result of "ip link set dev + up or down" and reflects whether the administrator wants to use +the device for traffic. + +However, an interface is not usable just because the admin enabled it +- ethernet requires to be plugged into the switch and, depending on +a site's networking policy and configuration, an 802.1X authentication +to be performed before user data can be transferred. Operational state +shows the ability of an interface to transmit this user data. + +Thanks to 802.1X, userspace must be granted the possibility to +influence operational state. To accommodate this, operational state is +split into two parts: Two flags that can be set by the driver only, and +a RFC2863 compatible state that is derived from these flags, a policy, +and changeable from userspace under certain rules. + + +2. Querying from userspace + +Both admin and operational state can be queried via the netlink +operation RTM_GETLINK. It is also possible to subscribe to RTMGRP_LINK +to be notified of updates. This is important for setting from userspace. + +These values contain interface state: + +ifinfomsg::if_flags & IFF_UP: + Interface is admin up +ifinfomsg::if_flags & IFF_RUNNING: + Interface is in RFC2863 operational state UP or UNKNOWN. This is for + backward compatibility, routing daemons, dhcp clients can use this + flag to determine whether they should use the interface. +ifinfomsg::if_flags & IFF_LOWER_UP: + Driver has signaled netif_carrier_on() +ifinfomsg::if_flags & IFF_DORMANT: + Driver has signaled netif_dormant_on() + +These interface flags can also be queried without netlink using the +SIOCGIFFLAGS ioctl. + +TLV IFLA_OPERSTATE + +contains RFC2863 state of the interface in numeric representation: + +IF_OPER_UNKNOWN (0): + Interface is in unknown state, neither driver nor userspace has set + operational state. Interface must be considered for user data as + setting operational state has not been implemented in every driver. +IF_OPER_NOTPRESENT (1): + Unused in current kernel (notpresent interfaces normally disappear), + just a numerical placeholder. +IF_OPER_DOWN (2): + Interface is unable to transfer data on L1, f.e. ethernet is not + plugged or interface is ADMIN down. +IF_OPER_LOWERLAYERDOWN (3): + Interfaces stacked on an interface that is IF_OPER_DOWN show this + state (f.e. VLAN). +IF_OPER_TESTING (4): + Unused in current kernel. +IF_OPER_DORMANT (5): + Interface is L1 up, but waiting for an external event, f.e. for a + protocol to establish. (802.1X) +IF_OPER_UP (6): + Interface is operational up and can be used. + +This TLV can also be queried via sysfs. + +TLV IFLA_LINKMODE + +contains link policy. This is needed for userspace interaction +described below. + +This TLV can also be queried via sysfs. + + +3. Kernel driver API + +Kernel drivers have access to two flags that map to IFF_LOWER_UP and +IFF_DORMANT. These flags can be set from everywhere, even from +interrupts. It is guaranteed that only the driver has write access, +however, if different layers of the driver manipulate the same flag, +the driver has to provide the synchronisation needed. + +__LINK_STATE_NOCARRIER, maps to !IFF_LOWER_UP: + +The driver uses netif_carrier_on() to clear and netif_carrier_off() to +set this flag. On netif_carrier_off(), the scheduler stops sending +packets. The name 'carrier' and the inversion are historical, think of +it as lower layer. + +netif_carrier_ok() can be used to query that bit. + +__LINK_STATE_DORMANT, maps to IFF_DORMANT: + +Set by the driver to express that the device cannot yet be used +because some driver controlled protocol establishment has to +complete. Corresponding functions are netif_dormant_on() to set the +flag, netif_dormant_off() to clear it and netif_dormant() to query. + +On device allocation, networking core sets the flags equivalent to +netif_carrier_ok() and !netif_dormant(). + + +Whenever the driver CHANGES one of these flags, a workqueue event is +scheduled to translate the flag combination to IFLA_OPERSTATE as +follows: + +!netif_carrier_ok(): + IF_OPER_LOWERLAYERDOWN if the interface is stacked, IF_OPER_DOWN + otherwise. Kernel can recognise stacked interfaces because their + ifindex != iflink. + +netif_carrier_ok() && netif_dormant(): + IF_OPER_DORMANT + +netif_carrier_ok() && !netif_dormant(): + IF_OPER_UP if userspace interaction is disabled. Otherwise + IF_OPER_DORMANT with the possibility for userspace to initiate the + IF_OPER_UP transition afterwards. + + +4. Setting from userspace + +Applications have to use the netlink interface to influence the +RFC2863 operational state of an interface. Setting IFLA_LINKMODE to 1 +via RTM_SETLINK instructs the kernel that an interface should go to +IF_OPER_DORMANT instead of IF_OPER_UP when the combination +netif_carrier_ok() && !netif_dormant() is set by the +driver. Afterwards, the userspace application can set IFLA_OPERSTATE +to IF_OPER_DORMANT or IF_OPER_UP as long as the driver does not set +netif_carrier_off() or netif_dormant_on(). Changes made by userspace +are multicasted on the netlink group RTMGRP_LINK. + +So basically a 802.1X supplicant interacts with the kernel like this: + +-subscribe to RTMGRP_LINK +-set IFLA_LINKMODE to 1 via RTM_SETLINK +-query RTM_GETLINK once to get initial state +-if initial flags are not (IFF_LOWER_UP && !IFF_DORMANT), wait until + netlink multicast signals this state +-do 802.1X, eventually abort if flags go down again +-send RTM_SETLINK to set operstate to IF_OPER_UP if authentication + succeeds, IF_OPER_DORMANT otherwise +-see how operstate and IFF_RUNNING is echoed via netlink multicast +-set interface back to IF_OPER_DORMANT if 802.1X reauthentication + fails +-restart if kernel changes IFF_LOWER_UP or IFF_DORMANT flag + +if supplicant goes down, bring back IFLA_LINKMODE to 0 and +IFLA_OPERSTATE to a sane value. + +A routing daemon or dhcp client just needs to care for IFF_RUNNING or +waiting for operstate to go IF_OPER_UP/IF_OPER_UNKNOWN before +considering the interface / querying a DHCP address. + + +For technical questions and/or comments please e-mail to Stefan Rompf +(stefan at loplof.de). -- cgit v1.2.3-70-g09d2 From 63cbd2fda38f3d1f107c4fd6261e5660be3eccf9 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 9 May 2006 15:18:50 -0700 Subject: [IPV4]: ip_options_fragment() has no effect on fragmentation Fix error point to options in ip_options_fragment(). optptr get a error pointer to the ipv4 header, correct is pointer to ipv4 options. Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller --- net/ipv4/ip_options.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index 9bebad07bf2e..cbcae6544622 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c @@ -209,7 +209,7 @@ int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb) void ip_options_fragment(struct sk_buff * skb) { - unsigned char * optptr = skb->nh.raw; + unsigned char * optptr = skb->nh.raw + sizeof(struct iphdr); struct ip_options * opt = &(IPCB(skb)->opt); int l = opt->optlen; int optlen; -- cgit v1.2.3-70-g09d2 From f07d5b946510a54937a75a3654941e855ffdc4c2 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 9 May 2006 15:23:03 -0700 Subject: [NET]: Make netdev_chain a raw notifier. From: Alan Stern This chain does it's own locking via the RTNL semaphore, and can also run recursively so adding a new mutex here was causing deadlocks. Signed-off-by: David S. Miller --- net/core/dev.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index 9ab3cfa58466..ced57430f6d8 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -193,7 +193,7 @@ static inline struct hlist_head *dev_index_hash(int ifindex) * Our notifier list */ -static BLOCKING_NOTIFIER_HEAD(netdev_chain); +static RAW_NOTIFIER_HEAD(netdev_chain); /* * Device drivers call our routines to queue packets here. We empty the @@ -736,7 +736,7 @@ int dev_change_name(struct net_device *dev, char *newname) if (!err) { hlist_del(&dev->name_hlist); hlist_add_head(&dev->name_hlist, dev_name_hash(dev->name)); - blocking_notifier_call_chain(&netdev_chain, + raw_notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev); } @@ -751,7 +751,7 @@ int dev_change_name(struct net_device *dev, char *newname) */ void netdev_features_change(struct net_device *dev) { - blocking_notifier_call_chain(&netdev_chain, NETDEV_FEAT_CHANGE, dev); + raw_notifier_call_chain(&netdev_chain, NETDEV_FEAT_CHANGE, dev); } EXPORT_SYMBOL(netdev_features_change); @@ -766,7 +766,7 @@ EXPORT_SYMBOL(netdev_features_change); void netdev_state_change(struct net_device *dev) { if (dev->flags & IFF_UP) { - blocking_notifier_call_chain(&netdev_chain, + raw_notifier_call_chain(&netdev_chain, NETDEV_CHANGE, dev); rtmsg_ifinfo(RTM_NEWLINK, dev, 0); } @@ -864,7 +864,7 @@ int dev_open(struct net_device *dev) /* * ... and announce new interface. */ - blocking_notifier_call_chain(&netdev_chain, NETDEV_UP, dev); + raw_notifier_call_chain(&netdev_chain, NETDEV_UP, dev); } return ret; } @@ -887,7 +887,7 @@ int dev_close(struct net_device *dev) * Tell people we are going down, so that they can * prepare to death, when device is still operating. */ - blocking_notifier_call_chain(&netdev_chain, NETDEV_GOING_DOWN, dev); + raw_notifier_call_chain(&netdev_chain, NETDEV_GOING_DOWN, dev); dev_deactivate(dev); @@ -924,7 +924,7 @@ int dev_close(struct net_device *dev) /* * Tell people we are down */ - blocking_notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev); + raw_notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev); return 0; } @@ -955,7 +955,7 @@ int register_netdevice_notifier(struct notifier_block *nb) int err; rtnl_lock(); - err = blocking_notifier_chain_register(&netdev_chain, nb); + err = raw_notifier_chain_register(&netdev_chain, nb); if (!err) { for (dev = dev_base; dev; dev = dev->next) { nb->notifier_call(nb, NETDEV_REGISTER, dev); @@ -983,7 +983,7 @@ int unregister_netdevice_notifier(struct notifier_block *nb) int err; rtnl_lock(); - err = blocking_notifier_chain_unregister(&netdev_chain, nb); + err = raw_notifier_chain_unregister(&netdev_chain, nb); rtnl_unlock(); return err; } @@ -994,12 +994,12 @@ int unregister_netdevice_notifier(struct notifier_block *nb) * @v: pointer passed unmodified to notifier function * * Call all network notifier blocks. Parameters and return value - * are as for blocking_notifier_call_chain(). + * are as for raw_notifier_call_chain(). */ int call_netdevice_notifiers(unsigned long val, void *v) { - return blocking_notifier_call_chain(&netdev_chain, val, v); + return raw_notifier_call_chain(&netdev_chain, val, v); } /* When > 0 there are consumers of rx skb time stamps */ @@ -2308,7 +2308,7 @@ int dev_change_flags(struct net_device *dev, unsigned flags) if (dev->flags & IFF_UP && ((old_flags ^ dev->flags) &~ (IFF_UP | IFF_PROMISC | IFF_ALLMULTI | IFF_VOLATILE))) - blocking_notifier_call_chain(&netdev_chain, + raw_notifier_call_chain(&netdev_chain, NETDEV_CHANGE, dev); if ((flags ^ dev->gflags) & IFF_PROMISC) { @@ -2353,7 +2353,7 @@ int dev_set_mtu(struct net_device *dev, int new_mtu) else dev->mtu = new_mtu; if (!err && dev->flags & IFF_UP) - blocking_notifier_call_chain(&netdev_chain, + raw_notifier_call_chain(&netdev_chain, NETDEV_CHANGEMTU, dev); return err; } @@ -2370,7 +2370,7 @@ int dev_set_mac_address(struct net_device *dev, struct sockaddr *sa) return -ENODEV; err = dev->set_mac_address(dev, sa); if (!err) - blocking_notifier_call_chain(&netdev_chain, + raw_notifier_call_chain(&netdev_chain, NETDEV_CHANGEADDR, dev); return err; } @@ -2427,7 +2427,7 @@ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd) return -EINVAL; memcpy(dev->broadcast, ifr->ifr_hwaddr.sa_data, min(sizeof ifr->ifr_hwaddr.sa_data, (size_t) dev->addr_len)); - blocking_notifier_call_chain(&netdev_chain, + raw_notifier_call_chain(&netdev_chain, NETDEV_CHANGEADDR, dev); return 0; @@ -2882,7 +2882,7 @@ int register_netdevice(struct net_device *dev) write_unlock_bh(&dev_base_lock); /* Notify protocols, that a new device appeared. */ - blocking_notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev); + raw_notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev); /* Finish registration after unlock */ net_set_todo(dev); @@ -2961,7 +2961,7 @@ static void netdev_wait_allrefs(struct net_device *dev) rtnl_lock(); /* Rebroadcast unregister notification */ - blocking_notifier_call_chain(&netdev_chain, + raw_notifier_call_chain(&netdev_chain, NETDEV_UNREGISTER, dev); if (test_bit(__LINK_STATE_LINKWATCH_PENDING, @@ -3216,7 +3216,7 @@ int unregister_netdevice(struct net_device *dev) /* Notify protocols, that we are about to destroy this device. They should clean all the things. */ - blocking_notifier_call_chain(&netdev_chain, NETDEV_UNREGISTER, dev); + raw_notifier_call_chain(&netdev_chain, NETDEV_UNREGISTER, dev); /* * Flush the multicast chain -- cgit v1.2.3-70-g09d2 From f353976dc2f31c9be092d4cb9476a39ba3973926 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Tue, 9 May 2006 15:24:49 -0700 Subject: [IRDA]: New maintainer. As agreed with Jean Tourrilhes, I am taking over IrDA maintainership. Signed-off-by: Samuel Ortiz Signed-off-by: David S. Miller --- MAINTAINERS | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index d6a8e5b434ec..5e3355871416 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1480,10 +1480,11 @@ L: netdev@vger.kernel.org S: Maintained IRDA SUBSYSTEM -P: Jean Tourrilhes +P: Samuel Ortiz +M: samuel@sortiz.org L: irda-users@lists.sourceforge.net (subscribers-only) W: http://irda.sourceforge.net/ -S: Odd Fixes +S: Maintained ISAPNP P: Jaroslav Kysela -- cgit v1.2.3-70-g09d2 From 11766199a0bb9a7ba57510119e7340140e7c3e24 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 9 May 2006 15:25:25 -0700 Subject: [IRDA]: Removing unused EXPORT_SYMBOLs This patch removes the following unused EXPORT_SYMBOL's: - irias_find_attrib - irias_new_string_value - irias_new_octseq_value Signed-off-by: Adrian Bunk Signed-off-by: Samuel Ortiz Signed-off-by: David S. Miller --- net/irda/irias_object.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/net/irda/irias_object.c b/net/irda/irias_object.c index c6d169fbdceb..82e665c79991 100644 --- a/net/irda/irias_object.c +++ b/net/irda/irias_object.c @@ -257,7 +257,6 @@ struct ias_attrib *irias_find_attrib(struct ias_object *obj, char *name) /* Unsafe (locking), attrib might change */ return attrib; } -EXPORT_SYMBOL(irias_find_attrib); /* * Function irias_add_attribute (obj, attrib) @@ -484,7 +483,6 @@ struct ias_value *irias_new_string_value(char *string) return value; } -EXPORT_SYMBOL(irias_new_string_value); /* * Function irias_new_octseq_value (octets, len) @@ -519,7 +517,6 @@ struct ias_value *irias_new_octseq_value(__u8 *octseq , int len) memcpy(value->t.oct_seq, octseq , len); return value; } -EXPORT_SYMBOL(irias_new_octseq_value); struct ias_value *irias_new_missing_value(void) { -- cgit v1.2.3-70-g09d2 From d94c77b9b55f2c868ffd63cbd1f9749755c4b3d0 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 9 May 2006 15:26:11 -0700 Subject: [IRDA]: smsc-ircc: Minimal hotplug support. Minimal PNP hotplug support for the smsc-ircc2 driver. A modular driver will be modprobed via hotplug, but still bypasses driver model probing. Signed-off-by: David Brownell Signed-off-by: Samuel Ortiz Signed-off-by: David S. Miller --- drivers/net/irda/smsc-ircc2.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c index 58f76cefbc83..a4674044bd6f 100644 --- a/drivers/net/irda/smsc-ircc2.c +++ b/drivers/net/irda/smsc-ircc2.c @@ -54,6 +54,7 @@ #include #include #include +#include #include #include @@ -358,6 +359,16 @@ static inline void register_bank(int iobase, int bank) iobase + IRCC_MASTER); } +#ifdef CONFIG_PNP +/* PNP hotplug support */ +static const struct pnp_device_id smsc_ircc_pnp_table[] = { + { .id = "SMCf010", .driver_data = 0 }, + /* and presumably others */ + { } +}; +MODULE_DEVICE_TABLE(pnp, smsc_ircc_pnp_table); +#endif + /******************************************************************************* * @@ -2072,7 +2083,8 @@ static void smsc_ircc_sir_wait_hw_transmitter_finish(struct smsc_ircc_cb *self) /* PROBING * - * + * REVISIT we can be told about the device by PNP, and should use that info + * instead of probing hardware and creating a platform_device ... */ static int __init smsc_ircc_look_for_chips(void) -- cgit v1.2.3-70-g09d2 From 788252e6616afc75098397cc6b0bcb5482ad07ac Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 9 May 2006 15:27:04 -0700 Subject: [IRDA]: Switching to a workqueue for the SIR work Since sir_kthread.c pretty much duplicates the workqueue functionality, we'd better switch. The SIR fsm has been merged into sir_dev.c and thus sir_kthread.c is deleted. Signed-off-by: Christoph Hellwig Signed-off-by: Samuel Ortiz Signed-off-by: David S. Miller --- drivers/net/irda/Makefile | 2 +- drivers/net/irda/sir-dev.h | 13 +- drivers/net/irda/sir_dev.c | 315 ++++++++++++++++++++++++- drivers/net/irda/sir_kthread.c | 508 ----------------------------------------- 4 files changed, 314 insertions(+), 524 deletions(-) delete mode 100644 drivers/net/irda/sir_kthread.c diff --git a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile index 27ab75f20799..c1ce2398efea 100644 --- a/drivers/net/irda/Makefile +++ b/drivers/net/irda/Makefile @@ -46,4 +46,4 @@ obj-$(CONFIG_MA600_DONGLE) += ma600-sir.o obj-$(CONFIG_TOIM3232_DONGLE) += toim3232-sir.o # The SIR helper module -sir-dev-objs := sir_dev.o sir_dongle.o sir_kthread.o +sir-dev-objs := sir_dev.o sir_dongle.o diff --git a/drivers/net/irda/sir-dev.h b/drivers/net/irda/sir-dev.h index f69fb4cec76f..9fa294a546d6 100644 --- a/drivers/net/irda/sir-dev.h +++ b/drivers/net/irda/sir-dev.h @@ -15,23 +15,14 @@ #define IRDA_SIR_H #include +#include #include #include // iobuff_t -/* FIXME: unify irda_request with sir_fsm! */ - -struct irda_request { - struct list_head lh_request; - unsigned long pending; - void (*func)(void *); - void *data; - struct timer_list timer; -}; - struct sir_fsm { struct semaphore sem; - struct irda_request rq; + struct work_struct work; unsigned state, substate; int param; int result; diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c index ea7c9464d46a..3b5854d10c17 100644 --- a/drivers/net/irda/sir_dev.c +++ b/drivers/net/irda/sir_dev.c @@ -23,6 +23,298 @@ #include "sir-dev.h" + +static struct workqueue_struct *irda_sir_wq; + +/* STATE MACHINE */ + +/* substate handler of the config-fsm to handle the cases where we want + * to wait for transmit completion before changing the port configuration + */ + +static int sirdev_tx_complete_fsm(struct sir_dev *dev) +{ + struct sir_fsm *fsm = &dev->fsm; + unsigned next_state, delay; + unsigned bytes_left; + + do { + next_state = fsm->substate; /* default: stay in current substate */ + delay = 0; + + switch(fsm->substate) { + + case SIRDEV_STATE_WAIT_XMIT: + if (dev->drv->chars_in_buffer) + bytes_left = dev->drv->chars_in_buffer(dev); + else + bytes_left = 0; + if (!bytes_left) { + next_state = SIRDEV_STATE_WAIT_UNTIL_SENT; + break; + } + + if (dev->speed > 115200) + delay = (bytes_left*8*10000) / (dev->speed/100); + else if (dev->speed > 0) + delay = (bytes_left*10*10000) / (dev->speed/100); + else + delay = 0; + /* expected delay (usec) until remaining bytes are sent */ + if (delay < 100) { + udelay(delay); + delay = 0; + break; + } + /* sleep some longer delay (msec) */ + delay = (delay+999) / 1000; + break; + + case SIRDEV_STATE_WAIT_UNTIL_SENT: + /* block until underlaying hardware buffer are empty */ + if (dev->drv->wait_until_sent) + dev->drv->wait_until_sent(dev); + next_state = SIRDEV_STATE_TX_DONE; + break; + + case SIRDEV_STATE_TX_DONE: + return 0; + + default: + IRDA_ERROR("%s - undefined state\n", __FUNCTION__); + return -EINVAL; + } + fsm->substate = next_state; + } while (delay == 0); + return delay; +} + +/* + * Function sirdev_config_fsm + * + * State machine to handle the configuration of the device (and attached dongle, if any). + * This handler is scheduled for execution in kIrDAd context, so we can sleep. + * however, kIrDAd is shared by all sir_dev devices so we better don't sleep there too + * long. Instead, for longer delays we start a timer to reschedule us later. + * On entry, fsm->sem is always locked and the netdev xmit queue stopped. + * Both must be unlocked/restarted on completion - but only on final exit. + */ + +static void sirdev_config_fsm(void *data) +{ + struct sir_dev *dev = data; + struct sir_fsm *fsm = &dev->fsm; + int next_state; + int ret = -1; + unsigned delay; + + IRDA_DEBUG(2, "%s(), <%ld>\n", __FUNCTION__, jiffies); + + do { + IRDA_DEBUG(3, "%s - state=0x%04x / substate=0x%04x\n", + __FUNCTION__, fsm->state, fsm->substate); + + next_state = fsm->state; + delay = 0; + + switch(fsm->state) { + + case SIRDEV_STATE_DONGLE_OPEN: + if (dev->dongle_drv != NULL) { + ret = sirdev_put_dongle(dev); + if (ret) { + fsm->result = -EINVAL; + next_state = SIRDEV_STATE_ERROR; + break; + } + } + + /* Initialize dongle */ + ret = sirdev_get_dongle(dev, fsm->param); + if (ret) { + fsm->result = ret; + next_state = SIRDEV_STATE_ERROR; + break; + } + + /* Dongles are powered through the modem control lines which + * were just set during open. Before resetting, let's wait for + * the power to stabilize. This is what some dongle drivers did + * in open before, while others didn't - should be safe anyway. + */ + + delay = 50; + fsm->substate = SIRDEV_STATE_DONGLE_RESET; + next_state = SIRDEV_STATE_DONGLE_RESET; + + fsm->param = 9600; + + break; + + case SIRDEV_STATE_DONGLE_CLOSE: + /* shouldn't we just treat this as success=? */ + if (dev->dongle_drv == NULL) { + fsm->result = -EINVAL; + next_state = SIRDEV_STATE_ERROR; + break; + } + + ret = sirdev_put_dongle(dev); + if (ret) { + fsm->result = ret; + next_state = SIRDEV_STATE_ERROR; + break; + } + next_state = SIRDEV_STATE_DONE; + break; + + case SIRDEV_STATE_SET_DTR_RTS: + ret = sirdev_set_dtr_rts(dev, + (fsm->param&0x02) ? TRUE : FALSE, + (fsm->param&0x01) ? TRUE : FALSE); + next_state = SIRDEV_STATE_DONE; + break; + + case SIRDEV_STATE_SET_SPEED: + fsm->substate = SIRDEV_STATE_WAIT_XMIT; + next_state = SIRDEV_STATE_DONGLE_CHECK; + break; + + case SIRDEV_STATE_DONGLE_CHECK: + ret = sirdev_tx_complete_fsm(dev); + if (ret < 0) { + fsm->result = ret; + next_state = SIRDEV_STATE_ERROR; + break; + } + if ((delay=ret) != 0) + break; + + if (dev->dongle_drv) { + fsm->substate = SIRDEV_STATE_DONGLE_RESET; + next_state = SIRDEV_STATE_DONGLE_RESET; + } + else { + dev->speed = fsm->param; + next_state = SIRDEV_STATE_PORT_SPEED; + } + break; + + case SIRDEV_STATE_DONGLE_RESET: + if (dev->dongle_drv->reset) { + ret = dev->dongle_drv->reset(dev); + if (ret < 0) { + fsm->result = ret; + next_state = SIRDEV_STATE_ERROR; + break; + } + } + else + ret = 0; + if ((delay=ret) == 0) { + /* set serial port according to dongle default speed */ + if (dev->drv->set_speed) + dev->drv->set_speed(dev, dev->speed); + fsm->substate = SIRDEV_STATE_DONGLE_SPEED; + next_state = SIRDEV_STATE_DONGLE_SPEED; + } + break; + + case SIRDEV_STATE_DONGLE_SPEED: + if (dev->dongle_drv->reset) { + ret = dev->dongle_drv->set_speed(dev, fsm->param); + if (ret < 0) { + fsm->result = ret; + next_state = SIRDEV_STATE_ERROR; + break; + } + } + else + ret = 0; + if ((delay=ret) == 0) + next_state = SIRDEV_STATE_PORT_SPEED; + break; + + case SIRDEV_STATE_PORT_SPEED: + /* Finally we are ready to change the serial port speed */ + if (dev->drv->set_speed) + dev->drv->set_speed(dev, dev->speed); + dev->new_speed = 0; + next_state = SIRDEV_STATE_DONE; + break; + + case SIRDEV_STATE_DONE: + /* Signal network layer so it can send more frames */ + netif_wake_queue(dev->netdev); + next_state = SIRDEV_STATE_COMPLETE; + break; + + default: + IRDA_ERROR("%s - undefined state\n", __FUNCTION__); + fsm->result = -EINVAL; + /* fall thru */ + + case SIRDEV_STATE_ERROR: + IRDA_ERROR("%s - error: %d\n", __FUNCTION__, fsm->result); + +#if 0 /* don't enable this before we have netdev->tx_timeout to recover */ + netif_stop_queue(dev->netdev); +#else + netif_wake_queue(dev->netdev); +#endif + /* fall thru */ + + case SIRDEV_STATE_COMPLETE: + /* config change finished, so we are not busy any longer */ + sirdev_enable_rx(dev); + up(&fsm->sem); + return; + } + fsm->state = next_state; + } while(!delay); + + queue_delayed_work(irda_sir_wq, &fsm->work, msecs_to_jiffies(delay)); +} + +/* schedule some device configuration task for execution by kIrDAd + * on behalf of the above state machine. + * can be called from process or interrupt/tasklet context. + */ + +int sirdev_schedule_request(struct sir_dev *dev, int initial_state, unsigned param) +{ + struct sir_fsm *fsm = &dev->fsm; + + IRDA_DEBUG(2, "%s - state=0x%04x / param=%u\n", __FUNCTION__, initial_state, param); + + if (down_trylock(&fsm->sem)) { + if (in_interrupt() || in_atomic() || irqs_disabled()) { + IRDA_DEBUG(1, "%s(), state machine busy!\n", __FUNCTION__); + return -EWOULDBLOCK; + } else + down(&fsm->sem); + } + + if (fsm->state == SIRDEV_STATE_DEAD) { + /* race with sirdev_close should never happen */ + IRDA_ERROR("%s(), instance staled!\n", __FUNCTION__); + up(&fsm->sem); + return -ESTALE; /* or better EPIPE? */ + } + + netif_stop_queue(dev->netdev); + atomic_set(&dev->enable_rx, 0); + + fsm->state = initial_state; + fsm->param = param; + fsm->result = 0; + + INIT_WORK(&fsm->work, sirdev_config_fsm, dev); + queue_work(irda_sir_wq, &fsm->work); + return 0; +} + + /***************************************************************************/ void sirdev_enable_rx(struct sir_dev *dev) @@ -619,10 +911,6 @@ struct sir_dev * sirdev_get_instance(const struct sir_driver *drv, const char *n spin_lock_init(&dev->tx_lock); init_MUTEX(&dev->fsm.sem); - INIT_LIST_HEAD(&dev->fsm.rq.lh_request); - dev->fsm.rq.pending = 0; - init_timer(&dev->fsm.rq.timer); - dev->drv = drv; dev->netdev = ndev; @@ -682,3 +970,22 @@ int sirdev_put_instance(struct sir_dev *dev) } EXPORT_SYMBOL(sirdev_put_instance); +static int __init sir_wq_init(void) +{ + irda_sir_wq = create_singlethread_workqueue("irda_sir_wq"); + if (!irda_sir_wq) + return -ENOMEM; + return 0; +} + +static void __exit sir_wq_exit(void) +{ + destroy_workqueue(irda_sir_wq); +} + +module_init(sir_wq_init); +module_exit(sir_wq_exit); + +MODULE_AUTHOR("Martin Diehl "); +MODULE_DESCRIPTION("IrDA SIR core"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/irda/sir_kthread.c b/drivers/net/irda/sir_kthread.c deleted file mode 100644 index e3904d6bfecd..000000000000 --- a/drivers/net/irda/sir_kthread.c +++ /dev/null @@ -1,508 +0,0 @@ -/********************************************************************* - * - * sir_kthread.c: dedicated thread to process scheduled - * sir device setup requests - * - * Copyright (c) 2002 Martin Diehl - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - ********************************************************************/ - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "sir-dev.h" - -/************************************************************************** - * - * kIrDAd kernel thread and config state machine - * - */ - -struct irda_request_queue { - struct list_head request_list; - spinlock_t lock; - task_t *thread; - struct completion exit; - wait_queue_head_t kick, done; - atomic_t num_pending; -}; - -static struct irda_request_queue irda_rq_queue; - -static int irda_queue_request(struct irda_request *rq) -{ - int ret = 0; - unsigned long flags; - - if (!test_and_set_bit(0, &rq->pending)) { - spin_lock_irqsave(&irda_rq_queue.lock, flags); - list_add_tail(&rq->lh_request, &irda_rq_queue.request_list); - wake_up(&irda_rq_queue.kick); - atomic_inc(&irda_rq_queue.num_pending); - spin_unlock_irqrestore(&irda_rq_queue.lock, flags); - ret = 1; - } - return ret; -} - -static void irda_request_timer(unsigned long data) -{ - struct irda_request *rq = (struct irda_request *)data; - unsigned long flags; - - spin_lock_irqsave(&irda_rq_queue.lock, flags); - list_add_tail(&rq->lh_request, &irda_rq_queue.request_list); - wake_up(&irda_rq_queue.kick); - spin_unlock_irqrestore(&irda_rq_queue.lock, flags); -} - -static int irda_queue_delayed_request(struct irda_request *rq, unsigned long delay) -{ - int ret = 0; - struct timer_list *timer = &rq->timer; - - if (!test_and_set_bit(0, &rq->pending)) { - timer->expires = jiffies + delay; - timer->function = irda_request_timer; - timer->data = (unsigned long)rq; - atomic_inc(&irda_rq_queue.num_pending); - add_timer(timer); - ret = 1; - } - return ret; -} - -static void run_irda_queue(void) -{ - unsigned long flags; - struct list_head *entry, *tmp; - struct irda_request *rq; - - spin_lock_irqsave(&irda_rq_queue.lock, flags); - list_for_each_safe(entry, tmp, &irda_rq_queue.request_list) { - rq = list_entry(entry, struct irda_request, lh_request); - list_del_init(entry); - spin_unlock_irqrestore(&irda_rq_queue.lock, flags); - - clear_bit(0, &rq->pending); - rq->func(rq->data); - - if (atomic_dec_and_test(&irda_rq_queue.num_pending)) - wake_up(&irda_rq_queue.done); - - spin_lock_irqsave(&irda_rq_queue.lock, flags); - } - spin_unlock_irqrestore(&irda_rq_queue.lock, flags); -} - -static int irda_thread(void *startup) -{ - DECLARE_WAITQUEUE(wait, current); - - daemonize("kIrDAd"); - - irda_rq_queue.thread = current; - - complete((struct completion *)startup); - - while (irda_rq_queue.thread != NULL) { - - /* We use TASK_INTERRUPTIBLE, rather than - * TASK_UNINTERRUPTIBLE. Andrew Morton made this - * change ; he told me that it is safe, because "signal - * blocking is now handled in daemonize()", he added - * that the problem is that "uninterruptible sleep - * contributes to load average", making user worry. - * Jean II */ - set_task_state(current, TASK_INTERRUPTIBLE); - add_wait_queue(&irda_rq_queue.kick, &wait); - if (list_empty(&irda_rq_queue.request_list)) - schedule(); - else - __set_task_state(current, TASK_RUNNING); - remove_wait_queue(&irda_rq_queue.kick, &wait); - - /* make swsusp happy with our thread */ - try_to_freeze(); - - run_irda_queue(); - } - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,35) - reparent_to_init(); -#endif - complete_and_exit(&irda_rq_queue.exit, 0); - /* never reached */ - return 0; -} - - -static void flush_irda_queue(void) -{ - if (atomic_read(&irda_rq_queue.num_pending)) { - - DECLARE_WAITQUEUE(wait, current); - - if (!list_empty(&irda_rq_queue.request_list)) - run_irda_queue(); - - set_task_state(current, TASK_UNINTERRUPTIBLE); - add_wait_queue(&irda_rq_queue.done, &wait); - if (atomic_read(&irda_rq_queue.num_pending)) - schedule(); - else - __set_task_state(current, TASK_RUNNING); - remove_wait_queue(&irda_rq_queue.done, &wait); - } -} - -/* substate handler of the config-fsm to handle the cases where we want - * to wait for transmit completion before changing the port configuration - */ - -static int irda_tx_complete_fsm(struct sir_dev *dev) -{ - struct sir_fsm *fsm = &dev->fsm; - unsigned next_state, delay; - unsigned bytes_left; - - do { - next_state = fsm->substate; /* default: stay in current substate */ - delay = 0; - - switch(fsm->substate) { - - case SIRDEV_STATE_WAIT_XMIT: - if (dev->drv->chars_in_buffer) - bytes_left = dev->drv->chars_in_buffer(dev); - else - bytes_left = 0; - if (!bytes_left) { - next_state = SIRDEV_STATE_WAIT_UNTIL_SENT; - break; - } - - if (dev->speed > 115200) - delay = (bytes_left*8*10000) / (dev->speed/100); - else if (dev->speed > 0) - delay = (bytes_left*10*10000) / (dev->speed/100); - else - delay = 0; - /* expected delay (usec) until remaining bytes are sent */ - if (delay < 100) { - udelay(delay); - delay = 0; - break; - } - /* sleep some longer delay (msec) */ - delay = (delay+999) / 1000; - break; - - case SIRDEV_STATE_WAIT_UNTIL_SENT: - /* block until underlaying hardware buffer are empty */ - if (dev->drv->wait_until_sent) - dev->drv->wait_until_sent(dev); - next_state = SIRDEV_STATE_TX_DONE; - break; - - case SIRDEV_STATE_TX_DONE: - return 0; - - default: - IRDA_ERROR("%s - undefined state\n", __FUNCTION__); - return -EINVAL; - } - fsm->substate = next_state; - } while (delay == 0); - return delay; -} - -/* - * Function irda_config_fsm - * - * State machine to handle the configuration of the device (and attached dongle, if any). - * This handler is scheduled for execution in kIrDAd context, so we can sleep. - * however, kIrDAd is shared by all sir_dev devices so we better don't sleep there too - * long. Instead, for longer delays we start a timer to reschedule us later. - * On entry, fsm->sem is always locked and the netdev xmit queue stopped. - * Both must be unlocked/restarted on completion - but only on final exit. - */ - -static void irda_config_fsm(void *data) -{ - struct sir_dev *dev = data; - struct sir_fsm *fsm = &dev->fsm; - int next_state; - int ret = -1; - unsigned delay; - - IRDA_DEBUG(2, "%s(), <%ld>\n", __FUNCTION__, jiffies); - - do { - IRDA_DEBUG(3, "%s - state=0x%04x / substate=0x%04x\n", - __FUNCTION__, fsm->state, fsm->substate); - - next_state = fsm->state; - delay = 0; - - switch(fsm->state) { - - case SIRDEV_STATE_DONGLE_OPEN: - if (dev->dongle_drv != NULL) { - ret = sirdev_put_dongle(dev); - if (ret) { - fsm->result = -EINVAL; - next_state = SIRDEV_STATE_ERROR; - break; - } - } - - /* Initialize dongle */ - ret = sirdev_get_dongle(dev, fsm->param); - if (ret) { - fsm->result = ret; - next_state = SIRDEV_STATE_ERROR; - break; - } - - /* Dongles are powered through the modem control lines which - * were just set during open. Before resetting, let's wait for - * the power to stabilize. This is what some dongle drivers did - * in open before, while others didn't - should be safe anyway. - */ - - delay = 50; - fsm->substate = SIRDEV_STATE_DONGLE_RESET; - next_state = SIRDEV_STATE_DONGLE_RESET; - - fsm->param = 9600; - - break; - - case SIRDEV_STATE_DONGLE_CLOSE: - /* shouldn't we just treat this as success=? */ - if (dev->dongle_drv == NULL) { - fsm->result = -EINVAL; - next_state = SIRDEV_STATE_ERROR; - break; - } - - ret = sirdev_put_dongle(dev); - if (ret) { - fsm->result = ret; - next_state = SIRDEV_STATE_ERROR; - break; - } - next_state = SIRDEV_STATE_DONE; - break; - - case SIRDEV_STATE_SET_DTR_RTS: - ret = sirdev_set_dtr_rts(dev, - (fsm->param&0x02) ? TRUE : FALSE, - (fsm->param&0x01) ? TRUE : FALSE); - next_state = SIRDEV_STATE_DONE; - break; - - case SIRDEV_STATE_SET_SPEED: - fsm->substate = SIRDEV_STATE_WAIT_XMIT; - next_state = SIRDEV_STATE_DONGLE_CHECK; - break; - - case SIRDEV_STATE_DONGLE_CHECK: - ret = irda_tx_complete_fsm(dev); - if (ret < 0) { - fsm->result = ret; - next_state = SIRDEV_STATE_ERROR; - break; - } - if ((delay=ret) != 0) - break; - - if (dev->dongle_drv) { - fsm->substate = SIRDEV_STATE_DONGLE_RESET; - next_state = SIRDEV_STATE_DONGLE_RESET; - } - else { - dev->speed = fsm->param; - next_state = SIRDEV_STATE_PORT_SPEED; - } - break; - - case SIRDEV_STATE_DONGLE_RESET: - if (dev->dongle_drv->reset) { - ret = dev->dongle_drv->reset(dev); - if (ret < 0) { - fsm->result = ret; - next_state = SIRDEV_STATE_ERROR; - break; - } - } - else - ret = 0; - if ((delay=ret) == 0) { - /* set serial port according to dongle default speed */ - if (dev->drv->set_speed) - dev->drv->set_speed(dev, dev->speed); - fsm->substate = SIRDEV_STATE_DONGLE_SPEED; - next_state = SIRDEV_STATE_DONGLE_SPEED; - } - break; - - case SIRDEV_STATE_DONGLE_SPEED: - if (dev->dongle_drv->reset) { - ret = dev->dongle_drv->set_speed(dev, fsm->param); - if (ret < 0) { - fsm->result = ret; - next_state = SIRDEV_STATE_ERROR; - break; - } - } - else - ret = 0; - if ((delay=ret) == 0) - next_state = SIRDEV_STATE_PORT_SPEED; - break; - - case SIRDEV_STATE_PORT_SPEED: - /* Finally we are ready to change the serial port speed */ - if (dev->drv->set_speed) - dev->drv->set_speed(dev, dev->speed); - dev->new_speed = 0; - next_state = SIRDEV_STATE_DONE; - break; - - case SIRDEV_STATE_DONE: - /* Signal network layer so it can send more frames */ - netif_wake_queue(dev->netdev); - next_state = SIRDEV_STATE_COMPLETE; - break; - - default: - IRDA_ERROR("%s - undefined state\n", __FUNCTION__); - fsm->result = -EINVAL; - /* fall thru */ - - case SIRDEV_STATE_ERROR: - IRDA_ERROR("%s - error: %d\n", __FUNCTION__, fsm->result); - -#if 0 /* don't enable this before we have netdev->tx_timeout to recover */ - netif_stop_queue(dev->netdev); -#else - netif_wake_queue(dev->netdev); -#endif - /* fall thru */ - - case SIRDEV_STATE_COMPLETE: - /* config change finished, so we are not busy any longer */ - sirdev_enable_rx(dev); - up(&fsm->sem); - return; - } - fsm->state = next_state; - } while(!delay); - - irda_queue_delayed_request(&fsm->rq, msecs_to_jiffies(delay)); -} - -/* schedule some device configuration task for execution by kIrDAd - * on behalf of the above state machine. - * can be called from process or interrupt/tasklet context. - */ - -int sirdev_schedule_request(struct sir_dev *dev, int initial_state, unsigned param) -{ - struct sir_fsm *fsm = &dev->fsm; - int xmit_was_down; - - IRDA_DEBUG(2, "%s - state=0x%04x / param=%u\n", __FUNCTION__, initial_state, param); - - if (down_trylock(&fsm->sem)) { - if (in_interrupt() || in_atomic() || irqs_disabled()) { - IRDA_DEBUG(1, "%s(), state machine busy!\n", __FUNCTION__); - return -EWOULDBLOCK; - } else - down(&fsm->sem); - } - - if (fsm->state == SIRDEV_STATE_DEAD) { - /* race with sirdev_close should never happen */ - IRDA_ERROR("%s(), instance staled!\n", __FUNCTION__); - up(&fsm->sem); - return -ESTALE; /* or better EPIPE? */ - } - - xmit_was_down = netif_queue_stopped(dev->netdev); - netif_stop_queue(dev->netdev); - atomic_set(&dev->enable_rx, 0); - - fsm->state = initial_state; - fsm->param = param; - fsm->result = 0; - - INIT_LIST_HEAD(&fsm->rq.lh_request); - fsm->rq.pending = 0; - fsm->rq.func = irda_config_fsm; - fsm->rq.data = dev; - - if (!irda_queue_request(&fsm->rq)) { /* returns 0 on error! */ - atomic_set(&dev->enable_rx, 1); - if (!xmit_was_down) - netif_wake_queue(dev->netdev); - up(&fsm->sem); - return -EAGAIN; - } - return 0; -} - -static int __init irda_thread_create(void) -{ - struct completion startup; - int pid; - - spin_lock_init(&irda_rq_queue.lock); - irda_rq_queue.thread = NULL; - INIT_LIST_HEAD(&irda_rq_queue.request_list); - init_waitqueue_head(&irda_rq_queue.kick); - init_waitqueue_head(&irda_rq_queue.done); - atomic_set(&irda_rq_queue.num_pending, 0); - - init_completion(&startup); - pid = kernel_thread(irda_thread, &startup, CLONE_FS|CLONE_FILES); - if (pid <= 0) - return -EAGAIN; - else - wait_for_completion(&startup); - - return 0; -} - -static void __exit irda_thread_join(void) -{ - if (irda_rq_queue.thread) { - flush_irda_queue(); - init_completion(&irda_rq_queue.exit); - irda_rq_queue.thread = NULL; - wake_up(&irda_rq_queue.kick); - wait_for_completion(&irda_rq_queue.exit); - } -} - -module_init(irda_thread_create); -module_exit(irda_thread_join); - -MODULE_AUTHOR("Martin Diehl "); -MODULE_DESCRIPTION("IrDA SIR core"); -MODULE_LICENSE("GPL"); - -- cgit v1.2.3-70-g09d2 From 8c1056839e808aad728db86d739ffec71d2d1db8 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 9 May 2006 15:27:54 -0700 Subject: [NET] linkwatch: Handle jiffies wrap-around The test used in the linkwatch does not handle wrap-arounds correctly. Since the intention of the code is to eliminate bursts of messages we can afford to delay things up to a second. Using that fact we can easily handle wrap-arounds by making sure that we don't delay things by more than one second. This is based on diagnosis and a patch by Stefan Rompf. Signed-off-by: Herbert Xu Acked-by: Stefan Rompf Signed-off-by: David S. Miller --- net/core/link_watch.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/net/core/link_watch.c b/net/core/link_watch.c index 341de44c7ed1..646937cc2d84 100644 --- a/net/core/link_watch.c +++ b/net/core/link_watch.c @@ -170,13 +170,13 @@ void linkwatch_fire_event(struct net_device *dev) spin_unlock_irqrestore(&lweventlist_lock, flags); if (!test_and_set_bit(LW_RUNNING, &linkwatch_flags)) { - unsigned long thisevent = jiffies; + unsigned long delay = linkwatch_nextevent - jiffies; - if (thisevent >= linkwatch_nextevent) { + /* If we wrap around we'll delay it by at most HZ. */ + if (!delay || delay > HZ) schedule_work(&linkwatch_work); - } else { - schedule_delayed_work(&linkwatch_work, linkwatch_nextevent - thisevent); - } + else + schedule_delayed_work(&linkwatch_work, delay); } } } -- cgit v1.2.3-70-g09d2 From 5941d079f2c3bdf0dffed1afb8941678fcd0bcb7 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 May 2006 22:54:59 -0700 Subject: IPoIB: Free child interfaces properly When deleting a child interface with a non-default P_Key via /sys/class/net/ibX/delete_child, the interface must be freed with free_netdev() (rather than kfree() on the private data). Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/ipoib/ipoib_vlan.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c index 4ca175553f9f..f887780e8093 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c @@ -158,10 +158,8 @@ int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey) if (priv->pkey == pkey) { unregister_netdev(priv->dev); ipoib_dev_cleanup(priv->dev); - list_del(&priv->list); - - kfree(priv); + free_netdev(priv->dev); ret = 0; break; -- cgit v1.2.3-70-g09d2 From a50bb7b9af9a7c39b2aba15678eb686ae428718c Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Tue, 9 May 2006 23:14:35 -0700 Subject: [TG3]: Fix possible NULL deref in tg3_run_loopback(). tg3_run_loopback doesn't check that dev_alloc_skb() returns anything useful. Even if dev_alloc_skb() fails to return an skb to us we'll happily go on and assume it did, so we risk dereferencing a NULL pointer. Much better to fail gracefully by returning -ENOMEM than crashing here. Signed-off-by: Jesper Juhl Signed-off-by: David S. Miller --- drivers/net/tg3.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index beeb612be98f..2bd9592b75cd 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -8454,6 +8454,9 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) tx_len = 1514; skb = dev_alloc_skb(tx_len); + if (!skb) + return -ENOMEM; + tx_data = skb_put(skb, tx_len); memcpy(tx_data, tp->dev->dev_addr, 6); memset(tx_data + 6, 0x0, 8); -- cgit v1.2.3-70-g09d2 From 6dd727da92290193d0f74fa39f3ad53f423524db Mon Sep 17 00:00:00 2001 From: "mdr@sgi.com" Date: Mon, 1 May 2006 13:07:04 -0500 Subject: [SCSI] mptfc: race between mptfc_register_dev and mptfc_target_alloc A race condition exists in mptfc between the thread registering a device with the fc transport and the scan work generated by the transport. This race existed prior to the application of the mptfc bug fix patch. mptfc_register_dev() calls fc_remote_port_add() with the FC_RPORT_ROLE_TARGET bit set in the rport ids passed to the function. Having this bit set causes fc_remote_port_add() to schedule a scan of the device. This scan can execute before mptfc_register_dev() can fill in the dd_data in the rport structure. When this happens, mptfc_target_alloc() will fail because dd_data is null. Attached is a patch which fixes the problem. The patch changes the rport ids passed to fc_remote_port_add() to not have the TARGET bit set. This prevents the scan from being scheduled. After mptfc_register_dev() fills in the rport dd_data field, fc_remote_port_rolechg() is called, changing the role of the rport to TARGET. Thus, the scan is scheduled after dd_data is filled in which prevents the failure in mptfc_target_alloc(). Signed-off-by: Michael Reed Signed-off-by: Eric Moore Signed-off-by: James Bottomley --- drivers/message/fusion/mptfc.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c index e1fb5a166366..856487741ef4 100644 --- a/drivers/message/fusion/mptfc.c +++ b/drivers/message/fusion/mptfc.c @@ -341,9 +341,6 @@ mptfc_generate_rport_ids(FCDevicePage0_t *pg0, struct fc_rport_identifiers *rid) rid->port_name = ((u64)pg0->WWPN.High) << 32 | (u64)pg0->WWPN.Low; rid->port_id = pg0->PortIdentifier; rid->roles = FC_RPORT_ROLE_UNKNOWN; - rid->roles |= FC_RPORT_ROLE_FCP_TARGET; - if (pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR) - rid->roles |= FC_RPORT_ROLE_FCP_INITIATOR; return 0; } @@ -357,10 +354,15 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0) int new_ri = 1; u64 pn, nn; VirtTarget *vtarget; + u32 roles = FC_RPORT_ROLE_UNKNOWN; if (mptfc_generate_rport_ids(pg0, &rport_ids) < 0) return; + roles |= FC_RPORT_ROLE_FCP_TARGET; + if (pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR) + roles |= FC_RPORT_ROLE_FCP_INITIATOR; + /* scan list looking for a match */ list_for_each_entry(ri, &ioc->fc_rports, list) { pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low; @@ -400,8 +402,9 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0) vtarget->bus_id = pg0->CurrentBus; } } - /* once dd_data is filled in, commands will issue to hardware */ *((struct mptfc_rport_info **)rport->dd_data) = ri; + /* scan will be scheduled once rport becomes a target */ + fc_remote_port_rolechg(rport,roles); pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low; nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low; -- cgit v1.2.3-70-g09d2 From b17a7c179dd3ce7d04373fddf660eda21efc9db9 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 10 May 2006 13:21:17 -0700 Subject: [NET]: Do sysfs registration as part of register_netdevice. The last step of netdevice registration was being done by a delayed call, but because it was delayed, it was impossible to return any error code if the class_device registration failed. Side effects: * one state in registration process is unnecessary. * register_netdevice can sleep inside class_device registration/hotplug * code in netdev_run_todo only does unregistration so it is simpler. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- include/linux/netdevice.h | 3 +-- net/core/dev.c | 63 ++++++++++++++++++++--------------------------- 2 files changed, 28 insertions(+), 38 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index a461b51d6076..f4169bbb60eb 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -433,8 +433,7 @@ struct net_device /* register/unregister state machine */ enum { NETREG_UNINITIALIZED=0, - NETREG_REGISTERING, /* called register_netdevice */ - NETREG_REGISTERED, /* completed register todo */ + NETREG_REGISTERED, /* completed register_netdevice */ NETREG_UNREGISTERING, /* called unregister_netdevice */ NETREG_UNREGISTERED, /* completed unregister todo */ NETREG_RELEASED, /* called free_netdev */ diff --git a/net/core/dev.c b/net/core/dev.c index ced57430f6d8..2dce673a039b 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2777,6 +2777,8 @@ int register_netdevice(struct net_device *dev) BUG_ON(dev_boot_phase); ASSERT_RTNL(); + might_sleep(); + /* When net_device's are persistent, this will be fatal. */ BUG_ON(dev->reg_state != NETREG_UNINITIALIZED); @@ -2863,6 +2865,11 @@ int register_netdevice(struct net_device *dev) if (!dev->rebuild_header) dev->rebuild_header = default_rebuild_header; + ret = netdev_register_sysfs(dev); + if (ret) + goto out_err; + dev->reg_state = NETREG_REGISTERED; + /* * Default initial state at registry is that the * device is present. @@ -2878,14 +2885,11 @@ int register_netdevice(struct net_device *dev) hlist_add_head(&dev->name_hlist, head); hlist_add_head(&dev->index_hlist, dev_index_hash(dev->ifindex)); dev_hold(dev); - dev->reg_state = NETREG_REGISTERING; write_unlock_bh(&dev_base_lock); /* Notify protocols, that a new device appeared. */ raw_notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev); - /* Finish registration after unlock */ - net_set_todo(dev); ret = 0; out: @@ -3008,7 +3012,7 @@ static void netdev_wait_allrefs(struct net_device *dev) * * We are invoked by rtnl_unlock() after it drops the semaphore. * This allows us to deal with problems: - * 1) We can create/delete sysfs objects which invoke hotplug + * 1) We can delete sysfs objects which invoke hotplug * without deadlocking with linkwatch via keventd. * 2) Since we run with the RTNL semaphore not held, we can sleep * safely in order to wait for the netdev refcnt to drop to zero. @@ -3017,8 +3021,6 @@ static DEFINE_MUTEX(net_todo_run_mutex); void netdev_run_todo(void) { struct list_head list = LIST_HEAD_INIT(list); - int err; - /* Need to guard against multiple cpu's getting out of order. */ mutex_lock(&net_todo_run_mutex); @@ -3041,40 +3043,29 @@ void netdev_run_todo(void) = list_entry(list.next, struct net_device, todo_list); list_del(&dev->todo_list); - switch(dev->reg_state) { - case NETREG_REGISTERING: - err = netdev_register_sysfs(dev); - if (err) - printk(KERN_ERR "%s: failed sysfs registration (%d)\n", - dev->name, err); - dev->reg_state = NETREG_REGISTERED; - break; - - case NETREG_UNREGISTERING: - netdev_unregister_sysfs(dev); - dev->reg_state = NETREG_UNREGISTERED; - - netdev_wait_allrefs(dev); + if (unlikely(dev->reg_state != NETREG_UNREGISTERING)) { + printk(KERN_ERR "network todo '%s' but state %d\n", + dev->name, dev->reg_state); + dump_stack(); + continue; + } - /* paranoia */ - BUG_ON(atomic_read(&dev->refcnt)); - BUG_TRAP(!dev->ip_ptr); - BUG_TRAP(!dev->ip6_ptr); - BUG_TRAP(!dev->dn_ptr); + netdev_unregister_sysfs(dev); + dev->reg_state = NETREG_UNREGISTERED; + netdev_wait_allrefs(dev); - /* It must be the very last action, - * after this 'dev' may point to freed up memory. - */ - if (dev->destructor) - dev->destructor(dev); - break; + /* paranoia */ + BUG_ON(atomic_read(&dev->refcnt)); + BUG_TRAP(!dev->ip_ptr); + BUG_TRAP(!dev->ip6_ptr); + BUG_TRAP(!dev->dn_ptr); - default: - printk(KERN_ERR "network todo '%s' but state %d\n", - dev->name, dev->reg_state); - break; - } + /* It must be the very last action, + * after this 'dev' may point to freed up memory. + */ + if (dev->destructor) + dev->destructor(dev); } out: -- cgit v1.2.3-70-g09d2 From ac05202e8b83594bf6797d241371e6c752f371e6 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 10 May 2006 13:21:53 -0700 Subject: [BRIDGE]: Do sysfs registration inside rtnl. Now that netdevice sysfs registration is done as part of register_netdevice; bridge code no longer has to be tricky when adding it's kobjects to bridges. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/bridge/br_if.c | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 59eef42d4a42..ad1c7af65ec8 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -308,26 +308,19 @@ int br_add_bridge(const char *name) if (ret) goto err2; - /* network device kobject is not setup until - * after rtnl_unlock does it's hotplug magic. - * so hold reference to avoid race. - */ - dev_hold(dev); - rtnl_unlock(); - ret = br_sysfs_addbr(dev); - dev_put(dev); - - if (ret) - unregister_netdev(dev); - out: - return ret; + if (ret) + goto err3; + rtnl_unlock(); + return 0; + err3: + unregister_netdev(dev); err2: free_netdev(dev); err1: rtnl_unlock(); - goto out; + return ret; } int br_del_bridge(const char *name) -- cgit v1.2.3-70-g09d2 From b0013fd47b14fc26eec07a6b2cec0c2a8954e1d7 Mon Sep 17 00:00:00 2001 From: Alexey Kuznetsov Date: Wed, 10 May 2006 13:24:38 -0700 Subject: [IPV6]: skb leakage in inet6_csk_xmit inet6_csk_xit does not free skb when routing fails. Signed-off-by: Alexey Kuznetsov Signed-off-by: David S. Miller --- net/ipv6/inet6_connection_sock.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c index f8f3a37a1494..eb2865d5ae28 100644 --- a/net/ipv6/inet6_connection_sock.c +++ b/net/ipv6/inet6_connection_sock.c @@ -173,6 +173,7 @@ int inet6_csk_xmit(struct sk_buff *skb, int ipfragok) if (err) { sk->sk_err_soft = -err; + kfree_skb(skb); return err; } @@ -181,6 +182,7 @@ int inet6_csk_xmit(struct sk_buff *skb, int ipfragok) if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) { sk->sk_route_caps = 0; + kfree_skb(skb); return err; } -- cgit v1.2.3-70-g09d2 From 7fc5b1e3a170d865f625e609c087cf8d84fd285d Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 10 May 2006 13:28:52 +0200 Subject: [Cardman 40x0] Fix udev device creation This patch corrects the order of the calls to register_chrdev() and pcmcia_register_driver(). Now udev correctly creates userspace device files /dev/cmmN and /dev/cmxN respectively. Based on an earlier patch by Jan Niehusmann . Signed-off-by: Harald Welte Signed-off-by: Linus Torvalds --- drivers/char/pcmcia/cm4000_cs.c | 10 ++++++---- drivers/char/pcmcia/cm4040_cs.c | 11 +++++++---- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c index 02114a0bd0d9..128b2632512d 100644 --- a/drivers/char/pcmcia/cm4000_cs.c +++ b/drivers/char/pcmcia/cm4000_cs.c @@ -1981,10 +1981,6 @@ static int __init cmm_init(void) if (!cmm_class) return -1; - rc = pcmcia_register_driver(&cm4000_driver); - if (rc < 0) - return rc; - major = register_chrdev(0, DEVICE_NAME, &cm4000_fops); if (major < 0) { printk(KERN_WARNING MODULE_NAME @@ -1992,6 +1988,12 @@ static int __init cmm_init(void) return -1; } + rc = pcmcia_register_driver(&cm4000_driver); + if (rc < 0) { + unregister_chrdev(major, DEVICE_NAME); + return rc; + } + return 0; } diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c index 29efa64580a8..47a8465bf95b 100644 --- a/drivers/char/pcmcia/cm4040_cs.c +++ b/drivers/char/pcmcia/cm4040_cs.c @@ -724,16 +724,19 @@ static int __init cm4040_init(void) if (!cmx_class) return -1; - rc = pcmcia_register_driver(&reader_driver); - if (rc < 0) - return rc; - major = register_chrdev(0, DEVICE_NAME, &reader_fops); if (major < 0) { printk(KERN_WARNING MODULE_NAME ": could not get major number\n"); return -1; } + + rc = pcmcia_register_driver(&reader_driver); + if (rc < 0) { + unregister_chrdev(major, DEVICE_NAME); + return rc; + } + return 0; } -- cgit v1.2.3-70-g09d2 From f4ea431bb7c4856b930eafca6eb1fb474dae9b40 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 9 May 2006 14:46:54 -0700 Subject: sky2: ifdown kills irq mask Bringing down a port also masks off the status and other IRQ's needed for device to function due to missing paren's. Signed-off-by: Stephen Hemminger --- drivers/net/sky2.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 227df9876a2c..27da9b75dedc 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -122,6 +122,7 @@ MODULE_DEVICE_TABLE(pci, sky2_id_table); /* Avoid conditionals by using array */ static const unsigned txqaddr[] = { Q_XA1, Q_XA2 }; static const unsigned rxqaddr[] = { Q_R1, Q_R2 }; +static const u32 portirq_msk[] = { Y2_IS_PORT_1, Y2_IS_PORT_2 }; /* This driver supports yukon2 chipset only */ static const char *yukon2_name[] = { @@ -1050,7 +1051,7 @@ static int sky2_up(struct net_device *dev) /* Enable interrupts from phy/mac for port */ imask = sky2_read32(hw, B0_IMSK); - imask |= (port == 0) ? Y2_IS_PORT_1 : Y2_IS_PORT_2; + imask |= portirq_msk[port]; sky2_write32(hw, B0_IMSK, imask); return 0; @@ -1401,7 +1402,7 @@ static int sky2_down(struct net_device *dev) /* Disable port IRQ */ imask = sky2_read32(hw, B0_IMSK); - imask &= ~(sky2->port == 0) ? Y2_IS_PORT_1 : Y2_IS_PORT_2; + imask &= ~portirq_msk[port]; sky2_write32(hw, B0_IMSK, imask); /* turn off LED's */ -- cgit v1.2.3-70-g09d2 From 64b1c2b42b555ef38c475d104f2faf3f6f93690d Mon Sep 17 00:00:00 2001 From: Herbert Valerio Riedel Date: Wed, 10 May 2006 12:12:57 -0400 Subject: phy: mdiobus_register(): initialize all phy_map entries make sure phy_map entries whose PHY address is masked are initialized to NULL, given that other code (such as mdiobus_unregister for instance) assumes that non-NULL phy_map entries are allocated phy_devices Signed-off-by: Herbert Valerio Riedel Signed-off-by: Stephen Hemminger --- drivers/net/phy/mdio_bus.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 459443b572ce..1b236bdf6b92 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -60,8 +60,10 @@ int mdiobus_register(struct mii_bus *bus) for (i = 0; i < PHY_MAX_ADDR; i++) { struct phy_device *phydev; - if (bus->phy_mask & (1 << i)) + if (bus->phy_mask & (1 << i)) { + bus->phy_map[i] = NULL; continue; + } phydev = get_phy_device(bus, i); -- cgit v1.2.3-70-g09d2 From 4c1b46226ce4424a93b8ac544e37afb26c8a72c6 Mon Sep 17 00:00:00 2001 From: Francois Romieu Date: Wed, 10 May 2006 12:48:57 -0700 Subject: dl2k: use DMA_48BIT_MASK constant Typo will be harder with this one. Signed-off-by: Francois Romieu Signed-off-by: Stephen Hemminger --- drivers/net/dl2k.c | 12 ++++++------ include/linux/dma-mapping.h | 1 + 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c index 1f3627470c95..1ddefd281213 100644 --- a/drivers/net/dl2k.c +++ b/drivers/net/dl2k.c @@ -765,7 +765,7 @@ rio_free_tx (struct net_device *dev, int irq) break; skb = np->tx_skbuff[entry]; pci_unmap_single (np->pdev, - np->tx_ring[entry].fraginfo & 0xffffffffffff, + np->tx_ring[entry].fraginfo & DMA_48BIT_MASK, skb->len, PCI_DMA_TODEVICE); if (irq) dev_kfree_skb_irq (skb); @@ -893,7 +893,7 @@ receive_packet (struct net_device *dev) /* Small skbuffs for short packets */ if (pkt_len > copy_thresh) { pci_unmap_single (np->pdev, - desc->fraginfo & 0xffffffffffff, + desc->fraginfo & DMA_48BIT_MASK, np->rx_buf_sz, PCI_DMA_FROMDEVICE); skb_put (skb = np->rx_skbuff[entry], pkt_len); @@ -901,7 +901,7 @@ receive_packet (struct net_device *dev) } else if ((skb = dev_alloc_skb (pkt_len + 2)) != NULL) { pci_dma_sync_single_for_cpu(np->pdev, desc->fraginfo & - 0xffffffffffff, + DMA_48BIT_MASK, np->rx_buf_sz, PCI_DMA_FROMDEVICE); skb->dev = dev; @@ -913,7 +913,7 @@ receive_packet (struct net_device *dev) skb_put (skb, pkt_len); pci_dma_sync_single_for_device(np->pdev, desc->fraginfo & - 0xffffffffffff, + DMA_48BIT_MASK, np->rx_buf_sz, PCI_DMA_FROMDEVICE); } @@ -1800,7 +1800,7 @@ rio_close (struct net_device *dev) skb = np->rx_skbuff[i]; if (skb) { pci_unmap_single(np->pdev, - np->rx_ring[i].fraginfo & 0xffffffffffff, + np->rx_ring[i].fraginfo & DMA_48BIT_MASK, skb->len, PCI_DMA_FROMDEVICE); dev_kfree_skb (skb); np->rx_skbuff[i] = NULL; @@ -1810,7 +1810,7 @@ rio_close (struct net_device *dev) skb = np->tx_skbuff[i]; if (skb) { pci_unmap_single(np->pdev, - np->tx_ring[i].fraginfo & 0xffffffffffff, + np->tx_ring[i].fraginfo & DMA_48BIT_MASK, skb->len, PCI_DMA_TODEVICE); dev_kfree_skb (skb); np->tx_skbuff[i] = NULL; diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h index ff61817082fa..635690cf3e3d 100644 --- a/include/linux/dma-mapping.h +++ b/include/linux/dma-mapping.h @@ -14,6 +14,7 @@ enum dma_data_direction { }; #define DMA_64BIT_MASK 0xffffffffffffffffULL +#define DMA_48BIT_MASK 0x0000ffffffffffffULL #define DMA_40BIT_MASK 0x000000ffffffffffULL #define DMA_39BIT_MASK 0x0000007fffffffffULL #define DMA_32BIT_MASK 0x00000000ffffffffULL -- cgit v1.2.3-70-g09d2 From d8e95e52a9db0e26b37f51ab5140b89da7c4b31e Mon Sep 17 00:00:00 2001 From: James Cameron Date: Wed, 10 May 2006 13:33:29 -0700 Subject: sis900: phy for FoxCon motherboard 661FX7MI-S motherboard which uses the SiS 661FX chipset. The patch adds an entry to mii_chip_info for the transceiver. The PHY ids were found using the sis900_c_122.diff patch from http://brownhat.org/sis900.html but that patch didn't solve the problem, because the PHY at address 1 was already being chosen. Without my patch, when bursts of packets arrive from other hosts on a LAN, the interface dropped one roughly 10% of the time, causing retransmits. There were fifth second pauses in refresh of large xterms, and it made Netrek suck. I can provide further test data. Workaround in lieu of patch is to use mii-tool to advertise 100baseTx-HD, then force renegotiation. I wasn't able to identify the actual transceiver, so the description field is a guess. This patch is similar to Artur Skawina's patch: http://marc.theaimsgroup.com/?l=linux-netdev&m=114297516729079&w=2 I'm not sure, but I wonder if it means the default behaviour should be changed, so as to better handle future transceivers. Diff is against 2.6.16.13. Signed-off-by: James Cameron Signed-off-by: Stephen Hemminger --- drivers/net/sis900.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index b82191d2bee1..f5a3bf4d959a 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -127,6 +127,7 @@ static const struct mii_chip_info { } mii_chip_table[] = { { "SiS 900 Internal MII PHY", 0x001d, 0x8000, LAN }, { "SiS 7014 Physical Layer Solution", 0x0016, 0xf830, LAN }, + { "SiS 900 on Foxconn 661 7MI", 0x0143, 0xBC70, LAN }, { "Altimata AC101LF PHY", 0x0022, 0x5520, LAN }, { "ADM 7001 LAN PHY", 0x002e, 0xcc60, LAN }, { "AMD 79C901 10BASE-T PHY", 0x0000, 0x6B70, LAN }, -- cgit v1.2.3-70-g09d2 From ce477ae4f8c75c94587c3157deffad8219db09a0 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Wed, 10 May 2006 17:58:41 +0300 Subject: IB/mthca: FMR ioremap fix Addresses for ioremap must be calculated off of pci_resource_start; we can't directly use the bus address as seen by the HCA. Fix the code that remaps device memory for FMR access. Based on patch by Klaus Smolin. Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_mr.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/hw/mthca/mthca_mr.c b/drivers/infiniband/hw/mthca/mthca_mr.c index 25e1c1db9a40..a486dec1707e 100644 --- a/drivers/infiniband/hw/mthca/mthca_mr.c +++ b/drivers/infiniband/hw/mthca/mthca_mr.c @@ -761,6 +761,7 @@ void mthca_arbel_fmr_unmap(struct mthca_dev *dev, struct mthca_fmr *fmr) int __devinit mthca_init_mr_table(struct mthca_dev *dev) { + unsigned long addr; int err, i; err = mthca_alloc_init(&dev->mr_table.mpt_alloc, @@ -796,9 +797,12 @@ int __devinit mthca_init_mr_table(struct mthca_dev *dev) goto err_fmr_mpt; } + addr = pci_resource_start(dev->pdev, 4) + + ((pci_resource_len(dev->pdev, 4) - 1) & + dev->mr_table.mpt_base); + dev->mr_table.tavor_fmr.mpt_base = - ioremap(dev->mr_table.mpt_base, - (1 << i) * sizeof (struct mthca_mpt_entry)); + ioremap(addr, (1 << i) * sizeof(struct mthca_mpt_entry)); if (!dev->mr_table.tavor_fmr.mpt_base) { mthca_warn(dev, "MPT ioremap for FMR failed.\n"); @@ -806,9 +810,12 @@ int __devinit mthca_init_mr_table(struct mthca_dev *dev) goto err_fmr_mpt; } + addr = pci_resource_start(dev->pdev, 4) + + ((pci_resource_len(dev->pdev, 4) - 1) & + dev->mr_table.mtt_base); + dev->mr_table.tavor_fmr.mtt_base = - ioremap(dev->mr_table.mtt_base, - (1 << i) * MTHCA_MTT_SEG_SIZE); + ioremap(addr, (1 << i) * MTHCA_MTT_SEG_SIZE); if (!dev->mr_table.tavor_fmr.mtt_base) { mthca_warn(dev, "MTT ioremap for FMR failed.\n"); err = -ENOMEM; -- cgit v1.2.3-70-g09d2 From f358166a9405e4f1d8e50d8f415c26d95505b6de Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 11 May 2006 11:08:49 -0700 Subject: ptrace_attach: fix possible deadlock schenario with irqs Eric Biederman points out that we can't take the task_lock while holding tasklist_lock for writing, because another CPU that holds the task lock might take an interrupt that then tries to take tasklist_lock for writing. Which would be a nasty deadlock, with one CPU spinning forever in an interrupt handler (although admittedly you need to really work at triggering it ;) Since the ptrace_attach() code is special and very unusual, just make it be extra careful, and use trylock+repeat to avoid the possible deadlock. Cc: Oleg Nesterov Cc: Eric W. Biederman Cc: Roland McGrath Signed-off-by: Linus Torvalds --- kernel/ptrace.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/kernel/ptrace.c b/kernel/ptrace.c index b0f8da80d7d4..921c22ad16e4 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -155,8 +155,26 @@ int ptrace_attach(struct task_struct *task) if (task->tgid == current->tgid) goto out; - write_lock_irq(&tasklist_lock); +repeat: + /* + * Nasty, nasty. + * + * We want to hold both the task-lock and the + * tasklist_lock for writing at the same time. + * But that's against the rules (tasklist_lock + * is taken for reading by interrupts on other + * cpu's that may have task_lock). + */ task_lock(task); + local_irq_disable(); + if (!write_trylock(&tasklist_lock)) { + local_irq_enable(); + task_unlock(task); + do { + cpu_relax(); + } while (!write_can_lock(&tasklist_lock)); + goto repeat; + } /* the same process cannot be attached many times */ if (task->ptrace & PT_PTRACED) -- cgit v1.2.3-70-g09d2 From 210525d65d33d17eb6bea6c965ce442d60d9aa8d Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 11 May 2006 12:22:03 -0700 Subject: [NET_SCHED]: HFSC: fix thinko in hfsc_adjust_levels() When deleting the last child the level of a class should drop to zero. Noticed by Andreas Mueller Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/sched/sch_hfsc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c index 91132f6871d7..f1c7bd29f2cd 100644 --- a/net/sched/sch_hfsc.c +++ b/net/sched/sch_hfsc.c @@ -974,10 +974,10 @@ hfsc_adjust_levels(struct hfsc_class *cl) do { level = 0; list_for_each_entry(p, &cl->children, siblings) { - if (p->level > level) - level = p->level; + if (p->level >= level) + level = p->level + 1; } - cl->level = level + 1; + cl->level = level; } while ((cl = cl->cl_parent) != NULL); } -- cgit v1.2.3-70-g09d2 From dac07ec121de66b6be988b14ae2cd9ce45357b21 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 11 May 2006 08:20:16 +0200 Subject: [BLOCK] limit request_fn recursion Don't recurse back into the driver even if the unplug threshold is met, when the driver asks for a requeue. This is both silly from a logical point of view (requeues typically happen due to driver/hardware shortage), and also dangerous since we could hit an endless request_fn -> requeue -> unplug -> request_fn loop and crash on stack overrun. Also limit blk_run_queue() to one level of recursion, similar to how blk_start_queue() works. This patch fixed a real problem with SLES10 and lpfc, and it could hit any SCSI lld that returns non-zero from it's ->queuecommand() handler. Signed-off-by: Jens Axboe Signed-off-by: Linus Torvalds --- block/elevator.c | 8 +++++++- block/ll_rw_blk.c | 17 +++++++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/block/elevator.c b/block/elevator.c index 29825792cbd5..8768a367fdde 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -333,6 +333,7 @@ void elv_insert(request_queue_t *q, struct request *rq, int where) { struct list_head *pos; unsigned ordseq; + int unplug_it = 1; blk_add_trace_rq(q, rq, BLK_TA_INSERT); @@ -399,6 +400,11 @@ void elv_insert(request_queue_t *q, struct request *rq, int where) } list_add_tail(&rq->queuelist, pos); + /* + * most requeues happen because of a busy condition, don't + * force unplug of the queue for that case. + */ + unplug_it = 0; break; default: @@ -407,7 +413,7 @@ void elv_insert(request_queue_t *q, struct request *rq, int where) BUG(); } - if (blk_queue_plugged(q)) { + if (unplug_it && blk_queue_plugged(q)) { int nrq = q->rq.count[READ] + q->rq.count[WRITE] - q->in_flight; diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index e5041a02e21f..eac48bec1479 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -1732,8 +1732,21 @@ void blk_run_queue(struct request_queue *q) spin_lock_irqsave(q->queue_lock, flags); blk_remove_plug(q); - if (!elv_queue_empty(q)) - q->request_fn(q); + + /* + * Only recurse once to avoid overrunning the stack, let the unplug + * handling reinvoke the handler shortly if we already got there. + */ + if (!elv_queue_empty(q)) { + if (!test_and_set_bit(QUEUE_FLAG_REENTER, &q->queue_flags)) { + q->request_fn(q); + clear_bit(QUEUE_FLAG_REENTER, &q->queue_flags); + } else { + blk_plug_device(q); + kblockd_schedule_work(&q->unplug_work); + } + } + spin_unlock_irqrestore(q->queue_lock, flags); } EXPORT_SYMBOL(blk_run_queue); -- cgit v1.2.3-70-g09d2 From d8c3291c73b958243b33f8509d4507e76dafd055 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 11 May 2006 16:31:53 -0700 Subject: Linux v2.6.17-rc4 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 9e4c5692a32f..3494c17c9fb9 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 17 -EXTRAVERSION =-rc3 +EXTRAVERSION =-rc4 NAME=Sliding Snow Leopard # *DOCUMENTATION* -- cgit v1.2.3-70-g09d2 From b68f7de02ae380ddb4e5e457e3fe945ddfd0aa08 Mon Sep 17 00:00:00 2001 From: Ken Brush Date: Mon, 8 May 2006 20:24:12 -0500 Subject: [PATCH] USB: Add Sieraa Wireless 580 evdo card to airprime.c This adds the Sierra Wireless card to airprime.c. I tested this on my laptop. Signed-off-by: Ken Brush Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/airprime.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c index dbf1f063098c..694b205f9b73 100644 --- a/drivers/usb/serial/airprime.c +++ b/drivers/usb/serial/airprime.c @@ -18,6 +18,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(0xf3d, 0x0112) }, /* AirPrime CDMA Wireless PC Card */ { USB_DEVICE(0x1410, 0x1110) }, /* Novatel Wireless Merlin CDMA */ + { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless Aircard 580 */ { }, }; MODULE_DEVICE_TABLE(usb, id_table); -- cgit v1.2.3-70-g09d2 From 332bbf613868a5d5938ad9fb7436b2beae72d53d Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Fri, 5 May 2006 11:07:21 +0200 Subject: [PATCH] USB: add an IBM USB keyboard to the HID_QUIRK_NOGET blacklist After recent changes, the USB keyboard as shipped with IBM pSeries systems does not work anymore, unless the keyboard is replugged after reboot. Adding this model to the blacklist fixes it. Signed-off-by: Olaf Hering Signed-off-by: Greg Kroah-Hartman --- drivers/usb/input/hid-core.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index f419bd82ab7f..435273e7c85c 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -1557,6 +1557,9 @@ void hid_init_reports(struct hid_device *hid) #define USB_VENDOR_ID_HP 0x03f0 #define USB_DEVICE_ID_HP_USBHUB_KB 0x020c +#define USB_VENDOR_ID_IBM 0x04b3 +#define USB_DEVICE_ID_IBM_USBHUB_KB 0x3005 + #define USB_VENDOR_ID_CREATIVELABS 0x062a #define USB_DEVICE_ID_CREATIVELABS_SILVERCREST 0x0201 @@ -1681,6 +1684,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_USBHUB_KB, HID_QUIRK_NOGET}, { USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_CREATIVELABS_SILVERCREST, HID_QUIRK_NOGET }, { USB_VENDOR_ID_HP, USB_DEVICE_ID_HP_USBHUB_KB, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_IBM, USB_DEVICE_ID_IBM_USBHUB_KB, HID_QUIRK_NOGET }, { USB_VENDOR_ID_TANGTOP, USB_DEVICE_ID_TANGTOP_USBPS2, HID_QUIRK_NOGET }, { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_SILVERCREST, USB_DEVICE_ID_SILVERCREST_KB, HID_QUIRK_NOGET }, -- cgit v1.2.3-70-g09d2 From 16c23f7d88cbcce491f9370b2846fad66e8ef319 Mon Sep 17 00:00:00 2001 From: Monty Date: Tue, 9 May 2006 12:37:22 -0700 Subject: [PATCH] USB: Emagic USB firmware loading fixes It's become apparent as machines get faster that the emagic kernel firmware loaders (based on the ezusb loader) have a reset race. a 400MHz TiBook never tripped it, but a 2GHz Pentium M seems to hit it about 30% of the time. The bug is seen as a hung USB box and the kernel error: drivers/usb/misc/emi62.c: emi62_load_firmware - error loading firmware: error = -110 The patch below inserts a delay after deasserting reset to allow the box to settle before a new command is issued. This affects only device startup. Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/emi26.c | 4 ++++ drivers/usb/misc/emi62.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/drivers/usb/misc/emi26.c b/drivers/usb/misc/emi26.c index 3824df33094e..1fd9cb85f4ca 100644 --- a/drivers/usb/misc/emi26.c +++ b/drivers/usb/misc/emi26.c @@ -15,6 +15,7 @@ #include #include #include +#include #define MAX_INTEL_HEX_RECORD_LENGTH 16 typedef struct _INTEL_HEX_RECORD @@ -114,6 +115,7 @@ static int emi26_load_firmware (struct usb_device *dev) /* De-assert reset (let the CPU run) */ err = emi26_set_reset(dev,0); + msleep(250); /* let device settle */ /* 2. We upload the FPGA firmware into the EMI * Note: collect up to 1023 (yes!) bytes and send them with @@ -150,6 +152,7 @@ static int emi26_load_firmware (struct usb_device *dev) goto wraperr; } } + msleep(250); /* let device settle */ /* De-assert reset (let the CPU run) */ err = emi26_set_reset(dev,0); @@ -192,6 +195,7 @@ static int emi26_load_firmware (struct usb_device *dev) err("%s - error loading firmware: error = %d", __FUNCTION__, err); goto wraperr; } + msleep(250); /* let device settle */ /* return 1 to fail the driver inialization * and give real driver change to load */ diff --git a/drivers/usb/misc/emi62.c b/drivers/usb/misc/emi62.c index 52fea2e08db8..fe351371f274 100644 --- a/drivers/usb/misc/emi62.c +++ b/drivers/usb/misc/emi62.c @@ -15,6 +15,7 @@ #include #include #include +#include #define MAX_INTEL_HEX_RECORD_LENGTH 16 typedef struct _INTEL_HEX_RECORD @@ -123,6 +124,7 @@ static int emi62_load_firmware (struct usb_device *dev) /* De-assert reset (let the CPU run) */ err = emi62_set_reset(dev,0); + msleep(250); /* let device settle */ /* 2. We upload the FPGA firmware into the EMI * Note: collect up to 1023 (yes!) bytes and send them with @@ -166,6 +168,7 @@ static int emi62_load_firmware (struct usb_device *dev) err("%s - error loading firmware: error = %d", __FUNCTION__, err); goto wraperr; } + msleep(250); /* let device settle */ /* 4. We put the part of the firmware that lies in the external RAM into the EZ-USB */ @@ -228,6 +231,7 @@ static int emi62_load_firmware (struct usb_device *dev) err("%s - error loading firmware: error = %d", __FUNCTION__, err); goto wraperr; } + msleep(250); /* let device settle */ kfree(buf); -- cgit v1.2.3-70-g09d2 From 704936a25bda9bb12e35bb222d5e3f26186dc279 Mon Sep 17 00:00:00 2001 From: Luiz Fernando Capitulino Date: Thu, 11 May 2006 22:34:17 -0300 Subject: [PATCH] usbserial: Fixes use-after-free in serial_open(). If the device is disconnected while serial_open() is executing and either try_module_get() or the device specific open function fails, the kref_put() call in the 'bailout_kref_put' label will free the memory pointed out by 'port'. The subsequent dereferences in the 'bailout_kref_put' label will be invalid. The fix is just to assure kref_put() is called after any 'port' usage. Signed-off-by: Luiz Fernando N. Capitulino Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/usb-serial.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 071f86a59c08..d9dceb4f57b9 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -225,9 +225,9 @@ static int serial_open (struct tty_struct *tty, struct file * filp) bailout_module_put: module_put(serial->type->driver.owner); bailout_kref_put: - kref_put(&serial->kref, destroy_serial); port->open_count = 0; mutex_unlock(&port->mutex); + kref_put(&serial->kref, destroy_serial); return retval; } -- cgit v1.2.3-70-g09d2 From 71a84163ca6b4e36744978385e94150af32f9d75 Mon Sep 17 00:00:00 2001 From: Luiz Fernando Capitulino Date: Thu, 11 May 2006 22:34:24 -0300 Subject: [PATCH] usbserial: Fixes leak in serial_open() error path. If serial_open() fails at the port assignment or mutex_lock_interruptible() is interrupted, the 'serial' object will never be freed. We should call kref_put() when those errors happens. Signed-off-by: Luiz Fernando N. Capitulino Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/usb-serial.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index d9dceb4f57b9..9c36f0ece20f 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -189,11 +189,15 @@ static int serial_open (struct tty_struct *tty, struct file * filp) portNumber = tty->index - serial->minor; port = serial->port[portNumber]; - if (!port) - return -ENODEV; + if (!port) { + retval = -ENODEV; + goto bailout_kref_put; + } - if (mutex_lock_interruptible(&port->mutex)) - return -ERESTARTSYS; + if (mutex_lock_interruptible(&port->mutex)) { + retval = -ERESTARTSYS; + goto bailout_kref_put; + } ++port->open_count; @@ -209,7 +213,7 @@ static int serial_open (struct tty_struct *tty, struct file * filp) * safe because we are called with BKL held */ if (!try_module_get(serial->type->driver.owner)) { retval = -ENODEV; - goto bailout_kref_put; + goto bailout_mutex_unlock; } /* only call the device specific open if this @@ -224,9 +228,10 @@ static int serial_open (struct tty_struct *tty, struct file * filp) bailout_module_put: module_put(serial->type->driver.owner); -bailout_kref_put: +bailout_mutex_unlock: port->open_count = 0; mutex_unlock(&port->mutex); +bailout_kref_put: kref_put(&serial->kref, destroy_serial); return retval; } -- cgit v1.2.3-70-g09d2 From 815ddc99dd8108908d14c699a37d0f5974da6def Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 12 May 2006 11:05:29 -0700 Subject: [PATCH] USB: add ark3116 usb to serial driver Based on Simon's original driver, with some minor code cleanups and tidying by me. Cc: Simon Schulz Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/Kconfig | 10 + drivers/usb/serial/Makefile | 1 + drivers/usb/serial/ark3116.c | 465 +++++++++++++++++++++++++++++++++++++++++++ drivers/usb/serial/generic.c | 1 + 4 files changed, 477 insertions(+) create mode 100644 drivers/usb/serial/ark3116.c diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index f96b73f54bf1..5c60be521561 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -71,6 +71,16 @@ config USB_SERIAL_ANYDATA To compile this driver as a module, choose M here: the module will be called anydata. +config USB_SERIAL_ARK3116 + tristate "USB ARK Micro 3116 USB Serial Driver (EXPERIMENTAL)" + depends on USB_SERIAL && EXPERIMENTAL + help + Say Y here if you want to use a ARK Micro 3116 USB to Serial + device. + + To compile this driver as a module, choose M here: the + module will be called ark3116 + config USB_SERIAL_BELKIN tristate "USB Belkin and Peracom Single Port Serial Driver" depends on USB_SERIAL diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile index 93c21245b1af..5a0960fc9d3e 100644 --- a/drivers/usb/serial/Makefile +++ b/drivers/usb/serial/Makefile @@ -13,6 +13,7 @@ usbserial-objs := usb-serial.o generic.o bus.o $(usbserial-obj-y) obj-$(CONFIG_USB_SERIAL_AIRPRIME) += airprime.o obj-$(CONFIG_USB_SERIAL_ANYDATA) += anydata.o +obj-$(CONFIG_USB_SERIAL_ARK3116) += ark3116.o obj-$(CONFIG_USB_SERIAL_BELKIN) += belkin_sa.o obj-$(CONFIG_USB_SERIAL_CP2101) += cp2101.o obj-$(CONFIG_USB_SERIAL_CYBERJACK) += cyberjack.o diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c new file mode 100644 index 000000000000..8dec796222a0 --- /dev/null +++ b/drivers/usb/serial/ark3116.c @@ -0,0 +1,465 @@ +/* + * ark3116 + * - implements a driver for the arkmicro ark3116 chipset (vendor=0x6547, + * productid=0x0232) (used in a datacable called KQ-U8A) + * + * - based on code by krisfx -> thanks !! + * (see http://www.linuxquestions.org/questions/showthread.php?p=2184457#post2184457) + * + * - based on logs created by usbsnoopy + * + * Author : Simon Schulz [ark3116_driverauctionant.de] + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include "usb-serial.h" + + +static int debug; + +static struct usb_device_id id_table [] = { + { USB_DEVICE(0x6547, 0x0232) }, + { }, +}; +MODULE_DEVICE_TABLE(usb, id_table); + +struct ark3116_private { + spinlock_t lock; + u8 termios_initialized; +}; + +static inline void ARK3116_SND(struct usb_serial *serial, int seq, + __u8 request, __u8 requesttype, + __u16 value, __u16 index) +{ + int result; + result = usb_control_msg(serial->dev, + usb_sndctrlpipe(serial->dev,0), + request, requesttype, value, index, + NULL,0x00, 1000); + dbg("%03d > ok",seq); +} + +static inline void ARK3116_RCV(struct usb_serial *serial, int seq, + __u8 request, __u8 requesttype, + __u16 value, __u16 index, __u8 expected, + char *buf) +{ + int result; + result = usb_control_msg(serial->dev, + usb_rcvctrlpipe(serial->dev,0), + request, requesttype, value, index, + buf, 0x0000001, 1000); + if (result) + dbg("%03d < %d bytes [0x%02X]",seq, result, buf[0]); + else + dbg("%03d < 0 bytes", seq); +} + + +static inline void ARK3116_RCV_QUIET(struct usb_serial *serial, + __u8 request, __u8 requesttype, + __u16 value, __u16 index, char *buf) +{ + usb_control_msg(serial->dev, + usb_rcvctrlpipe(serial->dev,0), + request, requesttype, value, index, + buf, 0x0000001, 1000); +} + + +static int ark3116_attach(struct usb_serial *serial) +{ + char *buf; + struct ark3116_private *priv; + int i; + + for (i = 0; i < serial->num_ports; ++i) { + priv = kmalloc (sizeof (struct ark3116_private), GFP_KERNEL); + if (!priv) + goto cleanup; + memset (priv, 0x00, sizeof (struct ark3116_private)); + spin_lock_init(&priv->lock); + + usb_set_serial_port_data(serial->port[i], priv); + } + + buf = kmalloc(1, GFP_KERNEL); + if (!buf) { + dbg("error kmalloc -> out of mem ?"); + goto cleanup; + } + + /* 3 */ + ARK3116_SND(serial, 3,0xFE,0x40,0x0008,0x0002); + ARK3116_SND(serial, 4,0xFE,0x40,0x0008,0x0001); + ARK3116_SND(serial, 5,0xFE,0x40,0x0000,0x0008); + ARK3116_SND(serial, 6,0xFE,0x40,0x0000,0x000B); + + /* <-- seq7 */ + ARK3116_RCV(serial, 7,0xFE,0xC0,0x0000,0x0003, 0x00, buf); + ARK3116_SND(serial, 8,0xFE,0x40,0x0080,0x0003); + ARK3116_SND(serial, 9,0xFE,0x40,0x001A,0x0000); + ARK3116_SND(serial,10,0xFE,0x40,0x0000,0x0001); + ARK3116_SND(serial,11,0xFE,0x40,0x0000,0x0003); + + /* <-- seq12 */ + ARK3116_RCV(serial,12,0xFE,0xC0,0x0000,0x0004, 0x00, buf); + ARK3116_SND(serial,13,0xFE,0x40,0x0000,0x0004); + + /* 14 */ + ARK3116_RCV(serial,14,0xFE,0xC0,0x0000,0x0004, 0x00, buf); + ARK3116_SND(serial,15,0xFE,0x40,0x0000,0x0004); + + /* 16 */ + ARK3116_RCV(serial,16,0xFE,0xC0,0x0000,0x0004, 0x00, buf); + /* --> seq17 */ + ARK3116_SND(serial,17,0xFE,0x40,0x0001,0x0004); + + /* <-- seq18 */ + ARK3116_RCV(serial,18,0xFE,0xC0,0x0000,0x0004, 0x01, buf); + + /* --> seq19 */ + ARK3116_SND(serial,19,0xFE,0x40,0x0003,0x0004); + + + /* <-- seq20 */ + /* seems like serial port status info (RTS, CTS,...) */ + /* returns modem control line status ?! */ + ARK3116_RCV(serial,20,0xFE,0xC0,0x0000,0x0006, 0xFF, buf); + + /* set 9600 baud & do some init ?! */ + ARK3116_SND(serial,147,0xFE,0x40,0x0083,0x0003); + ARK3116_SND(serial,148,0xFE,0x40,0x0038,0x0000); + ARK3116_SND(serial,149,0xFE,0x40,0x0001,0x0001); + ARK3116_SND(serial,150,0xFE,0x40,0x0003,0x0003); + ARK3116_RCV(serial,151,0xFE,0xC0,0x0000,0x0004,0x03, buf); + ARK3116_SND(serial,152,0xFE,0x40,0x0000,0x0003); + ARK3116_RCV(serial,153,0xFE,0xC0,0x0000,0x0003,0x00, buf); + ARK3116_SND(serial,154,0xFE,0x40,0x0003,0x0003); + + kfree(buf); + return(0); + +cleanup: + for (--i; i>=0; --i) + usb_set_serial_port_data(serial->port[i], NULL); + return -ENOMEM; +} + +static void ark3116_set_termios(struct usb_serial_port *port, + struct termios *old_termios) +{ + struct usb_serial *serial = port->serial; + struct ark3116_private *priv = usb_get_serial_port_data(port); + unsigned int cflag = port->tty->termios->c_cflag; + unsigned long flags; + int baud; + int ark3116_baud; + char *buf; + char config; + + config = 0; + + dbg("%s - port %d", __FUNCTION__, port->number); + + if ((!port->tty) || (!port->tty->termios)) { + dbg("%s - no tty structures", __FUNCTION__); + return; + } + + spin_lock_irqsave(&priv->lock, flags); + if (!priv->termios_initialized) { + *(port->tty->termios) = tty_std_termios; + port->tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; + priv->termios_initialized = 1; + } + spin_unlock_irqrestore(&priv->lock, flags); + + cflag = port->tty->termios->c_cflag; + + /* check that they really want us to change something: */ + if (old_termios) { + if ((cflag == old_termios->c_cflag) && + (RELEVANT_IFLAG(port->tty->termios->c_iflag) == + RELEVANT_IFLAG(old_termios->c_iflag))) { + dbg("%s - nothing to change...", __FUNCTION__); + return; + } + } + + buf = kmalloc(1, GFP_KERNEL); + if (!buf) { + dbg("error kmalloc"); + return; + } + + /* set data bit count (8/7/6/5) */ + if (cflag & CSIZE){ + switch (cflag & CSIZE){ + case CS5: + config |= 0x00; + dbg("setting CS5"); + break; + case CS6: + config |= 0x01; + dbg("setting CS6"); + break; + case CS7: + config |= 0x02; + dbg("setting CS7"); + break; + default: + err ("CSIZE was set but not CS5-CS8, using CS8!"); + case CS8: + config |= 0x03; + dbg("setting CS8"); + break; + } + } + + /* set parity (NONE,EVEN,ODD) */ + if (cflag & PARENB){ + if (cflag & PARODD) { + config |= 0x08; + dbg("setting parity to ODD"); + } else { + config |= 0x18; + dbg("setting parity to EVEN"); + } + } else { + dbg("setting parity to NONE"); + } + + /* SET STOPBIT (1/2) */ + if (cflag & CSTOPB) { + config |= 0x04; + dbg ("setting 2 stop bits"); + } else { + dbg ("setting 1 stop bit"); + } + + + /* set baudrate: */ + baud = 0; + switch (cflag & CBAUD){ + case B0: + err("can't set 0baud, using 9600 instead"); + break; + case B75: baud = 75; break; + case B150: baud = 150; break; + case B300: baud = 300; break; + case B600: baud = 600; break; + case B1200: baud = 1200; break; + case B1800: baud = 1800; break; + case B2400: baud = 2400; break; + case B4800: baud = 4800; break; + case B9600: baud = 9600; break; + case B19200: baud = 19200; break; + case B38400: baud = 38400; break; + case B57600: baud = 57600; break; + case B115200: baud = 115200; break; + case B230400: baud = 230400; break; + case B460800: baud = 460800; break; + default: + dbg("does not support the baudrate requested (fix it)"); + break; + } + + /* set 9600 as default (if given baudrate is invalid for example) */ + if (baud == 0) + baud = 9600; + + /* + * found by try'n'error, be careful, maybe there are other options + * for multiplicator etc! + */ + if (baud == 460800) + /* strange, for 460800 the formula is wrong + * (dont use round(), then 9600baud is wrong) */ + ark3116_baud = 7; + else + ark3116_baud = 3000000 / baud; + + /* ? */ + ARK3116_RCV(serial,0,0xFE,0xC0,0x0000,0x0003, 0x03, buf); + /* offset = buf[0]; */ + /* offset = 0x03; */ + /* dbg("using 0x%04X as target for 0x0003:",0x0080+offset); */ + + + /* set baudrate */ + dbg("setting baudrate to %d (->reg=%d)",baud,ark3116_baud); + ARK3116_SND(serial,147,0xFE,0x40,0x0083,0x0003); + ARK3116_SND(serial,148,0xFE,0x40,(ark3116_baud & 0x00FF) ,0x0000); + ARK3116_SND(serial,149,0xFE,0x40,(ark3116_baud & 0xFF00)>>8,0x0001); + ARK3116_SND(serial,150,0xFE,0x40,0x0003,0x0003); + + /* ? */ + ARK3116_RCV(serial,151,0xFE,0xC0,0x0000,0x0004,0x03, buf); + ARK3116_SND(serial,152,0xFE,0x40,0x0000,0x0003); + + /* set data bit count, stop bit count & parity: */ + dbg("updating bit count, stop bit or parity (cfg=0x%02X)", config); + ARK3116_RCV(serial,153,0xFE,0xC0,0x0000,0x0003,0x00, buf); + ARK3116_SND(serial,154,0xFE,0x40,config,0x0003); + + if (cflag & CRTSCTS) + dbg("CRTSCTS not supported by chipset ?!"); + + /* TEST ARK3116_SND(154,0xFE,0x40,0xFFFF, 0x0006); */ + + kfree(buf); + return; +} + +static int ark3116_open(struct usb_serial_port *port, struct file *filp) +{ + struct termios tmp_termios; + struct usb_serial *serial = port->serial; + char *buf; + int result = 0; + + dbg("%s - port %d", __FUNCTION__, port->number); + + buf = kmalloc(1, GFP_KERNEL); + if (!buf) { + dbg("error kmalloc -> out of mem ?"); + return -ENOMEM; + } + + result = usb_serial_generic_open(port, filp); + if (result) + return result; + + /* open */ + ARK3116_RCV(serial,111,0xFE,0xC0,0x0000,0x0003, 0x02, buf); + + ARK3116_SND(serial,112,0xFE,0x40,0x0082,0x0003); + ARK3116_SND(serial,113,0xFE,0x40,0x001A,0x0000); + ARK3116_SND(serial,114,0xFE,0x40,0x0000,0x0001); + ARK3116_SND(serial,115,0xFE,0x40,0x0002,0x0003); + + ARK3116_RCV(serial,116,0xFE,0xC0,0x0000,0x0004, 0x03, buf); + ARK3116_SND(serial,117,0xFE,0x40,0x0002,0x0004); + + ARK3116_RCV(serial,118,0xFE,0xC0,0x0000,0x0004, 0x02, buf); + ARK3116_SND(serial,119,0xFE,0x40,0x0000,0x0004); + + ARK3116_RCV(serial,120,0xFE,0xC0,0x0000,0x0004, 0x00, buf); + + ARK3116_SND(serial,121,0xFE,0x40,0x0001,0x0004); + + ARK3116_RCV(serial,122,0xFE,0xC0,0x0000,0x0004, 0x01, buf); + + ARK3116_SND(serial,123,0xFE,0x40,0x0003,0x0004); + + /* returns different values (control lines ?!) */ + ARK3116_RCV(serial,124,0xFE,0xC0,0x0000,0x0006, 0xFF, buf); + + /* initialise termios: */ + if (port->tty) + ark3116_set_termios(port, &tmp_termios); + + kfree(buf); + + return result; + +} + +static int ark3116_ioctl(struct usb_serial_port *port, struct file *file, + unsigned int cmd, unsigned long arg) +{ + dbg("ioctl not supported yet..."); + return -ENOIOCTLCMD; +} + +static int ark3116_tiocmget(struct usb_serial_port *port, struct file *file) +{ + struct usb_serial *serial = port->serial; + char *buf; + char temp; + + /* seems like serial port status info (RTS, CTS,...) is stored + * in reg(?) 0x0006 + * pcb connection point 11 = GND -> sets bit4 of response + * pcb connection point 7 = GND -> sets bit6 of response + */ + + buf = kmalloc(1, GFP_KERNEL); + if (!buf) { + dbg("error kmalloc"); + return -ENOMEM; + } + + /* read register: */ + ARK3116_RCV_QUIET(serial,0xFE,0xC0,0x0000,0x0006,buf); + temp = buf[0]; + kfree(buf); + + /* i do not really know if bit4=CTS and bit6=DSR... was just a + * quick guess !! + */ + return (temp & (1<<4) ? TIOCM_CTS : 0) | + (temp & (1<<6) ? TIOCM_DSR : 0); +} + +static struct usb_driver ark3116_driver = { + .name = "ark3116", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .id_table = id_table, +}; + +static struct usb_serial_driver ark3116_device = { + .driver = { + .owner = THIS_MODULE, + .name = "ark3116", + }, + .id_table = id_table, + .num_interrupt_in = 1, + .num_bulk_in = 1, + .num_bulk_out = 1, + .num_ports = 1, + .attach = ark3116_attach, + .set_termios = ark3116_set_termios, + .ioctl = ark3116_ioctl, + .tiocmget = ark3116_tiocmget, + .open = ark3116_open, +}; + +static int __init ark3116_init(void) +{ + int retval; + + retval = usb_serial_register(&ark3116_device); + if (retval) + return retval; + retval = usb_register(&ark3116_driver); + if (retval) + usb_serial_deregister(&ark3116_device); + return retval; +} + +static void __exit ark3116_exit(void) +{ + usb_deregister(&ark3116_driver); + usb_serial_deregister(&ark3116_device); +} + +module_init(ark3116_init); +module_exit(ark3116_exit); +MODULE_LICENSE("GPL"); + +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Debug enabled or not"); + diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index 476cda107f4f..c62cc2876519 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -138,6 +138,7 @@ int usb_serial_generic_open (struct usb_serial_port *port, struct file *filp) return result; } +EXPORT_SYMBOL_GPL(usb_serial_generic_open); static void generic_cleanup (struct usb_serial_port *port) { -- cgit v1.2.3-70-g09d2 From df3fccb14ad02c5fabe095a104a0323c223f2833 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 2 May 2006 08:44:45 +0200 Subject: [PATCH] USB: fix omninet driver bug I introduced this way back in 2.6.13 when adding the port lock logic. This device talks out through different "ports" all at the same time, so the lock logic was wrong, preventing any data from ever being sent properly. Thanks a lot to Bernhard Reiter for being patient and helping with debugging this. Cc: Bernhard Reiter Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/omninet.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c index 4d40704dea2c..238033a87092 100644 --- a/drivers/usb/serial/omninet.c +++ b/drivers/usb/serial/omninet.c @@ -257,14 +257,14 @@ static int omninet_write (struct usb_serial_port *port, const unsigned char *buf return (0); } - spin_lock(&port->lock); - if (port->write_urb_busy) { - spin_unlock(&port->lock); + spin_lock(&wport->lock); + if (wport->write_urb_busy) { + spin_unlock(&wport->lock); dbg("%s - already writing", __FUNCTION__); return 0; } - port->write_urb_busy = 1; - spin_unlock(&port->lock); + wport->write_urb_busy = 1; + spin_unlock(&wport->lock); count = (count > OMNINET_BULKOUTSIZE) ? OMNINET_BULKOUTSIZE : count; @@ -283,7 +283,7 @@ static int omninet_write (struct usb_serial_port *port, const unsigned char *buf wport->write_urb->dev = serial->dev; result = usb_submit_urb(wport->write_urb, GFP_ATOMIC); if (result) { - port->write_urb_busy = 0; + wport->write_urb_busy = 0; err("%s - failed submitting write urb, error %d", __FUNCTION__, result); } else result = count; -- cgit v1.2.3-70-g09d2 From 1a2acc9e9214699a99389e323e6686e9e0e2ca67 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 12 May 2006 12:08:46 -0700 Subject: Revert "[BLOCK] Fix oops on removal of SD/MMC card" This reverts commit 56cf6504fc1c0c221b82cebc16a444b684140fb7. Both Erik Mouw and Andrew Vasquez independently pinpointed this commit as causing problems, where the slab cache for a driver is never released (most obviously causing problems when immediately re-loading that driver, resulting in a "kmem_cache_create: duplicate cache " message, but it can also cause other trouble). James Bottomley dug into it, and reports: "OK, here's the scoop. The problem patch adds a get of driverfs_dev in add_disk(), but doesn't put it again until disk_release() (which occurs on final put_disk() of the gendisk). However, in SCSI, the driverfs_dev is the sdev_gendev. That means there's a reference held on sdev_gendev until final disk put. Unfortunately, we use the driver model driver_remove to trigger del_gendisk (which removes the gendisk from visibility and decrements the refcount), so we've introduced an unbreakable deadlock in the reference counting with this. I suggest simply reversing this patch at the moment. If Russell and Jens can tell me what they're trying to do I'll see if there's another way to do it." so hereby the patch gets reverted, waiting for a better fix. Cc: Jens Axboe Cc: Russell King Cc: James Bottomley Cc: Erik Mouw Cc: Andrew Vasquez Signed-off-by: Linus Torvalds --- block/genhd.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/block/genhd.c b/block/genhd.c index d96572589621..5a8d3bf02f17 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -182,7 +182,6 @@ static int exact_lock(dev_t dev, void *data) */ void add_disk(struct gendisk *disk) { - get_device(disk->driverfs_dev); disk->flags |= GENHD_FL_UP; blk_register_region(MKDEV(disk->major, disk->first_minor), disk->minors, NULL, exact_match, exact_lock, disk); @@ -428,7 +427,6 @@ static struct attribute * default_attrs[] = { static void disk_release(struct kobject * kobj) { struct gendisk *disk = to_disk(kobj); - put_device(disk->driverfs_dev); kfree(disk->random); kfree(disk->part); free_disk_stats(disk); -- cgit v1.2.3-70-g09d2 From 06a1be167ea77c436657587e26cd4d7d6401784c Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 12 May 2006 12:45:50 -0700 Subject: [SPARC]: Handle UNWIND_INFO properly. For sparc32 we need R_SPARC_UA32 relocation support, for sparc64 we need the handle R_SPARC_DISP32 relocations. Based upon reports and initial patch by Martin Habets. Signed-off-by: David S. Miller --- arch/sparc/kernel/module.c | 1 + arch/sparc64/defconfig | 3 ++- arch/sparc64/kernel/module.c | 5 +++++ lib/Kconfig.debug | 2 +- 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/arch/sparc/kernel/module.c b/arch/sparc/kernel/module.c index 787d5f1347ec..598682f31ebf 100644 --- a/arch/sparc/kernel/module.c +++ b/arch/sparc/kernel/module.c @@ -113,6 +113,7 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, switch (ELF32_R_TYPE(rel[i].r_info)) { case R_SPARC_32: + case R_SPARC_UA32: location[0] = v >> 24; location[1] = v >> 16; location[2] = v >> 8; diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig index 22ca69fc865c..f09a70b8aabd 100644 --- a/arch/sparc64/defconfig +++ b/arch/sparc64/defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Linux kernel version: 2.6.17-rc3 -# Mon May 8 15:12:53 2006 +# Fri May 12 12:43:49 2006 # CONFIG_SPARC=y CONFIG_SPARC64=y @@ -1309,6 +1309,7 @@ CONFIG_DEBUG_BUGVERBOSE=y # CONFIG_DEBUG_INFO is not set CONFIG_DEBUG_FS=y # CONFIG_DEBUG_VM is not set +# CONFIG_UNWIND_INFO is not set CONFIG_FORCED_INLINING=y # CONFIG_RCU_TORTURE_TEST is not set # CONFIG_DEBUG_STACK_USAGE is not set diff --git a/arch/sparc64/kernel/module.c b/arch/sparc64/kernel/module.c index 6c83e372f75d..579871527699 100644 --- a/arch/sparc64/kernel/module.c +++ b/arch/sparc64/kernel/module.c @@ -143,6 +143,11 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, location[3] = v >> 0; break; + case R_SPARC_DISP32: + v -= (Elf64_Addr) location; + *loc32 = v; + break; + case R_SPARC_WDISP30: v -= (Elf64_Addr) location; *loc32 = (*loc32 & ~0x3fffffff) | diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 6ecc180beb71..ccb0c1fdf1b5 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -189,7 +189,7 @@ config FRAME_POINTER config UNWIND_INFO bool "Compile the kernel with frame unwind information" depends on !IA64 - depends on !MODULES || !(MIPS || PARISC || PPC || SUPERH || SPARC64 || V850) + depends on !MODULES || !(MIPS || PARISC || PPC || SUPERH || V850) help If you say Y here the resulting kernel image will be slightly larger but not slower, and it will give very useful debugging information. -- cgit v1.2.3-70-g09d2 From ef34814426862c41c061520d4ac833be5914b5ba Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Fri, 12 May 2006 12:49:08 -0700 Subject: [TG3]: ethtool always report port is TP. Even with fiber cards ethtool reports that the connected port is TP, the patch fix this. Signed-off-by: Karsten Keil Acked-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 2bd9592b75cd..e1b33a25a25f 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -7653,21 +7653,23 @@ static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->supported |= (SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full); - if (!(tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)) + if (!(tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)) { cmd->supported |= (SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_MII); - else + cmd->port = PORT_TP; + } else { cmd->supported |= SUPPORTED_FIBRE; + cmd->port = PORT_FIBRE; + } cmd->advertising = tp->link_config.advertising; if (netif_running(dev)) { cmd->speed = tp->link_config.active_speed; cmd->duplex = tp->link_config.active_duplex; } - cmd->port = 0; cmd->phy_address = PHY_ADDR; cmd->transceiver = 0; cmd->autoneg = tp->link_config.autoneg; -- cgit v1.2.3-70-g09d2 From 586152560ae8df2a9babf1a8b667d7a145cb8208 Mon Sep 17 00:00:00 2001 From: Martin Habets Date: Fri, 12 May 2006 12:53:59 -0700 Subject: [SPARC]: Fix warning on prom_getproperty in openprom.c Signed-off-by: Martin Habets Signed-off-by: David S. Miller --- drivers/sbus/char/openprom.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c index 383a95f34a0d..239e108b8ed1 100644 --- a/drivers/sbus/char/openprom.c +++ b/drivers/sbus/char/openprom.c @@ -392,13 +392,16 @@ static int openprom_bsd_ioctl(struct inode * inode, struct file * file, return -ENOMEM; } - prom_getproperty(op.op_nodeid, str, tmp, len); - - tmp[len] = '\0'; + cnt = prom_getproperty(op.op_nodeid, str, tmp, len); + if (cnt <= 0) { + error = -EINVAL; + } else { + tmp[len] = '\0'; - if (__copy_to_user(argp, &op, sizeof(op)) != 0 - || copy_to_user(op.op_buf, tmp, len) != 0) - error = -EFAULT; + if (__copy_to_user(argp, &op, sizeof(op)) != 0 || + copy_to_user(op.op_buf, tmp, len) != 0) + error = -EFAULT; + } kfree(tmp); kfree(str); -- cgit v1.2.3-70-g09d2 From bd89efc532fe41f867f848144cc8b42054ddf6f9 Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Fri, 12 May 2006 14:56:08 -0700 Subject: [NEIGH]: Fix IP-over-ATM and ARP interaction. The classical IP over ATM code maintains its own IPv4 <-> ARP table, using the standard neighbour-table code. The neigh_table_init function adds this neighbour table to a linked list of all neighbor tables which is used by the functions neigh_delete() neigh_add() and neightbl_set(), all called by the netlink code. Once the ATM neighbour table is added to the list, there are two tables with family == AF_INET there, and ARP entries sent via netlink go into the first table with matching family. This is indeterminate and often wrong. To see the bug, on a kernel with CLIP enabled, create a standard IPv4 ARP entry by pinging an unused address on a local subnet. Then attempt to complete that entry by doing ip neigh replace lladdr nud reachable Looking at the ARP tables by using ip neigh show will reveal two ARP entries for the same address. One of these can be found in /proc/net/arp, and the other in /proc/net/atm/arp. This patch adds a new function, neigh_table_init_no_netlink() which does everything the neigh_table_init() does, except add the table to the netlink all-arp-tables chain. In addition neigh_table_init() has a check that all tables on the chain have a distinct address family. The init call in clip.c is changed to call neigh_table_init_no_netlink(). Since ATM ARP tables are rather more complicated than can currently be handled by the available rtattrs in the netlink protocol, no functionality is lost by this patch, and non-ATM ARP manipulation via netlink is rescued. A more complete solution would involve a rtattr for ATM ARP entries and some way for the netlink code to give neigh_add and friends more information than just address family with which to find the correct ARP table. [ I've changed the assertion checking in neigh_table_init() to not use BUG_ON() while holding neigh_tbl_lock. Instead we remember that we found an existing tbl with the same family, and after dropping the lock we'll give a diagnostic kernel log message and a stack dump. -DaveM ] Signed-off-by: Simon Kelley Signed-off-by: David S. Miller --- include/net/neighbour.h | 1 + net/atm/clip.c | 2 +- net/core/neighbour.c | 21 +++++++++++++++++++-- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/include/net/neighbour.h b/include/net/neighbour.h index b0666d66293f..4901ee446879 100644 --- a/include/net/neighbour.h +++ b/include/net/neighbour.h @@ -211,6 +211,7 @@ struct neigh_table #define NEIGH_UPDATE_F_ADMIN 0x80000000 extern void neigh_table_init(struct neigh_table *tbl); +extern void neigh_table_init_no_netlink(struct neigh_table *tbl); extern int neigh_table_clear(struct neigh_table *tbl); extern struct neighbour * neigh_lookup(struct neigh_table *tbl, const void *pkey, diff --git a/net/atm/clip.c b/net/atm/clip.c index 1a786bfaa416..72d852982664 100644 --- a/net/atm/clip.c +++ b/net/atm/clip.c @@ -963,7 +963,7 @@ static struct file_operations arp_seq_fops = { static int __init atm_clip_init(void) { struct proc_dir_entry *p; - neigh_table_init(&clip_tbl); + neigh_table_init_no_netlink(&clip_tbl); clip_tbl_hook = &clip_tbl; register_atm_ioctl(&clip_ioctl_ops); diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 4cf878efdb49..50a8c73caf97 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -1326,8 +1326,7 @@ void neigh_parms_destroy(struct neigh_parms *parms) kfree(parms); } - -void neigh_table_init(struct neigh_table *tbl) +void neigh_table_init_no_netlink(struct neigh_table *tbl) { unsigned long now = jiffies; unsigned long phsize; @@ -1383,10 +1382,27 @@ void neigh_table_init(struct neigh_table *tbl) tbl->last_flush = now; tbl->last_rand = now + tbl->parms.reachable_time * 20; +} + +void neigh_table_init(struct neigh_table *tbl) +{ + struct neigh_table *tmp; + + neigh_table_init_no_netlink(tbl); write_lock(&neigh_tbl_lock); + for (tmp = neigh_tables; tmp; tmp = tmp->next) { + if (tmp->family == tbl->family) + break; + } tbl->next = neigh_tables; neigh_tables = tbl; write_unlock(&neigh_tbl_lock); + + if (unlikely(tmp)) { + printk(KERN_ERR "NEIGH: Registering multiple tables for " + "family %d\n", tbl->family); + dump_stack(); + } } int neigh_table_clear(struct neigh_table *tbl) @@ -2657,6 +2673,7 @@ EXPORT_SYMBOL(neigh_rand_reach_time); EXPORT_SYMBOL(neigh_resolve_output); EXPORT_SYMBOL(neigh_table_clear); EXPORT_SYMBOL(neigh_table_init); +EXPORT_SYMBOL(neigh_table_init_no_netlink); EXPORT_SYMBOL(neigh_update); EXPORT_SYMBOL(neigh_update_hhs); EXPORT_SYMBOL(pneigh_enqueue); -- cgit v1.2.3-70-g09d2 From 6f4bb3d8205d943acafa2f536f37131777524b67 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Fri, 12 May 2006 14:57:52 -0700 Subject: IB/ipath: Properly terminate PCI ID table The ipath driver's table of PCI IDs needs a { 0, } entry at the end. This makes all of the device aliases visible to userspace so hotplug loads the module for all supported devices. Without the patch, modinfo ipath_core only shows: alias: pci:v00001FC1d0000000Dsv*sd*bc*sc*i* instead of the correct: alias: pci:v00001FC1d00000010sv*sd*bc*sc*i* alias: pci:v00001FC1d0000000Dsv*sd*bc*sc*i* Signed-off-by: Roland Dreier Signed-off-by: Bryan O'Sullivan --- drivers/infiniband/hw/ipath/ipath_driver.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c index 398add4d4cb1..3697edafd6d2 100644 --- a/drivers/infiniband/hw/ipath/ipath_driver.c +++ b/drivers/infiniband/hw/ipath/ipath_driver.c @@ -116,10 +116,9 @@ static int __devinit ipath_init_one(struct pci_dev *, #define PCI_DEVICE_ID_INFINIPATH_PE800 0x10 static const struct pci_device_id ipath_pci_tbl[] = { - {PCI_DEVICE(PCI_VENDOR_ID_PATHSCALE, - PCI_DEVICE_ID_INFINIPATH_HT)}, - {PCI_DEVICE(PCI_VENDOR_ID_PATHSCALE, - PCI_DEVICE_ID_INFINIPATH_PE800)}, + { PCI_DEVICE(PCI_VENDOR_ID_PATHSCALE, PCI_DEVICE_ID_INFINIPATH_HT) }, + { PCI_DEVICE(PCI_VENDOR_ID_PATHSCALE, PCI_DEVICE_ID_INFINIPATH_PE800) }, + { 0, } }; MODULE_DEVICE_TABLE(pci, ipath_pci_tbl); -- cgit v1.2.3-70-g09d2 From 1b52fa98edd1c3e663ea4a06519e3d20976084a8 Mon Sep 17 00:00:00 2001 From: Sean Hefty Date: Fri, 12 May 2006 14:57:52 -0700 Subject: IB: refcount race fixes Fix race condition during destruction calls to avoid possibility of accessing object after it has been freed. Instead of waking up a wait queue directly, which is susceptible to a race where the object is freed between the reference count going to 0 and the wake_up(), use a completion to wait in the function doing the freeing. Signed-off-by: Sean Hefty Signed-off-by: Roland Dreier --- drivers/infiniband/core/cm.c | 12 ++++++---- drivers/infiniband/core/mad.c | 47 ++++++++++++++++++++------------------ drivers/infiniband/core/mad_priv.h | 5 ++-- drivers/infiniband/core/mad_rmpp.c | 20 ++++++++-------- drivers/infiniband/core/ucm.c | 12 ++++++---- 5 files changed, 52 insertions(+), 44 deletions(-) diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index 7cfedb8d9bcd..86fee43502cd 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -34,6 +34,8 @@ * * $Id: cm.c 2821 2005-07-08 17:07:28Z sean.hefty $ */ + +#include #include #include #include @@ -122,7 +124,7 @@ struct cm_id_private { struct rb_node service_node; struct rb_node sidr_id_node; spinlock_t lock; /* Do not acquire inside cm.lock */ - wait_queue_head_t wait; + struct completion comp; atomic_t refcount; struct ib_mad_send_buf *msg; @@ -159,7 +161,7 @@ static void cm_work_handler(void *data); static inline void cm_deref_id(struct cm_id_private *cm_id_priv) { if (atomic_dec_and_test(&cm_id_priv->refcount)) - wake_up(&cm_id_priv->wait); + complete(&cm_id_priv->comp); } static int cm_alloc_msg(struct cm_id_private *cm_id_priv, @@ -559,7 +561,7 @@ struct ib_cm_id *ib_create_cm_id(struct ib_device *device, goto error; spin_lock_init(&cm_id_priv->lock); - init_waitqueue_head(&cm_id_priv->wait); + init_completion(&cm_id_priv->comp); INIT_LIST_HEAD(&cm_id_priv->work_list); atomic_set(&cm_id_priv->work_count, -1); atomic_set(&cm_id_priv->refcount, 1); @@ -724,8 +726,8 @@ retest: } cm_free_id(cm_id->local_id); - atomic_dec(&cm_id_priv->refcount); - wait_event(cm_id_priv->wait, !atomic_read(&cm_id_priv->refcount)); + cm_deref_id(cm_id_priv); + wait_for_completion(&cm_id_priv->comp); while ((work = cm_dequeue_work(cm_id_priv)) != NULL) cm_free_work(work); if (cm_id_priv->private_data && cm_id_priv->private_data_len) diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index 469b6923a2e2..5ad41a64314c 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -352,7 +352,7 @@ struct ib_mad_agent *ib_register_mad_agent(struct ib_device *device, INIT_WORK(&mad_agent_priv->local_work, local_completions, mad_agent_priv); atomic_set(&mad_agent_priv->refcount, 1); - init_waitqueue_head(&mad_agent_priv->wait); + init_completion(&mad_agent_priv->comp); return &mad_agent_priv->agent; @@ -467,7 +467,7 @@ struct ib_mad_agent *ib_register_mad_snoop(struct ib_device *device, mad_snoop_priv->agent.qp = port_priv->qp_info[qpn].qp; mad_snoop_priv->agent.port_num = port_num; mad_snoop_priv->mad_snoop_flags = mad_snoop_flags; - init_waitqueue_head(&mad_snoop_priv->wait); + init_completion(&mad_snoop_priv->comp); mad_snoop_priv->snoop_index = register_snoop_agent( &port_priv->qp_info[qpn], mad_snoop_priv); @@ -486,6 +486,18 @@ error1: } EXPORT_SYMBOL(ib_register_mad_snoop); +static inline void deref_mad_agent(struct ib_mad_agent_private *mad_agent_priv) +{ + if (atomic_dec_and_test(&mad_agent_priv->refcount)) + complete(&mad_agent_priv->comp); +} + +static inline void deref_snoop_agent(struct ib_mad_snoop_private *mad_snoop_priv) +{ + if (atomic_dec_and_test(&mad_snoop_priv->refcount)) + complete(&mad_snoop_priv->comp); +} + static void unregister_mad_agent(struct ib_mad_agent_private *mad_agent_priv) { struct ib_mad_port_private *port_priv; @@ -509,9 +521,8 @@ static void unregister_mad_agent(struct ib_mad_agent_private *mad_agent_priv) flush_workqueue(port_priv->wq); ib_cancel_rmpp_recvs(mad_agent_priv); - atomic_dec(&mad_agent_priv->refcount); - wait_event(mad_agent_priv->wait, - !atomic_read(&mad_agent_priv->refcount)); + deref_mad_agent(mad_agent_priv); + wait_for_completion(&mad_agent_priv->comp); kfree(mad_agent_priv->reg_req); ib_dereg_mr(mad_agent_priv->agent.mr); @@ -529,9 +540,8 @@ static void unregister_mad_snoop(struct ib_mad_snoop_private *mad_snoop_priv) atomic_dec(&qp_info->snoop_count); spin_unlock_irqrestore(&qp_info->snoop_lock, flags); - atomic_dec(&mad_snoop_priv->refcount); - wait_event(mad_snoop_priv->wait, - !atomic_read(&mad_snoop_priv->refcount)); + deref_snoop_agent(mad_snoop_priv); + wait_for_completion(&mad_snoop_priv->comp); kfree(mad_snoop_priv); } @@ -600,8 +610,7 @@ static void snoop_send(struct ib_mad_qp_info *qp_info, spin_unlock_irqrestore(&qp_info->snoop_lock, flags); mad_snoop_priv->agent.snoop_handler(&mad_snoop_priv->agent, send_buf, mad_send_wc); - if (atomic_dec_and_test(&mad_snoop_priv->refcount)) - wake_up(&mad_snoop_priv->wait); + deref_snoop_agent(mad_snoop_priv); spin_lock_irqsave(&qp_info->snoop_lock, flags); } spin_unlock_irqrestore(&qp_info->snoop_lock, flags); @@ -626,8 +635,7 @@ static void snoop_recv(struct ib_mad_qp_info *qp_info, spin_unlock_irqrestore(&qp_info->snoop_lock, flags); mad_snoop_priv->agent.recv_handler(&mad_snoop_priv->agent, mad_recv_wc); - if (atomic_dec_and_test(&mad_snoop_priv->refcount)) - wake_up(&mad_snoop_priv->wait); + deref_snoop_agent(mad_snoop_priv); spin_lock_irqsave(&qp_info->snoop_lock, flags); } spin_unlock_irqrestore(&qp_info->snoop_lock, flags); @@ -968,8 +976,7 @@ void ib_free_send_mad(struct ib_mad_send_buf *send_buf) free_send_rmpp_list(mad_send_wr); kfree(send_buf->mad); - if (atomic_dec_and_test(&mad_agent_priv->refcount)) - wake_up(&mad_agent_priv->wait); + deref_mad_agent(mad_agent_priv); } EXPORT_SYMBOL(ib_free_send_mad); @@ -1757,8 +1764,7 @@ static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv, mad_recv_wc = ib_process_rmpp_recv_wc(mad_agent_priv, mad_recv_wc); if (!mad_recv_wc) { - if (atomic_dec_and_test(&mad_agent_priv->refcount)) - wake_up(&mad_agent_priv->wait); + deref_mad_agent(mad_agent_priv); return; } } @@ -1770,8 +1776,7 @@ static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv, if (!mad_send_wr) { spin_unlock_irqrestore(&mad_agent_priv->lock, flags); ib_free_recv_mad(mad_recv_wc); - if (atomic_dec_and_test(&mad_agent_priv->refcount)) - wake_up(&mad_agent_priv->wait); + deref_mad_agent(mad_agent_priv); return; } ib_mark_mad_done(mad_send_wr); @@ -1790,8 +1795,7 @@ static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv, } else { mad_agent_priv->agent.recv_handler(&mad_agent_priv->agent, mad_recv_wc); - if (atomic_dec_and_test(&mad_agent_priv->refcount)) - wake_up(&mad_agent_priv->wait); + deref_mad_agent(mad_agent_priv); } } @@ -2021,8 +2025,7 @@ void ib_mad_complete_send_wr(struct ib_mad_send_wr_private *mad_send_wr, mad_send_wc); /* Release reference on agent taken when sending */ - if (atomic_dec_and_test(&mad_agent_priv->refcount)) - wake_up(&mad_agent_priv->wait); + deref_mad_agent(mad_agent_priv); return; done: spin_unlock_irqrestore(&mad_agent_priv->lock, flags); diff --git a/drivers/infiniband/core/mad_priv.h b/drivers/infiniband/core/mad_priv.h index 6c9c133d71ef..b4fa28d3160f 100644 --- a/drivers/infiniband/core/mad_priv.h +++ b/drivers/infiniband/core/mad_priv.h @@ -37,6 +37,7 @@ #ifndef __IB_MAD_PRIV_H__ #define __IB_MAD_PRIV_H__ +#include #include #include #include @@ -108,7 +109,7 @@ struct ib_mad_agent_private { struct list_head rmpp_list; atomic_t refcount; - wait_queue_head_t wait; + struct completion comp; }; struct ib_mad_snoop_private { @@ -117,7 +118,7 @@ struct ib_mad_snoop_private { int snoop_index; int mad_snoop_flags; atomic_t refcount; - wait_queue_head_t wait; + struct completion comp; }; struct ib_mad_send_wr_private { diff --git a/drivers/infiniband/core/mad_rmpp.c b/drivers/infiniband/core/mad_rmpp.c index dfd4e588ce03..d4704e054e30 100644 --- a/drivers/infiniband/core/mad_rmpp.c +++ b/drivers/infiniband/core/mad_rmpp.c @@ -49,7 +49,7 @@ struct mad_rmpp_recv { struct list_head list; struct work_struct timeout_work; struct work_struct cleanup_work; - wait_queue_head_t wait; + struct completion comp; enum rmpp_state state; spinlock_t lock; atomic_t refcount; @@ -69,10 +69,16 @@ struct mad_rmpp_recv { u8 method; }; +static inline void deref_rmpp_recv(struct mad_rmpp_recv *rmpp_recv) +{ + if (atomic_dec_and_test(&rmpp_recv->refcount)) + complete(&rmpp_recv->comp); +} + static void destroy_rmpp_recv(struct mad_rmpp_recv *rmpp_recv) { - atomic_dec(&rmpp_recv->refcount); - wait_event(rmpp_recv->wait, !atomic_read(&rmpp_recv->refcount)); + deref_rmpp_recv(rmpp_recv); + wait_for_completion(&rmpp_recv->comp); ib_destroy_ah(rmpp_recv->ah); kfree(rmpp_recv); } @@ -253,7 +259,7 @@ create_rmpp_recv(struct ib_mad_agent_private *agent, goto error; rmpp_recv->agent = agent; - init_waitqueue_head(&rmpp_recv->wait); + init_completion(&rmpp_recv->comp); INIT_WORK(&rmpp_recv->timeout_work, recv_timeout_handler, rmpp_recv); INIT_WORK(&rmpp_recv->cleanup_work, recv_cleanup_handler, rmpp_recv); spin_lock_init(&rmpp_recv->lock); @@ -279,12 +285,6 @@ error: kfree(rmpp_recv); return NULL; } -static inline void deref_rmpp_recv(struct mad_rmpp_recv *rmpp_recv) -{ - if (atomic_dec_and_test(&rmpp_recv->refcount)) - wake_up(&rmpp_recv->wait); -} - static struct mad_rmpp_recv * find_rmpp_recv(struct ib_mad_agent_private *agent, struct ib_mad_recv_wc *mad_recv_wc) diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c index f6a05965a4e8..9164a09b6ccd 100644 --- a/drivers/infiniband/core/ucm.c +++ b/drivers/infiniband/core/ucm.c @@ -32,6 +32,8 @@ * * $Id: ucm.c 2594 2005-06-13 19:46:02Z libor $ */ + +#include #include #include #include @@ -72,7 +74,7 @@ struct ib_ucm_file { struct ib_ucm_context { int id; - wait_queue_head_t wait; + struct completion comp; atomic_t ref; int events_reported; @@ -138,7 +140,7 @@ static struct ib_ucm_context *ib_ucm_ctx_get(struct ib_ucm_file *file, int id) static void ib_ucm_ctx_put(struct ib_ucm_context *ctx) { if (atomic_dec_and_test(&ctx->ref)) - wake_up(&ctx->wait); + complete(&ctx->comp); } static inline int ib_ucm_new_cm_id(int event) @@ -178,7 +180,7 @@ static struct ib_ucm_context *ib_ucm_ctx_alloc(struct ib_ucm_file *file) return NULL; atomic_set(&ctx->ref, 1); - init_waitqueue_head(&ctx->wait); + init_completion(&ctx->comp); ctx->file = file; INIT_LIST_HEAD(&ctx->events); @@ -586,8 +588,8 @@ static ssize_t ib_ucm_destroy_id(struct ib_ucm_file *file, if (IS_ERR(ctx)) return PTR_ERR(ctx); - atomic_dec(&ctx->ref); - wait_event(ctx->wait, !atomic_read(&ctx->ref)); + ib_ucm_ctx_put(ctx); + wait_for_completion(&ctx->comp); /* No new events will be generated after destroying the cm_id. */ ib_destroy_cm_id(ctx->cm_id); -- cgit v1.2.3-70-g09d2 From 032ebf2620ef99a4fedaa0f77dc2272095ac5863 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 12 May 2006 18:42:09 -0700 Subject: Alternative fix for MMC oops on unmount after removal Make sure to clear the driverfs_dev pointer when we do del_gendisk() (on disk removal), so that other users that may still have a ref to the disk won't try to use the stale pointer. Also move the KOBJ_REMOVE uevent handler up, so that the uevent still has access to the driverfs_dev data. This all should hopefully fix the problems with MMC umounts after device removals that caused commit 56cf6504fc1c0c221b82cebc16a444b684140fb7 and its reversal (1a2acc9e9214699a99389e323e6686e9e0e2ca67). Original problem reported by Todd Blumer and others. Acked-by: Greg KH Cc: Russell King Cc: James Bottomley Cc: Erik Mouw Cc: Andrew Vasquez Cc: Todd Blumer Signed-off-by: Linus Torvalds --- fs/partitions/check.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 45ae7dd3c650..7ef1f094de91 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -533,6 +533,7 @@ void del_gendisk(struct gendisk *disk) devfs_remove_disk(disk); + kobject_uevent(&disk->kobj, KOBJ_REMOVE); if (disk->holder_dir) kobject_unregister(disk->holder_dir); if (disk->slave_dir) @@ -545,7 +546,7 @@ void del_gendisk(struct gendisk *disk) kfree(disk_name); } put_device(disk->driverfs_dev); + disk->driverfs_dev = NULL; } - kobject_uevent(&disk->kobj, KOBJ_REMOVE); kobject_del(&disk->kobj); } -- cgit v1.2.3-70-g09d2 From c3f8abf481c2d2b221b028f7369bc6dd39a9590e Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sat, 13 May 2006 04:03:42 +0100 Subject: [MTD NAND] Use vmalloc for buffer when scanning for bad blocks. These new chips have 128KiB blocks. Don't try to kmalloc that. Signed-off-by: David Woodhouse --- drivers/mtd/nand/nand_bbt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index ca286999fe08..32f063b6e9a5 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -60,7 +60,7 @@ #include #include #include - +#include /** * check_pattern - [GENERIC] check if a pattern is in the buffer @@ -873,7 +873,7 @@ int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd) /* Allocate a temporary buffer for one eraseblock incl. oob */ len = (1 << this->bbt_erase_shift); len += (len >> this->page_shift) * mtd->oobsize; - buf = kmalloc (len, GFP_KERNEL); + buf = vmalloc(len); if (!buf) { printk (KERN_ERR "nand_bbt: Out of memory\n"); kfree (this->bbt); @@ -897,7 +897,7 @@ int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd) if (md) mark_bbt_region (mtd, md); - kfree (buf); + vfree (buf); return res; } -- cgit v1.2.3-70-g09d2 From 9d75414b4fa7390975ef0e2b56ff40425657fe52 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sat, 13 May 2006 04:12:40 +0100 Subject: [MTD NAND] Update CS553x NAND driver: Hardware ECC support, optimisations. - Implement HW ECC support, - Provide read_buf() and write_buf() routines using memcpy - Use on-flash bad block table - Fix module refcounting - Avoid read/modify/write in hwcontrol() - Minor cosmetic fixes Partly based on code and ideas from Tom Sylla Signed-off-by: David Woodhouse --- drivers/mtd/nand/cs553x_nand.c | 102 ++++++++++++++++++++++++++++++----------- 1 file changed, 75 insertions(+), 27 deletions(-) diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c index 91207a45ad55..4f0b338f2f30 100644 --- a/drivers/mtd/nand/cs553x_nand.c +++ b/drivers/mtd/nand/cs553x_nand.c @@ -4,6 +4,7 @@ * (C) 2005, 2006 Red Hat Inc. * * Author: David Woodhouse + * Tom Sylla * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -22,6 +23,7 @@ #include #include #include +#include #include #include @@ -87,11 +89,34 @@ #define CS_NAND_ECC_CLRECC (1<<1) #define CS_NAND_ECC_ENECC (1<<0) +static void cs553x_read_buf(struct mtd_info *mtd, u_char *buf, int len) +{ + struct nand_chip *this = mtd->priv; + + while (unlikely(len > 0x800)) { + memcpy_fromio(buf, this->IO_ADDR_R, 0x800); + buf += 0x800; + len -= 0x800; + } + memcpy_fromio(buf, this->IO_ADDR_R, len); +} + +static void cs553x_write_buf(struct mtd_info *mtd, const u_char *buf, int len) +{ + struct nand_chip *this = mtd->priv; + + while (unlikely(len > 0x800)) { + memcpy_toio(this->IO_ADDR_R, buf, 0x800); + buf += 0x800; + len -= 0x800; + } + memcpy_toio(this->IO_ADDR_R, buf, len); +} + static unsigned char cs553x_read_byte(struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; - unsigned char foo = readb(this->IO_ADDR_R); - return foo; + return readb(this->IO_ADDR_R); } static void cs553x_write_byte(struct mtd_info *mtd, u_char byte) @@ -110,35 +135,29 @@ static void cs553x_hwcontrol(struct mtd_info *mtd, int cmd) { struct nand_chip *this = mtd->priv; void __iomem *mmio_base = this->IO_ADDR_R; - - uint8_t old = readb(mmio_base + MM_NAND_CTL); + unsigned char ctl; switch(cmd) { case NAND_CTL_SETCLE: - old |= CS_NAND_CTL_CLE; + ctl = CS_NAND_CTL_CLE; break; case NAND_CTL_CLRCLE: - old &= ~CS_NAND_CTL_CLE; - break; - - case NAND_CTL_SETALE: - old |= CS_NAND_CTL_ALE; - break; - case NAND_CTL_CLRALE: - old &= ~CS_NAND_CTL_ALE; + case NAND_CTL_SETNCE: + ctl = 0; break; - case NAND_CTL_SETNCE: - old &= ~CS_NAND_CTL_CE; + case NAND_CTL_SETALE: + ctl = CS_NAND_CTL_ALE; break; + default: case NAND_CTL_CLRNCE: - old |= CS_NAND_CTL_CE; + ctl = CS_NAND_CTL_CE; break; } - writeb(old, mmio_base + MM_NAND_CTL); + writeb(ctl, mmio_base + MM_NAND_CTL); } @@ -151,6 +170,29 @@ static int cs553x_device_ready(struct mtd_info *mtd) return (foo & CS_NAND_STS_FLASH_RDY) && !(foo & CS_NAND_CTLR_BUSY); } + +static void cs_enable_hwecc(struct mtd_info *mtd, int mode) +{ + struct nand_chip *this = mtd->priv; + void __iomem *mmio_base = this->IO_ADDR_R; + + writeb(0x07, mmio_base + MM_NAND_ECC_CTL); +} + +static int cs_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code) +{ + uint32_t ecc; + struct nand_chip *this = mtd->priv; + void __iomem *mmio_base = this->IO_ADDR_R; + + ecc = readl(mmio_base + MM_NAND_STS); + + ecc_code[1] = ecc >> 8; + ecc_code[0] = ecc >> 16; + ecc_code[2] = ecc >> 24; + return 0; +} + static struct mtd_info *cs553x_mtd[4]; static int __init cs553x_init_one(int cs, int mmio, unsigned long adr) @@ -167,7 +209,7 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr) } /* Allocate memory for MTD device structure and private data */ - new_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip), GFP_KERNEL); + new_mtd = kmalloc(sizeof(struct mtd_info) + sizeof (struct nand_chip), GFP_KERNEL); if (!new_mtd) { printk(KERN_WARNING "Unable to allocate CS553X NAND MTD device structure.\n"); err = -ENOMEM; @@ -178,8 +220,8 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr) this = (struct nand_chip *) (&new_mtd[1]); /* Initialize structures */ - memset((char *) new_mtd, 0, sizeof(struct mtd_info)); - memset((char *) this, 0, sizeof(struct nand_chip)); + memset(new_mtd, 0, sizeof(struct mtd_info)); + memset(this, 0, sizeof(struct nand_chip)); /* Link the private data with the MTD structure */ new_mtd->priv = this; @@ -196,27 +238,33 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr) this->dev_ready = cs553x_device_ready; this->read_byte = cs553x_read_byte; this->write_byte = cs553x_write_byte; + this->read_buf = cs553x_read_buf; + this->write_buf = cs553x_write_buf; - /* 20 us command delay time */ - this->chip_delay = 20; - this->eccmode = NAND_ECC_SOFT; + this->chip_delay = 0; + this->eccmode = NAND_ECC_HW3_256; + this->enable_hwecc = cs_enable_hwecc; + this->calculate_ecc = cs_calculate_ecc; + this->correct_data = nand_correct_data; + /* Enable the following for a flash based bad block table */ - // this->options = NAND_USE_FLASH_BBT; + this->options = NAND_USE_FLASH_BBT | NAND_NO_AUTOINCR; /* Scan to find existance of the device */ - if (nand_scan (new_mtd, 1)) { + if (nand_scan(new_mtd, 1)) { err = -ENXIO; goto out_ior; } + new_mtd->owner = THIS_MODULE; cs553x_mtd[cs] = new_mtd; goto out; out_ior: iounmap((void *)this->IO_ADDR_R); out_mtd: - kfree (new_mtd); + kfree(new_mtd); out: return err; } @@ -283,7 +331,7 @@ static void __exit cs553x_cleanup (void) iounmap(mmio_base); /* Free the MTD device structure */ - kfree (mtd); + kfree(mtd); } } module_exit(cs553x_cleanup); -- cgit v1.2.3-70-g09d2 From 9be2f7c38e0bd64e8a0f74ea68df1e73e2ddfcc3 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sat, 13 May 2006 08:01:23 -0700 Subject: Revert "[PATCH] i386: export: memory more than 4G through /proc/iomem" This reverts commit 10dbe196a8da6b3196881269c6639c0ec11c36cb. The resource struct is still 32-bit, so trying to save a 64-bit memory size there obviously won't work. When we merge the 64-bit resource series, we can re-enable this. Thanks to Sachin Sant and Maneesh Soni for debugging Cc: Maneesh Soni Cc: Sachin Sant Cc: Russell King Cc: Sharyathi Nagesh Cc: Arjan van de Ven Cc: Vivek Goyal Signed-off-by: Linus Torvalds --- arch/i386/kernel/setup.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index d77e89ac0d54..846e1639ef7c 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c @@ -1320,6 +1320,8 @@ legacy_init_iomem_resources(struct resource *code_resource, struct resource *dat probe_roms(); for (i = 0; i < e820.nr_map; i++) { struct resource *res; + if (e820.map[i].addr + e820.map[i].size > 0x100000000ULL) + continue; res = kzalloc(sizeof(struct resource), GFP_ATOMIC); switch (e820.map[i].type) { case E820_RAM: res->name = "System RAM"; break; -- cgit v1.2.3-70-g09d2 From 6943f8af7d6583be57d67bba8b2644371f6a10ca Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sat, 13 May 2006 16:14:26 +0100 Subject: [MTD NAND] Reduce paranoia level when scanning for bad blocks on virgin chips We were scanning for 0xFF through the entire chip -- which takes a while when it's a 512MiB device as I have on my current toy. The specs only say we need to check certain bytes -- so do only that. Signed-off-by: David Woodhouse --- drivers/mtd/nand/nand_bbt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 32f063b6e9a5..ccc48a4a6ad0 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -981,14 +981,14 @@ static struct nand_bbt_descr largepage_memorybased = { }; static struct nand_bbt_descr smallpage_flashbased = { - .options = NAND_BBT_SCANEMPTY | NAND_BBT_SCANALLPAGES, + .options = NAND_BBT_SCAN2NDPAGE, .offs = 5, .len = 1, .pattern = scan_ff_pattern }; static struct nand_bbt_descr largepage_flashbased = { - .options = NAND_BBT_SCANEMPTY | NAND_BBT_SCANALLPAGES, + .options = NAND_BBT_SCAN2NDPAGE, .offs = 0, .len = 2, .pattern = scan_ff_pattern -- cgit v1.2.3-70-g09d2 From e0c7d7675331140e5186d2d1a0efce1d3877d379 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sat, 13 May 2006 18:07:53 +0100 Subject: [MTD NAND] Indent all of drivers/mtd/nand/*.c. It was just too painful to deal with. Signed-off-by: David Woodhouse --- drivers/mtd/nand/au1550nd.c | 143 ++++---- drivers/mtd/nand/autcpu12.c | 53 ++- drivers/mtd/nand/cs553x_nand.c | 30 +- drivers/mtd/nand/diskonchip.c | 415 ++++++++++++----------- drivers/mtd/nand/edb7312.c | 53 ++- drivers/mtd/nand/h1910.c | 57 ++-- drivers/mtd/nand/nand_base.c | 694 ++++++++++++++++++-------------------- drivers/mtd/nand/nand_bbt.c | 263 +++++++-------- drivers/mtd/nand/nand_ecc.c | 29 +- drivers/mtd/nand/nand_ids.c | 12 +- drivers/mtd/nand/ppchameleonevb.c | 181 +++++----- drivers/mtd/nand/rtc_from4.c | 256 +++++++------- drivers/mtd/nand/s3c2410.c | 79 ++--- drivers/mtd/nand/sharpsl.c | 93 +++-- drivers/mtd/nand/spia.c | 75 ++-- drivers/mtd/nand/toto.c | 65 ++-- drivers/mtd/nand/ts7250.c | 11 +- 17 files changed, 1217 insertions(+), 1292 deletions(-) diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c index bde3550910a2..50cbfd4826fb 100644 --- a/drivers/mtd/nand/au1550nd.c +++ b/drivers/mtd/nand/au1550nd.c @@ -38,22 +38,20 @@ */ static struct mtd_info *au1550_mtd = NULL; static void __iomem *p_nand; -static int nand_width = 1; /* default x8*/ +static int nand_width = 1; /* default x8 */ /* * Define partitions for flash device */ static const struct mtd_partition partition_info[] = { { - .name = "NAND FS 0", - .offset = 0, - .size = 8*1024*1024 - }, + .name = "NAND FS 0", + .offset = 0, + .size = 8 * 1024 * 1024}, { - .name = "NAND FS 1", - .offset = MTDPART_OFS_APPEND, - .size = MTDPART_SIZ_FULL - } + .name = "NAND FS 1", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL} }; /** @@ -157,7 +155,7 @@ static void au_write_buf(struct mtd_info *mtd, const u_char *buf, int len) int i; struct nand_chip *this = mtd->priv; - for (i=0; iIO_ADDR_W); au_sync(); } @@ -176,7 +174,7 @@ static void au_read_buf(struct mtd_info *mtd, u_char *buf, int len) int i; struct nand_chip *this = mtd->priv; - for (i=0; iIO_ADDR_R); au_sync(); } @@ -195,7 +193,7 @@ static int au_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) int i; struct nand_chip *this = mtd->priv; - for (i=0; iIO_ADDR_R)) return -EFAULT; au_sync(); @@ -219,7 +217,7 @@ static void au_write_buf16(struct mtd_info *mtd, const u_char *buf, int len) u16 *p = (u16 *) buf; len >>= 1; - for (i=0; iIO_ADDR_W); au_sync(); } @@ -241,7 +239,7 @@ static void au_read_buf16(struct mtd_info *mtd, u_char *buf, int len) u16 *p = (u16 *) buf; len >>= 1; - for (i=0; iIO_ADDR_R); au_sync(); } @@ -262,7 +260,7 @@ static int au_verify_buf16(struct mtd_info *mtd, const u_char *buf, int len) u16 *p = (u16 *) buf; len >>= 1; - for (i=0; iIO_ADDR_R)) return -EFAULT; au_sync(); @@ -275,27 +273,35 @@ static void au1550_hwcontrol(struct mtd_info *mtd, int cmd) { register struct nand_chip *this = mtd->priv; - switch(cmd){ + switch (cmd) { + + case NAND_CTL_SETCLE: + this->IO_ADDR_W = p_nand + MEM_STNAND_CMD; + break; + + case NAND_CTL_CLRCLE: + this->IO_ADDR_W = p_nand + MEM_STNAND_DATA; + break; - case NAND_CTL_SETCLE: this->IO_ADDR_W = p_nand + MEM_STNAND_CMD; break; - case NAND_CTL_CLRCLE: this->IO_ADDR_W = p_nand + MEM_STNAND_DATA; break; + case NAND_CTL_SETALE: + this->IO_ADDR_W = p_nand + MEM_STNAND_ADDR; + break; - case NAND_CTL_SETALE: this->IO_ADDR_W = p_nand + MEM_STNAND_ADDR; break; case NAND_CTL_CLRALE: this->IO_ADDR_W = p_nand + MEM_STNAND_DATA; - /* FIXME: Nobody knows why this is neccecary, + /* FIXME: Nobody knows why this is necessary, * but it works only that way */ udelay(1); break; case NAND_CTL_SETNCE: /* assert (force assert) chip enable */ - au_writel((1<<(4+NAND_CS)) , MEM_STNDCTL); break; + au_writel((1 << (4 + NAND_CS)), MEM_STNDCTL); break; case NAND_CTL_CLRNCE: - /* deassert chip enable */ - au_writel(0, MEM_STNDCTL); break; + /* deassert chip enable */ + au_writel(0, MEM_STNDCTL); break; } @@ -315,66 +321,63 @@ int au1550_device_ready(struct mtd_info *mtd) /* * Main initialization routine */ -int __init au1xxx_nand_init (void) +int __init au1xxx_nand_init(void) { struct nand_chip *this; - u16 boot_swapboot = 0; /* default value */ + u16 boot_swapboot = 0; /* default value */ int retval; u32 mem_staddr; u32 nand_phys; /* Allocate memory for MTD device structure and private data */ - au1550_mtd = kmalloc (sizeof(struct mtd_info) + - sizeof (struct nand_chip), GFP_KERNEL); + au1550_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); if (!au1550_mtd) { - printk ("Unable to allocate NAND MTD dev structure.\n"); + printk("Unable to allocate NAND MTD dev structure.\n"); return -ENOMEM; } /* Get pointer to private data */ - this = (struct nand_chip *) (&au1550_mtd[1]); + this = (struct nand_chip *)(&au1550_mtd[1]); /* Initialize structures */ - memset((char *) au1550_mtd, 0, sizeof(struct mtd_info)); - memset((char *) this, 0, sizeof(struct nand_chip)); + memset(au1550_mtd, 0, sizeof(struct mtd_info)); + memset(this, 0, sizeof(struct nand_chip)); /* Link the private data with the MTD structure */ au1550_mtd->priv = this; - /* disable interrupts */ - au_writel(au_readl(MEM_STNDCTL) & ~(1<<8), MEM_STNDCTL); + au_writel(au_readl(MEM_STNDCTL) & ~(1 << 8), MEM_STNDCTL); /* disable NAND boot */ - au_writel(au_readl(MEM_STNDCTL) & ~(1<<0), MEM_STNDCTL); + au_writel(au_readl(MEM_STNDCTL) & ~(1 << 0), MEM_STNDCTL); #ifdef CONFIG_MIPS_PB1550 /* set gpio206 high */ - au_writel(au_readl(GPIO2_DIR) & ~(1<<6), GPIO2_DIR); + au_writel(au_readl(GPIO2_DIR) & ~(1 << 6), GPIO2_DIR); - boot_swapboot = (au_readl(MEM_STSTAT) & (0x7<<1)) | - ((bcsr->status >> 6) & 0x1); + boot_swapboot = (au_readl(MEM_STSTAT) & (0x7 << 1)) | ((bcsr->status >> 6) & 0x1); switch (boot_swapboot) { - case 0: - case 2: - case 8: - case 0xC: - case 0xD: - /* x16 NAND Flash */ - nand_width = 0; - break; - case 1: - case 9: - case 3: - case 0xE: - case 0xF: - /* x8 NAND Flash */ - nand_width = 1; - break; - default: - printk("Pb1550 NAND: bad boot:swap\n"); - retval = -EINVAL; - goto outmem; + case 0: + case 2: + case 8: + case 0xC: + case 0xD: + /* x16 NAND Flash */ + nand_width = 0; + break; + case 1: + case 9: + case 3: + case 0xE: + case 0xF: + /* x8 NAND Flash */ + nand_width = 1; + break; + default: + printk("Pb1550 NAND: bad boot:swap\n"); + retval = -EINVAL; + goto outmem; } #endif @@ -424,14 +427,13 @@ int __init au1xxx_nand_init (void) /* make controller and MTD agree */ if (NAND_CS == 0) - nand_width = au_readl(MEM_STCFG0) & (1<<22); + nand_width = au_readl(MEM_STCFG0) & (1 << 22); if (NAND_CS == 1) - nand_width = au_readl(MEM_STCFG1) & (1<<22); + nand_width = au_readl(MEM_STCFG1) & (1 << 22); if (NAND_CS == 2) - nand_width = au_readl(MEM_STCFG2) & (1<<22); + nand_width = au_readl(MEM_STCFG2) & (1 << 22); if (NAND_CS == 3) - nand_width = au_readl(MEM_STCFG3) & (1<<22); - + nand_width = au_readl(MEM_STCFG3) & (1 << 22); /* Set address of hardware control function */ this->hwcontrol = au1550_hwcontrol; @@ -454,7 +456,7 @@ int __init au1xxx_nand_init (void) this->verify_buf = (!nand_width) ? au_verify_buf16 : au_verify_buf; /* Scan to find existence of the device */ - if (nand_scan (au1550_mtd, 1)) { + if (nand_scan(au1550_mtd, 1)) { retval = -ENXIO; goto outio; } @@ -465,10 +467,10 @@ int __init au1xxx_nand_init (void) return 0; outio: - iounmap ((void *)p_nand); + iounmap((void *)p_nand); outmem: - kfree (au1550_mtd); + kfree(au1550_mtd); return retval; } @@ -478,19 +480,20 @@ module_init(au1xxx_nand_init); * Clean up routine */ #ifdef MODULE -static void __exit au1550_cleanup (void) +static void __exit au1550_cleanup(void) { - struct nand_chip *this = (struct nand_chip *) &au1550_mtd[1]; + struct nand_chip *this = (struct nand_chip *)&au1550_mtd[1]; /* Release resources, unregister device */ - nand_release (au1550_mtd); + nand_release(au1550_mtd); /* Free the MTD device structure */ - kfree (au1550_mtd); + kfree(au1550_mtd); /* Unmap */ - iounmap ((void *)p_nand); + iounmap((void *)p_nand); } + module_exit(au1550_cleanup); #endif diff --git a/drivers/mtd/nand/autcpu12.c b/drivers/mtd/nand/autcpu12.c index a3c7fea404d0..9c9f21b0d260 100644 --- a/drivers/mtd/nand/autcpu12.c +++ b/drivers/mtd/nand/autcpu12.c @@ -47,7 +47,7 @@ static int autcpu12_io_base = CS89712_VIRT_BASE; static int autcpu12_fio_pbase = AUTCPU12_PHYS_SMC; static int autcpu12_fio_ctrl = AUTCPU12_SMC_SELECT_OFFSET; static int autcpu12_pedr = AUTCPU12_SMC_PORT_OFFSET; -static void __iomem * autcpu12_fio_base; +static void __iomem *autcpu12_fio_base; /* * Define partitions for flash devices @@ -95,10 +95,10 @@ static struct mtd_partition partition_info128k[] = { /* * hardware specific access to control-lines */ + static void autcpu12_hwcontrol(struct mtd_info *mtd, int cmd) { - - switch(cmd){ + switch (cmd) { case NAND_CTL_SETCLE: (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) |= AUTCPU12_SMC_CLE; break; case NAND_CTL_CLRCLE: (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) &= ~AUTCPU12_SMC_CLE; break; @@ -117,41 +117,40 @@ static void autcpu12_hwcontrol(struct mtd_info *mtd, int cmd) int autcpu12_device_ready(struct mtd_info *mtd) { - return ( (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) & AUTCPU12_SMC_RDY) ? 1 : 0; + return ((*(volatile unsigned char *)(autcpu12_io_base + autcpu12_pedr)) & AUTCPU12_SMC_RDY) ? 1 : 0; } /* * Main initialization routine */ -int __init autcpu12_init (void) +int __init autcpu12_init(void) { struct nand_chip *this; int err = 0; /* Allocate memory for MTD device structure and private data */ - autcpu12_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip), - GFP_KERNEL); + autcpu12_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); if (!autcpu12_mtd) { - printk ("Unable to allocate AUTCPU12 NAND MTD device structure.\n"); + printk("Unable to allocate AUTCPU12 NAND MTD device structure.\n"); err = -ENOMEM; goto out; } /* map physical adress */ - autcpu12_fio_base = ioremap(autcpu12_fio_pbase,SZ_1K); - if(!autcpu12_fio_base){ + autcpu12_fio_base = ioremap(autcpu12_fio_pbase, SZ_1K); + if (!autcpu12_fio_base) { printk("Ioremap autcpu12 SmartMedia Card failed\n"); err = -EIO; goto out_mtd; } /* Get pointer to private data */ - this = (struct nand_chip *) (&autcpu12_mtd[1]); + this = (struct nand_chip *)(&autcpu12_mtd[1]); /* Initialize structures */ - memset((char *) autcpu12_mtd, 0, sizeof(struct mtd_info)); - memset((char *) this, 0, sizeof(struct nand_chip)); + memset(autcpu12_mtd, 0, sizeof(struct mtd_info)); + memset(this, 0, sizeof(struct nand_chip)); /* Link the private data with the MTD structure */ autcpu12_mtd->priv = this; @@ -167,35 +166,34 @@ int __init autcpu12_init (void) /* Enable the following for a flash based bad block table */ /* - this->options = NAND_USE_FLASH_BBT; - */ + this->options = NAND_USE_FLASH_BBT; + */ this->options = NAND_USE_FLASH_BBT; /* Scan to find existance of the device */ - if (nand_scan (autcpu12_mtd, 1)) { + if (nand_scan(autcpu12_mtd, 1)) { err = -ENXIO; goto out_ior; } /* Register the partitions */ - switch(autcpu12_mtd->size){ + switch (autcpu12_mtd->size) { case SZ_16M: add_mtd_partitions(autcpu12_mtd, partition_info16k, NUM_PARTITIONS16K); break; case SZ_32M: add_mtd_partitions(autcpu12_mtd, partition_info32k, NUM_PARTITIONS32K); break; case SZ_64M: add_mtd_partitions(autcpu12_mtd, partition_info64k, NUM_PARTITIONS64K); break; case SZ_128M: add_mtd_partitions(autcpu12_mtd, partition_info128k, NUM_PARTITIONS128K); break; - default: { - printk ("Unsupported SmartMedia device\n"); + default: + printk("Unsupported SmartMedia device\n"); err = -ENXIO; goto out_ior; - } } goto out; -out_ior: + out_ior: iounmap((void *)autcpu12_fio_base); -out_mtd: - kfree (autcpu12_mtd); -out: + out_mtd: + kfree(autcpu12_mtd); + out: return err; } @@ -205,17 +203,18 @@ module_init(autcpu12_init); * Clean up routine */ #ifdef MODULE -static void __exit autcpu12_cleanup (void) +static void __exit autcpu12_cleanup(void) { /* Release resources, unregister device */ - nand_release (autcpu12_mtd); + nand_release(autcpu12_mtd); /* unmap physical adress */ iounmap((void *)autcpu12_fio_base); /* Free the MTD device structure */ - kfree (autcpu12_mtd); + kfree(autcpu12_mtd); } + module_exit(autcpu12_cleanup); #endif diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c index 4f0b338f2f30..fba7be5cffe3 100644 --- a/drivers/mtd/nand/cs553x_nand.c +++ b/drivers/mtd/nand/cs553x_nand.c @@ -50,7 +50,7 @@ /* Pin function selection MSR (IDE vs. flash on the IDE pins) */ #define MSR_DIVIL_BALL_OPTS 0x51400015 -#define PIN_OPT_IDE (1<<0) /* 0 for flash, 1 for IDE */ +#define PIN_OPT_IDE (1<<0) /* 0 for flash, 1 for IDE */ /* Registers within the NAND flash controller BAR -- memory mapped */ #define MM_NAND_DATA 0x00 /* 0 to 0x7ff, in fact */ @@ -128,7 +128,7 @@ static void cs553x_write_byte(struct mtd_info *mtd, u_char byte) udelay(1); i--; } - writeb(byte, this->IO_ADDR_W+0x801); + writeb(byte, this->IO_ADDR_W + 0x801); } static void cs553x_hwcontrol(struct mtd_info *mtd, int cmd) @@ -137,7 +137,7 @@ static void cs553x_hwcontrol(struct mtd_info *mtd, int cmd) void __iomem *mmio_base = this->IO_ADDR_R; unsigned char ctl; - switch(cmd) { + switch (cmd) { case NAND_CTL_SETCLE: ctl = CS_NAND_CTL_CLE; break; @@ -160,17 +160,15 @@ static void cs553x_hwcontrol(struct mtd_info *mtd, int cmd) writeb(ctl, mmio_base + MM_NAND_CTL); } - static int cs553x_device_ready(struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; void __iomem *mmio_base = this->IO_ADDR_R; unsigned char foo = readb(mmio_base + MM_NAND_STS); - return (foo & CS_NAND_STS_FLASH_RDY) && !(foo & CS_NAND_CTLR_BUSY); + return (foo & CS_NAND_STS_FLASH_RDY) && !(foo & CS_NAND_CTLR_BUSY); } - static void cs_enable_hwecc(struct mtd_info *mtd, int mode) { struct nand_chip *this = mtd->priv; @@ -209,7 +207,7 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr) } /* Allocate memory for MTD device structure and private data */ - new_mtd = kmalloc(sizeof(struct mtd_info) + sizeof (struct nand_chip), GFP_KERNEL); + new_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); if (!new_mtd) { printk(KERN_WARNING "Unable to allocate CS553X NAND MTD device structure.\n"); err = -ENOMEM; @@ -217,7 +215,7 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr) } /* Get pointer to private data */ - this = (struct nand_chip *) (&new_mtd[1]); + this = (struct nand_chip *)(&new_mtd[1]); /* Initialize structures */ memset(new_mtd, 0, sizeof(struct mtd_info)); @@ -286,16 +284,16 @@ int __init cs553x_init(void) return -ENXIO; } - for (i=0; iIO_ADDR_R; /* Release resources, unregister device */ - nand_release (cs553x_mtd[i]); + nand_release(cs553x_mtd[i]); cs553x_mtd[i] = NULL; /* unmap physical adress */ @@ -334,6 +333,7 @@ static void __exit cs553x_cleanup (void) kfree(mtd); } } + module_exit(cs553x_cleanup); MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index ec5e45e4e4ef..a2391c66a63f 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -58,10 +58,10 @@ static unsigned long __initdata doc_locations[] = { 0xe4000000, #elif defined(CONFIG_MOMENCO_OCELOT) 0x2f000000, - 0xff000000, + 0xff000000, #elif defined(CONFIG_MOMENCO_OCELOT_G) || defined (CONFIG_MOMENCO_OCELOT_C) - 0xff000000, -##else + 0xff000000, +#else #warning Unknown architecture for DiskOnChip. No default probe locations defined #endif 0xffffffff }; @@ -73,7 +73,7 @@ struct doc_priv { unsigned long physadr; u_char ChipID; u_char CDSNControl; - int chips_per_floor; /* The number of chips detected on each floor */ + int chips_per_floor; /* The number of chips detected on each floor */ int curfloor; int curchip; int mh0_page; @@ -84,6 +84,7 @@ struct doc_priv { /* This is the syndrome computed by the HW ecc generator upon reading an empty page, one with all 0xff for data and stored ecc code. */ static u_char empty_read_syndrome[6] = { 0x26, 0xff, 0x6d, 0x47, 0x73, 0x7a }; + /* This is the ecc value computed by the HW ecc generator upon writing an empty page, one with all 0xff for data. */ static u_char empty_write_ecc[6] = { 0x4b, 0x00, 0xe2, 0x0e, 0x93, 0xf7 }; @@ -97,25 +98,25 @@ static u_char empty_write_ecc[6] = { 0x4b, 0x00, 0xe2, 0x0e, 0x93, 0xf7 }; static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd); static void doc200x_select_chip(struct mtd_info *mtd, int chip); -static int debug=0; +static int debug = 0; module_param(debug, int, 0); -static int try_dword=1; +static int try_dword = 1; module_param(try_dword, int, 0); -static int no_ecc_failures=0; +static int no_ecc_failures = 0; module_param(no_ecc_failures, int, 0); -static int no_autopart=0; +static int no_autopart = 0; module_param(no_autopart, int, 0); -static int show_firmware_partition=0; +static int show_firmware_partition = 0; module_param(show_firmware_partition, int, 0); #ifdef MTD_NAND_DISKONCHIP_BBTWRITE -static int inftl_bbt_write=1; +static int inftl_bbt_write = 1; #else -static int inftl_bbt_write=0; +static int inftl_bbt_write = 0; #endif module_param(inftl_bbt_write, int, 0); @@ -123,7 +124,6 @@ static unsigned long doc_config_location = CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDR module_param(doc_config_location, ulong, 0); MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe for DiskOnChip"); - /* Sector size for HW ECC */ #define SECTOR_SIZE 512 /* The sector bytes are packed into NB_DATA 10 bit words */ @@ -147,7 +147,7 @@ static struct rs_control *rs_decoder; * some comments, improved a minor bit and converted it to make use * of the generic Reed-Solomon libary. tglx */ -static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc) +static int doc_ecc_decode(struct rs_control *rs, uint8_t *data, uint8_t *ecc) { int i, j, nerr, errpos[8]; uint8_t parity; @@ -168,18 +168,18 @@ static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc) * s[i] = ds[3]x^3 + ds[2]x^2 + ds[1]x^1 + ds[0] * where x = alpha^(FCR + i) */ - for(j = 1; j < NROOTS; j++) { - if(ds[j] == 0) + for (j = 1; j < NROOTS; j++) { + if (ds[j] == 0) continue; tmp = rs->index_of[ds[j]]; - for(i = 0; i < NROOTS; i++) + for (i = 0; i < NROOTS; i++) s[i] ^= rs->alpha_to[rs_modnn(rs, tmp + (FCR + i) * j)]; } /* Calc s[i] = s[i] / alpha^(v + i) */ for (i = 0; i < NROOTS; i++) { if (syn[i]) - syn[i] = rs_modnn(rs, rs->index_of[s[i]] + (NN - FCR - i)); + syn[i] = rs_modnn(rs, rs->index_of[s[i]] + (NN - FCR - i)); } /* Call the decoder library */ nerr = decode_rs16(rs, NULL, NULL, 1019, syn, 0, errpos, 0, errval); @@ -193,7 +193,7 @@ static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc) * but they are given by the design of the de/encoder circuit * in the DoC ASIC's. */ - for(i = 0;i < nerr; i++) { + for (i = 0; i < nerr; i++) { int index, bitpos, pos = 1015 - errpos[i]; uint8_t val; if (pos >= NB_DATA && pos < 1019) @@ -205,8 +205,7 @@ static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc) can be modified since pos is even */ index = (pos >> 3) ^ 1; bitpos = pos & 7; - if ((index >= 0 && index < SECTOR_SIZE) || - index == (SECTOR_SIZE + 1)) { + if ((index >= 0 && index < SECTOR_SIZE) || index == (SECTOR_SIZE + 1)) { val = (uint8_t) (errval[i] >> (2 + bitpos)); parity ^= val; if (index < SECTOR_SIZE) @@ -216,9 +215,8 @@ static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc) bitpos = (bitpos + 10) & 7; if (bitpos == 0) bitpos = 8; - if ((index >= 0 && index < SECTOR_SIZE) || - index == (SECTOR_SIZE + 1)) { - val = (uint8_t)(errval[i] << (8 - bitpos)); + if ((index >= 0 && index < SECTOR_SIZE) || index == (SECTOR_SIZE + 1)) { + val = (uint8_t) (errval[i] << (8 - bitpos)); parity ^= val; if (index < SECTOR_SIZE) data[index] ^= val; @@ -250,10 +248,11 @@ static void DoC_Delay(struct doc_priv *doc, unsigned short cycles) /* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */ static int _DoC_WaitReady(struct doc_priv *doc) { - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; unsigned long timeo = jiffies + (HZ * 10); - if(debug) printk("_DoC_WaitReady...\n"); + if (debug) + printk("_DoC_WaitReady...\n"); /* Out-of-line routine to wait for chip response */ if (DoC_is_MillenniumPlus(doc)) { while ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK) { @@ -280,7 +279,7 @@ static int _DoC_WaitReady(struct doc_priv *doc) static inline int DoC_WaitReady(struct doc_priv *doc) { - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; int ret = 0; if (DoC_is_MillenniumPlus(doc)) { @@ -298,7 +297,8 @@ static inline int DoC_WaitReady(struct doc_priv *doc) DoC_Delay(doc, 2); } - if(debug) printk("DoC_WaitReady OK\n"); + if (debug) + printk("DoC_WaitReady OK\n"); return ret; } @@ -306,9 +306,10 @@ static void doc2000_write_byte(struct mtd_info *mtd, u_char datum) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; - if(debug)printk("write_byte %02x\n", datum); + if (debug) + printk("write_byte %02x\n", datum); WriteDOC(datum, docptr, CDSNSlowIO); WriteDOC(datum, docptr, 2k_CDSN_IO); } @@ -317,77 +318,78 @@ static u_char doc2000_read_byte(struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; u_char ret; ReadDOC(docptr, CDSNSlowIO); DoC_Delay(doc, 2); ret = ReadDOC(docptr, 2k_CDSN_IO); - if (debug) printk("read_byte returns %02x\n", ret); + if (debug) + printk("read_byte returns %02x\n", ret); return ret; } -static void doc2000_writebuf(struct mtd_info *mtd, - const u_char *buf, int len) +static void doc2000_writebuf(struct mtd_info *mtd, const u_char *buf, int len) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; int i; - if (debug)printk("writebuf of %d bytes: ", len); - for (i=0; i < len; i++) { + if (debug) + printk("writebuf of %d bytes: ", len); + for (i = 0; i < len; i++) { WriteDOC_(buf[i], docptr, DoC_2k_CDSN_IO + i); if (debug && i < 16) printk("%02x ", buf[i]); } - if (debug) printk("\n"); + if (debug) + printk("\n"); } -static void doc2000_readbuf(struct mtd_info *mtd, - u_char *buf, int len) +static void doc2000_readbuf(struct mtd_info *mtd, u_char *buf, int len) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; - int i; + void __iomem *docptr = doc->virtadr; + int i; - if (debug)printk("readbuf of %d bytes: ", len); + if (debug) + printk("readbuf of %d bytes: ", len); - for (i=0; i < len; i++) { + for (i = 0; i < len; i++) { buf[i] = ReadDOC(docptr, 2k_CDSN_IO + i); } } -static void doc2000_readbuf_dword(struct mtd_info *mtd, - u_char *buf, int len) +static void doc2000_readbuf_dword(struct mtd_info *mtd, u_char *buf, int len) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; - int i; + void __iomem *docptr = doc->virtadr; + int i; - if (debug) printk("readbuf_dword of %d bytes: ", len); + if (debug) + printk("readbuf_dword of %d bytes: ", len); - if (unlikely((((unsigned long)buf)|len) & 3)) { - for (i=0; i < len; i++) { - *(uint8_t *)(&buf[i]) = ReadDOC(docptr, 2k_CDSN_IO + i); + if (unlikely((((unsigned long)buf) | len) & 3)) { + for (i = 0; i < len; i++) { + *(uint8_t *) (&buf[i]) = ReadDOC(docptr, 2k_CDSN_IO + i); } } else { - for (i=0; i < len; i+=4) { - *(uint32_t*)(&buf[i]) = readl(docptr + DoC_2k_CDSN_IO + i); + for (i = 0; i < len; i += 4) { + *(uint32_t *) (&buf[i]) = readl(docptr + DoC_2k_CDSN_IO + i); } } } -static int doc2000_verifybuf(struct mtd_info *mtd, - const u_char *buf, int len) +static int doc2000_verifybuf(struct mtd_info *mtd, const u_char *buf, int len) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; int i; - for (i=0; i < len; i++) + for (i = 0; i < len; i++) if (buf[i] != ReadDOC(docptr, 2k_CDSN_IO)) return -EFAULT; return 0; @@ -482,7 +484,7 @@ static void doc2001_write_byte(struct mtd_info *mtd, u_char datum) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; WriteDOC(datum, docptr, CDSNSlowIO); WriteDOC(datum, docptr, Mil_CDSN_IO); @@ -493,7 +495,7 @@ static u_char doc2001_read_byte(struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; //ReadDOC(docptr, CDSNSlowIO); /* 11.4.5 -- delay twice to allow extended length cycle */ @@ -503,50 +505,47 @@ static u_char doc2001_read_byte(struct mtd_info *mtd) return ReadDOC(docptr, LastDataRead); } -static void doc2001_writebuf(struct mtd_info *mtd, - const u_char *buf, int len) +static void doc2001_writebuf(struct mtd_info *mtd, const u_char *buf, int len) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; int i; - for (i=0; i < len; i++) + for (i = 0; i < len; i++) WriteDOC_(buf[i], docptr, DoC_Mil_CDSN_IO + i); /* Terminate write pipeline */ WriteDOC(0x00, docptr, WritePipeTerm); } -static void doc2001_readbuf(struct mtd_info *mtd, - u_char *buf, int len) +static void doc2001_readbuf(struct mtd_info *mtd, u_char *buf, int len) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; int i; /* Start read pipeline */ ReadDOC(docptr, ReadPipeInit); - for (i=0; i < len-1; i++) + for (i = 0; i < len - 1; i++) buf[i] = ReadDOC(docptr, Mil_CDSN_IO + (i & 0xff)); /* Terminate read pipeline */ buf[i] = ReadDOC(docptr, LastDataRead); } -static int doc2001_verifybuf(struct mtd_info *mtd, - const u_char *buf, int len) +static int doc2001_verifybuf(struct mtd_info *mtd, const u_char *buf, int len) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; int i; /* Start read pipeline */ ReadDOC(docptr, ReadPipeInit); - for (i=0; i < len-1; i++) + for (i = 0; i < len - 1; i++) if (buf[i] != ReadDOC(docptr, Mil_CDSN_IO)) { ReadDOC(docptr, LastDataRead); return i; @@ -560,87 +559,90 @@ static u_char doc2001plus_read_byte(struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; u_char ret; - ReadDOC(docptr, Mplus_ReadPipeInit); - ReadDOC(docptr, Mplus_ReadPipeInit); - ret = ReadDOC(docptr, Mplus_LastDataRead); - if (debug) printk("read_byte returns %02x\n", ret); + ReadDOC(docptr, Mplus_ReadPipeInit); + ReadDOC(docptr, Mplus_ReadPipeInit); + ret = ReadDOC(docptr, Mplus_LastDataRead); + if (debug) + printk("read_byte returns %02x\n", ret); return ret; } -static void doc2001plus_writebuf(struct mtd_info *mtd, - const u_char *buf, int len) +static void doc2001plus_writebuf(struct mtd_info *mtd, const u_char *buf, int len) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; int i; - if (debug)printk("writebuf of %d bytes: ", len); - for (i=0; i < len; i++) { + if (debug) + printk("writebuf of %d bytes: ", len); + for (i = 0; i < len; i++) { WriteDOC_(buf[i], docptr, DoC_Mil_CDSN_IO + i); if (debug && i < 16) printk("%02x ", buf[i]); } - if (debug) printk("\n"); + if (debug) + printk("\n"); } -static void doc2001plus_readbuf(struct mtd_info *mtd, - u_char *buf, int len) +static void doc2001plus_readbuf(struct mtd_info *mtd, u_char *buf, int len) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; int i; - if (debug)printk("readbuf of %d bytes: ", len); + if (debug) + printk("readbuf of %d bytes: ", len); /* Start read pipeline */ ReadDOC(docptr, Mplus_ReadPipeInit); ReadDOC(docptr, Mplus_ReadPipeInit); - for (i=0; i < len-2; i++) { + for (i = 0; i < len - 2; i++) { buf[i] = ReadDOC(docptr, Mil_CDSN_IO); if (debug && i < 16) printk("%02x ", buf[i]); } /* Terminate read pipeline */ - buf[len-2] = ReadDOC(docptr, Mplus_LastDataRead); + buf[len - 2] = ReadDOC(docptr, Mplus_LastDataRead); if (debug && i < 16) - printk("%02x ", buf[len-2]); - buf[len-1] = ReadDOC(docptr, Mplus_LastDataRead); + printk("%02x ", buf[len - 2]); + buf[len - 1] = ReadDOC(docptr, Mplus_LastDataRead); if (debug && i < 16) - printk("%02x ", buf[len-1]); - if (debug) printk("\n"); + printk("%02x ", buf[len - 1]); + if (debug) + printk("\n"); } -static int doc2001plus_verifybuf(struct mtd_info *mtd, - const u_char *buf, int len) +static int doc2001plus_verifybuf(struct mtd_info *mtd, const u_char *buf, int len) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; int i; - if (debug)printk("verifybuf of %d bytes: ", len); + if (debug) + printk("verifybuf of %d bytes: ", len); /* Start read pipeline */ ReadDOC(docptr, Mplus_ReadPipeInit); ReadDOC(docptr, Mplus_ReadPipeInit); - for (i=0; i < len-2; i++) + for (i = 0; i < len - 2; i++) if (buf[i] != ReadDOC(docptr, Mil_CDSN_IO)) { ReadDOC(docptr, Mplus_LastDataRead); ReadDOC(docptr, Mplus_LastDataRead); return i; } - if (buf[len-2] != ReadDOC(docptr, Mplus_LastDataRead)) - return len-2; - if (buf[len-1] != ReadDOC(docptr, Mplus_LastDataRead)) - return len-1; + if (buf[len - 2] != ReadDOC(docptr, Mplus_LastDataRead)) + return len - 2; + if (buf[len - 1] != ReadDOC(docptr, Mplus_LastDataRead)) + return len - 1; return 0; } @@ -648,10 +650,11 @@ static void doc2001plus_select_chip(struct mtd_info *mtd, int chip) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; int floor = 0; - if(debug)printk("select chip (%d)\n", chip); + if (debug) + printk("select chip (%d)\n", chip); if (chip == -1) { /* Disable flash internally */ @@ -660,7 +663,7 @@ static void doc2001plus_select_chip(struct mtd_info *mtd, int chip) } floor = chip / doc->chips_per_floor; - chip -= (floor * doc->chips_per_floor); + chip -= (floor * doc->chips_per_floor); /* Assert ChipEnable and deassert WriteProtect */ WriteDOC((DOC_FLASH_CE), docptr, Mplus_FlashSelect); @@ -674,16 +677,17 @@ static void doc200x_select_chip(struct mtd_info *mtd, int chip) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; int floor = 0; - if(debug)printk("select chip (%d)\n", chip); + if (debug) + printk("select chip (%d)\n", chip); if (chip == -1) return; floor = chip / doc->chips_per_floor; - chip -= (floor * doc->chips_per_floor); + chip -= (floor * doc->chips_per_floor); /* 11.4.4 -- deassert CE before changing chip */ doc200x_hwcontrol(mtd, NAND_CTL_CLRNCE); @@ -701,9 +705,9 @@ static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; - switch(cmd) { + switch (cmd) { case NAND_CTL_SETNCE: doc->CDSNControl |= CDSN_CTRL_CE; break; @@ -729,17 +733,18 @@ static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd) doc->CDSNControl &= ~CDSN_CTRL_WP; break; } - if (debug)printk("hwcontrol(%d): %02x\n", cmd, doc->CDSNControl); + if (debug) + printk("hwcontrol(%d): %02x\n", cmd, doc->CDSNControl); WriteDOC(doc->CDSNControl, docptr, CDSNControl); /* 11.4.3 -- 4 NOPs after CSDNControl write */ DoC_Delay(doc, 4); } -static void doc2001plus_command (struct mtd_info *mtd, unsigned command, int column, int page_addr) +static void doc2001plus_command(struct mtd_info *mtd, unsigned command, int column, int page_addr) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; /* * Must terminate write pipeline before sending any commands @@ -782,25 +787,26 @@ static void doc2001plus_command (struct mtd_info *mtd, unsigned command, int col WriteDOC(column, docptr, Mplus_FlashAddress); } if (page_addr != -1) { - WriteDOC((unsigned char) (page_addr & 0xff), docptr, Mplus_FlashAddress); - WriteDOC((unsigned char) ((page_addr >> 8) & 0xff), docptr, Mplus_FlashAddress); + WriteDOC((unsigned char)(page_addr & 0xff), docptr, Mplus_FlashAddress); + WriteDOC((unsigned char)((page_addr >> 8) & 0xff), docptr, Mplus_FlashAddress); /* One more address cycle for higher density devices */ if (this->chipsize & 0x0c000000) { - WriteDOC((unsigned char) ((page_addr >> 16) & 0x0f), docptr, Mplus_FlashAddress); + WriteDOC((unsigned char)((page_addr >> 16) & 0x0f), docptr, Mplus_FlashAddress); printk("high density\n"); } } WriteDOC(0, docptr, Mplus_WritePipeTerm); WriteDOC(0, docptr, Mplus_WritePipeTerm); /* deassert ALE */ - if (command == NAND_CMD_READ0 || command == NAND_CMD_READ1 || command == NAND_CMD_READOOB || command == NAND_CMD_READID) + if (command == NAND_CMD_READ0 || command == NAND_CMD_READ1 || + command == NAND_CMD_READOOB || command == NAND_CMD_READID) WriteDOC(0, docptr, Mplus_FlashControl); } /* * program and erase have their own busy handlers * status and sequential in needs no delay - */ + */ switch (command) { case NAND_CMD_PAGEPROG: @@ -817,55 +823,57 @@ static void doc2001plus_command (struct mtd_info *mtd, unsigned command, int col WriteDOC(NAND_CMD_STATUS, docptr, Mplus_FlashCmd); WriteDOC(0, docptr, Mplus_WritePipeTerm); WriteDOC(0, docptr, Mplus_WritePipeTerm); - while ( !(this->read_byte(mtd) & 0x40)); + while (!(this->read_byte(mtd) & 0x40)) ; return; - /* This applies to read commands */ + /* This applies to read commands */ default: /* * If we don't have access to the busy pin, we apply the given * command delay - */ + */ if (!this->dev_ready) { - udelay (this->chip_delay); + udelay(this->chip_delay); return; } } /* Apply this short delay always to ensure that we do wait tWB in * any case on any machine. */ - ndelay (100); + ndelay(100); /* wait until command is processed */ - while (!this->dev_ready(mtd)); + while (!this->dev_ready(mtd)) ; } static int doc200x_dev_ready(struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; if (DoC_is_MillenniumPlus(doc)) { /* 11.4.2 -- must NOP four times before checking FR/B# */ DoC_Delay(doc, 4); if ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK) { - if(debug) + if (debug) printk("not ready\n"); return 0; } - if (debug)printk("was ready\n"); + if (debug) + printk("was ready\n"); return 1; } else { /* 11.4.2 -- must NOP four times before checking FR/B# */ DoC_Delay(doc, 4); if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) { - if(debug) + if (debug) printk("not ready\n"); return 0; } /* 11.4.2 -- Must NOP twice if it's ready */ DoC_Delay(doc, 2); - if (debug)printk("was ready\n"); + if (debug) + printk("was ready\n"); return 1; } } @@ -881,10 +889,10 @@ static void doc200x_enable_hwecc(struct mtd_info *mtd, int mode) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; /* Prime the ECC engine */ - switch(mode) { + switch (mode) { case NAND_ECC_READ: WriteDOC(DOC_ECC_RESET, docptr, ECCConf); WriteDOC(DOC_ECC_EN, docptr, ECCConf); @@ -900,10 +908,10 @@ static void doc2001plus_enable_hwecc(struct mtd_info *mtd, int mode) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; /* Prime the ECC engine */ - switch(mode) { + switch (mode) { case NAND_ECC_READ: WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf); WriteDOC(DOC_ECC_EN, docptr, Mplus_ECCConf); @@ -916,12 +924,11 @@ static void doc2001plus_enable_hwecc(struct mtd_info *mtd, int mode) } /* This code is only called on write */ -static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat, - unsigned char *ecc_code) +static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat, unsigned char *ecc_code) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; int i; int emptymatch = 1; @@ -961,7 +968,8 @@ static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat, often. It could be optimized away by examining the data in the writebuf routine, and remembering the result. */ for (i = 0; i < 512; i++) { - if (dat[i] == 0xff) continue; + if (dat[i] == 0xff) + continue; emptymatch = 0; break; } @@ -969,7 +977,8 @@ static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat, /* If emptymatch still =1, we do have an all-0xff data buffer. Return all-0xff ecc value instead of the computed one, so it'll look just like a freshly-erased page. */ - if (emptymatch) memset(ecc_code, 0xff, 6); + if (emptymatch) + memset(ecc_code, 0xff, 6); #endif return 0; } @@ -979,7 +988,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ int i, ret = 0; struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; volatile u_char dummy; int emptymatch = 1; @@ -1012,18 +1021,20 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ all-0xff data and stored ecc block. Check the stored ecc. */ if (emptymatch) { for (i = 0; i < 6; i++) { - if (read_ecc[i] == 0xff) continue; + if (read_ecc[i] == 0xff) + continue; emptymatch = 0; break; } } /* If emptymatch still =1, check the data block. */ if (emptymatch) { - /* Note: this somewhat expensive test should not be triggered - often. It could be optimized away by examining the data in - the readbuf routine, and remembering the result. */ + /* Note: this somewhat expensive test should not be triggered + often. It could be optimized away by examining the data in + the readbuf routine, and remembering the result. */ for (i = 0; i < 512; i++) { - if (dat[i] == 0xff) continue; + if (dat[i] == 0xff) + continue; emptymatch = 0; break; } @@ -1032,7 +1043,8 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ erased block, in which case the ECC will not come out right. We'll suppress the error and tell the caller everything's OK. Because it is. */ - if (!emptymatch) ret = doc_ecc_decode (rs_decoder, dat, calc_ecc); + if (!emptymatch) + ret = doc_ecc_decode(rs_decoder, dat, calc_ecc); if (ret > 0) printk(KERN_ERR "doc200x_correct_data corrected %d errors\n", ret); } @@ -1060,10 +1072,10 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ * be able to handle out-of-order segments. */ static struct nand_oobinfo doc200x_oobinfo = { - .useecc = MTD_NANDECC_AUTOPLACE, - .eccbytes = 6, - .eccpos = {0, 1, 2, 3, 4, 5}, - .oobfree = { {8, 8}, {6, 2} } + .useecc = MTD_NANDECC_AUTOPLACE, + .eccbytes = 6, + .eccpos = {0, 1, 2, 3, 4, 5}, + .oobfree = {{8, 8}, {6, 2}} }; /* Find the (I)NFTL Media Header, and optionally also the mirror media header. @@ -1072,8 +1084,7 @@ static struct nand_oobinfo doc200x_oobinfo = { either "ANAND" or "BNAND". If findmirror=1, also look for the mirror media header. The page #s of the found media headers are placed in mh0_page and mh1_page in the DOC private structure. */ -static int __init find_media_headers(struct mtd_info *mtd, u_char *buf, - const char *id, int findmirror) +static int __init find_media_headers(struct mtd_info *mtd, u_char *buf, const char *id, int findmirror) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; @@ -1083,16 +1094,18 @@ static int __init find_media_headers(struct mtd_info *mtd, u_char *buf, for (offs = 0; offs < mtd->size; offs += mtd->erasesize) { ret = mtd->read(mtd, offs, mtd->oobblock, &retlen, buf); - if (retlen != mtd->oobblock) continue; + if (retlen != mtd->oobblock) + continue; if (ret) { - printk(KERN_WARNING "ECC error scanning DOC at 0x%x\n", - offs); + printk(KERN_WARNING "ECC error scanning DOC at 0x%x\n", offs); } - if (memcmp(buf, id, 6)) continue; + if (memcmp(buf, id, 6)) + continue; printk(KERN_INFO "Found DiskOnChip %s Media Header at 0x%x\n", id, offs); if (doc->mh0_page == -1) { doc->mh0_page = offs >> this->page_shift; - if (!findmirror) return 1; + if (!findmirror) + return 1; continue; } doc->mh1_page = offs >> this->page_shift; @@ -1114,8 +1127,7 @@ static int __init find_media_headers(struct mtd_info *mtd, u_char *buf, return 1; } -static inline int __init nftl_partscan(struct mtd_info *mtd, - struct mtd_partition *parts) +static inline int __init nftl_partscan(struct mtd_info *mtd, struct mtd_partition *parts) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; @@ -1132,8 +1144,9 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, printk(KERN_ERR "DiskOnChip mediaheader kmalloc failed!\n"); return 0; } - if (!(numheaders=find_media_headers(mtd, buf, "ANAND", 1))) goto out; - mh = (struct NFTLMediaHeader *) buf; + if (!(numheaders = find_media_headers(mtd, buf, "ANAND", 1))) + goto out; + mh = (struct NFTLMediaHeader *)buf; mh->NumEraseUnits = le16_to_cpu(mh->NumEraseUnits); mh->FirstPhysicalEUN = le16_to_cpu(mh->FirstPhysicalEUN); @@ -1155,8 +1168,8 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, /* Auto-determine UnitSizeFactor. The constraints are: - There can be at most 32768 virtual blocks. - There can be at most (virtual block size - page size) - virtual blocks (because MediaHeader+BBT must fit in 1). - */ + virtual blocks (because MediaHeader+BBT must fit in 1). + */ mh->UnitSizeFactor = 0xff; while (blocks > maxblocks) { blocks >>= 1; @@ -1211,14 +1224,13 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, } ret = numparts; -out: + out: kfree(buf); return ret; } /* This is a stripped-down copy of the code in inftlmount.c */ -static inline int __init inftl_partscan(struct mtd_info *mtd, - struct mtd_partition *parts) +static inline int __init inftl_partscan(struct mtd_info *mtd, struct mtd_partition *parts) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; @@ -1241,9 +1253,10 @@ static inline int __init inftl_partscan(struct mtd_info *mtd, return 0; } - if (!find_media_headers(mtd, buf, "BNAND", 0)) goto out; + if (!find_media_headers(mtd, buf, "BNAND", 0)) + goto out; doc->mh1_page = doc->mh0_page + (4096 >> this->page_shift); - mh = (struct INFTLMediaHeader *) buf; + mh = (struct INFTLMediaHeader *)buf; mh->NoOfBootImageBlocks = le32_to_cpu(mh->NoOfBootImageBlocks); mh->NoOfBinaryPartitions = le32_to_cpu(mh->NoOfBinaryPartitions); @@ -1319,8 +1332,10 @@ static inline int __init inftl_partscan(struct mtd_info *mtd, parts[numparts].offset = ip->firstUnit << vshift; parts[numparts].size = (1 + ip->lastUnit - ip->firstUnit) << vshift; numparts++; - if (ip->lastUnit > lastvunit) lastvunit = ip->lastUnit; - if (ip->flags & INFTL_LAST) break; + if (ip->lastUnit > lastvunit) + lastvunit = ip->lastUnit; + if (ip->flags & INFTL_LAST) + break; } lastvunit++; if ((lastvunit << vshift) < end) { @@ -1330,7 +1345,7 @@ static inline int __init inftl_partscan(struct mtd_info *mtd, numparts++; } ret = numparts; -out: + out: kfree(buf); return ret; } @@ -1342,11 +1357,12 @@ static int __init nftl_scan_bbt(struct mtd_info *mtd) struct doc_priv *doc = this->priv; struct mtd_partition parts[2]; - memset((char *) parts, 0, sizeof(parts)); + memset((char *)parts, 0, sizeof(parts)); /* On NFTL, we have to find the media headers before we can read the BBTs, since they're stored in the media header eraseblocks. */ numparts = nftl_partscan(mtd, parts); - if (!numparts) return -EIO; + if (!numparts) + return -EIO; this->bbt_td->options = NAND_BBT_ABSPAGE | NAND_BBT_8BIT | NAND_BBT_SAVECONTENT | NAND_BBT_WRITE | NAND_BBT_VERSION; @@ -1393,8 +1409,7 @@ static int __init inftl_scan_bbt(struct mtd_info *mtd) this->bbt_td->pages[0] = 2; this->bbt_md = NULL; } else { - this->bbt_td->options = NAND_BBT_LASTBLOCK | NAND_BBT_8BIT | - NAND_BBT_VERSION; + this->bbt_td->options = NAND_BBT_LASTBLOCK | NAND_BBT_8BIT | NAND_BBT_VERSION; if (inftl_bbt_write) this->bbt_td->options |= NAND_BBT_WRITE; this->bbt_td->offs = 8; @@ -1404,8 +1419,7 @@ static int __init inftl_scan_bbt(struct mtd_info *mtd) this->bbt_td->reserved_block_code = 0x01; this->bbt_td->pattern = "MSYS_BBT"; - this->bbt_md->options = NAND_BBT_LASTBLOCK | NAND_BBT_8BIT | - NAND_BBT_VERSION; + this->bbt_md->options = NAND_BBT_LASTBLOCK | NAND_BBT_8BIT | NAND_BBT_VERSION; if (inftl_bbt_write) this->bbt_md->options |= NAND_BBT_WRITE; this->bbt_md->offs = 8; @@ -1420,12 +1434,13 @@ static int __init inftl_scan_bbt(struct mtd_info *mtd) At least as nand_bbt.c is currently written. */ if ((ret = nand_scan_bbt(mtd, NULL))) return ret; - memset((char *) parts, 0, sizeof(parts)); + memset((char *)parts, 0, sizeof(parts)); numparts = inftl_partscan(mtd, parts); /* At least for now, require the INFTL Media Header. We could probably do without it for non-INFTL use, since all it gives us is autopartitioning, but I want to give it more thought. */ - if (!numparts) return -EIO; + if (!numparts) + return -EIO; add_mtd_device(mtd); #ifdef CONFIG_MTD_PARTITIONS if (!no_autopart) @@ -1535,20 +1550,16 @@ static int __init doc_probe(unsigned long physadr) save_control = ReadDOC(virtadr, DOCControl); /* Reset the DiskOnChip ASIC */ - WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, - virtadr, DOCControl); - WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, - virtadr, DOCControl); + WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, virtadr, DOCControl); + WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, virtadr, DOCControl); /* Enable the DiskOnChip ASIC */ - WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, - virtadr, DOCControl); - WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, - virtadr, DOCControl); + WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, virtadr, DOCControl); + WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, virtadr, DOCControl); ChipID = ReadDOC(virtadr, ChipID); - switch(ChipID) { + switch (ChipID) { case DOC_ChipID_Doc2k: reg = DoC_2k_ECCStatus; break; @@ -1564,15 +1575,13 @@ static int __init doc_probe(unsigned long physadr) ReadDOC(virtadr, Mplus_Power); /* Reset the Millennium Plus ASIC */ - tmp = DOC_MODE_RESET | DOC_MODE_MDWREN | DOC_MODE_RST_LAT | - DOC_MODE_BDECT; + tmp = DOC_MODE_RESET | DOC_MODE_MDWREN | DOC_MODE_RST_LAT | DOC_MODE_BDECT; WriteDOC(tmp, virtadr, Mplus_DOCControl); WriteDOC(~tmp, virtadr, Mplus_CtrlConfirm); mdelay(1); /* Enable the Millennium Plus ASIC */ - tmp = DOC_MODE_NORMAL | DOC_MODE_MDWREN | DOC_MODE_RST_LAT | - DOC_MODE_BDECT; + tmp = DOC_MODE_NORMAL | DOC_MODE_MDWREN | DOC_MODE_RST_LAT | DOC_MODE_BDECT; WriteDOC(tmp, virtadr, Mplus_DOCControl); WriteDOC(~tmp, virtadr, Mplus_CtrlConfirm); mdelay(1); @@ -1596,7 +1605,7 @@ static int __init doc_probe(unsigned long physadr) goto notfound; } /* Check the TOGGLE bit in the ECC register */ - tmp = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT; + tmp = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT; tmpb = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT; tmpc = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT; if ((tmp == tmpb) || (tmp != tmpc)) { @@ -1626,11 +1635,11 @@ static int __init doc_probe(unsigned long physadr) if (ChipID == DOC_ChipID_DocMilPlus16) { WriteDOC(~newval, virtadr, Mplus_AliasResolution); oldval = ReadDOC(doc->virtadr, Mplus_AliasResolution); - WriteDOC(newval, virtadr, Mplus_AliasResolution); // restore it + WriteDOC(newval, virtadr, Mplus_AliasResolution); // restore it } else { WriteDOC(~newval, virtadr, AliasResolution); oldval = ReadDOC(doc->virtadr, AliasResolution); - WriteDOC(newval, virtadr, AliasResolution); // restore it + WriteDOC(newval, virtadr, AliasResolution); // restore it } newval = ~newval; if (oldval == newval) { @@ -1642,10 +1651,8 @@ static int __init doc_probe(unsigned long physadr) printk(KERN_NOTICE "DiskOnChip found at 0x%lx\n", physadr); len = sizeof(struct mtd_info) + - sizeof(struct nand_chip) + - sizeof(struct doc_priv) + - (2 * sizeof(struct nand_bbt_descr)); - mtd = kmalloc(len, GFP_KERNEL); + sizeof(struct nand_chip) + sizeof(struct doc_priv) + (2 * sizeof(struct nand_bbt_descr)); + mtd = kmalloc(len, GFP_KERNEL); if (!mtd) { printk(KERN_ERR "DiskOnChip kmalloc (%d bytes) failed!\n", len); ret = -ENOMEM; @@ -1707,18 +1714,18 @@ static int __init doc_probe(unsigned long physadr) doclist = mtd; return 0; -notfound: + notfound: /* Put back the contents of the DOCControl register, in case it's not actually a DiskOnChip. */ WriteDOC(save_control, virtadr, DOCControl); -fail: + fail: iounmap(virtadr); return ret; } static void release_nanddoc(void) { - struct mtd_info *mtd, *nextmtd; + struct mtd_info *mtd, *nextmtd; struct nand_chip *nand; struct doc_priv *doc; @@ -1747,8 +1754,8 @@ static int __init init_nanddoc(void) * generator polinomial degree = 4 */ rs_decoder = init_rs(10, 0x409, FCR, 1, NROOTS); - if (!rs_decoder) { - printk (KERN_ERR "DiskOnChip: Could not create a RS decoder\n"); + if (!rs_decoder) { + printk(KERN_ERR "DiskOnChip: Could not create a RS decoder\n"); return -ENOMEM; } @@ -1758,7 +1765,7 @@ static int __init init_nanddoc(void) if (ret < 0) goto outerr; } else { - for (i=0; (doc_locations[i] != 0xffffffff); i++) { + for (i = 0; (doc_locations[i] != 0xffffffff); i++) { doc_probe(doc_locations[i]); } } @@ -1770,7 +1777,7 @@ static int __init init_nanddoc(void) goto outerr; } return 0; -outerr: + outerr: free_rs(rs_decoder); return ret; } diff --git a/drivers/mtd/nand/edb7312.c b/drivers/mtd/nand/edb7312.c index 9b1fd2f387fa..8467d770710c 100644 --- a/drivers/mtd/nand/edb7312.c +++ b/drivers/mtd/nand/edb7312.c @@ -25,7 +25,7 @@ #include #include #include -#include /* for CLPS7111_VIRT_BASE */ +#include /* for CLPS7111_VIRT_BASE */ #include #include @@ -54,29 +54,29 @@ static struct mtd_info *ep7312_mtd = NULL; */ static unsigned long ep7312_fio_pbase = EP7312_FIO_PBASE; -static void __iomem * ep7312_pxdr = (void __iomem *) EP7312_PXDR; -static void __iomem * ep7312_pxddr = (void __iomem *) EP7312_PXDDR; +static void __iomem *ep7312_pxdr = (void __iomem *)EP7312_PXDR; +static void __iomem *ep7312_pxddr = (void __iomem *)EP7312_PXDDR; #ifdef CONFIG_MTD_PARTITIONS /* * Define static partitions for flash device */ static struct mtd_partition partition_info[] = { - { .name = "EP7312 Nand Flash", - .offset = 0, - .size = 8*1024*1024 } + {.name = "EP7312 Nand Flash", + .offset = 0, + .size = 8 * 1024 * 1024} }; + #define NUM_PARTITIONS 1 #endif - /* * hardware specific access to control-lines */ static void ep7312_hwcontrol(struct mtd_info *mtd, int cmd) { - switch(cmd) { + switch (cmd) { case NAND_CTL_SETCLE: clps_writeb(clps_readb(ep7312_pxdr) | 0x10, ep7312_pxdr); @@ -108,6 +108,7 @@ static int ep7312_device_ready(struct mtd_info *mtd) { return 1; } + #ifdef CONFIG_MTD_PARTITIONS const char *part_probes[] = { "cmdlinepart", NULL }; #endif @@ -115,18 +116,16 @@ const char *part_probes[] = { "cmdlinepart", NULL }; /* * Main initialization routine */ -static int __init ep7312_init (void) +static int __init ep7312_init(void) { struct nand_chip *this; const char *part_type = 0; int mtd_parts_nb = 0; struct mtd_partition *mtd_parts = 0; - void __iomem * ep7312_fio_base; + void __iomem *ep7312_fio_base; /* Allocate memory for MTD device structure and private data */ - ep7312_mtd = kmalloc(sizeof(struct mtd_info) + - sizeof(struct nand_chip), - GFP_KERNEL); + ep7312_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); if (!ep7312_mtd) { printk("Unable to allocate EDB7312 NAND MTD device structure.\n"); return -ENOMEM; @@ -134,18 +133,18 @@ static int __init ep7312_init (void) /* map physical adress */ ep7312_fio_base = ioremap(ep7312_fio_pbase, SZ_1K); - if(!ep7312_fio_base) { + if (!ep7312_fio_base) { printk("ioremap EDB7312 NAND flash failed\n"); kfree(ep7312_mtd); return -EIO; } /* Get pointer to private data */ - this = (struct nand_chip *) (&ep7312_mtd[1]); + this = (struct nand_chip *)(&ep7312_mtd[1]); /* Initialize structures */ - memset((char *) ep7312_mtd, 0, sizeof(struct mtd_info)); - memset((char *) this, 0, sizeof(struct nand_chip)); + memset(ep7312_mtd, 0, sizeof(struct mtd_info)); + memset(this, 0, sizeof(struct nand_chip)); /* Link the private data with the MTD structure */ ep7312_mtd->priv = this; @@ -165,16 +164,14 @@ static int __init ep7312_init (void) this->chip_delay = 15; /* Scan to find existence of the device */ - if (nand_scan (ep7312_mtd, 1)) { + if (nand_scan(ep7312_mtd, 1)) { iounmap((void *)ep7312_fio_base); - kfree (ep7312_mtd); + kfree(ep7312_mtd); return -ENXIO; } - #ifdef CONFIG_MTD_PARTITIONS ep7312_mtd->name = "edb7312-nand"; - mtd_parts_nb = parse_mtd_partitions(ep7312_mtd, part_probes, - &mtd_parts, 0); + mtd_parts_nb = parse_mtd_partitions(ep7312_mtd, part_probes, &mtd_parts, 0); if (mtd_parts_nb > 0) part_type = "command line"; else @@ -193,24 +190,26 @@ static int __init ep7312_init (void) /* Return happy */ return 0; } + module_init(ep7312_init); /* * Clean up routine */ -static void __exit ep7312_cleanup (void) +static void __exit ep7312_cleanup(void) { - struct nand_chip *this = (struct nand_chip *) &ep7312_mtd[1]; + struct nand_chip *this = (struct nand_chip *)&ep7312_mtd[1]; /* Release resources, unregister device */ - nand_release (ap7312_mtd); + nand_release(ap7312_mtd); /* Free internal data buffer */ - kfree (this->data_buf); + kfree(this->data_buf); /* Free the MTD device structure */ - kfree (ep7312_mtd); + kfree(ep7312_mtd); } + module_exit(ep7312_cleanup); MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/nand/h1910.c b/drivers/mtd/nand/h1910.c index f68f7a99a630..efa53a9adf23 100644 --- a/drivers/mtd/nand/h1910.c +++ b/drivers/mtd/nand/h1910.c @@ -26,7 +26,7 @@ #include #include #include -#include /* for CLPS7111_VIRT_BASE */ +#include /* for CLPS7111_VIRT_BASE */ #include #include #include @@ -45,23 +45,23 @@ static struct mtd_info *h1910_nand_mtd = NULL; * Define static partitions for flash device */ static struct mtd_partition partition_info[] = { - { name: "h1910 NAND Flash", - offset: 0, - size: 16*1024*1024 } + {name:"h1910 NAND Flash", + offset:0, + size:16 * 1024 * 1024} }; + #define NUM_PARTITIONS 1 #endif - /* * hardware specific access to control-lines */ static void h1910_hwcontrol(struct mtd_info *mtd, int cmd) { - struct nand_chip* this = (struct nand_chip *) (mtd->priv); + struct nand_chip *this = (struct nand_chip *)(mtd->priv); - switch(cmd) { + switch (cmd) { case NAND_CTL_SETCLE: this->IO_ADDR_R |= (1 << 2); @@ -101,7 +101,7 @@ static int h1910_device_ready(struct mtd_info *mtd) /* * Main initialization routine */ -static int __init h1910_init (void) +static int __init h1910_init(void) { struct nand_chip *this; const char *part_type = 0; @@ -119,21 +119,19 @@ static int __init h1910_init (void) } /* Allocate memory for MTD device structure and private data */ - h1910_nand_mtd = kmalloc(sizeof(struct mtd_info) + - sizeof(struct nand_chip), - GFP_KERNEL); + h1910_nand_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); if (!h1910_nand_mtd) { printk("Unable to allocate h1910 NAND MTD device structure.\n"); - iounmap ((void *) nandaddr); + iounmap((void *)nandaddr); return -ENOMEM; } /* Get pointer to private data */ - this = (struct nand_chip *) (&h1910_nand_mtd[1]); + this = (struct nand_chip *)(&h1910_nand_mtd[1]); /* Initialize structures */ - memset((char *) h1910_nand_mtd, 0, sizeof(struct mtd_info)); - memset((char *) this, 0, sizeof(struct nand_chip)); + memset(h1910_nand_mtd, 0, sizeof(struct mtd_info)); + memset(this, 0, sizeof(struct nand_chip)); /* Link the private data with the MTD structure */ h1910_nand_mtd->priv = this; @@ -154,23 +152,20 @@ static int __init h1910_init (void) this->options = NAND_NO_AUTOINCR; /* Scan to find existence of the device */ - if (nand_scan (h1910_nand_mtd, 1)) { + if (nand_scan(h1910_nand_mtd, 1)) { printk(KERN_NOTICE "No NAND device - returning -ENXIO\n"); - kfree (h1910_nand_mtd); - iounmap ((void *) nandaddr); + kfree(h1910_nand_mtd); + iounmap((void *)nandaddr); return -ENXIO; } - #ifdef CONFIG_MTD_CMDLINE_PARTS - mtd_parts_nb = parse_cmdline_partitions(h1910_nand_mtd, &mtd_parts, - "h1910-nand"); + mtd_parts_nb = parse_cmdline_partitions(h1910_nand_mtd, &mtd_parts, "h1910-nand"); if (mtd_parts_nb > 0) - part_type = "command line"; + part_type = "command line"; else - mtd_parts_nb = 0; + mtd_parts_nb = 0; #endif - if (mtd_parts_nb == 0) - { + if (mtd_parts_nb == 0) { mtd_parts = partition_info; mtd_parts_nb = NUM_PARTITIONS; part_type = "static"; @@ -183,24 +178,26 @@ static int __init h1910_init (void) /* Return happy */ return 0; } + module_init(h1910_init); /* * Clean up routine */ -static void __exit h1910_cleanup (void) +static void __exit h1910_cleanup(void) { - struct nand_chip *this = (struct nand_chip *) &h1910_nand_mtd[1]; + struct nand_chip *this = (struct nand_chip *)&h1910_nand_mtd[1]; /* Release resources, unregister device */ - nand_release (h1910_nand_mtd); + nand_release(h1910_nand_mtd); /* Release io resource */ - iounmap ((void *) this->IO_ADDR_W); + iounmap((void *)this->IO_ADDR_W); /* Free the MTD device structure */ - kfree (h1910_nand_mtd); + kfree(h1910_nand_mtd); } + module_exit(h1910_cleanup); MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 95e96fa1fceb..fdaf32083ada 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -92,24 +92,24 @@ static struct nand_oobinfo nand_oob_8 = { .useecc = MTD_NANDECC_AUTOPLACE, .eccbytes = 3, .eccpos = {0, 1, 2}, - .oobfree = { {3, 2}, {6, 2} } + .oobfree = {{3, 2}, {6, 2}} }; static struct nand_oobinfo nand_oob_16 = { .useecc = MTD_NANDECC_AUTOPLACE, .eccbytes = 6, .eccpos = {0, 1, 2, 3, 6, 7}, - .oobfree = { {8, 8} } + .oobfree = {{8, 8}} }; static struct nand_oobinfo nand_oob_64 = { .useecc = MTD_NANDECC_AUTOPLACE, .eccbytes = 24, .eccpos = { - 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 61, 62, 63}, - .oobfree = { {2, 38} } + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63}, + .oobfree = {{2, 38}} }; /* This is used for padding purposes in nand_write_oob */ @@ -131,32 +131,32 @@ static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len); static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len); static int nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len); -static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf); -static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, - size_t * retlen, u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel); -static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf); -static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf); -static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, - size_t * retlen, const u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel); -static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char *buf); -static int nand_writev (struct mtd_info *mtd, const struct kvec *vecs, - unsigned long count, loff_t to, size_t * retlen); -static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, - unsigned long count, loff_t to, size_t * retlen, u_char *eccbuf, struct nand_oobinfo *oobsel); -static int nand_erase (struct mtd_info *mtd, struct erase_info *instr); -static void nand_sync (struct mtd_info *mtd); +static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); +static int nand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel); +static int nand_read_oob(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); +static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); +static int nand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel); +static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); +static int nand_writev(struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen); +static int nand_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, + unsigned long count, loff_t to, size_t *retlen, u_char *eccbuf, + struct nand_oobinfo *oobsel); +static int nand_erase(struct mtd_info *mtd, struct erase_info *instr); +static void nand_sync(struct mtd_info *mtd); /* Some internal functions */ -static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, u_char *oob_buf, - struct nand_oobinfo *oobsel, int mode); +static int nand_write_page(struct mtd_info *mtd, struct nand_chip *this, int page, u_char * oob_buf, + struct nand_oobinfo *oobsel, int mode); #ifdef CONFIG_MTD_NAND_VERIFY_WRITE -static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages, - u_char *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode); +static int nand_verify_pages(struct mtd_info *mtd, struct nand_chip *this, int page, int numpages, + u_char *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode); #else #define nand_verify_pages(...) (0) #endif -static int nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state); +static int nand_get_device(struct nand_chip *this, struct mtd_info *mtd, int new_state); /** * nand_release_device - [GENERIC] release chip @@ -164,7 +164,7 @@ static int nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int ne * * Deselect, release chip lock and wake up anyone waiting on the device */ -static void nand_release_device (struct mtd_info *mtd) +static void nand_release_device(struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; @@ -276,7 +276,7 @@ static void nand_write_word(struct mtd_info *mtd, u16 word) static void nand_select_chip(struct mtd_info *mtd, int chip) { struct nand_chip *this = mtd->priv; - switch(chip) { + switch (chip) { case -1: this->hwcontrol(mtd, NAND_CTL_CLRNCE); break; @@ -302,7 +302,7 @@ static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) int i; struct nand_chip *this = mtd->priv; - for (i=0; iIO_ADDR_W); } @@ -319,7 +319,7 @@ static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) int i; struct nand_chip *this = mtd->priv; - for (i=0; iIO_ADDR_R); } @@ -336,7 +336,7 @@ static int nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) int i; struct nand_chip *this = mtd->priv; - for (i=0; iIO_ADDR_R)) return -EFAULT; @@ -358,7 +358,7 @@ static void nand_write_buf16(struct mtd_info *mtd, const u_char *buf, int len) u16 *p = (u16 *) buf; len >>= 1; - for (i=0; iIO_ADDR_W); } @@ -378,7 +378,7 @@ static void nand_read_buf16(struct mtd_info *mtd, u_char *buf, int len) u16 *p = (u16 *) buf; len >>= 1; - for (i=0; iIO_ADDR_R); } @@ -397,7 +397,7 @@ static int nand_verify_buf16(struct mtd_info *mtd, const u_char *buf, int len) u16 *p = (u16 *) buf; len >>= 1; - for (i=0; iIO_ADDR_R)) return -EFAULT; @@ -423,22 +423,22 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) chipnr = (int)(ofs >> this->chip_shift); /* Grab the lock and see if the device is available */ - nand_get_device (this, mtd, FL_READING); + nand_get_device(this, mtd, FL_READING); /* Select the NAND device */ this->select_chip(mtd, chipnr); } else - page = (int) ofs; + page = (int)ofs; if (this->options & NAND_BUSWIDTH_16) { - this->cmdfunc (mtd, NAND_CMD_READOOB, this->badblockpos & 0xFE, page & this->pagemask); + this->cmdfunc(mtd, NAND_CMD_READOOB, this->badblockpos & 0xFE, page & this->pagemask); bad = cpu_to_le16(this->read_word(mtd)); if (this->badblockpos & 0x1) bad >>= 8; if ((bad & 0xFF) != 0xff) res = 1; } else { - this->cmdfunc (mtd, NAND_CMD_READOOB, this->badblockpos, page & this->pagemask); + this->cmdfunc(mtd, NAND_CMD_READOOB, this->badblockpos, page & this->pagemask); if (this->read_byte(mtd) != 0xff) res = 1; } @@ -462,22 +462,22 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) { struct nand_chip *this = mtd->priv; - u_char buf[2] = {0, 0}; - size_t retlen; + u_char buf[2] = { 0, 0 }; + size_t retlen; int block; /* Get block number */ - block = ((int) ofs) >> this->bbt_erase_shift; + block = ((int)ofs) >> this->bbt_erase_shift; if (this->bbt) this->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1); /* Do we have a flash based bad block table ? */ if (this->options & NAND_USE_FLASH_BBT) - return nand_update_bbt (mtd, ofs); + return nand_update_bbt(mtd, ofs); /* We write two bytes, so we dont have to mess with 16 bit access */ ofs += mtd->oobsize + (this->badblockpos & ~0x01); - return nand_write_oob (mtd, ofs , 2, &retlen, buf); + return nand_write_oob(mtd, ofs, 2, &retlen, buf); } /** @@ -487,11 +487,11 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) * * The function expects, that the device is already selected */ -static int nand_check_wp (struct mtd_info *mtd) +static int nand_check_wp(struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; /* Check the WP bit */ - this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); + this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); return (this->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1; } @@ -505,7 +505,7 @@ static int nand_check_wp (struct mtd_info *mtd) * Check, if the block is bad. Either by reading the bad block table or * calling of the scan function. */ -static int nand_block_checkbad (struct mtd_info *mtd, loff_t ofs, int getchip, int allowbbt) +static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip, int allowbbt) { struct nand_chip *this = mtd->priv; @@ -513,7 +513,7 @@ static int nand_block_checkbad (struct mtd_info *mtd, loff_t ofs, int getchip, i return this->block_bad(mtd, ofs, getchip); /* Return info from the table */ - return nand_isbad_bbt (mtd, ofs, allowbbt); + return nand_isbad_bbt(mtd, ofs, allowbbt); } DEFINE_LED_TRIGGER(nand_led_trigger); @@ -525,7 +525,7 @@ DEFINE_LED_TRIGGER(nand_led_trigger); static void nand_wait_ready(struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; - unsigned long timeo = jiffies + 2; + unsigned long timeo = jiffies + 2; led_trigger_event(nand_led_trigger, LED_FULL); /* wait until command is processed or timeout occures */ @@ -547,7 +547,7 @@ static void nand_wait_ready(struct mtd_info *mtd) * Send command to NAND device. This function is used for small page * devices (256/512 Bytes per page) */ -static void nand_command (struct mtd_info *mtd, unsigned command, int column, int page_addr) +static void nand_command(struct mtd_info *mtd, unsigned command, int column, int page_addr) { register struct nand_chip *this = mtd->priv; @@ -588,11 +588,11 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in this->write_byte(mtd, column); } if (page_addr != -1) { - this->write_byte(mtd, (unsigned char) (page_addr & 0xff)); - this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff)); + this->write_byte(mtd, (unsigned char)(page_addr & 0xff)); + this->write_byte(mtd, (unsigned char)((page_addr >> 8) & 0xff)); /* One more address cycle for devices > 32MiB */ if (this->chipsize > (32 << 20)) - this->write_byte(mtd, (unsigned char) ((page_addr >> 16) & 0x0f)); + this->write_byte(mtd, (unsigned char)((page_addr >> 16) & 0x0f)); } /* Latch in address */ this->hwcontrol(mtd, NAND_CTL_CLRALE); @@ -601,7 +601,7 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in /* * program and erase have their own busy handlers * status and sequential in needs no delay - */ + */ switch (command) { case NAND_CMD_PAGEPROG: @@ -618,23 +618,23 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in this->hwcontrol(mtd, NAND_CTL_SETCLE); this->write_byte(mtd, NAND_CMD_STATUS); this->hwcontrol(mtd, NAND_CTL_CLRCLE); - while ( !(this->read_byte(mtd) & NAND_STATUS_READY)); + while (!(this->read_byte(mtd) & NAND_STATUS_READY)) ; return; - /* This applies to read commands */ + /* This applies to read commands */ default: /* * If we don't have access to the busy pin, we apply the given * command delay - */ + */ if (!this->dev_ready) { - udelay (this->chip_delay); + udelay(this->chip_delay); return; } } /* Apply this short delay always to ensure that we do wait tWB in * any case on any machine. */ - ndelay (100); + ndelay(100); nand_wait_ready(mtd); } @@ -647,11 +647,11 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in * @page_addr: the page address for this command, -1 if none * * Send command to NAND device. This is the version for the new large page devices - * We dont have the seperate regions as we have in the small page devices. + * We dont have the separate regions as we have in the small page devices. * We must emulate NAND_CMD_READOOB to keep the code compatible. * */ -static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, int page_addr) +static void nand_command_lp(struct mtd_info *mtd, unsigned command, int column, int page_addr) { register struct nand_chip *this = mtd->priv; @@ -661,7 +661,6 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, command = NAND_CMD_READ0; } - /* Begin command latch cycle */ this->hwcontrol(mtd, NAND_CTL_SETCLE); /* Write out the command to the device. */ @@ -681,11 +680,11 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, this->write_byte(mtd, column >> 8); } if (page_addr != -1) { - this->write_byte(mtd, (unsigned char) (page_addr & 0xff)); - this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff)); + this->write_byte(mtd, (unsigned char)(page_addr & 0xff)); + this->write_byte(mtd, (unsigned char)((page_addr >> 8) & 0xff)); /* One more address cycle for devices > 128MiB */ if (this->chipsize > (128 << 20)) - this->write_byte(mtd, (unsigned char) ((page_addr >> 16) & 0xff)); + this->write_byte(mtd, (unsigned char)((page_addr >> 16) & 0xff)); } /* Latch in address */ this->hwcontrol(mtd, NAND_CTL_CLRALE); @@ -706,9 +705,9 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, case NAND_CMD_DEPLETE1: return; - /* - * read error status commands require only a short delay - */ + /* + * read error status commands require only a short delay + */ case NAND_CMD_STATUS_ERROR: case NAND_CMD_STATUS_ERROR0: case NAND_CMD_STATUS_ERROR1: @@ -724,7 +723,7 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, this->hwcontrol(mtd, NAND_CTL_SETCLE); this->write_byte(mtd, NAND_CMD_STATUS); this->hwcontrol(mtd, NAND_CTL_CLRCLE); - while ( !(this->read_byte(mtd) & NAND_STATUS_READY)); + while (!(this->read_byte(mtd) & NAND_STATUS_READY)) ; return; case NAND_CMD_READ0: @@ -736,21 +735,21 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, this->hwcontrol(mtd, NAND_CTL_CLRCLE); /* Fall through into ready check */ - /* This applies to read commands */ + /* This applies to read commands */ default: /* * If we don't have access to the busy pin, we apply the given * command delay - */ + */ if (!this->dev_ready) { - udelay (this->chip_delay); + udelay(this->chip_delay); return; } } /* Apply this short delay always to ensure that we do wait tWB in * any case on any machine. */ - ndelay (100); + ndelay(100); nand_wait_ready(mtd); } @@ -763,16 +762,16 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, * * Get the device and lock it for exclusive access */ -static int nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state) +static int nand_get_device(struct nand_chip *this, struct mtd_info *mtd, int new_state) { struct nand_chip *active; spinlock_t *lock; wait_queue_head_t *wq; - DECLARE_WAITQUEUE (wait, current); + DECLARE_WAITQUEUE(wait, current); lock = (this->controller) ? &this->controller->lock : &this->chip_lock; wq = (this->controller) ? &this->controller->wq : &this->wq; -retry: + retry: active = this; spin_lock(lock); @@ -814,24 +813,24 @@ retry: static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state) { - unsigned long timeo = jiffies; - int status; + unsigned long timeo = jiffies; + int status; if (state == FL_ERASING) - timeo += (HZ * 400) / 1000; + timeo += (HZ * 400) / 1000; else - timeo += (HZ * 20) / 1000; + timeo += (HZ * 20) / 1000; led_trigger_event(nand_led_trigger, LED_FULL); /* Apply this short delay always to ensure that we do wait tWB in * any case on any machine. */ - ndelay (100); + ndelay(100); if ((state == FL_ERASING) && (this->options & NAND_IS_AND)) - this->cmdfunc (mtd, NAND_CMD_STATUS_MULTI, -1, -1); + this->cmdfunc(mtd, NAND_CMD_STATUS_MULTI, -1, -1); else - this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); + this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); while (time_before(jiffies, timeo)) { /* Check, if we were interrupted */ @@ -849,7 +848,7 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state) } led_trigger_event(nand_led_trigger, LED_OFF); - status = (int) this->read_byte(mtd); + status = (int)this->read_byte(mtd); return status; } @@ -868,31 +867,31 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state) * * Cached programming is not supported yet. */ -static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, - u_char *oob_buf, struct nand_oobinfo *oobsel, int cached) +static int nand_write_page(struct mtd_info *mtd, struct nand_chip *this, int page, + u_char *oob_buf, struct nand_oobinfo *oobsel, int cached) { - int i, status; - u_char ecc_code[32]; - int eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE; - int *oob_config = oobsel->eccpos; - int datidx = 0, eccidx = 0, eccsteps = this->eccsteps; - int eccbytes = 0; + int i, status; + u_char ecc_code[32]; + int eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE; + int *oob_config = oobsel->eccpos; + int datidx = 0, eccidx = 0, eccsteps = this->eccsteps; + int eccbytes = 0; /* FIXME: Enable cached programming */ cached = 0; /* Send command to begin auto page programming */ - this->cmdfunc (mtd, NAND_CMD_SEQIN, 0x00, page); + this->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); /* Write out complete page of data, take care of eccmode */ switch (eccmode) { - /* No ecc, write all */ + /* No ecc, write all */ case NAND_ECC_NONE: - printk (KERN_WARNING "Writing data without ECC to NAND-FLASH is not recommended\n"); + printk(KERN_WARNING "Writing data without ECC to NAND-FLASH is not recommended\n"); this->write_buf(mtd, this->data_poi, mtd->oobblock); break; - /* Software ecc 3/256, write all */ + /* Software ecc 3/256, write all */ case NAND_ECC_SOFT: for (; eccsteps; eccsteps--) { this->calculate_ecc(mtd, &this->data_poi[datidx], ecc_code); @@ -928,11 +927,11 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa this->write_buf(mtd, oob_buf, mtd->oobsize); /* Send command to actually program the data */ - this->cmdfunc (mtd, cached ? NAND_CMD_CACHEDPROG : NAND_CMD_PAGEPROG, -1, -1); + this->cmdfunc(mtd, cached ? NAND_CMD_CACHEDPROG : NAND_CMD_PAGEPROG, -1, -1); if (!cached) { /* call wait ready function */ - status = this->waitfunc (mtd, this, FL_WRITING); + status = this->waitfunc(mtd, this, FL_WRITING); /* See if operation failed and additional status checks are available */ if ((status & NAND_STATUS_FAIL) && (this->errstat)) { @@ -941,12 +940,12 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa /* See if device thinks it succeeded */ if (status & NAND_STATUS_FAIL) { - DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write, page 0x%08x, ", __FUNCTION__, page); + DEBUG(MTD_DEBUG_LEVEL0, "%s: " "Failed write, page 0x%08x, ", __FUNCTION__, page); return -EIO; } } else { /* FIXME: Implement cached programming ! */ - /* wait until cache is ready*/ + /* wait until cache is ready */ // status = this->waitfunc (mtd, this, FL_CACHEDRPG); } return 0; @@ -972,24 +971,24 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa * the error later when the ECC page check fails, but we would rather catch * it early in the page write stage. Better to write no data than invalid data. */ -static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages, - u_char *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode) +static int nand_verify_pages(struct mtd_info *mtd, struct nand_chip *this, int page, int numpages, + u_char *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode) { - int i, j, datidx = 0, oobofs = 0, res = -EIO; - int eccsteps = this->eccsteps; - int hweccbytes; - u_char oobdata[64]; + int i, j, datidx = 0, oobofs = 0, res = -EIO; + int eccsteps = this->eccsteps; + int hweccbytes; + u_char oobdata[64]; hweccbytes = (this->options & NAND_HWECC_SYNDROME) ? (oobsel->eccbytes / eccsteps) : 0; /* Send command to read back the first page */ - this->cmdfunc (mtd, NAND_CMD_READ0, 0, page); + this->cmdfunc(mtd, NAND_CMD_READ0, 0, page); - for(;;) { + for (;;) { for (j = 0; j < eccsteps; j++) { /* Loop through and verify the data */ if (this->verify_buf(mtd, &this->data_poi[datidx], mtd->eccsize)) { - DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page); + DEBUG(MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page); goto out; } datidx += mtd->eccsize; @@ -997,7 +996,7 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int if (!hweccbytes) continue; if (this->verify_buf(mtd, &this->oob_buf[oobofs], hweccbytes)) { - DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page); + DEBUG(MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page); goto out; } oobofs += hweccbytes; @@ -1008,7 +1007,7 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int */ if (oobmode) { if (this->verify_buf(mtd, &oob_buf[oobofs], mtd->oobsize - hweccbytes * eccsteps)) { - DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page); + DEBUG(MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page); goto out; } } else { @@ -1020,10 +1019,9 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int for (i = 0; i < ecccnt; i++) { int idx = oobsel->eccpos[i]; - if (oobdata[idx] != oob_buf[oobofs + idx] ) { - DEBUG (MTD_DEBUG_LEVEL0, - "%s: Failed ECC write " - "verify, page 0x%08x, " "%6i bytes were succesful\n", __FUNCTION__, page, i); + if (oobdata[idx] != oob_buf[oobofs + idx]) { + DEBUG(MTD_DEBUG_LEVEL0, "%s: Failed ECC write verify, page 0x%08x, %6i bytes were succesful\n", + __FUNCTION__, page, i); goto out; } } @@ -1039,9 +1037,9 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int * is marked as NOAUTOINCR by the board driver. * Do this also before returning, so the chip is * ready for the next command. - */ + */ if (!this->dev_ready) - udelay (this->chip_delay); + udelay(this->chip_delay); else nand_wait_ready(mtd); @@ -1049,17 +1047,16 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int if (!numpages) return 0; - /* Check, if the chip supports auto page increment */ if (!NAND_CANAUTOINCR(this)) - this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page); + this->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); } /* * Terminate the read command. We come here in case of an error * So we must issue a reset command. */ -out: - this->cmdfunc (mtd, NAND_CMD_RESET, -1, -1); + out: + this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); return res; } #endif @@ -1075,12 +1072,11 @@ out: * This function simply calls nand_do_read_ecc with oob buffer and oobsel = NULL * and flags = 0xff */ -static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf) +static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { - return nand_do_read_ecc (mtd, from, len, retlen, buf, NULL, &mtd->oobinfo, 0xff); + return nand_do_read_ecc(mtd, from, len, retlen, buf, NULL, &mtd->oobinfo, 0xff); } - /** * nand_read_ecc - [MTD Interface] MTD compability function for nand_do_read_ecc * @mtd: MTD device structure @@ -1093,8 +1089,8 @@ static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * re * * This function simply calls nand_do_read_ecc with flags = 0xff */ -static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, - size_t * retlen, u_char * buf, u_char * oob_buf, struct nand_oobinfo *oobsel) +static int nand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf, u_char *oob_buf, struct nand_oobinfo *oobsel) { /* use userspace supplied oobinfo, if zero */ if (oobsel == NULL) @@ -1102,7 +1098,6 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, return nand_do_read_ecc(mtd, from, len, retlen, buf, oob_buf, oobsel, 0xff); } - /** * nand_do_read_ecc - [MTD Interface] Read data with ECC * @mtd: MTD device structure @@ -1119,9 +1114,8 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, * * NAND read with ECC */ -int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, - size_t * retlen, u_char * buf, u_char * oob_buf, - struct nand_oobinfo *oobsel, int flags) +int nand_do_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf, u_char *oob_buf, struct nand_oobinfo *oobsel, int flags) { int i, j, col, realpage, page, end, ecc, chipnr, sndcmd = 1; @@ -1130,26 +1124,25 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, u_char *data_poi, *oob_data = oob_buf; u_char ecc_calc[32]; u_char ecc_code[32]; - int eccmode, eccsteps; - int *oob_config, datidx; - int blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1; - int eccbytes; - int compareecc = 1; - int oobreadlen; + int eccmode, eccsteps; + int *oob_config, datidx; + int blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1; + int eccbytes; + int compareecc = 1; + int oobreadlen; - - DEBUG (MTD_DEBUG_LEVEL3, "nand_read_ecc: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); + DEBUG(MTD_DEBUG_LEVEL3, "nand_read_ecc: from = 0x%08x, len = %i\n", (unsigned int)from, (int)len); /* Do not allow reads past end of device */ if ((from + len) > mtd->size) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: Attempt read beyond end of device\n"); + DEBUG(MTD_DEBUG_LEVEL0, "nand_read_ecc: Attempt read beyond end of device\n"); *retlen = 0; return -EINVAL; } /* Grab the lock and see if the device is available */ if (flags & NAND_GET_DEVICE) - nand_get_device (this, mtd, FL_READING); + nand_get_device(this, mtd, FL_READING); /* Autoplace of oob data ? Use the default placement scheme */ if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) @@ -1163,7 +1156,7 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, this->select_chip(mtd, chipnr); /* First we calculate the starting page */ - realpage = (int) (from >> this->page_shift); + realpage = (int)(from >> this->page_shift); page = realpage & this->pagemask; /* Get raw starting column */ @@ -1201,13 +1194,13 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, if (realpage == this->pagebuf && !oob_buf) { /* aligned read ? */ if (aligned) - memcpy (data_poi, this->data_buf, end); + memcpy(data_poi, this->data_buf, end); goto readdata; } /* Check, if we must send the read command */ if (sndcmd) { - this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page); + this->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); sndcmd = 0; } @@ -1219,24 +1212,26 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, eccsteps = this->eccsteps; switch (eccmode) { - case NAND_ECC_NONE: { /* No ECC, Read in a page */ - static unsigned long lastwhinge = 0; - if ((lastwhinge / HZ) != (jiffies / HZ)) { - printk (KERN_WARNING "Reading data from NAND FLASH without ECC is not recommended\n"); - lastwhinge = jiffies; + case NAND_ECC_NONE:{ + /* No ECC, Read in a page */ + static unsigned long lastwhinge = 0; + if ((lastwhinge / HZ) != (jiffies / HZ)) { + printk(KERN_WARNING + "Reading data from NAND FLASH without ECC is not recommended\n"); + lastwhinge = jiffies; + } + this->read_buf(mtd, data_poi, end); + break; } - this->read_buf(mtd, data_poi, end); - break; - } case NAND_ECC_SOFT: /* Software ECC 3/256: Read in a page + oob data */ this->read_buf(mtd, data_poi, end); - for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=3, datidx += ecc) + for (i = 0, datidx = 0; eccsteps; eccsteps--, i += 3, datidx += ecc) this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]); break; default: - for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=eccbytes, datidx += ecc) { + for (i = 0, datidx = 0; eccsteps; eccsteps--, i += eccbytes, datidx += ecc) { this->enable_hwecc(mtd, NAND_ECC_READ); this->read_buf(mtd, &data_poi[datidx], ecc); @@ -1252,8 +1247,8 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, * does the error correction on the fly */ ecc_status = this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]); if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " - "Failed ECC read, page 0x%08x on chip %d\n", page, chipnr); + DEBUG(MTD_DEBUG_LEVEL0, "nand_read_ecc: " + "Failed ECC read, page 0x%08x on chip %d\n", page, chipnr); ecc_failed++; } } else { @@ -1274,7 +1269,7 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, for (j = 0; j < oobsel->eccbytes; j++) ecc_code[j] = oob_data[oob_config[j]]; - /* correct data, if neccecary */ + /* correct data, if necessary */ for (i = 0, j = 0, datidx = 0; i < this->eccsteps; i++, datidx += ecc) { ecc_status = this->correct_data(mtd, &data_poi[datidx], &ecc_code[j], &ecc_calc[j]); @@ -1291,16 +1286,16 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, } if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page); + DEBUG(MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page); ecc_failed++; } } - readoob: + readoob: /* check, if we have a fs supplied oob-buffer */ if (oob_buf) { /* without autoplace. Legacy mode used by YAFFS1 */ - switch(oobsel->useecc) { + switch (oobsel->useecc) { case MTD_NANDECC_AUTOPLACE: case MTD_NANDECC_AUTOPL_USR: /* Walk through the autoplace chunks */ @@ -1313,7 +1308,7 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, break; case MTD_NANDECC_PLACE: /* YAFFS1 legacy mode */ - oob_data += this->eccsteps * sizeof (int); + oob_data += this->eccsteps * sizeof(int); default: oob_data += mtd->oobsize; } @@ -1331,9 +1326,9 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, * Do this before the AUTOINCR check, so no problems * arise if a chip which does auto increment * is marked as NOAUTOINCR by the board driver. - */ + */ if (!this->dev_ready) - udelay (this->chip_delay); + udelay(this->chip_delay); else nand_wait_ready(mtd); @@ -1354,7 +1349,7 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, } /* Check, if the chip supports auto page increment * or if we have hit a block boundary. - */ + */ if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) sndcmd = 1; } @@ -1382,13 +1377,13 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, * * NAND read out-of-band data from the spare area */ -static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf) +static int nand_read_oob(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { int i, col, page, chipnr; struct nand_chip *this = mtd->priv; - int blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1; + int blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1; - DEBUG (MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); + DEBUG(MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08x, len = %i\n", (unsigned int)from, (int)len); /* Shift to get page */ page = (int)(from >> this->page_shift); @@ -1402,19 +1397,19 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t /* Do not allow reads past end of device */ if ((from + len) > mtd->size) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_read_oob: Attempt read beyond end of device\n"); + DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: Attempt read beyond end of device\n"); *retlen = 0; return -EINVAL; } /* Grab the lock and see if the device is available */ - nand_get_device (this, mtd , FL_READING); + nand_get_device(this, mtd, FL_READING); /* Select the NAND device */ this->select_chip(mtd, chipnr); /* Send the read command */ - this->cmdfunc (mtd, NAND_CMD_READOOB, col, page & this->pagemask); + this->cmdfunc(mtd, NAND_CMD_READOOB, col, page & this->pagemask); /* * Read the data, if we read more than one page * oob data, let the device transfer the data ! @@ -1444,16 +1439,16 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t * is marked as NOAUTOINCR by the board driver. */ if (!this->dev_ready) - udelay (this->chip_delay); + udelay(this->chip_delay); else nand_wait_ready(mtd); /* Check, if the chip supports auto page increment * or if we have hit a block boundary. - */ + */ if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) { /* For subsequent page reads set offset to 0 */ - this->cmdfunc (mtd, NAND_CMD_READOOB, 0x0, page & this->pagemask); + this->cmdfunc(mtd, NAND_CMD_READOOB, 0x0, page & this->pagemask); } } } @@ -1476,43 +1471,43 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t * * Read raw data including oob into buffer */ -int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, size_t ooblen) +int nand_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, size_t ooblen) { struct nand_chip *this = mtd->priv; - int page = (int) (from >> this->page_shift); - int chip = (int) (from >> this->chip_shift); + int page = (int)(from >> this->page_shift); + int chip = (int)(from >> this->chip_shift); int sndcmd = 1; int cnt = 0; int pagesize = mtd->oobblock + mtd->oobsize; - int blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1; + int blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1; /* Do not allow reads past end of device */ if ((from + len) > mtd->size) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_read_raw: Attempt read beyond end of device\n"); + DEBUG(MTD_DEBUG_LEVEL0, "nand_read_raw: Attempt read beyond end of device\n"); return -EINVAL; } /* Grab the lock and see if the device is available */ - nand_get_device (this, mtd , FL_READING); + nand_get_device(this, mtd, FL_READING); - this->select_chip (mtd, chip); + this->select_chip(mtd, chip); /* Add requested oob length */ len += ooblen; while (len) { if (sndcmd) - this->cmdfunc (mtd, NAND_CMD_READ0, 0, page & this->pagemask); + this->cmdfunc(mtd, NAND_CMD_READ0, 0, page & this->pagemask); sndcmd = 0; - this->read_buf (mtd, &buf[cnt], pagesize); + this->read_buf(mtd, &buf[cnt], pagesize); len -= pagesize; cnt += pagesize; page++; if (!this->dev_ready) - udelay (this->chip_delay); + udelay(this->chip_delay); else nand_wait_ready(mtd); @@ -1526,7 +1521,6 @@ int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, return 0; } - /** * nand_prepare_oobbuf - [GENERIC] Prepare the out of band buffer * @mtd: MTD device structure @@ -1550,8 +1544,8 @@ int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, * forces the 0xff fill before using the buffer again. * */ -static u_char * nand_prepare_oobbuf (struct mtd_info *mtd, u_char *fsbuf, struct nand_oobinfo *oobsel, - int autoplace, int numpages) +static u_char *nand_prepare_oobbuf(struct mtd_info *mtd, u_char *fsbuf, struct nand_oobinfo *oobsel, + int autoplace, int numpages) { struct nand_chip *this = mtd->priv; int i, len, ofs; @@ -1562,8 +1556,7 @@ static u_char * nand_prepare_oobbuf (struct mtd_info *mtd, u_char *fsbuf, struct /* Check, if the buffer must be filled with ff again */ if (this->oobdirty) { - memset (this->oob_buf, 0xff, - mtd->oobsize << (this->phys_erase_shift - this->page_shift)); + memset(this->oob_buf, 0xff, mtd->oobsize << (this->phys_erase_shift - this->page_shift)); this->oobdirty = 0; } @@ -1578,7 +1571,7 @@ static u_char * nand_prepare_oobbuf (struct mtd_info *mtd, u_char *fsbuf, struct for (i = 0, len = 0; len < mtd->oobavail; i++) { int to = ofs + oobsel->oobfree[i][0]; int num = oobsel->oobfree[i][1]; - memcpy (&this->oob_buf[to], fsbuf, num); + memcpy(&this->oob_buf[to], fsbuf, num); len += num; fsbuf += num; } @@ -1600,9 +1593,9 @@ static u_char * nand_prepare_oobbuf (struct mtd_info *mtd, u_char *fsbuf, struct * This function simply calls nand_write_ecc with oob buffer and oobsel = NULL * */ -static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf) +static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) { - return (nand_write_ecc (mtd, to, len, retlen, buf, NULL, NULL)); + return (nand_write_ecc(mtd, to, len, retlen, buf, NULL, NULL)); } /** @@ -1617,34 +1610,35 @@ static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, size_t * ret * * NAND write with ECC */ -static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, - size_t * retlen, const u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel) +static int nand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf, u_char *eccbuf, + struct nand_oobinfo *oobsel) { int startpage, page, ret = -EIO, oob = 0, written = 0, chipnr; int autoplace = 0, numpages, totalpages; struct nand_chip *this = mtd->priv; u_char *oobbuf, *bufstart; - int ppblock = (1 << (this->phys_erase_shift - this->page_shift)); + int ppblock = (1 << (this->phys_erase_shift - this->page_shift)); - DEBUG (MTD_DEBUG_LEVEL3, "nand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); + DEBUG(MTD_DEBUG_LEVEL3, "nand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int)to, (int)len); /* Initialize retlen, in case of early exit */ *retlen = 0; /* Do not allow write past end of device */ if ((to + len) > mtd->size) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: Attempt to write past end of page\n"); + DEBUG(MTD_DEBUG_LEVEL0, "nand_write_ecc: Attempt to write past end of page\n"); return -EINVAL; } /* reject writes, which are not page aligned */ - if (NOTALIGNED (to) || NOTALIGNED(len)) { - printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n"); + if (NOTALIGNED(to) || NOTALIGNED(len)) { + printk(KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n"); return -EINVAL; } /* Grab the lock and see if the device is available */ - nand_get_device (this, mtd, FL_WRITING); + nand_get_device(this, mtd, FL_WRITING); /* Calculate chipnr */ chipnr = (int)(to >> this->chip_shift); @@ -1669,7 +1663,7 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, /* Setup variables and oob buffer */ totalpages = len >> this->page_shift; - page = (int) (to >> this->page_shift); + page = (int)(to >> this->page_shift); /* Invalidate the page cache, if we write to the cached page */ if (page <= this->pagebuf && this->pagebuf < (page + totalpages)) this->pagebuf = -1; @@ -1678,22 +1672,22 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, page &= this->pagemask; startpage = page; /* Calc number of pages we can write in one go */ - numpages = min (ppblock - (startpage & (ppblock - 1)), totalpages); - oobbuf = nand_prepare_oobbuf (mtd, eccbuf, oobsel, autoplace, numpages); - bufstart = (u_char *)buf; + numpages = min(ppblock - (startpage & (ppblock - 1)), totalpages); + oobbuf = nand_prepare_oobbuf(mtd, eccbuf, oobsel, autoplace, numpages); + bufstart = (u_char *) buf; /* Loop until all data is written */ while (written < len) { - this->data_poi = (u_char*) &buf[written]; + this->data_poi = (u_char *) &buf[written]; /* Write one page. If this is the last page to write * or the last page in this block, then use the * real pageprogram command, else select cached programming * if supported by the chip. */ - ret = nand_write_page (mtd, this, page, &oobbuf[oob], oobsel, (--numpages > 0)); + ret = nand_write_page(mtd, this, page, &oobbuf[oob], oobsel, (--numpages > 0)); if (ret) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: write_page failed %d\n", ret); + DEBUG(MTD_DEBUG_LEVEL0, "nand_write_ecc: write_page failed %d\n", ret); goto out; } /* Next oob page */ @@ -1709,15 +1703,14 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, /* Have we hit a block boundary ? Then we have to verify and * if verify is ok, we have to setup the oob buffer for * the next pages. - */ - if (!(page & (ppblock - 1))){ + */ + if (!(page & (ppblock - 1))) { int ofs; this->data_poi = bufstart; - ret = nand_verify_pages (mtd, this, startpage, - page - startpage, - oobbuf, oobsel, chipnr, (eccbuf != NULL)); + ret = nand_verify_pages(mtd, this, startpage, page - startpage, + oobbuf, oobsel, chipnr, (eccbuf != NULL)); if (ret) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret); + DEBUG(MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret); goto out; } *retlen = written; @@ -1726,11 +1719,10 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, if (eccbuf) eccbuf += (page - startpage) * ofs; totalpages -= page - startpage; - numpages = min (totalpages, ppblock); + numpages = min(totalpages, ppblock); page &= this->pagemask; startpage = page; - oobbuf = nand_prepare_oobbuf (mtd, eccbuf, oobsel, - autoplace, numpages); + oobbuf = nand_prepare_oobbuf(mtd, eccbuf, oobsel, autoplace, numpages); oob = 0; /* Check, if we cross a chip boundary */ if (!page) { @@ -1741,23 +1733,21 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, } } /* Verify the remaining pages */ -cmp: + cmp: this->data_poi = bufstart; - ret = nand_verify_pages (mtd, this, startpage, totalpages, - oobbuf, oobsel, chipnr, (eccbuf != NULL)); + ret = nand_verify_pages(mtd, this, startpage, totalpages, oobbuf, oobsel, chipnr, (eccbuf != NULL)); if (!ret) *retlen = written; else - DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret); + DEBUG(MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret); -out: + out: /* Deselect and wake up anyone waiting on the device */ nand_release_device(mtd); return ret; } - /** * nand_write_oob - [MTD Interface] NAND write out-of-band * @mtd: MTD device structure @@ -1768,16 +1758,16 @@ out: * * NAND write out-of-band */ -static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf) +static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) { int column, page, status, ret = -EIO, chipnr; struct nand_chip *this = mtd->priv; - DEBUG (MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); + DEBUG(MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n", (unsigned int)to, (int)len); /* Shift to get page */ - page = (int) (to >> this->page_shift); - chipnr = (int) (to >> this->chip_shift); + page = (int)(to >> this->page_shift); + chipnr = (int)(to >> this->chip_shift); /* Mask to get column */ column = to & (mtd->oobsize - 1); @@ -1787,12 +1777,12 @@ static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * /* Do not allow write past end of page */ if ((column + len) > mtd->oobsize) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: Attempt to write past end of page\n"); + DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: Attempt to write past end of page\n"); return -EINVAL; } /* Grab the lock and see if the device is available */ - nand_get_device (this, mtd, FL_WRITING); + nand_get_device(this, mtd, FL_WRITING); /* Select the NAND device */ this->select_chip(mtd, chipnr); @@ -1814,27 +1804,27 @@ static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * if (NAND_MUST_PAD(this)) { /* Write out desired data */ - this->cmdfunc (mtd, NAND_CMD_SEQIN, mtd->oobblock, page & this->pagemask); + this->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->oobblock, page & this->pagemask); /* prepad 0xff for partial programming */ this->write_buf(mtd, ffchars, column); /* write data */ this->write_buf(mtd, buf, len); /* postpad 0xff for partial programming */ - this->write_buf(mtd, ffchars, mtd->oobsize - (len+column)); + this->write_buf(mtd, ffchars, mtd->oobsize - (len + column)); } else { /* Write out desired data */ - this->cmdfunc (mtd, NAND_CMD_SEQIN, mtd->oobblock + column, page & this->pagemask); + this->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->oobblock + column, page & this->pagemask); /* write data */ this->write_buf(mtd, buf, len); } /* Send command to program the OOB data */ - this->cmdfunc (mtd, NAND_CMD_PAGEPROG, -1, -1); + this->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); - status = this->waitfunc (mtd, this, FL_WRITING); + status = this->waitfunc(mtd, this, FL_WRITING); /* See if device thinks it succeeded */ if (status & NAND_STATUS_FAIL) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write, page 0x%08x\n", page); + DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write, page 0x%08x\n", page); ret = -EIO; goto out; } @@ -1843,23 +1833,22 @@ static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * #ifdef CONFIG_MTD_NAND_VERIFY_WRITE /* Send command to read back the data */ - this->cmdfunc (mtd, NAND_CMD_READOOB, column, page & this->pagemask); + this->cmdfunc(mtd, NAND_CMD_READOOB, column, page & this->pagemask); if (this->verify_buf(mtd, buf, len)) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write verify, page 0x%08x\n", page); + DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write verify, page 0x%08x\n", page); ret = -EIO; goto out; } #endif ret = 0; -out: + out: /* Deselect and wake up anyone waiting on the device */ nand_release_device(mtd); return ret; } - /** * nand_writev - [MTD Interface] compabilty function for nand_writev_ecc * @mtd: MTD device structure @@ -1870,10 +1859,10 @@ out: * * NAND write with kvec. This just calls the ecc function */ -static int nand_writev (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, - loff_t to, size_t * retlen) +static int nand_writev(struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, + loff_t to, size_t *retlen) { - return (nand_writev_ecc (mtd, vecs, count, to, retlen, NULL, NULL)); + return (nand_writev_ecc(mtd, vecs, count, to, retlen, NULL, NULL)); } /** @@ -1888,13 +1877,13 @@ static int nand_writev (struct mtd_info *mtd, const struct kvec *vecs, unsigned * * NAND write with iovec with ecc */ -static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, - loff_t to, size_t * retlen, u_char *eccbuf, struct nand_oobinfo *oobsel) +static int nand_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, + loff_t to, size_t *retlen, u_char *eccbuf, struct nand_oobinfo *oobsel) { int i, page, len, total_len, ret = -EIO, written = 0, chipnr; int oob, numpages, autoplace = 0, startpage; struct nand_chip *this = mtd->priv; - int ppblock = (1 << (this->phys_erase_shift - this->page_shift)); + int ppblock = (1 << (this->phys_erase_shift - this->page_shift)); u_char *oobbuf, *bufstart; /* Preset written len for early exit */ @@ -1903,28 +1892,27 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig /* Calculate total length of data */ total_len = 0; for (i = 0; i < count; i++) - total_len += (int) vecs[i].iov_len; + total_len += (int)vecs[i].iov_len; - DEBUG (MTD_DEBUG_LEVEL3, - "nand_writev: to = 0x%08x, len = %i, count = %ld\n", (unsigned int) to, (unsigned int) total_len, count); + DEBUG(MTD_DEBUG_LEVEL3, "nand_writev: to = 0x%08x, len = %i, count = %ld\n", (unsigned int)to, (unsigned int)total_len, count); /* Do not allow write past end of page */ if ((to + total_len) > mtd->size) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_writev: Attempted write past end of device\n"); + DEBUG(MTD_DEBUG_LEVEL0, "nand_writev: Attempted write past end of device\n"); return -EINVAL; } /* reject writes, which are not page aligned */ - if (NOTALIGNED (to) || NOTALIGNED(total_len)) { - printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n"); + if (NOTALIGNED(to) || NOTALIGNED(total_len)) { + printk(KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n"); return -EINVAL; } /* Grab the lock and see if the device is available */ - nand_get_device (this, mtd, FL_WRITING); + nand_get_device(this, mtd, FL_WRITING); /* Get the current chip-nr */ - chipnr = (int) (to >> this->chip_shift); + chipnr = (int)(to >> this->chip_shift); /* Select the NAND device */ this->select_chip(mtd, chipnr); @@ -1945,7 +1933,7 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig autoplace = 1; /* Setup start page */ - page = (int) (to >> this->page_shift); + page = (int)(to >> this->page_shift); /* Invalidate the page cache, if we write to the cached page */ if (page <= this->pagebuf && this->pagebuf < ((to + total_len) >> this->page_shift)) this->pagebuf = -1; @@ -1963,9 +1951,9 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig * out of this iov in one go */ numpages = (vecs->iov_len - len) >> this->page_shift; /* Do not cross block boundaries */ - numpages = min (ppblock - (startpage & (ppblock - 1)), numpages); - oobbuf = nand_prepare_oobbuf (mtd, NULL, oobsel, autoplace, numpages); - bufstart = (u_char *)vecs->iov_base; + numpages = min(ppblock - (startpage & (ppblock - 1)), numpages); + oobbuf = nand_prepare_oobbuf(mtd, NULL, oobsel, autoplace, numpages); + bufstart = (u_char *) vecs->iov_base; bufstart += len; this->data_poi = bufstart; oob = 0; @@ -1974,8 +1962,8 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig * then use the real pageprogram command, else select * cached programming if supported by the chip. */ - ret = nand_write_page (mtd, this, page & this->pagemask, - &oobbuf[oob], oobsel, i != numpages); + ret = nand_write_page(mtd, this, page & this->pagemask, + &oobbuf[oob], oobsel, i != numpages); if (ret) goto out; this->data_poi += mtd->oobblock; @@ -1984,7 +1972,7 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig page++; } /* Check, if we have to switch to the next tuple */ - if (len >= (int) vecs->iov_len) { + if (len >= (int)vecs->iov_len) { vecs++; len = 0; count--; @@ -1998,7 +1986,7 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig if (vecs->iov_base != NULL && vecs->iov_len) this->data_buf[cnt++] = ((u_char *) vecs->iov_base)[len++]; /* Check, if we have to switch to the next tuple */ - if (len >= (int) vecs->iov_len) { + if (len >= (int)vecs->iov_len) { vecs++; len = 0; count--; @@ -2008,16 +1996,15 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig this->data_poi = this->data_buf; bufstart = this->data_poi; numpages = 1; - oobbuf = nand_prepare_oobbuf (mtd, NULL, oobsel, autoplace, numpages); - ret = nand_write_page (mtd, this, page & this->pagemask, - oobbuf, oobsel, 0); + oobbuf = nand_prepare_oobbuf(mtd, NULL, oobsel, autoplace, numpages); + ret = nand_write_page(mtd, this, page & this->pagemask, oobbuf, oobsel, 0); if (ret) goto out; page++; } this->data_poi = bufstart; - ret = nand_verify_pages (mtd, this, startpage, numpages, oobbuf, oobsel, chipnr, 0); + ret = nand_verify_pages(mtd, this, startpage, numpages, oobbuf, oobsel, chipnr, 0); if (ret) goto out; @@ -2035,7 +2022,7 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig } } ret = 0; -out: + out: /* Deselect and wake up anyone waiting on the device */ nand_release_device(mtd); @@ -2050,12 +2037,12 @@ out: * * Standard erase command for NAND chips */ -static void single_erase_cmd (struct mtd_info *mtd, int page) +static void single_erase_cmd(struct mtd_info *mtd, int page) { struct nand_chip *this = mtd->priv; /* Send commands to erase a block */ - this->cmdfunc (mtd, NAND_CMD_ERASE1, -1, page); - this->cmdfunc (mtd, NAND_CMD_ERASE2, -1, -1); + this->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page); + this->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1); } /** @@ -2066,15 +2053,15 @@ static void single_erase_cmd (struct mtd_info *mtd, int page) * AND multi block erase command function * Erase 4 consecutive blocks */ -static void multi_erase_cmd (struct mtd_info *mtd, int page) +static void multi_erase_cmd(struct mtd_info *mtd, int page) { struct nand_chip *this = mtd->priv; /* Send commands to erase a block */ - this->cmdfunc (mtd, NAND_CMD_ERASE1, -1, page++); - this->cmdfunc (mtd, NAND_CMD_ERASE1, -1, page++); - this->cmdfunc (mtd, NAND_CMD_ERASE1, -1, page++); - this->cmdfunc (mtd, NAND_CMD_ERASE1, -1, page); - this->cmdfunc (mtd, NAND_CMD_ERASE2, -1, -1); + this->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++); + this->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++); + this->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++); + this->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page); + this->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1); } /** @@ -2084,9 +2071,9 @@ static void multi_erase_cmd (struct mtd_info *mtd, int page) * * Erase one ore more blocks */ -static int nand_erase (struct mtd_info *mtd, struct erase_info *instr) +static int nand_erase(struct mtd_info *mtd, struct erase_info *instr) { - return nand_erase_nand (mtd, instr, 0); + return nand_erase_nand(mtd, instr, 0); } #define BBT_PAGE_MASK 0xffffff3f @@ -2098,7 +2085,7 @@ static int nand_erase (struct mtd_info *mtd, struct erase_info *instr) * * Erase one ore more blocks */ -int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbbt) +int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, int allowbbt) { int page, len, status, pages_per_block, ret, chipnr; struct nand_chip *this = mtd->priv; @@ -2107,35 +2094,34 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb /* It is used to see if the current page is in the same */ /* 256 block group and the same bank as the bbt. */ - DEBUG (MTD_DEBUG_LEVEL3, - "nand_erase: start = 0x%08x, len = %i\n", (unsigned int) instr->addr, (unsigned int) instr->len); + DEBUG(MTD_DEBUG_LEVEL3, "nand_erase: start = 0x%08x, len = %i\n", (unsigned int)instr->addr, (unsigned int)instr->len); /* Start address must align on block boundary */ if (instr->addr & ((1 << this->phys_erase_shift) - 1)) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Unaligned address\n"); + DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: Unaligned address\n"); return -EINVAL; } /* Length must align on block boundary */ if (instr->len & ((1 << this->phys_erase_shift) - 1)) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Length not block aligned\n"); + DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: Length not block aligned\n"); return -EINVAL; } /* Do not allow erase past end of device */ if ((instr->len + instr->addr) > mtd->size) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Erase past end of device\n"); + DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: Erase past end of device\n"); return -EINVAL; } instr->fail_addr = 0xffffffff; /* Grab the lock and see if the device is available */ - nand_get_device (this, mtd, FL_ERASING); + nand_get_device(this, mtd, FL_ERASING); /* Shift to get first page */ - page = (int) (instr->addr >> this->page_shift); - chipnr = (int) (instr->addr >> this->chip_shift); + page = (int)(instr->addr >> this->page_shift); + chipnr = (int)(instr->addr >> this->chip_shift); /* Calculate pages in each block */ pages_per_block = 1 << (this->phys_erase_shift - this->page_shift); @@ -2146,7 +2132,7 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb /* Check the WP bit */ /* Check, if it is write protected */ if (nand_check_wp(mtd)) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Device is write protected!!!\n"); + DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: Device is write protected!!!\n"); instr->state = MTD_ERASE_FAILED; goto erase_exit; } @@ -2166,7 +2152,7 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb while (len) { /* Check if we have a bad block, we do not erase bad blocks ! */ if (nand_block_checkbad(mtd, ((loff_t) page) << this->page_shift, 0, allowbbt)) { - printk (KERN_WARNING "nand_erase: attempt to erase a bad block at page 0x%08x\n", page); + printk(KERN_WARNING "nand_erase: attempt to erase a bad block at page 0x%08x\n", page); instr->state = MTD_ERASE_FAILED; goto erase_exit; } @@ -2176,9 +2162,9 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb if (page <= this->pagebuf && this->pagebuf < (page + pages_per_block)) this->pagebuf = -1; - this->erase_cmd (mtd, page & this->pagemask); + this->erase_cmd(mtd, page & this->pagemask); - status = this->waitfunc (mtd, this, FL_ERASING); + status = this->waitfunc(mtd, this, FL_ERASING); /* See if operation failed and additional status checks are available */ if ((status & NAND_STATUS_FAIL) && (this->errstat)) { @@ -2187,7 +2173,7 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb /* See if block erase succeeded */ if (status & NAND_STATUS_FAIL) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase, page 0x%08x\n", page); + DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase, page 0x%08x\n", page); instr->state = MTD_ERASE_FAILED; instr->fail_addr = (page << this->page_shift); goto erase_exit; @@ -2221,7 +2207,7 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb } instr->state = MTD_ERASE_DONE; -erase_exit: + erase_exit: ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO; /* Do call back function */ @@ -2236,9 +2222,9 @@ erase_exit: for (chipnr = 0; chipnr < this->numchips; chipnr++) { if (rewrite_bbt[chipnr]) { /* update the BBT for chip */ - DEBUG (MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt (%d:0x%0x 0x%0x)\n", - chipnr, rewrite_bbt[chipnr], this->bbt_td->pages[chipnr]); - nand_update_bbt (mtd, rewrite_bbt[chipnr]); + DEBUG(MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt (%d:0x%0x 0x%0x)\n", + chipnr, rewrite_bbt[chipnr], this->bbt_td->pages[chipnr]); + nand_update_bbt(mtd, rewrite_bbt[chipnr]); } } } @@ -2253,31 +2239,30 @@ erase_exit: * * Sync is actually a wait for chip ready function */ -static void nand_sync (struct mtd_info *mtd) +static void nand_sync(struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; - DEBUG (MTD_DEBUG_LEVEL3, "nand_sync: called\n"); + DEBUG(MTD_DEBUG_LEVEL3, "nand_sync: called\n"); /* Grab the lock and see if the device is available */ - nand_get_device (this, mtd, FL_SYNCING); + nand_get_device(this, mtd, FL_SYNCING); /* Release it and go back */ - nand_release_device (mtd); + nand_release_device(mtd); } - /** * nand_block_isbad - [MTD Interface] Check whether the block at the given offset is bad * @mtd: MTD device structure * @ofs: offset relative to mtd start */ -static int nand_block_isbad (struct mtd_info *mtd, loff_t ofs) +static int nand_block_isbad(struct mtd_info *mtd, loff_t ofs) { /* Check for invalid offset */ if (ofs > mtd->size) return -EINVAL; - return nand_block_checkbad (mtd, ofs, 1, 0); + return nand_block_checkbad(mtd, ofs, 1, 0); } /** @@ -2285,17 +2270,17 @@ static int nand_block_isbad (struct mtd_info *mtd, loff_t ofs) * @mtd: MTD device structure * @ofs: offset relative to mtd start */ -static int nand_block_markbad (struct mtd_info *mtd, loff_t ofs) +static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs) { struct nand_chip *this = mtd->priv; int ret; - if ((ret = nand_block_isbad(mtd, ofs))) { - /* If it was bad already, return success and do nothing. */ + if ((ret = nand_block_isbad(mtd, ofs))) { + /* If it was bad already, return success and do nothing. */ if (ret > 0) return 0; - return ret; - } + return ret; + } return this->block_markbad(mtd, ofs); } @@ -2308,7 +2293,7 @@ static int nand_suspend(struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; - return nand_get_device (this, mtd, FL_PM_SUSPENDED); + return nand_get_device(this, mtd, FL_PM_SUSPENDED); } /** @@ -2322,12 +2307,10 @@ static void nand_resume(struct mtd_info *mtd) if (this->state == FL_PM_SUSPENDED) nand_release_device(mtd); else - printk(KERN_ERR "resume() called for the chip which is not " - "in suspended state\n"); + printk(KERN_ERR "resume() called for the chip which is not in suspended state\n"); } - /** * nand_scan - [NAND Interface] Scan for the NAND device * @mtd: MTD device structure @@ -2340,12 +2323,12 @@ static void nand_resume(struct mtd_info *mtd) * they are not provided by the board driver * */ -int nand_scan (struct mtd_info *mtd, int maxchips) +int nand_scan(struct mtd_info *mtd, int maxchips) { int i, nand_maf_id, nand_dev_id, busw, maf_id; struct nand_chip *this = mtd->priv; - /* Get buswidth to select the correct functions*/ + /* Get buswidth to select the correct functions */ busw = this->options & NAND_BUSWIDTH_16; /* check for proper chip_delay setup, set 20us if not */ @@ -2387,7 +2370,7 @@ int nand_scan (struct mtd_info *mtd, int maxchips) this->select_chip(mtd, 0); /* Send the command for reading device ID */ - this->cmdfunc (mtd, NAND_CMD_READID, 0x00, -1); + this->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); /* Read manufacturer and device IDs */ nand_maf_id = this->read_byte(mtd); @@ -2399,7 +2382,8 @@ int nand_scan (struct mtd_info *mtd, int maxchips) if (nand_dev_id != nand_flash_ids[i].id) continue; - if (!mtd->name) mtd->name = nand_flash_ids[i].name; + if (!mtd->name) + mtd->name = nand_flash_ids[i].name; this->chipsize = nand_flash_ids[i].chipsize << 20; /* New devices have all the information in additional id bytes */ @@ -2416,7 +2400,7 @@ int nand_scan (struct mtd_info *mtd, int maxchips) mtd->oobsize = (8 << (extid & 0x01)) * (mtd->oobblock >> 9); extid >>= 2; /* Calc blocksize. Blocksize is multiples of 64KiB */ - mtd->erasesize = (64 * 1024) << (extid & 0x03); + mtd->erasesize = (64 * 1024) << (extid & 0x03); extid >>= 2; /* Get buswidth information */ busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0; @@ -2439,13 +2423,12 @@ int nand_scan (struct mtd_info *mtd, int maxchips) /* Check, if buswidth is correct. Hardware drivers should set * this correct ! */ if (busw != (this->options & NAND_BUSWIDTH_16)) { - printk (KERN_INFO "NAND device: Manufacturer ID:" - " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, - nand_manuf_ids[maf_id].name , mtd->name); - printk (KERN_WARNING - "NAND bus width %d instead %d bit\n", - (this->options & NAND_BUSWIDTH_16) ? 16 : 8, - busw ? 16 : 8); + printk(KERN_INFO "NAND device: Manufacturer ID:" + " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, + nand_manuf_ids[maf_id].name, mtd->name); + printk(KERN_WARNING + "NAND bus width %d instead %d bit\n", + (this->options & NAND_BUSWIDTH_16) ? 16 : 8, busw ? 16 : 8); this->select_chip(mtd, -1); return 1; } @@ -2456,13 +2439,12 @@ int nand_scan (struct mtd_info *mtd, int maxchips) this->chip_shift = ffs(this->chipsize) - 1; /* Set the bad block position */ - this->badblockpos = mtd->oobblock > 512 ? - NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS; + this->badblockpos = mtd->oobblock > 512 ? NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS; /* Get chip options, preserve non chip based options */ this->options &= ~NAND_CHIPOPTIONS_MSK; this->options |= nand_flash_ids[i].options & NAND_CHIPOPTIONS_MSK; - /* Set this as a default. Board drivers can override it, if neccecary */ + /* Set this as a default. Board drivers can override it, if necessary */ this->options |= NAND_NO_AUTOINCR; /* Check if this is a not a samsung device. Do not clear the options * for chips which are not having an extended id. @@ -2480,23 +2462,23 @@ int nand_scan (struct mtd_info *mtd, int maxchips) if (mtd->oobblock > 512 && this->cmdfunc == nand_command) this->cmdfunc = nand_command_lp; - printk (KERN_INFO "NAND device: Manufacturer ID:" - " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, - nand_manuf_ids[maf_id].name , nand_flash_ids[i].name); + printk(KERN_INFO "NAND device: Manufacturer ID:" + " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, + nand_manuf_ids[maf_id].name, nand_flash_ids[i].name); break; } if (!nand_flash_ids[i].name) { - printk (KERN_WARNING "No NAND device found!!!\n"); + printk(KERN_WARNING "No NAND device found!!!\n"); this->select_chip(mtd, -1); return 1; } - for (i=1; i < maxchips; i++) { + for (i = 1; i < maxchips; i++) { this->select_chip(mtd, i); /* Send the command for reading device ID */ - this->cmdfunc (mtd, NAND_CMD_READID, 0x00, -1); + this->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); /* Read manufacturer and device IDs */ if (nand_maf_id != this->read_byte(mtd) || @@ -2506,13 +2488,13 @@ int nand_scan (struct mtd_info *mtd, int maxchips) if (i > 1) printk(KERN_INFO "%d NAND chips detected\n", i); - /* Allocate buffers, if neccecary */ + /* Allocate buffers, if necessary */ if (!this->oob_buf) { size_t len; len = mtd->oobsize << (this->phys_erase_shift - this->page_shift); - this->oob_buf = kmalloc (len, GFP_KERNEL); + this->oob_buf = kmalloc(len, GFP_KERNEL); if (!this->oob_buf) { - printk (KERN_ERR "nand_scan(): Cannot allocate oob_buf\n"); + printk(KERN_ERR "nand_scan(): Cannot allocate oob_buf\n"); return -ENOMEM; } this->options |= NAND_OOBBUF_ALLOC; @@ -2521,11 +2503,11 @@ int nand_scan (struct mtd_info *mtd, int maxchips) if (!this->data_buf) { size_t len; len = mtd->oobblock + mtd->oobsize; - this->data_buf = kmalloc (len, GFP_KERNEL); + this->data_buf = kmalloc(len, GFP_KERNEL); if (!this->data_buf) { if (this->options & NAND_OOBBUF_ALLOC) - kfree (this->oob_buf); - printk (KERN_ERR "nand_scan(): Cannot allocate data_buf\n"); + kfree(this->oob_buf); + printk(KERN_ERR "nand_scan(): Cannot allocate data_buf\n"); return -ENOMEM; } this->options |= NAND_DATABUF_ALLOC; @@ -2555,8 +2537,7 @@ int nand_scan (struct mtd_info *mtd, int maxchips) this->autooob = &nand_oob_64; break; default: - printk (KERN_WARNING "No oob scheme defined for oobsize %d\n", - mtd->oobsize); + printk(KERN_WARNING "No oob scheme defined for oobsize %d\n", mtd->oobsize); BUG(); } } @@ -2571,7 +2552,7 @@ int nand_scan (struct mtd_info *mtd, int maxchips) * check ECC mode, default to software * if 3byte/512byte hardware ECC is selected and we have 256 byte pagesize * fallback to software ECC - */ + */ this->eccsize = 256; /* set default eccsize */ this->eccbytes = 3; @@ -2591,19 +2572,19 @@ int nand_scan (struct mtd_info *mtd, int maxchips) case NAND_ECC_HW6_512: case NAND_ECC_HW8_512: if (mtd->oobblock == 256) { - printk (KERN_WARNING "512 byte HW ECC not possible on 256 Byte pagesize, fallback to SW ECC \n"); + printk(KERN_WARNING "512 byte HW ECC not possible on 256 Byte pagesize, fallback to SW ECC \n"); this->eccmode = NAND_ECC_SOFT; this->calculate_ecc = nand_calculate_ecc; this->correct_data = nand_correct_data; } else - this->eccsize = 512; /* set eccsize to 512 */ + this->eccsize = 512; /* set eccsize to 512 */ break; case NAND_ECC_HW3_256: break; case NAND_ECC_NONE: - printk (KERN_WARNING "NAND_ECC_NONE selected by board driver. This is not recommended !!\n"); + printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. This is not recommended !!\n"); this->eccmode = NAND_ECC_NONE; break; @@ -2613,13 +2594,13 @@ int nand_scan (struct mtd_info *mtd, int maxchips) break; default: - printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode); + printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode); BUG(); } /* Check hardware ecc function availability and adjust number of ecc bytes per * calculation step - */ + */ switch (this->eccmode) { case NAND_ECC_HW12_2048: this->eccbytes += 4; @@ -2631,7 +2612,7 @@ int nand_scan (struct mtd_info *mtd, int maxchips) case NAND_ECC_HW3_256: if (this->calculate_ecc && this->correct_data && this->enable_hwecc) break; - printk (KERN_WARNING "No ECC functions supplied, Hardware ECC not possible\n"); + printk(KERN_WARNING "No ECC functions supplied, Hardware ECC not possible\n"); BUG(); } @@ -2659,8 +2640,8 @@ int nand_scan (struct mtd_info *mtd, int maxchips) /* Initialize state, waitqueue and spinlock */ this->state = FL_READY; - init_waitqueue_head (&this->wq); - spin_lock_init (&this->chip_lock); + init_waitqueue_head(&this->wq); + spin_lock_init(&this->chip_lock); /* De-select the device */ this->select_chip(mtd, -1); @@ -2702,37 +2683,36 @@ int nand_scan (struct mtd_info *mtd, int maxchips) return 0; /* Build bad block table */ - return this->scan_bbt (mtd); + return this->scan_bbt(mtd); } /** * nand_release - [NAND Interface] Free resources held by the NAND device * @mtd: MTD device structure */ -void nand_release (struct mtd_info *mtd) +void nand_release(struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; #ifdef CONFIG_MTD_PARTITIONS /* Deregister partitions */ - del_mtd_partitions (mtd); + del_mtd_partitions(mtd); #endif /* Deregister the device */ - del_mtd_device (mtd); + del_mtd_device(mtd); /* Free bad block table memory */ - kfree (this->bbt); + kfree(this->bbt); /* Buffer allocated by nand_scan ? */ if (this->options & NAND_OOBBUF_ALLOC) - kfree (this->oob_buf); + kfree(this->oob_buf); /* Buffer allocated by nand_scan ? */ if (this->options & NAND_DATABUF_ALLOC) - kfree (this->data_buf); + kfree(this->data_buf); } -EXPORT_SYMBOL_GPL (nand_scan); -EXPORT_SYMBOL_GPL (nand_release); - +EXPORT_SYMBOL_GPL(nand_scan); +EXPORT_SYMBOL_GPL(nand_release); static int __init nand_base_init(void) { @@ -2748,6 +2728,6 @@ static void __exit nand_base_exit(void) module_init(nand_base_init); module_exit(nand_base_exit); -MODULE_LICENSE ("GPL"); -MODULE_AUTHOR ("Steven J. Hill , Thomas Gleixner "); -MODULE_DESCRIPTION ("Generic NAND flash driver code"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Steven J. Hill , Thomas Gleixner "); +MODULE_DESCRIPTION("Generic NAND flash driver code"); diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index ccc48a4a6ad0..9adc6d62332a 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -48,7 +48,7 @@ * * Following assumptions are made: * - bbts start at a page boundary, if autolocated on a block boundary - * - the space neccecary for a bbt in FLASH does not exceed a block boundary + * - the space necessary for a bbt in FLASH does not exceed a block boundary * */ @@ -75,7 +75,7 @@ * pattern area contain 0xff * */ -static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td) +static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td) { int i, end = 0; uint8_t *p = buf; @@ -116,7 +116,7 @@ static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_des * no optional empty check * */ -static int check_short_pattern (uint8_t *buf, struct nand_bbt_descr *td) +static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td) { int i; uint8_t *p = buf; @@ -142,8 +142,8 @@ static int check_short_pattern (uint8_t *buf, struct nand_bbt_descr *td) * Read the bad block table starting from page. * */ -static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num, - int bits, int offs, int reserved_block_code) +static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, + int bits, int offs, int reserved_block_code) { int res, i, j, act = 0; struct nand_chip *this = mtd->priv; @@ -152,17 +152,17 @@ static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num, uint8_t msk = (uint8_t) ((1 << bits) - 1); totlen = (num * bits) >> 3; - from = ((loff_t)page) << this->page_shift; + from = ((loff_t) page) << this->page_shift; while (totlen) { - len = min (totlen, (size_t) (1 << this->bbt_erase_shift)); - res = mtd->read_ecc (mtd, from, len, &retlen, buf, NULL, this->autooob); + len = min(totlen, (size_t) (1 << this->bbt_erase_shift)); + res = mtd->read_ecc(mtd, from, len, &retlen, buf, NULL, this->autooob); if (res < 0) { if (retlen != len) { - printk (KERN_INFO "nand_bbt: Error reading bad block table\n"); + printk(KERN_INFO "nand_bbt: Error reading bad block table\n"); return res; } - printk (KERN_WARNING "nand_bbt: ECC error while reading bad block table\n"); + printk(KERN_WARNING "nand_bbt: ECC error while reading bad block table\n"); } /* Analyse data */ @@ -172,17 +172,16 @@ static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num, uint8_t tmp = (dat >> j) & msk; if (tmp == msk) continue; - if (reserved_block_code && - (tmp == reserved_block_code)) { - printk (KERN_DEBUG "nand_read_bbt: Reserved block at 0x%08x\n", - ((offs << 2) + (act >> 1)) << this->bbt_erase_shift); + if (reserved_block_code && (tmp == reserved_block_code)) { + printk(KERN_DEBUG "nand_read_bbt: Reserved block at 0x%08x\n", + ((offs << 2) + (act >> 1)) << this->bbt_erase_shift); this->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06); continue; } /* Leave it for now, if its matured we can move this * message to MTD_DEBUG_LEVEL0 */ - printk (KERN_DEBUG "nand_read_bbt: Bad block at 0x%08x\n", - ((offs << 2) + (act >> 1)) << this->bbt_erase_shift); + printk(KERN_DEBUG "nand_read_bbt: Bad block at 0x%08x\n", + ((offs << 2) + (act >> 1)) << this->bbt_erase_shift); /* Factory marked bad or worn out ? */ if (tmp == 0) this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06); @@ -207,7 +206,7 @@ static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num, * Read the bad block table for all chips starting at a given page * We assume that the bbt bits are in consecutive order. */ -static int read_abs_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, int chip) +static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, int chip) { struct nand_chip *this = mtd->priv; int res = 0, i; @@ -242,23 +241,22 @@ static int read_abs_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des * We assume that the bbt bits are in consecutive order. * */ -static int read_abs_bbts (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, - struct nand_bbt_descr *md) +static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md) { struct nand_chip *this = mtd->priv; /* Read the primary version, if available */ if (td->options & NAND_BBT_VERSION) { - nand_read_raw (mtd, buf, td->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize); + nand_read_raw(mtd, buf, td->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize); td->version[0] = buf[mtd->oobblock + td->veroffs]; - printk (KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", td->pages[0], td->version[0]); + printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", td->pages[0], td->version[0]); } /* Read the mirror version, if available */ if (md && (md->options & NAND_BBT_VERSION)) { - nand_read_raw (mtd, buf, md->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize); + nand_read_raw(mtd, buf, md->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize); md->version[0] = buf[mtd->oobblock + md->veroffs]; - printk (KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", md->pages[0], md->version[0]); + printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", md->pages[0], md->version[0]); } return 1; @@ -275,7 +273,7 @@ static int read_abs_bbts (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_de * Create a bad block table by scanning the device * for the given good/bad block identify pattern */ -static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip) +static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip) { struct nand_chip *this = mtd->priv; int i, j, numblocks, len, scanlen; @@ -283,7 +281,7 @@ static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr loff_t from; size_t readlen, ooblen; - printk (KERN_INFO "Scanning device for bad blocks\n"); + printk(KERN_INFO "Scanning device for bad blocks\n"); if (bd->options & NAND_BBT_SCANALLPAGES) len = 1 << (this->bbt_erase_shift - this->page_shift); @@ -300,7 +298,7 @@ static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr readlen = bd->len; } else { /* Full page content should be read */ - scanlen = mtd->oobblock + mtd->oobsize; + scanlen = mtd->oobblock + mtd->oobsize; readlen = len * mtd->oobblock; ooblen = len * mtd->oobsize; } @@ -313,8 +311,8 @@ static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr from = 0; } else { if (chip >= this->numchips) { - printk (KERN_WARNING "create_bbt(): chipnr (%d) > available chips (%d)\n", - chip + 1, this->numchips); + printk(KERN_WARNING "create_bbt(): chipnr (%d) > available chips (%d)\n", + chip + 1, this->numchips); return -EINVAL; } numblocks = this->chipsize >> (this->bbt_erase_shift - 1); @@ -327,7 +325,7 @@ static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr int ret; if (bd->options & NAND_BBT_SCANEMPTY) - if ((ret = nand_read_raw (mtd, buf, from, readlen, ooblen))) + if ((ret = nand_read_raw(mtd, buf, from, readlen, ooblen))) return ret; for (j = 0; j < len; j++) { @@ -336,22 +334,21 @@ static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr /* Read the full oob until read_oob is fixed to * handle single byte reads for 16 bit buswidth */ - ret = mtd->read_oob(mtd, from + j * mtd->oobblock, - mtd->oobsize, &retlen, buf); + ret = mtd->read_oob(mtd, from + j * mtd->oobblock, mtd->oobsize, &retlen, buf); if (ret) return ret; - if (check_short_pattern (buf, bd)) { + if (check_short_pattern(buf, bd)) { this->bbt[i >> 3] |= 0x03 << (i & 0x6); - printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n", - i >> 1, (unsigned int) from); + printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n", + i >> 1, (unsigned int)from); break; } } else { - if (check_pattern (&buf[j * scanlen], scanlen, mtd->oobblock, bd)) { + if (check_pattern(&buf[j * scanlen], scanlen, mtd->oobblock, bd)) { this->bbt[i >> 3] |= 0x03 << (i & 0x6); - printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n", - i >> 1, (unsigned int) from); + printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n", + i >> 1, (unsigned int)from); break; } } @@ -374,12 +371,12 @@ static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr * block. * If the option NAND_BBT_PERCHIP is given, each chip is searched * for a bbt, which contains the bad block information of this chip. - * This is neccecary to provide support for certain DOC devices. + * This is necessary to provide support for certain DOC devices. * * The bbt ident pattern resides in the oob area of the first page * in a block. */ -static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td) +static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td) { struct nand_chip *this = mtd->priv; int i, chips; @@ -389,7 +386,7 @@ static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr /* Search direction top -> down ? */ if (td->options & NAND_BBT_LASTBLOCK) { - startblock = (mtd->size >> this->bbt_erase_shift) -1; + startblock = (mtd->size >> this->bbt_erase_shift) - 1; dir = -1; } else { startblock = 0; @@ -417,7 +414,7 @@ static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr for (block = 0; block < td->maxblocks; block++) { int actblock = startblock + dir * block; /* Read first page */ - nand_read_raw (mtd, buf, actblock << this->bbt_erase_shift, mtd->oobblock, mtd->oobsize); + nand_read_raw(mtd, buf, actblock << this->bbt_erase_shift, mtd->oobblock, mtd->oobsize); if (!check_pattern(buf, scanlen, mtd->oobblock, td)) { td->pages[i] = actblock << (this->bbt_erase_shift - this->page_shift); if (td->options & NAND_BBT_VERSION) { @@ -431,9 +428,10 @@ static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr /* Check, if we found a bbt for each requested chip */ for (i = 0; i < chips; i++) { if (td->pages[i] == -1) - printk (KERN_WARNING "Bad block table not found for chip %d\n", i); + printk(KERN_WARNING "Bad block table not found for chip %d\n", i); else - printk (KERN_DEBUG "Bad block table found at page %d, version 0x%02X\n", td->pages[i], td->version[i]); + printk(KERN_DEBUG "Bad block table found at page %d, version 0x%02X\n", td->pages[i], + td->version[i]); } return 0; } @@ -447,21 +445,19 @@ static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr * * Search and read the bad block table(s) */ -static int search_read_bbts (struct mtd_info *mtd, uint8_t *buf, - struct nand_bbt_descr *td, struct nand_bbt_descr *md) +static int search_read_bbts(struct mtd_info *mtd, uint8_t * buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md) { /* Search the primary table */ - search_bbt (mtd, buf, td); + search_bbt(mtd, buf, td); /* Search the mirror table */ if (md) - search_bbt (mtd, buf, md); + search_bbt(mtd, buf, md); /* Force result check */ return 1; } - /** * write_bbt - [GENERIC] (Re)write the bad block table * @@ -474,8 +470,8 @@ static int search_read_bbts (struct mtd_info *mtd, uint8_t *buf, * (Re)write the bad block table * */ -static int write_bbt (struct mtd_info *mtd, uint8_t *buf, - struct nand_bbt_descr *td, struct nand_bbt_descr *md, int chipsel) +static int write_bbt(struct mtd_info *mtd, uint8_t *buf, + struct nand_bbt_descr *td, struct nand_bbt_descr *md, int chipsel) { struct nand_chip *this = mtd->priv; struct nand_oobinfo oobinfo; @@ -492,7 +488,7 @@ static int write_bbt (struct mtd_info *mtd, uint8_t *buf, rcode = 0xff; /* Write bad block table per chip rather than per device ? */ if (td->options & NAND_BBT_PERCHIP) { - numblocks = (int) (this->chipsize >> this->bbt_erase_shift); + numblocks = (int)(this->chipsize >> this->bbt_erase_shift); /* Full device write or specific chip ? */ if (chipsel == -1) { nrchips = this->numchips; @@ -501,7 +497,7 @@ static int write_bbt (struct mtd_info *mtd, uint8_t *buf, chip = chipsel; } } else { - numblocks = (int) (mtd->size >> this->bbt_erase_shift); + numblocks = (int)(mtd->size >> this->bbt_erase_shift); nrchips = 1; } @@ -540,9 +536,9 @@ static int write_bbt (struct mtd_info *mtd, uint8_t *buf, if (!md || md->pages[chip] != page) goto write; } - printk (KERN_ERR "No space left to write bad block table\n"); + printk(KERN_ERR "No space left to write bad block table\n"); return -ENOSPC; -write: + write: /* Set up shift count and masks for the flash table */ bits = td->options & NAND_BBT_NRBITS_MSK; @@ -558,7 +554,7 @@ write: to = ((loff_t) page) << this->page_shift; - memcpy (&oobinfo, this->autooob, sizeof(oobinfo)); + memcpy(&oobinfo, this->autooob, sizeof(oobinfo)); oobinfo.useecc = MTD_NANDECC_PLACEONLY; /* Must we save the block contents ? */ @@ -566,22 +562,23 @@ write: /* Make it block aligned */ to &= ~((loff_t) ((1 << this->bbt_erase_shift) - 1)); len = 1 << this->bbt_erase_shift; - res = mtd->read_ecc (mtd, to, len, &retlen, buf, &buf[len], &oobinfo); + res = mtd->read_ecc(mtd, to, len, &retlen, buf, &buf[len], &oobinfo); if (res < 0) { if (retlen != len) { - printk (KERN_INFO "nand_bbt: Error reading block for writing the bad block table\n"); + printk(KERN_INFO + "nand_bbt: Error reading block for writing the bad block table\n"); return res; } - printk (KERN_WARNING "nand_bbt: ECC error while reading block for writing bad block table\n"); + printk(KERN_WARNING "nand_bbt: ECC error while reading block for writing bad block table\n"); } /* Calc the byte offset in the buffer */ pageoffs = page - (int)(to >> this->page_shift); offs = pageoffs << this->page_shift; /* Preset the bbt area with 0xff */ - memset (&buf[offs], 0xff, (size_t)(numblocks >> sft)); + memset(&buf[offs], 0xff, (size_t) (numblocks >> sft)); /* Preset the bbt's oob area with 0xff */ - memset (&buf[len + pageoffs * mtd->oobsize], 0xff, - ((len >> this->page_shift) - pageoffs) * mtd->oobsize); + memset(&buf[len + pageoffs * mtd->oobsize], 0xff, + ((len >> this->page_shift) - pageoffs) * mtd->oobsize); if (td->options & NAND_BBT_VERSION) { buf[len + (pageoffs * mtd->oobsize) + td->veroffs] = td->version[chip]; } @@ -589,22 +586,22 @@ write: /* Calc length */ len = (size_t) (numblocks >> sft); /* Make it page aligned ! */ - len = (len + (mtd->oobblock-1)) & ~(mtd->oobblock-1); + len = (len + (mtd->oobblock - 1)) & ~(mtd->oobblock - 1); /* Preset the buffer with 0xff */ - memset (buf, 0xff, len + (len >> this->page_shift) * mtd->oobsize); + memset(buf, 0xff, len + (len >> this->page_shift) * mtd->oobsize); offs = 0; /* Pattern is located in oob area of first page */ - memcpy (&buf[len + td->offs], td->pattern, td->len); + memcpy(&buf[len + td->offs], td->pattern, td->len); if (td->options & NAND_BBT_VERSION) { buf[len + td->veroffs] = td->version[chip]; } } /* walk through the memory table */ - for (i = 0; i < numblocks; ) { + for (i = 0; i < numblocks;) { uint8_t dat; dat = this->bbt[bbtoffs + (i >> 2)]; - for (j = 0; j < 4; j++ , i++) { + for (j = 0; j < 4; j++, i++) { int sftcnt = (i << (3 - sft)) & sftmsk; /* Do not store the reserved bbt blocks ! */ buf[offs + (i >> sft)] &= ~(msk[dat & 0x03] << sftcnt); @@ -612,23 +609,23 @@ write: } } - memset (&einfo, 0, sizeof (einfo)); + memset(&einfo, 0, sizeof(einfo)); einfo.mtd = mtd; - einfo.addr = (unsigned long) to; + einfo.addr = (unsigned long)to; einfo.len = 1 << this->bbt_erase_shift; - res = nand_erase_nand (mtd, &einfo, 1); + res = nand_erase_nand(mtd, &einfo, 1); if (res < 0) { - printk (KERN_WARNING "nand_bbt: Error during block erase: %d\n", res); + printk(KERN_WARNING "nand_bbt: Error during block erase: %d\n", res); return res; } - res = mtd->write_ecc (mtd, to, len, &retlen, buf, &buf[len], &oobinfo); + res = mtd->write_ecc(mtd, to, len, &retlen, buf, &buf[len], &oobinfo); if (res < 0) { - printk (KERN_WARNING "nand_bbt: Error while writing bad block table %d\n", res); + printk(KERN_WARNING "nand_bbt: Error while writing bad block table %d\n", res); return res; } - printk (KERN_DEBUG "Bad block table written to 0x%08x, version 0x%02X\n", - (unsigned int) to, td->version[chip]); + printk(KERN_DEBUG "Bad block table written to 0x%08x, version 0x%02X\n", + (unsigned int)to, td->version[chip]); /* Mark it as used */ td->pages[chip] = page; @@ -644,27 +641,27 @@ write: * The function creates a memory based bbt by scanning the device * for manufacturer / software marked good / bad blocks */ -static inline int nand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd) +static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) { struct nand_chip *this = mtd->priv; bd->options &= ~NAND_BBT_SCANEMPTY; - return create_bbt (mtd, this->data_buf, bd, -1); + return create_bbt(mtd, this->data_buf, bd, -1); } /** - * check_create - [GENERIC] create and write bbt(s) if neccecary + * check_create - [GENERIC] create and write bbt(s) if necessary * @mtd: MTD device structure * @buf: temporary buffer * @bd: descriptor for the good/bad block search pattern * * The function checks the results of the previous call to read_bbt - * and creates / updates the bbt(s) if neccecary - * Creation is neccecary if no bbt was found for the chip/device - * Update is neccecary if one of the tables is missing or the + * and creates / updates the bbt(s) if necessary + * Creation is necessary if no bbt was found for the chip/device + * Update is necessary if one of the tables is missing or the * version nr. of one table is less than the other */ -static int check_create (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd) +static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd) { int i, chips, writeops, chipsel, res; struct nand_chip *this = mtd->priv; @@ -732,35 +729,35 @@ static int check_create (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des rd = td; goto writecheck; } -create: + create: /* Create the bad block table by scanning the device ? */ if (!(td->options & NAND_BBT_CREATE)) continue; /* Create the table in memory by scanning the chip(s) */ - create_bbt (mtd, buf, bd, chipsel); + create_bbt(mtd, buf, bd, chipsel); td->version[i] = 1; if (md) md->version[i] = 1; -writecheck: + writecheck: /* read back first ? */ if (rd) - read_abs_bbt (mtd, buf, rd, chipsel); + read_abs_bbt(mtd, buf, rd, chipsel); /* If they weren't versioned, read both. */ if (rd2) - read_abs_bbt (mtd, buf, rd2, chipsel); + read_abs_bbt(mtd, buf, rd2, chipsel); /* Write the bad block table to the device ? */ if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) { - res = write_bbt (mtd, buf, td, md, chipsel); + res = write_bbt(mtd, buf, td, md, chipsel); if (res < 0) return res; } /* Write the mirror bad block table to the device ? */ if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) { - res = write_bbt (mtd, buf, md, td, chipsel); + res = write_bbt(mtd, buf, md, td, chipsel); if (res < 0) return res; } @@ -777,7 +774,7 @@ writecheck: * accidental erasures / writes. The regions are identified by * the mark 0x02. */ -static void mark_bbt_region (struct mtd_info *mtd, struct nand_bbt_descr *td) +static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) { struct nand_chip *this = mtd->priv; int i, j, chips, block, nrblocks, update; @@ -795,7 +792,8 @@ static void mark_bbt_region (struct mtd_info *mtd, struct nand_bbt_descr *td) for (i = 0; i < chips; i++) { if ((td->options & NAND_BBT_ABSPAGE) || !(td->options & NAND_BBT_WRITE)) { - if (td->pages[i] == -1) continue; + if (td->pages[i] == -1) + continue; block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift); block <<= 1; oldval = this->bbt[(block >> 3)]; @@ -815,7 +813,8 @@ static void mark_bbt_region (struct mtd_info *mtd, struct nand_bbt_descr *td) oldval = this->bbt[(block >> 3)]; newval = oldval | (0x2 << (block & 0x06)); this->bbt[(block >> 3)] = newval; - if (oldval != newval) update = 1; + if (oldval != newval) + update = 1; block += 2; } /* If we want reserved blocks to be recorded to flash, and some @@ -840,7 +839,7 @@ static void mark_bbt_region (struct mtd_info *mtd, struct nand_bbt_descr *td) * by calling the nand_free_bbt function. * */ -int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd) +int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) { struct nand_chip *this = mtd->priv; int len, res = 0; @@ -850,21 +849,21 @@ int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd) len = mtd->size >> (this->bbt_erase_shift + 2); /* Allocate memory (2bit per block) */ - this->bbt = kmalloc (len, GFP_KERNEL); + this->bbt = kmalloc(len, GFP_KERNEL); if (!this->bbt) { - printk (KERN_ERR "nand_scan_bbt: Out of memory\n"); + printk(KERN_ERR "nand_scan_bbt: Out of memory\n"); return -ENOMEM; } /* Clear the memory bad block table */ - memset (this->bbt, 0x00, len); + memset(this->bbt, 0x00, len); /* If no primary table decriptor is given, scan the device * to build a memory based bad block table */ if (!td) { if ((res = nand_memory_bbt(mtd, bd))) { - printk (KERN_ERR "nand_bbt: Can't scan flash and build the RAM-based BBT\n"); - kfree (this->bbt); + printk(KERN_ERR "nand_bbt: Can't scan flash and build the RAM-based BBT\n"); + kfree(this->bbt); this->bbt = NULL; } return res; @@ -875,33 +874,32 @@ int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd) len += (len >> this->page_shift) * mtd->oobsize; buf = vmalloc(len); if (!buf) { - printk (KERN_ERR "nand_bbt: Out of memory\n"); - kfree (this->bbt); + printk(KERN_ERR "nand_bbt: Out of memory\n"); + kfree(this->bbt); this->bbt = NULL; return -ENOMEM; } /* Is the bbt at a given page ? */ if (td->options & NAND_BBT_ABSPAGE) { - res = read_abs_bbts (mtd, buf, td, md); + res = read_abs_bbts(mtd, buf, td, md); } else { /* Search the bad block table using a pattern in oob */ - res = search_read_bbts (mtd, buf, td, md); + res = search_read_bbts(mtd, buf, td, md); } if (res) - res = check_create (mtd, buf, bd); + res = check_create(mtd, buf, bd); /* Prevent the bbt regions from erasing / writing */ - mark_bbt_region (mtd, td); + mark_bbt_region(mtd, td); if (md) - mark_bbt_region (mtd, md); + mark_bbt_region(mtd, md); - vfree (buf); + vfree(buf); return res; } - /** * nand_update_bbt - [NAND Interface] update bad block table(s) * @mtd: MTD device structure @@ -909,7 +907,7 @@ int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd) * * The function updates the bad block table(s) */ -int nand_update_bbt (struct mtd_info *mtd, loff_t offs) +int nand_update_bbt(struct mtd_info *mtd, loff_t offs) { struct nand_chip *this = mtd->priv; int len, res = 0, writeops = 0; @@ -925,9 +923,9 @@ int nand_update_bbt (struct mtd_info *mtd, loff_t offs) /* Allocate a temporary buffer for one eraseblock incl. oob */ len = (1 << this->bbt_erase_shift); len += (len >> this->page_shift) * mtd->oobsize; - buf = kmalloc (len, GFP_KERNEL); + buf = kmalloc(len, GFP_KERNEL); if (!buf) { - printk (KERN_ERR "nand_update_bbt: Out of memory\n"); + printk(KERN_ERR "nand_update_bbt: Out of memory\n"); return -ENOMEM; } @@ -935,7 +933,7 @@ int nand_update_bbt (struct mtd_info *mtd, loff_t offs) /* Do we have a bbt per chip ? */ if (td->options & NAND_BBT_PERCHIP) { - chip = (int) (offs >> this->chip_shift); + chip = (int)(offs >> this->chip_shift); chipsel = chip; } else { chip = 0; @@ -948,17 +946,17 @@ int nand_update_bbt (struct mtd_info *mtd, loff_t offs) /* Write the bad block table to the device ? */ if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) { - res = write_bbt (mtd, buf, td, md, chipsel); + res = write_bbt(mtd, buf, td, md, chipsel); if (res < 0) goto out; } /* Write the mirror bad block table to the device ? */ if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) { - res = write_bbt (mtd, buf, md, td, chipsel); + res = write_bbt(mtd, buf, md, td, chipsel); } -out: - kfree (buf); + out: + kfree(buf); return res; } @@ -1036,7 +1034,7 @@ static struct nand_bbt_descr bbt_mirror_descr = { * support for the device and calls the nand_scan_bbt function * */ -int nand_default_bbt (struct mtd_info *mtd) +int nand_default_bbt(struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; @@ -1046,7 +1044,7 @@ int nand_default_bbt (struct mtd_info *mtd) * of the good / bad information, so we _must_ store * this information in a good / bad table during * startup - */ + */ if (this->options & NAND_IS_AND) { /* Use the default pattern descriptors */ if (!this->bbt_td) { @@ -1054,10 +1052,9 @@ int nand_default_bbt (struct mtd_info *mtd) this->bbt_md = &bbt_mirror_descr; } this->options |= NAND_USE_FLASH_BBT; - return nand_scan_bbt (mtd, &agand_flashbased); + return nand_scan_bbt(mtd, &agand_flashbased); } - /* Is a flash based bad block table requested ? */ if (this->options & NAND_USE_FLASH_BBT) { /* Use the default pattern descriptors */ @@ -1066,18 +1063,17 @@ int nand_default_bbt (struct mtd_info *mtd) this->bbt_md = &bbt_mirror_descr; } if (!this->badblock_pattern) { - this->badblock_pattern = (mtd->oobblock > 512) ? - &largepage_flashbased : &smallpage_flashbased; + this->badblock_pattern = (mtd->oobblock > 512) ? &largepage_flashbased : &smallpage_flashbased; } } else { this->bbt_td = NULL; this->bbt_md = NULL; if (!this->badblock_pattern) { this->badblock_pattern = (mtd->oobblock > 512) ? - &largepage_memorybased : &smallpage_memorybased; + &largepage_memorybased : &smallpage_memorybased; } } - return nand_scan_bbt (mtd, this->badblock_pattern); + return nand_scan_bbt(mtd, this->badblock_pattern); } /** @@ -1087,26 +1083,29 @@ int nand_default_bbt (struct mtd_info *mtd) * @allowbbt: allow access to bad block table region * */ -int nand_isbad_bbt (struct mtd_info *mtd, loff_t offs, int allowbbt) +int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt) { struct nand_chip *this = mtd->priv; int block; - uint8_t res; + uint8_t res; /* Get block number * 2 */ - block = (int) (offs >> (this->bbt_erase_shift - 1)); + block = (int)(offs >> (this->bbt_erase_shift - 1)); res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03; - DEBUG (MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n", - (unsigned int)offs, block >> 1, res); + DEBUG(MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n", + (unsigned int)offs, block >> 1, res); switch ((int)res) { - case 0x00: return 0; - case 0x01: return 1; - case 0x02: return allowbbt ? 0 : 1; + case 0x00: + return 0; + case 0x01: + return 1; + case 0x02: + return allowbbt ? 0 : 1; } return 1; } -EXPORT_SYMBOL (nand_scan_bbt); -EXPORT_SYMBOL (nand_default_bbt); +EXPORT_SYMBOL(nand_scan_bbt); +EXPORT_SYMBOL(nand_default_bbt); diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c index 40ac909150a3..101892985b02 100644 --- a/drivers/mtd/nand/nand_ecc.c +++ b/drivers/mtd/nand/nand_ecc.c @@ -62,7 +62,6 @@ static const u_char nand_ecc_precalc_table[] = { 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00 }; - /** * nand_trans_result - [GENERIC] create non-inverted ECC * @reg2: line parity reg 2 @@ -71,8 +70,7 @@ static const u_char nand_ecc_precalc_table[] = { * * Creates non-inverted ECC code from line parity */ -static void nand_trans_result(u_char reg2, u_char reg3, - u_char *ecc_code) +static void nand_trans_result(u_char reg2, u_char reg3, u_char *ecc_code) { u_char a, b, i, tmp1, tmp2; @@ -82,10 +80,10 @@ static void nand_trans_result(u_char reg2, u_char reg3, /* Calculate first ECC byte */ for (i = 0; i < 4; i++) { - if (reg3 & a) /* LP15,13,11,9 --> ecc_code[0] */ + if (reg3 & a) /* LP15,13,11,9 --> ecc_code[0] */ tmp1 |= b; b >>= 1; - if (reg2 & a) /* LP14,12,10,8 --> ecc_code[0] */ + if (reg2 & a) /* LP14,12,10,8 --> ecc_code[0] */ tmp1 |= b; b >>= 1; a >>= 1; @@ -94,10 +92,10 @@ static void nand_trans_result(u_char reg2, u_char reg3, /* Calculate second ECC byte */ b = 0x80; for (i = 0; i < 4; i++) { - if (reg3 & a) /* LP7,5,3,1 --> ecc_code[1] */ + if (reg3 & a) /* LP7,5,3,1 --> ecc_code[1] */ tmp2 |= b; b >>= 1; - if (reg2 & a) /* LP6,4,2,0 --> ecc_code[1] */ + if (reg2 & a) /* LP6,4,2,0 --> ecc_code[1] */ tmp2 |= b; b >>= 1; a >>= 1; @@ -124,7 +122,7 @@ int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code ecc_code[0] = ecc_code[1] = ecc_code[2] = 0; /* Build up column parity */ - for(j = 0; j < 256; j++) { + for (j = 0; j < 256; j++) { /* Get CP0 - CP5 from table */ idx = nand_ecc_precalc_table[dat[j]]; @@ -168,8 +166,7 @@ int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_cha if ((d1 | d2 | d3) == 0) { /* No errors */ return 0; - } - else { + } else { a = (d1 ^ (d1 >> 1)) & 0x55; b = (d2 ^ (d2 >> 1)) & 0x55; c = (d3 ^ (d3 >> 1)) & 0x54; @@ -179,14 +176,14 @@ int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_cha c = 0x80; add = 0; a = 0x80; - for (i=0; i<4; i++) { + for (i = 0; i < 4; i++) { if (d1 & c) add |= a; c >>= 2; a >>= 1; } c = 0x80; - for (i=0; i<4; i++) { + for (i = 0; i < 4; i++) { if (d2 & c) add |= a; c >>= 2; @@ -195,7 +192,7 @@ int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_cha bit = 0; b = 0x04; c = 0x80; - for (i=0; i<3; i++) { + for (i = 0; i < 3; i++) { if (d3 & c) bit |= b; c >>= 2; @@ -206,8 +203,7 @@ int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_cha a ^= (b << bit); dat[add] = a; return 1; - } - else { + } else { i = 0; while (d1) { if (d1 & 0x01) @@ -230,8 +226,7 @@ int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_cha read_ecc[1] = calc_ecc[1]; read_ecc[2] = calc_ecc[2]; return 2; - } - else { + } else { /* Uncorrectable Error */ return -1; } diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index dbc7e55a4247..a9d52fc6e5d7 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c @@ -125,13 +125,13 @@ struct nand_manufacturers nand_manuf_ids[] = { {NAND_MFR_NATIONAL, "National"}, {NAND_MFR_RENESAS, "Renesas"}, {NAND_MFR_STMICRO, "ST Micro"}, - {NAND_MFR_HYNIX, "Hynix"}, + {NAND_MFR_HYNIX, "Hynix"}, {0x0, "Unknown"} }; -EXPORT_SYMBOL (nand_manuf_ids); -EXPORT_SYMBOL (nand_flash_ids); +EXPORT_SYMBOL(nand_manuf_ids); +EXPORT_SYMBOL(nand_flash_ids); -MODULE_LICENSE ("GPL"); -MODULE_AUTHOR ("Thomas Gleixner "); -MODULE_DESCRIPTION ("Nand device & manufacturer ID's"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Thomas Gleixner "); +MODULE_DESCRIPTION("Nand device & manufacturer IDs"); diff --git a/drivers/mtd/nand/ppchameleonevb.c b/drivers/mtd/nand/ppchameleonevb.c index 91a95f34a6ee..405beece9c5a 100644 --- a/drivers/mtd/nand/ppchameleonevb.c +++ b/drivers/mtd/nand/ppchameleonevb.c @@ -58,21 +58,21 @@ /* * MTD structure for PPChameleonEVB board */ -static struct mtd_info *ppchameleon_mtd = NULL; +static struct mtd_info *ppchameleon_mtd = NULL; static struct mtd_info *ppchameleonevb_mtd = NULL; /* * Module stuff */ -static unsigned long ppchameleon_fio_pbase = CFG_NAND0_PADDR; +static unsigned long ppchameleon_fio_pbase = CFG_NAND0_PADDR; static unsigned long ppchameleonevb_fio_pbase = CFG_NAND1_PADDR; #ifdef MODULE module_param(ppchameleon_fio_pbase, ulong, 0); module_param(ppchameleonevb_fio_pbase, ulong, 0); #else -__setup("ppchameleon_fio_pbase=",ppchameleon_fio_pbase); -__setup("ppchameleonevb_fio_pbase=",ppchameleonevb_fio_pbase); +__setup("ppchameleon_fio_pbase=", ppchameleon_fio_pbase); +__setup("ppchameleonevb_fio_pbase=", ppchameleonevb_fio_pbase); #endif #ifdef CONFIG_MTD_PARTITIONS @@ -80,80 +80,80 @@ __setup("ppchameleonevb_fio_pbase=",ppchameleonevb_fio_pbase); * Define static partitions for flash devices */ static struct mtd_partition partition_info_hi[] = { - { name: "PPChameleon HI Nand Flash", - offset: 0, - size: 128*1024*1024 } + { .name = "PPChameleon HI Nand Flash", + offset = 0, + .size = 128 * 1024 * 1024 + } }; static struct mtd_partition partition_info_me[] = { - { name: "PPChameleon ME Nand Flash", - offset: 0, - size: 32*1024*1024 } + { .name = "PPChameleon ME Nand Flash", + .offset = 0, + .size = 32 * 1024 * 1024 + } }; static struct mtd_partition partition_info_evb[] = { - { name: "PPChameleonEVB Nand Flash", - offset: 0, - size: 32*1024*1024 } + { .name = "PPChameleonEVB Nand Flash", + .offset = 0, + .size = 32 * 1024 * 1024 + } }; #define NUM_PARTITIONS 1 -extern int parse_cmdline_partitions(struct mtd_info *master, - struct mtd_partition **pparts, - const char *mtd_id); +extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partition **pparts, const char *mtd_id); #endif - /* * hardware specific access to control-lines */ static void ppchameleon_hwcontrol(struct mtd_info *mtdinfo, int cmd) { - switch(cmd) { + switch (cmd) { case NAND_CTL_SETCLE: - MACRO_NAND_CTL_SETCLE((unsigned long)CFG_NAND0_PADDR); + MACRO_NAND_CTL_SETCLE((unsigned long)CFG_NAND0_PADDR); break; case NAND_CTL_CLRCLE: - MACRO_NAND_CTL_CLRCLE((unsigned long)CFG_NAND0_PADDR); + MACRO_NAND_CTL_CLRCLE((unsigned long)CFG_NAND0_PADDR); break; case NAND_CTL_SETALE: - MACRO_NAND_CTL_SETALE((unsigned long)CFG_NAND0_PADDR); + MACRO_NAND_CTL_SETALE((unsigned long)CFG_NAND0_PADDR); break; case NAND_CTL_CLRALE: - MACRO_NAND_CTL_CLRALE((unsigned long)CFG_NAND0_PADDR); + MACRO_NAND_CTL_CLRALE((unsigned long)CFG_NAND0_PADDR); break; case NAND_CTL_SETNCE: - MACRO_NAND_ENABLE_CE((unsigned long)CFG_NAND0_PADDR); + MACRO_NAND_ENABLE_CE((unsigned long)CFG_NAND0_PADDR); break; case NAND_CTL_CLRNCE: - MACRO_NAND_DISABLE_CE((unsigned long)CFG_NAND0_PADDR); + MACRO_NAND_DISABLE_CE((unsigned long)CFG_NAND0_PADDR); break; } } static void ppchameleonevb_hwcontrol(struct mtd_info *mtdinfo, int cmd) { - switch(cmd) { + switch (cmd) { case NAND_CTL_SETCLE: - MACRO_NAND_CTL_SETCLE((unsigned long)CFG_NAND1_PADDR); + MACRO_NAND_CTL_SETCLE((unsigned long)CFG_NAND1_PADDR); break; case NAND_CTL_CLRCLE: - MACRO_NAND_CTL_CLRCLE((unsigned long)CFG_NAND1_PADDR); + MACRO_NAND_CTL_CLRCLE((unsigned long)CFG_NAND1_PADDR); break; case NAND_CTL_SETALE: - MACRO_NAND_CTL_SETALE((unsigned long)CFG_NAND1_PADDR); + MACRO_NAND_CTL_SETALE((unsigned long)CFG_NAND1_PADDR); break; case NAND_CTL_CLRALE: - MACRO_NAND_CTL_CLRALE((unsigned long)CFG_NAND1_PADDR); + MACRO_NAND_CTL_CLRALE((unsigned long)CFG_NAND1_PADDR); break; case NAND_CTL_SETNCE: - MACRO_NAND_ENABLE_CE((unsigned long)CFG_NAND1_PADDR); + MACRO_NAND_ENABLE_CE((unsigned long)CFG_NAND1_PADDR); break; case NAND_CTL_CLRNCE: - MACRO_NAND_DISABLE_CE((unsigned long)CFG_NAND1_PADDR); + MACRO_NAND_DISABLE_CE((unsigned long)CFG_NAND1_PADDR); break; } } @@ -164,15 +164,15 @@ static void ppchameleonevb_hwcontrol(struct mtd_info *mtdinfo, int cmd) */ static int ppchameleon_device_ready(struct mtd_info *minfo) { - if (in_be32((volatile unsigned*)GPIO0_IR) & NAND_RB_GPIO_PIN) + if (in_be32((volatile unsigned *)GPIO0_IR) & NAND_RB_GPIO_PIN) return 1; return 0; } static int ppchameleonevb_device_ready(struct mtd_info *minfo) { - if (in_be32((volatile unsigned*)GPIO0_IR) & NAND_EVB_RB_GPIO_PIN) - return 1; + if (in_be32((volatile unsigned *)GPIO0_IR) & NAND_EVB_RB_GPIO_PIN) + return 1; return 0; } #endif @@ -185,7 +185,7 @@ const char *part_probes_evb[] = { "cmdlinepart", NULL }; /* * Main initialization routine */ -static int __init ppchameleonevb_init (void) +static int __init ppchameleonevb_init(void) { struct nand_chip *this; const char *part_type = 0; @@ -194,13 +194,11 @@ static int __init ppchameleonevb_init (void) void __iomem *ppchameleon_fio_base; void __iomem *ppchameleonevb_fio_base; - /********************************* * Processor module NAND (if any) * *********************************/ /* Allocate memory for MTD device structure and private data */ - ppchameleon_mtd = kmalloc(sizeof(struct mtd_info) + - sizeof(struct nand_chip), GFP_KERNEL); + ppchameleon_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); if (!ppchameleon_mtd) { printk("Unable to allocate PPChameleon NAND MTD device structure.\n"); return -ENOMEM; @@ -208,43 +206,45 @@ static int __init ppchameleonevb_init (void) /* map physical address */ ppchameleon_fio_base = ioremap(ppchameleon_fio_pbase, SZ_4M); - if(!ppchameleon_fio_base) { + if (!ppchameleon_fio_base) { printk("ioremap PPChameleon NAND flash failed\n"); kfree(ppchameleon_mtd); return -EIO; } /* Get pointer to private data */ - this = (struct nand_chip *) (&ppchameleon_mtd[1]); + this = (struct nand_chip *)(&ppchameleon_mtd[1]); /* Initialize structures */ - memset((char *) ppchameleon_mtd, 0, sizeof(struct mtd_info)); - memset((char *) this, 0, sizeof(struct nand_chip)); + memset(ppchameleon_mtd, 0, sizeof(struct mtd_info)); + memset(this, 0, sizeof(struct nand_chip)); /* Link the private data with the MTD structure */ ppchameleon_mtd->priv = this; - /* Initialize GPIOs */ + /* Initialize GPIOs */ /* Pin mapping for NAND chip */ /* - CE GPIO_01 - CLE GPIO_02 - ALE GPIO_03 - R/B GPIO_04 - */ + CE GPIO_01 + CLE GPIO_02 + ALE GPIO_03 + R/B GPIO_04 + */ /* output select */ - out_be32((volatile unsigned*)GPIO0_OSRH, in_be32((volatile unsigned*)GPIO0_OSRH) & 0xC0FFFFFF); + out_be32((volatile unsigned *)GPIO0_OSRH, in_be32((volatile unsigned *)GPIO0_OSRH) & 0xC0FFFFFF); /* three-state select */ - out_be32((volatile unsigned*)GPIO0_TSRH, in_be32((volatile unsigned*)GPIO0_TSRH) & 0xC0FFFFFF); + out_be32((volatile unsigned *)GPIO0_TSRH, in_be32((volatile unsigned *)GPIO0_TSRH) & 0xC0FFFFFF); /* enable output driver */ - out_be32((volatile unsigned*)GPIO0_TCR, in_be32((volatile unsigned*)GPIO0_TCR) | NAND_nCE_GPIO_PIN | NAND_CLE_GPIO_PIN | NAND_ALE_GPIO_PIN); + out_be32((volatile unsigned *)GPIO0_TCR, + in_be32((volatile unsigned *)GPIO0_TCR) | NAND_nCE_GPIO_PIN | NAND_CLE_GPIO_PIN | NAND_ALE_GPIO_PIN); #ifdef USE_READY_BUSY_PIN /* three-state select */ - out_be32((volatile unsigned*)GPIO0_TSRH, in_be32((volatile unsigned*)GPIO0_TSRH) & 0xFF3FFFFF); + out_be32((volatile unsigned *)GPIO0_TSRH, in_be32((volatile unsigned *)GPIO0_TSRH) & 0xFF3FFFFF); /* high-impedecence */ - out_be32((volatile unsigned*)GPIO0_TCR, in_be32((volatile unsigned*)GPIO0_TCR) & (~NAND_RB_GPIO_PIN)); + out_be32((volatile unsigned *)GPIO0_TCR, in_be32((volatile unsigned *)GPIO0_TCR) & (~NAND_RB_GPIO_PIN)); /* input select */ - out_be32((volatile unsigned*)GPIO0_ISR1H, (in_be32((volatile unsigned*)GPIO0_ISR1H) & 0xFF3FFFFF) | 0x00400000); + out_be32((volatile unsigned *)GPIO0_ISR1H, + (in_be32((volatile unsigned *)GPIO0_ISR1H) & 0xFF3FFFFF) | 0x00400000); #endif /* insert callbacks */ @@ -259,12 +259,11 @@ static int __init ppchameleonevb_init (void) this->eccmode = NAND_ECC_SOFT; /* Scan to find existence of the device (it could not be mounted) */ - if (nand_scan (ppchameleon_mtd, 1)) { + if (nand_scan(ppchameleon_mtd, 1)) { iounmap((void *)ppchameleon_fio_base); - kfree (ppchameleon_mtd); + kfree(ppchameleon_mtd); goto nand_evb_init; } - #ifndef USE_READY_BUSY_PIN /* Adjust delay if necessary */ if (ppchameleon_mtd->size == NAND_SMALL_SIZE) @@ -275,12 +274,11 @@ static int __init ppchameleonevb_init (void) ppchameleon_mtd->name = "ppchameleon-nand"; mtd_parts_nb = parse_mtd_partitions(ppchameleon_mtd, part_probes, &mtd_parts, 0); if (mtd_parts_nb > 0) - part_type = "command line"; + part_type = "command line"; else - mtd_parts_nb = 0; + mtd_parts_nb = 0; #endif - if (mtd_parts_nb == 0) - { + if (mtd_parts_nb == 0) { if (ppchameleon_mtd->size == NAND_SMALL_SIZE) mtd_parts = partition_info_me; else @@ -293,13 +291,12 @@ static int __init ppchameleonevb_init (void) printk(KERN_NOTICE "Using %s partition definition\n", part_type); add_mtd_partitions(ppchameleon_mtd, mtd_parts, mtd_parts_nb); -nand_evb_init: + nand_evb_init: /**************************** * EVB NAND (always present) * ****************************/ /* Allocate memory for MTD device structure and private data */ - ppchameleonevb_mtd = kmalloc(sizeof(struct mtd_info) + - sizeof(struct nand_chip), GFP_KERNEL); + ppchameleonevb_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); if (!ppchameleonevb_mtd) { printk("Unable to allocate PPChameleonEVB NAND MTD device structure.\n"); return -ENOMEM; @@ -307,46 +304,47 @@ nand_evb_init: /* map physical address */ ppchameleonevb_fio_base = ioremap(ppchameleonevb_fio_pbase, SZ_4M); - if(!ppchameleonevb_fio_base) { + if (!ppchameleonevb_fio_base) { printk("ioremap PPChameleonEVB NAND flash failed\n"); kfree(ppchameleonevb_mtd); return -EIO; } /* Get pointer to private data */ - this = (struct nand_chip *) (&ppchameleonevb_mtd[1]); + this = (struct nand_chip *)(&ppchameleonevb_mtd[1]); /* Initialize structures */ - memset((char *) ppchameleonevb_mtd, 0, sizeof(struct mtd_info)); - memset((char *) this, 0, sizeof(struct nand_chip)); + memset(ppchameleonevb_mtd, 0, sizeof(struct mtd_info)); + memset(this, 0, sizeof(struct nand_chip)); /* Link the private data with the MTD structure */ ppchameleonevb_mtd->priv = this; - /* Initialize GPIOs */ + /* Initialize GPIOs */ /* Pin mapping for NAND chip */ /* - CE GPIO_14 - CLE GPIO_15 - ALE GPIO_16 - R/B GPIO_31 - */ + CE GPIO_14 + CLE GPIO_15 + ALE GPIO_16 + R/B GPIO_31 + */ /* output select */ - out_be32((volatile unsigned*)GPIO0_OSRH, in_be32((volatile unsigned*)GPIO0_OSRH) & 0xFFFFFFF0); - out_be32((volatile unsigned*)GPIO0_OSRL, in_be32((volatile unsigned*)GPIO0_OSRL) & 0x3FFFFFFF); + out_be32((volatile unsigned *)GPIO0_OSRH, in_be32((volatile unsigned *)GPIO0_OSRH) & 0xFFFFFFF0); + out_be32((volatile unsigned *)GPIO0_OSRL, in_be32((volatile unsigned *)GPIO0_OSRL) & 0x3FFFFFFF); /* three-state select */ - out_be32((volatile unsigned*)GPIO0_TSRH, in_be32((volatile unsigned*)GPIO0_TSRH) & 0xFFFFFFF0); - out_be32((volatile unsigned*)GPIO0_TSRL, in_be32((volatile unsigned*)GPIO0_TSRL) & 0x3FFFFFFF); + out_be32((volatile unsigned *)GPIO0_TSRH, in_be32((volatile unsigned *)GPIO0_TSRH) & 0xFFFFFFF0); + out_be32((volatile unsigned *)GPIO0_TSRL, in_be32((volatile unsigned *)GPIO0_TSRL) & 0x3FFFFFFF); /* enable output driver */ - out_be32((volatile unsigned*)GPIO0_TCR, in_be32((volatile unsigned*)GPIO0_TCR) | NAND_EVB_nCE_GPIO_PIN | + out_be32((volatile unsigned *)GPIO0_TCR, in_be32((volatile unsigned *)GPIO0_TCR) | NAND_EVB_nCE_GPIO_PIN | NAND_EVB_CLE_GPIO_PIN | NAND_EVB_ALE_GPIO_PIN); #ifdef USE_READY_BUSY_PIN /* three-state select */ - out_be32((volatile unsigned*)GPIO0_TSRL, in_be32((volatile unsigned*)GPIO0_TSRL) & 0xFFFFFFFC); + out_be32((volatile unsigned *)GPIO0_TSRL, in_be32((volatile unsigned *)GPIO0_TSRL) & 0xFFFFFFFC); /* high-impedecence */ - out_be32((volatile unsigned*)GPIO0_TCR, in_be32((volatile unsigned*)GPIO0_TCR) & (~NAND_EVB_RB_GPIO_PIN)); + out_be32((volatile unsigned *)GPIO0_TCR, in_be32((volatile unsigned *)GPIO0_TCR) & (~NAND_EVB_RB_GPIO_PIN)); /* input select */ - out_be32((volatile unsigned*)GPIO0_ISR1L, (in_be32((volatile unsigned*)GPIO0_ISR1L) & 0xFFFFFFFC) | 0x00000001); + out_be32((volatile unsigned *)GPIO0_ISR1L, + (in_be32((volatile unsigned *)GPIO0_ISR1L) & 0xFFFFFFFC) | 0x00000001); #endif /* insert callbacks */ @@ -362,22 +360,20 @@ nand_evb_init: this->eccmode = NAND_ECC_SOFT; /* Scan to find existence of the device */ - if (nand_scan (ppchameleonevb_mtd, 1)) { + if (nand_scan(ppchameleonevb_mtd, 1)) { iounmap((void *)ppchameleonevb_fio_base); - kfree (ppchameleonevb_mtd); + kfree(ppchameleonevb_mtd); return -ENXIO; } - #ifdef CONFIG_MTD_PARTITIONS ppchameleonevb_mtd->name = NAND_EVB_MTD_NAME; mtd_parts_nb = parse_mtd_partitions(ppchameleonevb_mtd, part_probes_evb, &mtd_parts, 0); if (mtd_parts_nb > 0) - part_type = "command line"; + part_type = "command line"; else - mtd_parts_nb = 0; + mtd_parts_nb = 0; #endif - if (mtd_parts_nb == 0) - { + if (mtd_parts_nb == 0) { mtd_parts = partition_info_evb; mtd_parts_nb = NUM_PARTITIONS; part_type = "static"; @@ -390,18 +386,19 @@ nand_evb_init: /* Return happy */ return 0; } + module_init(ppchameleonevb_init); /* * Clean up routine */ -static void __exit ppchameleonevb_cleanup (void) +static void __exit ppchameleonevb_cleanup(void) { struct nand_chip *this; /* Release resources, unregister device(s) */ - nand_release (ppchameleon_mtd); - nand_release (ppchameleonevb_mtd); + nand_release(ppchameleon_mtd); + nand_release(ppchameleonevb_mtd); /* Release iomaps */ this = (struct nand_chip *) &ppchameleon_mtd[1]; diff --git a/drivers/mtd/nand/rtc_from4.c b/drivers/mtd/nand/rtc_from4.c index 4129c03dfd90..1887989fb885 100644 --- a/drivers/mtd/nand/rtc_from4.c +++ b/drivers/mtd/nand/rtc_from4.c @@ -97,12 +97,12 @@ static struct mtd_info *rtc_from4_mtd = NULL; static void __iomem *rtc_from4_fio_base = (void *)P2SEGADDR(RTC_FROM4_FIO_BASE); static const struct mtd_partition partition_info[] = { - { - .name = "Renesas flash partition 1", - .offset = 0, - .size = MTDPART_SIZ_FULL - }, + { + .name = "Renesas flash partition 1", + .offset = 0, + .size = MTDPART_SIZ_FULL}, }; + #define NUM_PARTITIONS 1 /* @@ -111,8 +111,8 @@ static const struct mtd_partition partition_info[] = { * NAND_BBT_CREATE and/or NAND_BBT_WRITE * */ -static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' }; -static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' }; +static uint8_t bbt_pattern[] = { 'B', 'b', 't', '0' }; +static uint8_t mirror_pattern[] = { '1', 't', 'b', 'B' }; static struct nand_bbt_descr rtc_from4_bbt_main_descr = { .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE @@ -134,8 +134,6 @@ static struct nand_bbt_descr rtc_from4_bbt_mirror_descr = { .pattern = mirror_pattern }; - - #ifdef RTC_FROM4_HWECC /* the Reed Solomon control structure */ @@ -148,11 +146,11 @@ static struct nand_oobinfo rtc_from4_nand_oobinfo = { .useecc = MTD_NANDECC_AUTOPLACE, .eccbytes = 32, .eccpos = { - 0, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31}, - .oobfree = { {32, 32} } + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31}, + .oobfree = {{32, 32}} }; /* Aargh. I missed the reversed bit order, when I @@ -162,44 +160,42 @@ static struct nand_oobinfo rtc_from4_nand_oobinfo = { * of the ecc byte which we get from the FPGA */ static uint8_t revbits[256] = { - 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, - 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, - 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, - 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, - 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, - 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, - 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, - 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, - 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, - 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, - 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, - 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, - 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, - 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, - 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, - 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, - 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, - 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, - 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, - 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, - 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, - 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, - 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, - 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, - 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, - 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, - 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, - 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, - 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, - 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, - 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, - 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, + 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, + 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, + 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, + 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, + 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, + 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, + 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, }; #endif - - /* * rtc_from4_hwcontrol - hardware specific access to control-lines * @mtd: MTD device structure @@ -214,9 +210,9 @@ static uint8_t revbits[256] = { */ static void rtc_from4_hwcontrol(struct mtd_info *mtd, int cmd) { - struct nand_chip* this = (struct nand_chip *) (mtd->priv); + struct nand_chip *this = (struct nand_chip *)(mtd->priv); - switch(cmd) { + switch (cmd) { case NAND_CTL_SETCLE: this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | RTC_FROM4_CLE); @@ -240,7 +236,6 @@ static void rtc_from4_hwcontrol(struct mtd_info *mtd, int cmd) } } - /* * rtc_from4_nand_select_chip - hardware specific chip select * @mtd: MTD device structure @@ -252,26 +247,25 @@ static void rtc_from4_hwcontrol(struct mtd_info *mtd, int cmd) */ static void rtc_from4_nand_select_chip(struct mtd_info *mtd, int chip) { - struct nand_chip *this = mtd->priv; + struct nand_chip *this = mtd->priv; this->IO_ADDR_R = (void __iomem *)((unsigned long)this->IO_ADDR_R & ~RTC_FROM4_NAND_ADDR_MASK); this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W & ~RTC_FROM4_NAND_ADDR_MASK); - switch(chip) { + switch (chip) { - case 0: /* select slot 3 chip */ + case 0: /* select slot 3 chip */ this->IO_ADDR_R = (void __iomem *)((unsigned long)this->IO_ADDR_R | RTC_FROM4_NAND_ADDR_SLOT3); this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | RTC_FROM4_NAND_ADDR_SLOT3); - break; - case 1: /* select slot 4 chip */ + break; + case 1: /* select slot 4 chip */ this->IO_ADDR_R = (void __iomem *)((unsigned long)this->IO_ADDR_R | RTC_FROM4_NAND_ADDR_SLOT4); this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | RTC_FROM4_NAND_ADDR_SLOT4); - break; + break; - } + } } - /* * rtc_from4_nand_device_ready - hardware specific ready/busy check * @mtd: MTD device structure @@ -290,7 +284,6 @@ static int rtc_from4_nand_device_ready(struct mtd_info *mtd) } - /* * deplete - code to perform device recovery in case there was a power loss * @mtd: MTD device structure @@ -306,24 +299,23 @@ static int rtc_from4_nand_device_ready(struct mtd_info *mtd) */ static void deplete(struct mtd_info *mtd, int chip) { - struct nand_chip *this = mtd->priv; + struct nand_chip *this = mtd->priv; - /* wait until device is ready */ - while (!this->dev_ready(mtd)); + /* wait until device is ready */ + while (!this->dev_ready(mtd)) ; this->select_chip(mtd, chip); /* Send the commands for device recovery, phase 1 */ - this->cmdfunc (mtd, NAND_CMD_DEPLETE1, 0x0000, 0x0000); - this->cmdfunc (mtd, NAND_CMD_DEPLETE2, -1, -1); + this->cmdfunc(mtd, NAND_CMD_DEPLETE1, 0x0000, 0x0000); + this->cmdfunc(mtd, NAND_CMD_DEPLETE2, -1, -1); /* Send the commands for device recovery, phase 2 */ - this->cmdfunc (mtd, NAND_CMD_DEPLETE1, 0x0000, 0x0004); - this->cmdfunc (mtd, NAND_CMD_DEPLETE2, -1, -1); + this->cmdfunc(mtd, NAND_CMD_DEPLETE1, 0x0000, 0x0004); + this->cmdfunc(mtd, NAND_CMD_DEPLETE2, -1, -1); } - #ifdef RTC_FROM4_HWECC /* * rtc_from4_enable_hwecc - hardware specific hardware ECC enable function @@ -335,39 +327,35 @@ static void deplete(struct mtd_info *mtd, int chip) */ static void rtc_from4_enable_hwecc(struct mtd_info *mtd, int mode) { - volatile unsigned short * rs_ecc_ctl = (volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_RS_ECC_CTL); + volatile unsigned short *rs_ecc_ctl = (volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_RS_ECC_CTL); unsigned short status; switch (mode) { - case NAND_ECC_READ : - status = RTC_FROM4_RS_ECC_CTL_CLR - | RTC_FROM4_RS_ECC_CTL_FD_E; + case NAND_ECC_READ: + status = RTC_FROM4_RS_ECC_CTL_CLR | RTC_FROM4_RS_ECC_CTL_FD_E; *rs_ecc_ctl = status; break; - case NAND_ECC_READSYN : - status = 0x00; + case NAND_ECC_READSYN: + status = 0x00; *rs_ecc_ctl = status; break; - case NAND_ECC_WRITE : - status = RTC_FROM4_RS_ECC_CTL_CLR - | RTC_FROM4_RS_ECC_CTL_GEN - | RTC_FROM4_RS_ECC_CTL_FD_E; + case NAND_ECC_WRITE: + status = RTC_FROM4_RS_ECC_CTL_CLR | RTC_FROM4_RS_ECC_CTL_GEN | RTC_FROM4_RS_ECC_CTL_FD_E; *rs_ecc_ctl = status; break; - default: + default: BUG(); break; } } - /* * rtc_from4_calculate_ecc - hardware specific code to read ECC code * @mtd: MTD device structure @@ -383,7 +371,7 @@ static void rtc_from4_enable_hwecc(struct mtd_info *mtd, int mode) */ static void rtc_from4_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code) { - volatile unsigned short * rs_eccn = (volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_RS_ECCN); + volatile unsigned short *rs_eccn = (volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_RS_ECCN); unsigned short value; int i; @@ -395,7 +383,6 @@ static void rtc_from4_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_c ecc_code[7] |= 0x0f; /* set the last four bits (not used) */ } - /* * rtc_from4_correct_data - hardware specific code to correct data using ECC code * @mtd: MTD device structure @@ -414,7 +401,7 @@ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_cha unsigned short status; uint16_t par[6], syn[6]; uint8_t ecc[8]; - volatile unsigned short *rs_ecc; + volatile unsigned short *rs_ecc; status = *((volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_RS_ECC_CHK)); @@ -424,23 +411,18 @@ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_cha /* Read the syndrom pattern from the FPGA and correct the bitorder */ rs_ecc = (volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_RS_ECC); - for (i = 0; i < 8; i++) { - ecc[i] = revbits[(*rs_ecc) & 0xFF]; - rs_ecc++; - } + for (i = 0; i < 8; i++) { + ecc[i] = revbits[(*rs_ecc) & 0xFF]; + rs_ecc++; + } /* convert into 6 10bit syndrome fields */ - par[5] = rs_decoder->index_of[(((uint16_t)ecc[0] >> 0) & 0x0ff) | - (((uint16_t)ecc[1] << 8) & 0x300)]; - par[4] = rs_decoder->index_of[(((uint16_t)ecc[1] >> 2) & 0x03f) | - (((uint16_t)ecc[2] << 6) & 0x3c0)]; - par[3] = rs_decoder->index_of[(((uint16_t)ecc[2] >> 4) & 0x00f) | - (((uint16_t)ecc[3] << 4) & 0x3f0)]; - par[2] = rs_decoder->index_of[(((uint16_t)ecc[3] >> 6) & 0x003) | - (((uint16_t)ecc[4] << 2) & 0x3fc)]; - par[1] = rs_decoder->index_of[(((uint16_t)ecc[5] >> 0) & 0x0ff) | - (((uint16_t)ecc[6] << 8) & 0x300)]; - par[0] = (((uint16_t)ecc[6] >> 2) & 0x03f) | (((uint16_t)ecc[7] << 6) & 0x3c0); + par[5] = rs_decoder->index_of[(((uint16_t) ecc[0] >> 0) & 0x0ff) | (((uint16_t) ecc[1] << 8) & 0x300)]; + par[4] = rs_decoder->index_of[(((uint16_t) ecc[1] >> 2) & 0x03f) | (((uint16_t) ecc[2] << 6) & 0x3c0)]; + par[3] = rs_decoder->index_of[(((uint16_t) ecc[2] >> 4) & 0x00f) | (((uint16_t) ecc[3] << 4) & 0x3f0)]; + par[2] = rs_decoder->index_of[(((uint16_t) ecc[3] >> 6) & 0x003) | (((uint16_t) ecc[4] << 2) & 0x3fc)]; + par[1] = rs_decoder->index_of[(((uint16_t) ecc[5] >> 0) & 0x0ff) | (((uint16_t) ecc[6] << 8) & 0x300)]; + par[0] = (((uint16_t) ecc[6] >> 2) & 0x03f) | (((uint16_t) ecc[7] << 6) & 0x3c0); /* Convert to computable syndrome */ for (i = 0; i < 6; i++) { @@ -453,16 +435,14 @@ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_cha syn[i] = rs_decoder->index_of[syn[i]]; } - /* Let the library code do its magic.*/ - res = decode_rs8(rs_decoder, (uint8_t *)buf, par, 512, syn, 0, NULL, 0xff, NULL); + /* Let the library code do its magic. */ + res = decode_rs8(rs_decoder, (uint8_t *) buf, par, 512, syn, 0, NULL, 0xff, NULL); if (res > 0) { - DEBUG (MTD_DEBUG_LEVEL0, "rtc_from4_correct_data: " - "ECC corrected %d errors on read\n", res); + DEBUG(MTD_DEBUG_LEVEL0, "rtc_from4_correct_data: " "ECC corrected %d errors on read\n", res); } return res; } - /** * rtc_from4_errstat - perform additional error status checks * @mtd: MTD device structure @@ -480,44 +460,44 @@ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_cha */ static int rtc_from4_errstat(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page) { - int er_stat=0; - int rtn, retlen; - size_t len; + int er_stat = 0; + int rtn, retlen; + size_t len; uint8_t *buf; - int i; + int i; - this->cmdfunc (mtd, NAND_CMD_STATUS_CLEAR, -1, -1); + this->cmdfunc(mtd, NAND_CMD_STATUS_CLEAR, -1, -1); - if (state == FL_ERASING) { - for (i=0; i<4; i++) { - if (status & 1<<(i+1)) { - this->cmdfunc (mtd, (NAND_CMD_STATUS_ERROR + i + 1), -1, -1); + if (state == FL_ERASING) { + for (i = 0; i < 4; i++) { + if (status & 1 << (i + 1)) { + this->cmdfunc(mtd, (NAND_CMD_STATUS_ERROR + i + 1), -1, -1); rtn = this->read_byte(mtd); - this->cmdfunc (mtd, NAND_CMD_STATUS_RESET, -1, -1); + this->cmdfunc(mtd, NAND_CMD_STATUS_RESET, -1, -1); if (!(rtn & ERR_STAT_ECC_AVAILABLE)) { - er_stat |= 1<<(i+1); /* err_ecc_not_avail */ + er_stat |= 1 << (i + 1); /* err_ecc_not_avail */ } } } } else if (state == FL_WRITING) { /* single bank write logic */ - this->cmdfunc (mtd, NAND_CMD_STATUS_ERROR, -1, -1); + this->cmdfunc(mtd, NAND_CMD_STATUS_ERROR, -1, -1); rtn = this->read_byte(mtd); - this->cmdfunc (mtd, NAND_CMD_STATUS_RESET, -1, -1); + this->cmdfunc(mtd, NAND_CMD_STATUS_RESET, -1, -1); if (!(rtn & ERR_STAT_ECC_AVAILABLE)) { - er_stat |= 1<<1; /* err_ecc_not_avail */ + er_stat |= 1 << 1; /* err_ecc_not_avail */ } else { len = mtd->oobblock; - buf = kmalloc (len, GFP_KERNEL); + buf = kmalloc(len, GFP_KERNEL); if (!buf) { - printk (KERN_ERR "rtc_from4_errstat: Out of memory!\n"); - er_stat = 1; /* if we can't check, assume failed */ + printk(KERN_ERR "rtc_from4_errstat: Out of memory!\n"); + er_stat = 1; /* if we can't check, assume failed */ } else { /* recovery read */ /* page read */ - rtn = nand_do_read_ecc (mtd, page, len, &retlen, buf, NULL, this->autooob, 1); + rtn = nand_do_read_ecc(mtd, page, len, &retlen, buf, NULL, this->autooob, 1); if (rtn) { /* if read failed or > 1-bit error corrected */ - er_stat |= 1<<1; /* ECC read failed */ + er_stat |= 1 << 1; /* ECC read failed */ } kfree(buf); } @@ -525,7 +505,7 @@ static int rtc_from4_errstat(struct mtd_info *mtd, struct nand_chip *this, int s } rtn = status; - if (er_stat == 0) { /* if ECC is available */ + if (er_stat == 0) { /* if ECC is available */ rtn = (status & ~NAND_STATUS_FAIL); /* clear the error bit */ } @@ -533,30 +513,28 @@ static int rtc_from4_errstat(struct mtd_info *mtd, struct nand_chip *this, int s } #endif - /* * Main initialization routine */ -int __init rtc_from4_init (void) +int __init rtc_from4_init(void) { struct nand_chip *this; unsigned short bcr1, bcr2, wcr2; int i; /* Allocate memory for MTD device structure and private data */ - rtc_from4_mtd = kmalloc(sizeof(struct mtd_info) + sizeof (struct nand_chip), - GFP_KERNEL); + rtc_from4_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); if (!rtc_from4_mtd) { - printk ("Unable to allocate Renesas NAND MTD device structure.\n"); + printk("Unable to allocate Renesas NAND MTD device structure.\n"); return -ENOMEM; } /* Get pointer to private data */ - this = (struct nand_chip *) (&rtc_from4_mtd[1]); + this = (struct nand_chip *)(&rtc_from4_mtd[1]); /* Initialize structures */ - memset((char *) rtc_from4_mtd, 0, sizeof(struct mtd_info)); - memset((char *) this, 0, sizeof(struct nand_chip)); + memset(rtc_from4_mtd, 0, sizeof(struct mtd_info)); + memset(this, 0, sizeof(struct nand_chip)); /* Link the private data with the MTD structure */ rtc_from4_mtd->priv = this; @@ -582,7 +560,7 @@ int __init rtc_from4_init (void) /* Set address of hardware control function */ this->hwcontrol = rtc_from4_hwcontrol; /* Set address of chip select function */ - this->select_chip = rtc_from4_nand_select_chip; + this->select_chip = rtc_from4_nand_select_chip; /* command delay time (in us) */ this->chip_delay = 100; /* return the status of the Ready/Busy line */ @@ -591,7 +569,7 @@ int __init rtc_from4_init (void) #ifdef RTC_FROM4_HWECC printk(KERN_INFO "rtc_from4_init: using hardware ECC detection.\n"); - this->eccmode = NAND_ECC_HW8_512; + this->eccmode = NAND_ECC_HW8_512; this->options |= NAND_HWECC_SYNDROME; /* return the status of extra status and ECC checks */ this->errstat = rtc_from4_errstat; @@ -617,7 +595,7 @@ int __init rtc_from4_init (void) } /* Perform 'device recovery' for each chip in case there was a power loss. */ - for (i=0; i < this->numchips; i++) { + for (i = 0; i < this->numchips; i++) { deplete(rtc_from4_mtd, i); } @@ -643,7 +621,7 @@ int __init rtc_from4_init (void) */ rs_decoder = init_rs(10, 0x409, 0, 1, 6); if (!rs_decoder) { - printk (KERN_ERR "Could not create a RS decoder\n"); + printk(KERN_ERR "Could not create a RS decoder\n"); nand_release(rtc_from4_mtd); kfree(rtc_from4_mtd); return -ENOMEM; @@ -652,20 +630,20 @@ int __init rtc_from4_init (void) /* Return happy */ return 0; } -module_init(rtc_from4_init); +module_init(rtc_from4_init); /* * Clean up routine */ #ifdef MODULE -static void __exit rtc_from4_cleanup (void) +static void __exit rtc_from4_cleanup(void) { /* Release resource, unregister partitions */ nand_release(rtc_from4_mtd); /* Free the MTD device structure */ - kfree (rtc_from4_mtd); + kfree(rtc_from4_mtd); #ifdef RTC_FROM4_HWECC /* Free the reed solomon resources */ @@ -674,10 +652,10 @@ static void __exit rtc_from4_cleanup (void) } #endif } + module_exit(rtc_from4_cleanup); #endif MODULE_LICENSE("GPL"); MODULE_AUTHOR("d.marlin max) { - printk("%d ns is too big for current clock rate %ld\n", - wanted, clk); + printk("%d ns is too big for current clock rate %ld\n", wanted, clk); return -1; } @@ -164,8 +163,7 @@ static int s3c2410_nand_calc_rate(int wanted, unsigned long clk, int max) /* controller setup */ -static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, - struct platform_device *pdev) +static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, struct platform_device *pdev) { struct s3c2410_platform_nand *plat = to_nand_plat(pdev); unsigned long clkrate = clk_get_rate(info->clk); @@ -177,7 +175,7 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, clkrate /= 1000; /* turn clock into kHz for ease of use */ if (plat != NULL) { - tacls = s3c2410_nand_calc_rate(plat->tacls, clkrate, 4); + tacls = s3c2410_nand_calc_rate(plat->tacls, clkrate, 4); twrph0 = s3c2410_nand_calc_rate(plat->twrph0, clkrate, 8); twrph1 = s3c2410_nand_calc_rate(plat->twrph1, clkrate, 8); } else { @@ -193,19 +191,17 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, } printk(KERN_INFO PFX "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n", - tacls, to_ns(tacls, clkrate), - twrph0, to_ns(twrph0, clkrate), - twrph1, to_ns(twrph1, clkrate)); + tacls, to_ns(tacls, clkrate), twrph0, to_ns(twrph0, clkrate), twrph1, to_ns(twrph1, clkrate)); if (!info->is_s3c2440) { - cfg = S3C2410_NFCONF_EN; - cfg |= S3C2410_NFCONF_TACLS(tacls-1); - cfg |= S3C2410_NFCONF_TWRPH0(twrph0-1); - cfg |= S3C2410_NFCONF_TWRPH1(twrph1-1); + cfg = S3C2410_NFCONF_EN; + cfg |= S3C2410_NFCONF_TACLS(tacls - 1); + cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1); + cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1); } else { - cfg = S3C2440_NFCONF_TACLS(tacls-1); - cfg |= S3C2440_NFCONF_TWRPH0(twrph0-1); - cfg |= S3C2440_NFCONF_TWRPH1(twrph1-1); + cfg = S3C2440_NFCONF_TACLS(tacls - 1); + cfg |= S3C2440_NFCONF_TWRPH0(twrph0 - 1); + cfg |= S3C2440_NFCONF_TWRPH1(twrph1 - 1); } pr_debug(PFX "NF_CONF is 0x%lx\n", cfg); @@ -229,7 +225,7 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip) info = nmtd->info; bit = (info->is_s3c2440) ? S3C2440_NFCONT_nFCE : S3C2410_NFCONF_nFCE; - reg = info->regs+((info->is_s3c2440) ? S3C2440_NFCONT:S3C2410_NFCONF); + reg = info->regs + ((info->is_s3c2440) ? S3C2440_NFCONT : S3C2410_NFCONF); cur = readl(reg); @@ -243,7 +239,7 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip) if (info->platform != NULL) { if (info->platform->select_chip != NULL) - (info->platform->select_chip)(nmtd->set, chip); + (info->platform->select_chip) (nmtd->set, chip); } cur &= ~bit; @@ -330,22 +326,16 @@ static int s3c2410_nand_devready(struct mtd_info *mtd) return readb(info->regs + S3C2410_NFSTAT) & S3C2410_NFSTAT_BUSY; } - /* ECC handling functions */ -static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat, - u_char *read_ecc, u_char *calc_ecc) +static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc) { - pr_debug("s3c2410_nand_correct_data(%p,%p,%p,%p)\n", - mtd, dat, read_ecc, calc_ecc); + pr_debug("s3c2410_nand_correct_data(%p,%p,%p,%p)\n", mtd, dat, read_ecc, calc_ecc); pr_debug("eccs: read %02x,%02x,%02x vs calc %02x,%02x,%02x\n", - read_ecc[0], read_ecc[1], read_ecc[2], - calc_ecc[0], calc_ecc[1], calc_ecc[2]); + read_ecc[0], read_ecc[1], read_ecc[2], calc_ecc[0], calc_ecc[1], calc_ecc[2]); - if (read_ecc[0] == calc_ecc[0] && - read_ecc[1] == calc_ecc[1] && - read_ecc[2] == calc_ecc[2]) + if (read_ecc[0] == calc_ecc[0] && read_ecc[1] == calc_ecc[1] && read_ecc[2] == calc_ecc[2]) return 0; /* we curently have no method for correcting the error */ @@ -378,8 +368,7 @@ static void s3c2440_nand_enable_hwecc(struct mtd_info *mtd, int mode) writel(ctrl | S3C2440_NFCONT_INITECC, info->regs + S3C2440_NFCONT); } -static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, - const u_char *dat, u_char *ecc_code) +static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code) { struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); @@ -387,15 +376,12 @@ static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, ecc_code[1] = readb(info->regs + S3C2410_NFECC + 1); ecc_code[2] = readb(info->regs + S3C2410_NFECC + 2); - pr_debug("calculate_ecc: returning ecc %02x,%02x,%02x\n", - ecc_code[0], ecc_code[1], ecc_code[2]); + pr_debug("calculate_ecc: returning ecc %02x,%02x,%02x\n", ecc_code[0], ecc_code[1], ecc_code[2]); return 0; } - -static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, - const u_char *dat, u_char *ecc_code) +static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code) { struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); unsigned long ecc = readl(info->regs + S3C2440_NFMECC0); @@ -404,13 +390,11 @@ static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, ecc_code[1] = ecc >> 8; ecc_code[2] = ecc >> 16; - pr_debug("calculate_ecc: returning ecc %02x,%02x,%02x\n", - ecc_code[0], ecc_code[1], ecc_code[2]); + pr_debug("calculate_ecc: returning ecc %02x,%02x,%02x\n", ecc_code[0], ecc_code[1], ecc_code[2]); return 0; } - /* over-ride the standard functions for a little more speed. We can * use read/write block to move the data buffers to/from the controller */ @@ -421,8 +405,7 @@ static void s3c2410_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) readsb(this->IO_ADDR_R, buf, len); } -static void s3c2410_nand_write_buf(struct mtd_info *mtd, - const u_char *buf, int len) +static void s3c2410_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) { struct nand_chip *this = mtd->priv; writesb(this->IO_ADDR_W, buf, len); @@ -488,9 +471,7 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info, return add_mtd_device(&mtd->mtd); if (set->nr_partitions > 0 && set->partitions != NULL) { - return add_mtd_partitions(&mtd->mtd, - set->partitions, - set->nr_partitions); + return add_mtd_partitions(&mtd->mtd, set->partitions, set->nr_partitions); } return add_mtd_device(&mtd->mtd); @@ -654,13 +635,11 @@ static int s3c24xx_nand_probe(struct platform_device *pdev, int is_s3c2440) nmtd = info->mtds; for (setno = 0; setno < nr_sets; setno++, nmtd++) { - pr_debug("initialising set %d (%p, info %p)\n", - setno, nmtd, info); + pr_debug("initialising set %d (%p, info %p)\n", setno, nmtd, info); s3c2410_nand_init_chip(info, nmtd, sets); - nmtd->scan_res = nand_scan(&nmtd->mtd, - (sets) ? sets->nr_chips : 1); + nmtd->scan_res = nand_scan(&nmtd->mtd, (sets) ? sets->nr_chips : 1); if (nmtd->scan_res == 0) { s3c2410_nand_add_partition(info, nmtd, sets); diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c index c294374871a4..25322a8d44d8 100644 --- a/drivers/mtd/nand/sharpsl.c +++ b/drivers/mtd/nand/sharpsl.c @@ -46,7 +46,6 @@ static int sharpsl_phys_base = 0x0C000000; #define FLCLE (1 << 1) #define FLCE0 (1 << 0) - /* * MTD structure for SharpSL */ @@ -60,27 +59,26 @@ static struct mtd_info *sharpsl_mtd = NULL; static int nr_partitions; static struct mtd_partition sharpsl_nand_default_partition_info[] = { { - .name = "System Area", - .offset = 0, - .size = 7 * 1024 * 1024, - }, + .name = "System Area", + .offset = 0, + .size = 7 * 1024 * 1024, + }, { - .name = "Root Filesystem", - .offset = 7 * 1024 * 1024, - .size = 30 * 1024 * 1024, - }, + .name = "Root Filesystem", + .offset = 7 * 1024 * 1024, + .size = 30 * 1024 * 1024, + }, { - .name = "Home Filesystem", - .offset = MTDPART_OFS_APPEND , - .size = MTDPART_SIZ_FULL , - }, + .name = "Home Filesystem", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + }, }; /* * hardware specific access to control-lines */ -static void -sharpsl_nand_hwcontrol(struct mtd_info* mtd, int cmd) +static void sharpsl_nand_hwcontrol(struct mtd_info *mtd, int cmd) { switch (cmd) { case NAND_CTL_SETCLE: @@ -98,10 +96,10 @@ sharpsl_nand_hwcontrol(struct mtd_info* mtd, int cmd) break; case NAND_CTL_SETNCE: - writeb(readb(FLASHCTL) & ~(FLCE0|FLCE1), FLASHCTL); + writeb(readb(FLASHCTL) & ~(FLCE0 | FLCE1), FLASHCTL); break; case NAND_CTL_CLRNCE: - writeb(readb(FLASHCTL) | (FLCE0|FLCE1), FLASHCTL); + writeb(readb(FLASHCTL) | (FLCE0 | FLCE1), FLASHCTL); break; } } @@ -126,27 +124,23 @@ static struct nand_oobinfo akita_oobinfo = { .useecc = MTD_NANDECC_AUTOPLACE, .eccbytes = 24, .eccpos = { - 0x5, 0x1, 0x2, 0x3, 0x6, 0x7, 0x15, 0x11, - 0x12, 0x13, 0x16, 0x17, 0x25, 0x21, 0x22, 0x23, - 0x26, 0x27, 0x35, 0x31, 0x32, 0x33, 0x36, 0x37}, - .oobfree = { {0x08, 0x09} } + 0x5, 0x1, 0x2, 0x3, 0x6, 0x7, 0x15, 0x11, + 0x12, 0x13, 0x16, 0x17, 0x25, 0x21, 0x22, 0x23, + 0x26, 0x27, 0x35, 0x31, 0x32, 0x33, 0x36, 0x37}, + .oobfree = {{0x08, 0x09}} }; -static int -sharpsl_nand_dev_ready(struct mtd_info* mtd) +static int sharpsl_nand_dev_ready(struct mtd_info *mtd) { return !((readb(FLASHCTL) & FLRYBY) == 0); } -static void -sharpsl_nand_enable_hwecc(struct mtd_info* mtd, int mode) +static void sharpsl_nand_enable_hwecc(struct mtd_info *mtd, int mode) { - writeb(0 ,ECCCLRR); + writeb(0, ECCCLRR); } -static int -sharpsl_nand_calculate_ecc(struct mtd_info* mtd, const u_char* dat, - u_char* ecc_code) +static int sharpsl_nand_calculate_ecc(struct mtd_info *mtd, const u_char * dat, u_char * ecc_code) { ecc_code[0] = ~readb(ECCLPUB); ecc_code[1] = ~readb(ECCLPLB); @@ -154,44 +148,40 @@ sharpsl_nand_calculate_ecc(struct mtd_info* mtd, const u_char* dat, return readb(ECCCNTR) != 0; } - #ifdef CONFIG_MTD_PARTITIONS const char *part_probes[] = { "cmdlinepart", NULL }; #endif - /* * Main initialization routine */ -int __init -sharpsl_nand_init(void) +int __init sharpsl_nand_init(void) { struct nand_chip *this; - struct mtd_partition* sharpsl_partition_info; + struct mtd_partition *sharpsl_partition_info; int err = 0; /* Allocate memory for MTD device structure and private data */ - sharpsl_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), - GFP_KERNEL); + sharpsl_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); if (!sharpsl_mtd) { - printk ("Unable to allocate SharpSL NAND MTD device structure.\n"); + printk("Unable to allocate SharpSL NAND MTD device structure.\n"); return -ENOMEM; } /* map physical adress */ sharpsl_io_base = ioremap(sharpsl_phys_base, 0x1000); - if(!sharpsl_io_base){ + if (!sharpsl_io_base) { printk("ioremap to access Sharp SL NAND chip failed\n"); kfree(sharpsl_mtd); return -EIO; } /* Get pointer to private data */ - this = (struct nand_chip *) (&sharpsl_mtd[1]); + this = (struct nand_chip *)(&sharpsl_mtd[1]); /* Initialize structures */ - memset((char *) sharpsl_mtd, 0, sizeof(struct mtd_info)); - memset((char *) this, 0, sizeof(struct nand_chip)); + memset(sharpsl_mtd, 0, sizeof(struct mtd_info)); + memset(this, 0, sizeof(struct nand_chip)); /* Link the private data with the MTD structure */ sharpsl_mtd->priv = this; @@ -221,7 +211,7 @@ sharpsl_nand_init(void) this->correct_data = nand_correct_data; /* Scan to find existence of the device */ - err=nand_scan(sharpsl_mtd,1); + err = nand_scan(sharpsl_mtd, 1); if (err) { iounmap(sharpsl_io_base); kfree(sharpsl_mtd); @@ -230,24 +220,23 @@ sharpsl_nand_init(void) /* Register the partitions */ sharpsl_mtd->name = "sharpsl-nand"; - nr_partitions = parse_mtd_partitions(sharpsl_mtd, part_probes, - &sharpsl_partition_info, 0); + nr_partitions = parse_mtd_partitions(sharpsl_mtd, part_probes, &sharpsl_partition_info, 0); if (nr_partitions <= 0) { nr_partitions = DEFAULT_NUM_PARTITIONS; sharpsl_partition_info = sharpsl_nand_default_partition_info; if (machine_is_poodle()) { - sharpsl_partition_info[1].size=22 * 1024 * 1024; + sharpsl_partition_info[1].size = 22 * 1024 * 1024; } else if (machine_is_corgi() || machine_is_shepherd()) { - sharpsl_partition_info[1].size=25 * 1024 * 1024; + sharpsl_partition_info[1].size = 25 * 1024 * 1024; } else if (machine_is_husky()) { - sharpsl_partition_info[1].size=53 * 1024 * 1024; + sharpsl_partition_info[1].size = 53 * 1024 * 1024; } else if (machine_is_spitz()) { - sharpsl_partition_info[1].size=5 * 1024 * 1024; + sharpsl_partition_info[1].size = 5 * 1024 * 1024; } else if (machine_is_akita()) { - sharpsl_partition_info[1].size=58 * 1024 * 1024; + sharpsl_partition_info[1].size = 58 * 1024 * 1024; } else if (machine_is_borzoi()) { - sharpsl_partition_info[1].size=32 * 1024 * 1024; + sharpsl_partition_info[1].size = 32 * 1024 * 1024; } } @@ -261,6 +250,7 @@ sharpsl_nand_init(void) /* Return happy */ return 0; } + module_init(sharpsl_nand_init); /* @@ -269,7 +259,7 @@ module_init(sharpsl_nand_init); #ifdef MODULE static void __exit sharpsl_nand_cleanup(void) { - struct nand_chip *this = (struct nand_chip *) &sharpsl_mtd[1]; + struct nand_chip *this = (struct nand_chip *)&sharpsl_mtd[1]; /* Release resources, unregister device */ nand_release(sharpsl_mtd); @@ -279,6 +269,7 @@ static void __exit sharpsl_nand_cleanup(void) /* Free the MTD device structure */ kfree(sharpsl_mtd); } + module_exit(sharpsl_nand_cleanup); #endif diff --git a/drivers/mtd/nand/spia.c b/drivers/mtd/nand/spia.c index 9cf1ce718ec1..a11354b9afa2 100644 --- a/drivers/mtd/nand/spia.c +++ b/drivers/mtd/nand/spia.c @@ -39,16 +39,16 @@ static struct mtd_info *spia_mtd = NULL; */ #define SPIA_IO_BASE 0xd0000000 /* Start of EP7212 IO address space */ #define SPIA_FIO_BASE 0xf0000000 /* Address where flash is mapped */ -#define SPIA_PEDR 0x0080 /* - * IO offset to Port E data register - * where the CLE, ALE and NCE pins - * are wired to. - */ -#define SPIA_PEDDR 0x00c0 /* - * IO offset to Port E data direction - * register so we can control the IO - * lines. - */ +#define SPIA_PEDR 0x0080 /* + * IO offset to Port E data register + * where the CLE, ALE and NCE pins + * are wired to. + */ +#define SPIA_PEDDR 0x00c0 /* + * IO offset to Port E data direction + * register so we can control the IO + * lines. + */ /* * Module stuff @@ -69,25 +69,23 @@ module_param(spia_peddr, int, 0); */ static const struct mtd_partition partition_info[] = { { - .name = "SPIA flash partition 1", - .offset = 0, - .size = 2*1024*1024 - }, + .name = "SPIA flash partition 1", + .offset = 0, + .size = 2 * 1024 * 1024}, { - .name = "SPIA flash partition 2", - .offset = 2*1024*1024, - .size = 6*1024*1024 - } + .name = "SPIA flash partition 2", + .offset = 2 * 1024 * 1024, + .size = 6 * 1024 * 1024} }; -#define NUM_PARTITIONS 2 +#define NUM_PARTITIONS 2 /* * hardware specific access to control-lines */ -static void spia_hwcontrol(struct mtd_info *mtd, int cmd){ - - switch(cmd){ +static void spia_hwcontrol(struct mtd_info *mtd, int cmd) +{ + switch (cmd) { case NAND_CTL_SETCLE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) |= 0x01; break; case NAND_CTL_CLRCLE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) &= ~0x01; break; @@ -97,30 +95,29 @@ static void spia_hwcontrol(struct mtd_info *mtd, int cmd){ case NAND_CTL_SETNCE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) &= ~0x04; break; case NAND_CTL_CLRNCE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) |= 0x04; break; - } + } } /* * Main initialization routine */ -int __init spia_init (void) +int __init spia_init(void) { struct nand_chip *this; /* Allocate memory for MTD device structure and private data */ - spia_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip), - GFP_KERNEL); + spia_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); if (!spia_mtd) { - printk ("Unable to allocate SPIA NAND MTD device structure.\n"); + printk("Unable to allocate SPIA NAND MTD device structure.\n"); return -ENOMEM; } /* Get pointer to private data */ - this = (struct nand_chip *) (&spia_mtd[1]); + this = (struct nand_chip *)(&spia_mtd[1]); /* Initialize structures */ - memset((char *) spia_mtd, 0, sizeof(struct mtd_info)); - memset((char *) this, 0, sizeof(struct nand_chip)); + memset(spia_mtd, 0, sizeof(struct mtd_info)); + memset(this, 0, sizeof(struct nand_chip)); /* Link the private data with the MTD structure */ spia_mtd->priv = this; @@ -129,19 +126,19 @@ int __init spia_init (void) * Set GPIO Port E control register so that the pins are configured * to be outputs for controlling the NAND flash. */ - (*(volatile unsigned char *) (spia_io_base + spia_peddr)) = 0x07; + (*(volatile unsigned char *)(spia_io_base + spia_peddr)) = 0x07; /* Set address of NAND IO lines */ - this->IO_ADDR_R = (void __iomem *) spia_fio_base; - this->IO_ADDR_W = (void __iomem *) spia_fio_base; + this->IO_ADDR_R = (void __iomem *)spia_fio_base; + this->IO_ADDR_W = (void __iomem *)spia_fio_base; /* Set address of hardware control function */ this->hwcontrol = spia_hwcontrol; /* 15 us command delay time */ this->chip_delay = 15; /* Scan to find existence of the device */ - if (nand_scan (spia_mtd, 1)) { - kfree (spia_mtd); + if (nand_scan(spia_mtd, 1)) { + kfree(spia_mtd); return -ENXIO; } @@ -151,20 +148,22 @@ int __init spia_init (void) /* Return happy */ return 0; } + module_init(spia_init); /* * Clean up routine */ #ifdef MODULE -static void __exit spia_cleanup (void) +static void __exit spia_cleanup(void) { /* Release resources, unregister device */ - nand_release (spia_mtd); + nand_release(spia_mtd); /* Free the MTD device structure */ - kfree (spia_mtd); + kfree(spia_mtd); } + module_exit(spia_cleanup); #endif diff --git a/drivers/mtd/nand/toto.c b/drivers/mtd/nand/toto.c index 7609c43cb3ec..e3a90e60e249 100644 --- a/drivers/mtd/nand/toto.c +++ b/drivers/mtd/nand/toto.c @@ -48,7 +48,7 @@ static unsigned long toto_io_base = OMAP_FLASH_1_BASE; #define T_NAND_CTL_CLRALE(iob) gpiosetout(NAND_ALE, 0) #define T_NAND_CTL_SETALE(iob) gpiosetout(NAND_ALE, NAND_ALE) -#ifdef CONFIG_NAND_WORKAROUND /* "some" dev boards busted, blue wired to rts2 :( */ +#ifdef CONFIG_NAND_WORKAROUND /* "some" dev boards busted, blue wired to rts2 :( */ #define T_NAND_CTL_CLRCLE(iob) gpiosetout(NAND_CLE, 0); rts2setout(2, 2) #define T_NAND_CTL_SETCLE(iob) gpiosetout(NAND_CLE, NAND_CLE); rts2setout(2, 0) #else @@ -98,9 +98,8 @@ static struct mtd_partition partition_info32M[] = { static void toto_hwcontrol(struct mtd_info *mtd, int cmd) { - udelay(1); /* hopefully enough time for tc make proceding write to clear */ - switch(cmd){ - + udelay(1); /* hopefully enough time for tc make proceding write to clear */ + switch (cmd) { case NAND_CTL_SETCLE: T_NAND_CTL_SETCLE(cmd); break; case NAND_CTL_CLRCLE: T_NAND_CTL_CLRCLE(cmd); break; @@ -110,32 +109,31 @@ static void toto_hwcontrol(struct mtd_info *mtd, int cmd) case NAND_CTL_SETNCE: T_NAND_CTL_SETNCE(cmd); break; case NAND_CTL_CLRNCE: T_NAND_CTL_CLRNCE(cmd); break; } - udelay(1); /* allow time to ensure gpio state to over take memory write */ + udelay(1); /* allow time to ensure gpio state to over take memory write */ } /* * Main initialization routine */ -int __init toto_init (void) +int __init toto_init(void) { struct nand_chip *this; int err = 0; /* Allocate memory for MTD device structure and private data */ - toto_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip), - GFP_KERNEL); + toto_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); if (!toto_mtd) { - printk (KERN_WARNING "Unable to allocate toto NAND MTD device structure.\n"); + printk(KERN_WARNING "Unable to allocate toto NAND MTD device structure.\n"); err = -ENOMEM; goto out; } /* Get pointer to private data */ - this = (struct nand_chip *) (&toto_mtd[1]); + this = (struct nand_chip *)(&toto_mtd[1]); /* Initialize structures */ - memset((char *) toto_mtd, 0, sizeof(struct mtd_info)); - memset((char *) this, 0, sizeof(struct nand_chip)); + memset(toto_mtd, 0, sizeof(struct mtd_info)); + memset(this, 0, sizeof(struct nand_chip)); /* Link the private data with the MTD structure */ toto_mtd->priv = this; @@ -149,33 +147,37 @@ int __init toto_init (void) this->chip_delay = 30; this->eccmode = NAND_ECC_SOFT; - /* Scan to find existance of the device */ - if (nand_scan (toto_mtd, 1)) { + /* Scan to find existance of the device */ + if (nand_scan(toto_mtd, 1)) { err = -ENXIO; goto out_mtd; } /* Register the partitions */ - switch(toto_mtd->size){ - case SZ_64M: add_mtd_partitions(toto_mtd, partition_info64M, NUM_PARTITIONS64M); break; - case SZ_32M: add_mtd_partitions(toto_mtd, partition_info32M, NUM_PARTITIONS32M); break; - default: { - printk (KERN_WARNING "Unsupported Nand device\n"); + switch (toto_mtd->size) { + case SZ_64M: + add_mtd_partitions(toto_mtd, partition_info64M, NUM_PARTITIONS64M); + break; + case SZ_32M: + add_mtd_partitions(toto_mtd, partition_info32M, NUM_PARTITIONS32M); + break; + default:{ + printk(KERN_WARNING "Unsupported Nand device\n"); err = -ENXIO; goto out_buf; } } - gpioreserve(NAND_MASK); /* claim our gpios */ - archflashwp(0,0); /* open up flash for writing */ + gpioreserve(NAND_MASK); /* claim our gpios */ + archflashwp(0, 0); /* open up flash for writing */ goto out; -out_buf: - kfree (this->data_buf); -out_mtd: - kfree (toto_mtd); -out: + out_buf: + kfree(this->data_buf); + out_mtd: + kfree(toto_mtd); + out: return err; } @@ -184,20 +186,21 @@ module_init(toto_init); /* * Clean up routine */ -static void __exit toto_cleanup (void) +static void __exit toto_cleanup(void) { /* Release resources, unregister device */ - nand_release (toto_mtd); + nand_release(toto_mtd); /* Free the MTD device structure */ - kfree (toto_mtd); + kfree(toto_mtd); /* stop flash writes */ - archflashwp(0,1); + archflashwp(0, 1); /* release gpios to system */ - gpiorelease(NAND_MASK); + gpiorelease(NAND_MASK); } + module_exit(toto_cleanup); MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/nand/ts7250.c b/drivers/mtd/nand/ts7250.c index 643633d91a8b..d2b7d57ace42 100644 --- a/drivers/mtd/nand/ts7250.c +++ b/drivers/mtd/nand/ts7250.c @@ -88,7 +88,7 @@ static void ts7250_hwcontrol(struct mtd_info *mtd, int cmd) { unsigned long ctrl = TS72XX_NAND_CONTROL_VIRT_BASE; - switch(cmd) { + switch (cmd) { case NAND_CTL_SETCLE: __raw_writeb(__raw_readb(ctrl) | 0x2, ctrl); break; @@ -132,8 +132,7 @@ static int __init ts7250_init(void) return -ENXIO; /* Allocate memory for MTD device structure and private data */ - ts7250_mtd = kmalloc(sizeof(struct mtd_info) + - sizeof(struct nand_chip), GFP_KERNEL); + ts7250_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); if (!ts7250_mtd) { printk("Unable to allocate TS7250 NAND MTD device structure.\n"); return -ENOMEM; @@ -163,11 +162,9 @@ static int __init ts7250_init(void) kfree(ts7250_mtd); return -ENXIO; } - #ifdef CONFIG_MTD_PARTITIONS ts7250_mtd->name = "ts7250-nand"; - mtd_parts_nb = parse_mtd_partitions(ts7250_mtd, part_probes, - &mtd_parts, 0); + mtd_parts_nb = parse_mtd_partitions(ts7250_mtd, part_probes, &mtd_parts, 0); if (mtd_parts_nb > 0) part_type = "command line"; else @@ -188,6 +185,7 @@ static int __init ts7250_init(void) /* Return happy */ return 0; } + module_init(ts7250_init); /* @@ -201,6 +199,7 @@ static void __exit ts7250_cleanup(void) /* Free the MTD device structure */ kfree(ts7250_mtd); } + module_exit(ts7250_cleanup); MODULE_LICENSE("GPL"); -- cgit v1.2.3-70-g09d2 From 4f678a58d335291ce9213c049bbe16e6d24487ed Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Sun, 14 May 2006 01:07:18 +0200 Subject: mtd: fix memory leaks in phram_setup There are two code paths in drivers/mtd/devices/phram.c::phram_setup() that will leak memory. Memory is allocated to the variable 'name' with kmalloc() by the parse_name() function, but if we leave by way of the parse_err() macro, then that memory is never kfree()'d, nor is it ever used with register_device() so it won't be freed later either - leak. Found by the Coverity checker as #593 - simple fix below. Signed-off-by: Jesper Juhl Signed-off-by: David Woodhouse --- drivers/mtd/devices/phram.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c index 41af9693d880..68d39cc9df71 100644 --- a/drivers/mtd/devices/phram.c +++ b/drivers/mtd/devices/phram.c @@ -266,12 +266,16 @@ static int phram_setup(const char *val, struct kernel_param *kp) return 0; ret = parse_num32(&start, token[1]); - if (ret) + if (ret) { + kfree(name); parse_err("illegal start address\n"); + } ret = parse_num32(&len, token[2]); - if (ret) + if (ret) { + kfree(name); parse_err("illegal device length\n"); + } register_device(name, start, len); -- cgit v1.2.3-70-g09d2 From 552d9205186428a1e2a49ed577bcbba9f777af37 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sun, 14 May 2006 01:20:46 +0100 Subject: [MTD] Fix module refcounting in NAND board drivers. The _board_ driver needs to be mtd->owner, and it in turn pins the nand.ko module. Fix them all to actually do that, and fix nand.ko not to overwrite it -- and also to check that the caller sets it, if the caller is a module. Signed-off-by: David Woodhouse --- drivers/mtd/nand/au1550nd.c | 1 + drivers/mtd/nand/autcpu12.c | 1 + drivers/mtd/nand/cs553x_nand.c | 2 +- drivers/mtd/nand/edb7312.c | 1 + drivers/mtd/nand/h1910.c | 1 + drivers/mtd/nand/nand_base.c | 16 +++++++++++++--- drivers/mtd/nand/nandsim.c | 2 ++ drivers/mtd/nand/ppchameleonevb.c | 1 + drivers/mtd/nand/rtc_from4.c | 1 + drivers/mtd/nand/s3c2410.c | 1 + drivers/mtd/nand/sharpsl.c | 1 + drivers/mtd/nand/spia.c | 1 + drivers/mtd/nand/toto.c | 1 + drivers/mtd/nand/ts7250.c | 1 + 14 files changed, 27 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c index 50cbfd4826fb..87d34351a86d 100644 --- a/drivers/mtd/nand/au1550nd.c +++ b/drivers/mtd/nand/au1550nd.c @@ -345,6 +345,7 @@ int __init au1xxx_nand_init(void) /* Link the private data with the MTD structure */ au1550_mtd->priv = this; + au1550_mtd->owner = THIS_MODULE; /* disable interrupts */ au_writel(au_readl(MEM_STNDCTL) & ~(1 << 8), MEM_STNDCTL); diff --git a/drivers/mtd/nand/autcpu12.c b/drivers/mtd/nand/autcpu12.c index 9c9f21b0d260..330deb032217 100644 --- a/drivers/mtd/nand/autcpu12.c +++ b/drivers/mtd/nand/autcpu12.c @@ -154,6 +154,7 @@ int __init autcpu12_init(void) /* Link the private data with the MTD structure */ autcpu12_mtd->priv = this; + autcpu12_mtd->owner = THIS_MODULE; /* Set address of NAND IO lines */ this->IO_ADDR_R = autcpu12_fio_base; diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c index fba7be5cffe3..d5b05514bb8b 100644 --- a/drivers/mtd/nand/cs553x_nand.c +++ b/drivers/mtd/nand/cs553x_nand.c @@ -223,6 +223,7 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr) /* Link the private data with the MTD structure */ new_mtd->priv = this; + new_mtd->owner = THIS_MODULE; /* map physical address */ this->IO_ADDR_R = this->IO_ADDR_W = ioremap(adr, 4096); @@ -255,7 +256,6 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr) goto out_ior; } - new_mtd->owner = THIS_MODULE; cs553x_mtd[cs] = new_mtd; goto out; diff --git a/drivers/mtd/nand/edb7312.c b/drivers/mtd/nand/edb7312.c index 8467d770710c..ad4488abfb0b 100644 --- a/drivers/mtd/nand/edb7312.c +++ b/drivers/mtd/nand/edb7312.c @@ -148,6 +148,7 @@ static int __init ep7312_init(void) /* Link the private data with the MTD structure */ ep7312_mtd->priv = this; + ep7312_mtd->owner = THIS_MODULE; /* * Set GPIO Port B control register so that the pins are configured diff --git a/drivers/mtd/nand/h1910.c b/drivers/mtd/nand/h1910.c index efa53a9adf23..b47a15c23d1c 100644 --- a/drivers/mtd/nand/h1910.c +++ b/drivers/mtd/nand/h1910.c @@ -135,6 +135,7 @@ static int __init h1910_init(void) /* Link the private data with the MTD structure */ h1910_nand_mtd->priv = this; + h1910_nand_mtd->owner = THIS_MODULE; /* * Enable VPEN diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index fdaf32083ada..42cff0a2b93d 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -69,6 +69,7 @@ * */ +#include #include #include #include @@ -2316,11 +2317,12 @@ static void nand_resume(struct mtd_info *mtd) * @mtd: MTD device structure * @maxchips: Number of chips to scan for * - * This fills out all the not initialized function pointers + * This fills out all the uninitialized function pointers * with the defaults. * The flash ID is read and the mtd/chip structures are * filled with the appropriate values. Buffers are allocated if * they are not provided by the board driver + * The mtd->owner field must be set to the module of the caller * */ int nand_scan(struct mtd_info *mtd, int maxchips) @@ -2328,6 +2330,16 @@ int nand_scan(struct mtd_info *mtd, int maxchips) int i, nand_maf_id, nand_dev_id, busw, maf_id; struct nand_chip *this = mtd->priv; + /* module_text_address() isn't exported. But if _this_ is a module, + it's a fairly safe bet that its caller is a module too... and + that means the call to module_text_address() gets optimised out + without having to resort to ifdefs */ + if (!mtd->owner && (THIS_MODULE || + module_text_address((unsigned long)__builtin_return_address(0)))) { + printk(KERN_CRIT "nand_scan() called with NULL mtd->owner!\n"); + BUG(); + } + /* Get buswidth to select the correct functions */ busw = this->options & NAND_BUSWIDTH_16; @@ -2676,8 +2688,6 @@ int nand_scan(struct mtd_info *mtd, int maxchips) /* and make the autooob the default one */ memcpy(&mtd->oobinfo, this->autooob, sizeof(mtd->oobinfo)); - mtd->owner = THIS_MODULE; - /* Check, if we should skip the bad block table scan */ if (this->options & NAND_SKIP_BBTSCAN) return 0; diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index a0af92cc7efd..6903f5b903c6 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -1546,6 +1546,8 @@ static int __init ns_init_module(void) chip->options |= NAND_BUSWIDTH_16; } + nsmtd->owner = THIS_MODULE; + if ((retval = nand_scan(nsmtd, 1)) != 0) { NS_ERR("can't register NAND Simulator\n"); if (retval > 0) diff --git a/drivers/mtd/nand/ppchameleonevb.c b/drivers/mtd/nand/ppchameleonevb.c index 405beece9c5a..5d4d16fb1df6 100644 --- a/drivers/mtd/nand/ppchameleonevb.c +++ b/drivers/mtd/nand/ppchameleonevb.c @@ -221,6 +221,7 @@ static int __init ppchameleonevb_init(void) /* Link the private data with the MTD structure */ ppchameleon_mtd->priv = this; + ppchameleon_mtd->owner = THIS_MODULE; /* Initialize GPIOs */ /* Pin mapping for NAND chip */ diff --git a/drivers/mtd/nand/rtc_from4.c b/drivers/mtd/nand/rtc_from4.c index 1887989fb885..0c56a6629128 100644 --- a/drivers/mtd/nand/rtc_from4.c +++ b/drivers/mtd/nand/rtc_from4.c @@ -538,6 +538,7 @@ int __init rtc_from4_init(void) /* Link the private data with the MTD structure */ rtc_from4_mtd->priv = this; + rtc_from4_mtd->owner = THIS_MODULE; /* set area 5 as PCMCIA mode to clear the spec of tDH(Data hold time;9ns min) */ bcr1 = *SH77X9_BCR1 & ~0x0002; diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index 338fda87b9e5..f8002596de8b 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -516,6 +516,7 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, nmtd->info = info; nmtd->mtd.priv = chip; + nmtd->mtd.owner = THIS_MODULE; nmtd->set = set; if (hardware_ecc) { diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c index 25322a8d44d8..d375cb3e77d6 100644 --- a/drivers/mtd/nand/sharpsl.c +++ b/drivers/mtd/nand/sharpsl.c @@ -185,6 +185,7 @@ int __init sharpsl_nand_init(void) /* Link the private data with the MTD structure */ sharpsl_mtd->priv = this; + sharpsl_mtd->owner = THIS_MODULE; /* * PXA initialize diff --git a/drivers/mtd/nand/spia.c b/drivers/mtd/nand/spia.c index a11354b9afa2..b06aada31f79 100644 --- a/drivers/mtd/nand/spia.c +++ b/drivers/mtd/nand/spia.c @@ -121,6 +121,7 @@ int __init spia_init(void) /* Link the private data with the MTD structure */ spia_mtd->priv = this; + spia_mtd->owner = THIS_MODULE; /* * Set GPIO Port E control register so that the pins are configured diff --git a/drivers/mtd/nand/toto.c b/drivers/mtd/nand/toto.c index e3a90e60e249..24cfa9e2e025 100644 --- a/drivers/mtd/nand/toto.c +++ b/drivers/mtd/nand/toto.c @@ -137,6 +137,7 @@ int __init toto_init(void) /* Link the private data with the MTD structure */ toto_mtd->priv = this; + toto_mtd->owner = THIS_MODULE; /* Set address of NAND IO lines */ this->IO_ADDR_R = toto_io_base; diff --git a/drivers/mtd/nand/ts7250.c b/drivers/mtd/nand/ts7250.c index d2b7d57ace42..756ef64b0efd 100644 --- a/drivers/mtd/nand/ts7250.c +++ b/drivers/mtd/nand/ts7250.c @@ -147,6 +147,7 @@ static int __init ts7250_init(void) /* Link the private data with the MTD structure */ ts7250_mtd->priv = this; + ts7250_mtd->owner = THIS_MODULE; /* insert callbacks */ this->IO_ADDR_R = (void *)TS72XX_NAND_DATA_VIRT_BASE; -- cgit v1.2.3-70-g09d2 From a6550e57f9d074511cf420bdb802ab5e56edc3bb Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Sun, 14 May 2006 01:42:25 +0200 Subject: mtd: fix memory leak in block2mtd_setup() There's a mem leak in drivers/mtd/devices/block2mtd.c::block2mtd_setup() We can leak 'name' allocated with kmalloc in 'parse_name' if leave via the 'parse_err' macro since it contains a return but doesn't do any freeing. Spotted by coverity checker as bug 615. Signed-off-by: Jesper Juhl Signed-off-by: David Woodhouse --- drivers/mtd/devices/block2mtd.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c index f54e4bf9b968..45606921364b 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c @@ -429,7 +429,8 @@ static inline void kill_final_newline(char *str) static int block2mtd_setup(const char *val, struct kernel_param *kp) { - char buf[80+12], *str=buf; /* 80 for device, 12 for erase size */ + char buf[80+12]; /* 80 for device, 12 for erase size */ + char *str = buf; char *token[2]; char *name; size_t erase_size = PAGE_SIZE; @@ -441,7 +442,7 @@ static int block2mtd_setup(const char *val, struct kernel_param *kp) strcpy(str, val); kill_final_newline(str); - for (i=0; i<2; i++) + for (i = 0; i < 2; i++) token[i] = strsep(&str, ","); if (str) @@ -460,8 +461,10 @@ static int block2mtd_setup(const char *val, struct kernel_param *kp) if (token[1]) { ret = parse_num(&erase_size, token[1]); - if (ret) + if (ret) { + kfree(name); parse_err("illegal erase size"); + } } add_device(name, erase_size); -- cgit v1.2.3-70-g09d2 From 0f5ae3d2e9f49af55eb2a9b7cb54b4c0c2373017 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sun, 14 May 2006 01:40:50 +0100 Subject: [MTD] Deal correctly with NOR chips which are smaller than the map window We used to calculate the number of chips to be zero, allocate an array of that size, then nasty things would happen when we attempt to access the first object in that zero-sized array. Now, if the number of _full_ chips that would fit into the map is zero, we allocate an array of one anyway, and then artificially reduce the total size of the resulting MTD device to fit in the map. Signed-off-by: David Woodhouse --- drivers/mtd/chips/gen_probe.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/chips/gen_probe.c b/drivers/mtd/chips/gen_probe.c index 9b252d2e4a70..b2d30525c04c 100644 --- a/drivers/mtd/chips/gen_probe.c +++ b/drivers/mtd/chips/gen_probe.c @@ -37,8 +37,15 @@ struct mtd_info *mtd_do_chip_probe(struct map_info *map, struct chip_probe *cp) if (!mtd) mtd = check_cmd_set(map, 0); /* Then the secondary */ - if (mtd) + if (mtd) { + if (mtd->size > map->size) { + printk(KERN_WARNING "Reducing visibility of %lKiB chip to %lKiB\n", + (unsigned long)mtd->size >> 10, + (unsigned long)map->size >> 10); + mtd->size = map->size; + } return mtd; + } printk(KERN_WARNING"gen_probe: No supported Vendor Command Set found\n"); @@ -100,7 +107,12 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi * Align bitmap storage size to full byte. */ max_chips = map->size >> cfi.chipshift; - mapsize = (max_chips / 8) + ((max_chips % 8) ? 1 : 0); + if (!max_chips) { + printk(KERN_WARNING "NOR chip too large to fit in mapping. Attempting to cope...\n"); + max_chips = 1; + } + + mapsize = (max_chips + BITS_PER_LONG-1) / BITS_PER_LONG; chip_map = kmalloc(mapsize, GFP_KERNEL); if (!chip_map) { printk(KERN_WARNING "%s: kmalloc failed for CFI chip map\n", map->name); -- cgit v1.2.3-70-g09d2 From 151e76590f66f5406eb2e1f4270c5323f385d2e8 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sun, 14 May 2006 01:51:54 +0100 Subject: [MTD] Fix legacy character sets throughout drivers/mtd, include/linux/mtd Signed-off-by: David Woodhouse --- drivers/mtd/chips/cfi_cmdset_0001.c | 2 +- drivers/mtd/chips/cfi_probe.c | 8 ++++---- drivers/mtd/devices/block2mtd.c | 2 +- drivers/mtd/devices/phram.c | 6 +++--- drivers/mtd/maps/cfi_flagadm.c | 4 ++-- drivers/mtd/maps/dbox2-flash.c | 2 +- drivers/mtd/maps/mtx-1_flash.c | 2 +- drivers/mtd/nand/edb7312.c | 2 +- drivers/mtd/nand/h1910.c | 2 +- drivers/mtd/nand/ts7250.c | 2 +- include/linux/mtd/mtd.h | 2 +- 11 files changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index fe00af3f9195..898c321ab86d 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -1475,7 +1475,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, ENABLE_VPP(map); xip_disable(map, chip, cmd_adr); - /* §4.8 of the 28FxxxJ3A datasheet says "Any time SR.4 and/or SR.5 is set + /* §4.8 of the 28FxxxJ3A datasheet says "Any time SR.4 and/or SR.5 is set [...], the device will not accept any more Write to Buffer commands". So we must check here and reset those bits if they're set. Otherwise we're just pissing in the wind */ diff --git a/drivers/mtd/chips/cfi_probe.c b/drivers/mtd/chips/cfi_probe.c index e636aa86bc24..4bf9f8cac0dd 100644 --- a/drivers/mtd/chips/cfi_probe.c +++ b/drivers/mtd/chips/cfi_probe.c @@ -349,12 +349,12 @@ static void print_cfi_ident(struct cfi_ident *cfip) else printk("No Vpp line\n"); - printk("Typical byte/word write timeout: %d µs\n", 1<WordWriteTimeoutTyp); - printk("Maximum byte/word write timeout: %d µs\n", (1<WordWriteTimeoutMax) * (1<WordWriteTimeoutTyp)); + printk("Typical byte/word write timeout: %d µs\n", 1<WordWriteTimeoutTyp); + printk("Maximum byte/word write timeout: %d µs\n", (1<WordWriteTimeoutMax) * (1<WordWriteTimeoutTyp)); if (cfip->BufWriteTimeoutTyp || cfip->BufWriteTimeoutMax) { - printk("Typical full buffer write timeout: %d µs\n", 1<BufWriteTimeoutTyp); - printk("Maximum full buffer write timeout: %d µs\n", (1<BufWriteTimeoutMax) * (1<BufWriteTimeoutTyp)); + printk("Typical full buffer write timeout: %d µs\n", 1<BufWriteTimeoutTyp); + printk("Maximum full buffer write timeout: %d µs\n", (1<BufWriteTimeoutMax) * (1<BufWriteTimeoutTyp)); } else printk("Full buffer write not supported\n"); diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c index 45606921364b..8ca04f4e03f0 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c @@ -4,7 +4,7 @@ * block2mtd.c - create an mtd from a block device * * Copyright (C) 2001,2002 Simon Evans - * Copyright (C) 2004-2006 Jörn Engel + * Copyright (C) 2004-2006 Jörn Engel * * Licence: GPL */ diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c index 68d39cc9df71..e09e416667d3 100644 --- a/drivers/mtd/devices/phram.c +++ b/drivers/mtd/devices/phram.c @@ -1,8 +1,8 @@ /** * $Id: phram.c,v 1.16 2005/11/07 11:14:25 gleixner Exp $ * - * Copyright (c) ???? Jochen Schäuble - * Copyright (c) 2003-2004 Jörn Engel + * Copyright (c) ???? Jochen Schäuble + * Copyright (c) 2003-2004 Jörn Engel * * Usage: * @@ -300,5 +300,5 @@ module_init(init_phram); module_exit(cleanup_phram); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Jörn Engel "); +MODULE_AUTHOR("Jörn Engel "); MODULE_DESCRIPTION("MTD driver for physical RAM"); diff --git a/drivers/mtd/maps/cfi_flagadm.c b/drivers/mtd/maps/cfi_flagadm.c index fd0f0d3187de..92b5d883d7b0 100644 --- a/drivers/mtd/maps/cfi_flagadm.c +++ b/drivers/mtd/maps/cfi_flagadm.c @@ -1,5 +1,5 @@ /* - * Copyright © 2001 Flaga hf. Medical Devices, Kári Davíðsson + * Copyright © 2001 Flaga hf. Medical Devices, Kári Davíðsson * * $Id: cfi_flagadm.c,v 1.15 2005/11/07 11:14:26 gleixner Exp $ * @@ -135,5 +135,5 @@ module_exit(cleanup_flagadm); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Kári Davíðsson "); +MODULE_AUTHOR("Kári Davíðsson "); MODULE_DESCRIPTION("MTD map driver for Flaga digital module"); diff --git a/drivers/mtd/maps/dbox2-flash.c b/drivers/mtd/maps/dbox2-flash.c index 652813cd6c2d..85c2a9e22b1e 100644 --- a/drivers/mtd/maps/dbox2-flash.c +++ b/drivers/mtd/maps/dbox2-flash.c @@ -122,5 +122,5 @@ module_exit(cleanup_dbox2_flash); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Kári Davíðsson , Bastian Blank , Alexander Wild "); +MODULE_AUTHOR("Kári Davíðsson , Bastian Blank , Alexander Wild "); MODULE_DESCRIPTION("MTD map driver for D-Box 2 board"); diff --git a/drivers/mtd/maps/mtx-1_flash.c b/drivers/mtd/maps/mtx-1_flash.c index d1e66e186746..5c25d4e552c6 100644 --- a/drivers/mtd/maps/mtx-1_flash.c +++ b/drivers/mtd/maps/mtx-1_flash.c @@ -4,7 +4,7 @@ * $Id: mtx-1_flash.c,v 1.2 2005/11/07 11:14:27 gleixner Exp $ * * (C) 2005 Bruno Randolf - * (C) 2005 Jörn Engel + * (C) 2005 Jörn Engel * */ diff --git a/drivers/mtd/nand/edb7312.c b/drivers/mtd/nand/edb7312.c index ad4488abfb0b..8e56570af91f 100644 --- a/drivers/mtd/nand/edb7312.c +++ b/drivers/mtd/nand/edb7312.c @@ -1,7 +1,7 @@ /* * drivers/mtd/nand/edb7312.c * - * Copyright (C) 2002 Marius Gröger (mag@sysgo.de) + * Copyright (C) 2002 Marius Gröger (mag@sysgo.de) * * Derived from drivers/mtd/nand/autcpu12.c * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) diff --git a/drivers/mtd/nand/h1910.c b/drivers/mtd/nand/h1910.c index b47a15c23d1c..9848eb09b884 100644 --- a/drivers/mtd/nand/h1910.c +++ b/drivers/mtd/nand/h1910.c @@ -4,7 +4,7 @@ * Copyright (C) 2003 Joshua Wise (joshua@joshuawise.com) * * Derived from drivers/mtd/nand/edb7312.c - * Copyright (C) 2002 Marius Gröger (mag@sysgo.de) + * Copyright (C) 2002 Marius Gröger (mag@sysgo.de) * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) * * $Id: h1910.c,v 1.6 2005/11/07 11:14:30 gleixner Exp $ diff --git a/drivers/mtd/nand/ts7250.c b/drivers/mtd/nand/ts7250.c index 756ef64b0efd..622db3127f7c 100644 --- a/drivers/mtd/nand/ts7250.c +++ b/drivers/mtd/nand/ts7250.c @@ -4,7 +4,7 @@ * Copyright (C) 2004 Technologic Systems (support@embeddedARM.com) * * Derived from drivers/mtd/nand/edb7312.c - * Copyright (C) 2004 Marius Gröger (mag@sysgo.de) + * Copyright (C) 2004 Marius Gröger (mag@sysgo.de) * * Derived from drivers/mtd/nand/autcpu12.c * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index b6f2fdae65c6..73620ef83364 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -61,7 +61,7 @@ struct mtd_info { u_int32_t flags; u_int32_t size; // Total size of the MTD - /* "Major" erase size for the device. Naïve users may take this + /* "Major" erase size for the device. Naïve users may take this * to be the only erase size available, or may use the more detailed * information below if they desire */ -- cgit v1.2.3-70-g09d2 From cf5eba53346fbfdf1b80e05ca3fd7fe2ec841077 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sun, 14 May 2006 04:06:24 +0100 Subject: [JFFS2] Reduce excessive node count for syslog files. We currently get fairly poor behaviour with files which get many short writes, such as system logs. This is because we end up with many tiny data nodes, and the rbtree gets massive. None of these nodes are actually obsolete, so they are counted as 'clean' space. Eraseblocks can be entirely full of these nodes (which are REF_NORMAL instead of REF_PRISTINE), and still they count entirely towards 'used_size' and the eraseblocks can sit on the clean_list for a long time without being picked for GC. One way to alleviate this in the long term is to account REF_NORMAL space separately from REF_PRISTINE space, rather than counting them both towards used_size. Then these eraseblocks can be picked for GC and the offending nodes will be garbage collected. The short-term fix, though -- which probably makes sense even if we do eventually implement the above -- is to merge these nodes as they're written. When we write the last byte in a page, write the _whole_ page. This obsoletes the earlier nodes in the page _immediately_ and we don't even need to wait for the garbage collection to do it. Original implementation from Ferenc Havasi Signed-off-by: David Woodhouse --- fs/jffs2/file.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c index 9f4171213e58..3349db0a7863 100644 --- a/fs/jffs2/file.c +++ b/fs/jffs2/file.c @@ -215,12 +215,20 @@ static int jffs2_commit_write (struct file *filp, struct page *pg, D1(printk(KERN_DEBUG "jffs2_commit_write(): ino #%lu, page at 0x%lx, range %d-%d, flags %lx\n", inode->i_ino, pg->index << PAGE_CACHE_SHIFT, start, end, pg->flags)); - if (!start && end == PAGE_CACHE_SIZE) { - /* We need to avoid deadlock with page_cache_read() in - jffs2_garbage_collect_pass(). So we have to mark the - page up to date, to prevent page_cache_read() from - trying to re-lock it. */ - SetPageUptodate(pg); + if (end == PAGE_CACHE_SIZE) { + if (!start) { + /* We need to avoid deadlock with page_cache_read() in + jffs2_garbage_collect_pass(). So we have to mark the + page up to date, to prevent page_cache_read() from + trying to re-lock it. */ + SetPageUptodate(pg); + } else { + /* When writing out the end of a page, write out the + _whole_ page. This helps to reduce the number of + nodes in files which have many short writes, like + syslog files. */ + start = aligned_start = 0; + } } ri = jffs2_alloc_raw_inode(); -- cgit v1.2.3-70-g09d2 From 2f206701ae9b5c13719c2be26121b9461f05f87c Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sun, 14 May 2006 11:59:20 +0100 Subject: [MTD] Remove gratuitous inclusion of ARM-only header from physmap.c The physmap platform driver conversion added to physmap.c an include of asm/mach/flash.h which is 1) ARM-specific; and 2) isn't actually necessary. Remove it. Signed-off-by: Lennert Buytenhek Signed-off-by: David Woodhouse --- drivers/mtd/maps/physmap.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c index 76ce9bd943aa..bc82f702aa3c 100644 --- a/drivers/mtd/maps/physmap.c +++ b/drivers/mtd/maps/physmap.c @@ -22,7 +22,6 @@ #include #include #include -#include struct physmap_flash_info { struct mtd_info *mtd; -- cgit v1.2.3-70-g09d2 From 0d4e30d26a279f1b6a008a233a6835ad2af571e4 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sun, 14 May 2006 12:25:19 +0100 Subject: [MTD] Clean up to fix modular build ... and also fix the multiple inclusion guard so it actually _works_ Signed-off-by: David Woodhouse --- include/linux/mtd/physmap.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/include/linux/mtd/physmap.h b/include/linux/mtd/physmap.h index 50f954461aa8..86831e3594f6 100644 --- a/include/linux/mtd/physmap.h +++ b/include/linux/mtd/physmap.h @@ -15,10 +15,7 @@ */ #ifndef __LINUX_MTD_PHYSMAP__ - -#include - -#if defined(CONFIG_MTD_PHYSMAP) +#define __LINUX_MTD_PHYSMAP__ #include #include @@ -37,7 +34,7 @@ struct physmap_flash_data { void physmap_configure(unsigned long addr, unsigned long size, int bankwidth, void (*set_vpp)(struct map_info *, int) ); -#if defined(CONFIG_MTD_PARTITIONS) +#ifdef CONFIG_MTD_PARTITIONS /* * Machines that wish to do flash partition may want to call this function in @@ -51,6 +48,5 @@ void physmap_configure(unsigned long addr, unsigned long size, void physmap_set_partitions(struct mtd_partition *parts, int num_parts); #endif /* defined(CONFIG_MTD_PARTITIONS) */ -#endif /* defined(CONFIG_MTD) */ #endif /* __LINUX_MTD_PHYSMAP__ */ -- cgit v1.2.3-70-g09d2 From 52239da1b06ff445bf71d35e04d8ce74e4c6fe7b Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sun, 14 May 2006 16:54:39 +0100 Subject: [MTD NAND] Modify check for modules registering NAND devices without ->owner Make it work even with compilers which lack the wit to notice that THIS_MODULE is always non-NULL. Use #ifdef MODULE instead. It's only a temporary debugging check anyway. Signed-off-by: David Woodhouse --- drivers/mtd/nand/nand_base.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 42cff0a2b93d..08dffb7a9389 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2312,6 +2312,15 @@ static void nand_resume(struct mtd_info *mtd) } +/* module_text_address() isn't exported, and it's mostly a pointless + test if this is a module _anyway_ -- they'd have to try _really_ hard + to call us from in-kernel code if the core NAND support is modular. */ +#ifdef MODULE +#define caller_is_module() (1) +#else +#define caller_is_module() module_text_address((unsigned long)__builtin_return_address(0)) +#endif + /** * nand_scan - [NAND Interface] Scan for the NAND device * @mtd: MTD device structure @@ -2330,12 +2339,8 @@ int nand_scan(struct mtd_info *mtd, int maxchips) int i, nand_maf_id, nand_dev_id, busw, maf_id; struct nand_chip *this = mtd->priv; - /* module_text_address() isn't exported. But if _this_ is a module, - it's a fairly safe bet that its caller is a module too... and - that means the call to module_text_address() gets optimised out - without having to resort to ifdefs */ - if (!mtd->owner && (THIS_MODULE || - module_text_address((unsigned long)__builtin_return_address(0)))) { + /* Many callers got this wrong, so check for it for a while... */ + if (!mtd->owner && caller_is_module()) { printk(KERN_CRIT "nand_scan() called with NULL mtd->owner!\n"); BUG(); } -- cgit v1.2.3-70-g09d2 From 3e68fbb59b3d4e6b47b65e9928b5929e02179759 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Mon, 15 May 2006 00:49:43 +0100 Subject: [JFFS2] Don't pack on-medium structures, because GCC emits crappy code If we use __attribute__((packed)), GCC will _also_ assume that the structures aren't sensibly aligned, and it'll emit code to cope with that instead of straight word load/save. This can be _very_ suboptimal on architectures like ARM. Ideally, we want an attribute which just tells GCC not to do any padding, without the alignment side-effects. In the absense of that, we'll just drop the 'packed' attribute and hope that everything stays as it was (which to be fair is fairly much what we expect). And add some paranoia checks in the initialisation code, which should be optimised away completely in the normal case. Signed-off-by: David Woodhouse --- fs/jffs2/super.c | 14 +++++++++++++- include/linux/jffs2.h | 14 +++++++------- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index ffd8e84b22cc..5f73de586928 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c @@ -320,6 +320,18 @@ static int __init init_jffs2_fs(void) { int ret; + /* Paranoia checks for on-medium structures. If we ask GCC + to pack them with __attribute__((packed)) then it _also_ + assumes that they're not aligned -- so it emits crappy + code on some architectures. Ideally we want an attribute + which means just 'no padding', without the alignment + thing. But GCC doesn't have that -- we have to just + hope the structs are the right sizes, instead. */ + BUG_ON(sizeof(struct jffs2_unknown_node) != 12); + BUG_ON(sizeof(struct jffs2_raw_dirent) != 40); + BUG_ON(sizeof(struct jffs2_raw_inode) != 68); + BUG_ON(sizeof(struct jffs2_raw_summary) != 32); + printk(KERN_INFO "JFFS2 version 2.2." #ifdef CONFIG_JFFS2_FS_WRITEBUFFER " (NAND)" @@ -327,7 +339,7 @@ static int __init init_jffs2_fs(void) #ifdef CONFIG_JFFS2_SUMMARY " (SUMMARY) " #endif - " (C) 2001-2003 Red Hat, Inc.\n"); + " (C) 2001-2006 Red Hat, Inc.\n"); jffs2_inode_cachep = kmem_cache_create("jffs2_i", sizeof(struct jffs2_inode_info), diff --git a/include/linux/jffs2.h b/include/linux/jffs2.h index cf792bb3c726..228ad72f7dd8 100644 --- a/include/linux/jffs2.h +++ b/include/linux/jffs2.h @@ -82,15 +82,15 @@ typedef struct { uint32_t v32; -} __attribute__((packed)) jint32_t; +} jint32_t; typedef struct { uint32_t m; -} __attribute__((packed)) jmode_t; +} jmode_t; typedef struct { uint16_t v16; -} __attribute__((packed)) jint16_t; +} jint16_t; struct jffs2_unknown_node { @@ -99,7 +99,7 @@ struct jffs2_unknown_node jint16_t nodetype; jint32_t totlen; /* So we can skip over nodes we don't grok */ jint32_t hdr_crc; -} __attribute__((packed)); +}; struct jffs2_raw_dirent { @@ -117,7 +117,7 @@ struct jffs2_raw_dirent jint32_t node_crc; jint32_t name_crc; uint8_t name[0]; -} __attribute__((packed)); +}; /* The JFFS2 raw inode structure: Used for storage on physical media. */ /* The uid, gid, atime, mtime and ctime members could be longer, but @@ -149,7 +149,7 @@ struct jffs2_raw_inode jint32_t data_crc; /* CRC for the (compressed) data. */ jint32_t node_crc; /* CRC for the raw inode (excluding data) */ uint8_t data[0]; -} __attribute__((packed)); +}; struct jffs2_raw_summary { @@ -163,7 +163,7 @@ struct jffs2_raw_summary jint32_t sum_crc; /* summary information crc */ jint32_t node_crc; /* node crc */ jint32_t sum[0]; /* inode summary info */ -} __attribute__((packed)); +}; union jffs2_node_union { -- cgit v1.2.3-70-g09d2 From 184f565210c6c8a852c53ffc070f9add61e0f331 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 15 May 2006 13:45:58 +0100 Subject: [JFFS2] Fix printk format in some error messages. fs/jffs2/nodelist.c: In function `check_node_data': fs/jffs2/nodelist.c:441: warning: unsigned int format, different type arg (arg 4) fs/jffs2/nodelist.c:464: warning: int format, different type arg (arg 5) Modified from Andrew's original fix because while his terminal may indeed only have eighty columns, mine only has _TWENTYFOUR_ lines. So the cosmetic fluff is perfectly OK out past column 80 where it was -- the casual reader doesn't _care_ about anything more than the fact that it goes 'if (foo) JFFS2_WARNING...', and there's no point wasting a whole line to display the tail end of the printk which nobody actually cares about. Signed-off-by: Andrew Morton Signed-off-by: David Woodhouse --- fs/jffs2/nodelist.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c index d4d0c41490cd..7d71593d7fd3 100644 --- a/fs/jffs2/nodelist.c +++ b/fs/jffs2/nodelist.c @@ -438,7 +438,7 @@ static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info if (c->mtd->point) { err = c->mtd->point(c->mtd, ofs, len, &retlen, &buffer); if (!err && retlen < tn->csize) { - JFFS2_WARNING("MTD point returned len too short: %u instead of %u.\n", retlen, tn->csize); + JFFS2_WARNING("MTD point returned len too short: %zu instead of %u.\n", retlen, tn->csize); c->mtd->unpoint(c->mtd, buffer, ofs, len); } else if (err) JFFS2_WARNING("MTD point failed: error code %d.\n", err); @@ -461,7 +461,7 @@ static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info } if (retlen != len) { - JFFS2_ERROR("short read at %#08x: %d instead of %d.\n", ofs, retlen, len); + JFFS2_ERROR("short read at %#08x: %zd instead of %d.\n", ofs, retlen, len); err = -EIO; goto free_out; } -- cgit v1.2.3-70-g09d2 From 0cccca06f9870eb6daa89357b8a99ad041865553 Mon Sep 17 00:00:00 2001 From: "Serge E. Hallyn" Date: Mon, 15 May 2006 09:43:48 -0700 Subject: [PATCH] selinux: check for failed kmalloc in security_sid_to_context() Check for NULL kmalloc return value before writing to it. Signed-off-by: Serge E. Hallyn Acked-by: James Morris Cc: Stephen Smalley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- security/selinux/ss/services.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 7177e98df7f3..c284dbb8b8c0 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -594,6 +594,10 @@ int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len) *scontext_len = strlen(initial_sid_to_string[sid]) + 1; scontextp = kmalloc(*scontext_len,GFP_ATOMIC); + if (!scontextp) { + rc = -ENOMEM; + goto out; + } strcpy(scontextp, initial_sid_to_string[sid]); *scontext = scontextp; goto out; -- cgit v1.2.3-70-g09d2 From 6aff5cb8ec270db569800b1bb59bd20003a76f07 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 15 May 2006 09:43:50 -0700 Subject: [PATCH] fs/open.c: unexport sys_openat Remove the unused EXPORT_SYMBOL_GPL(sys_openat). Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/open.c | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/open.c b/fs/open.c index 53ec28c36777..317b7c7f38a7 100644 --- a/fs/open.c +++ b/fs/open.c @@ -1124,7 +1124,6 @@ asmlinkage long sys_openat(int dfd, const char __user *filename, int flags, prevent_tail_call(ret); return ret; } -EXPORT_SYMBOL_GPL(sys_openat); #ifndef __alpha__ -- cgit v1.2.3-70-g09d2 From a5370553952a9a414860d878b67c49eff11313bd Mon Sep 17 00:00:00 2001 From: Ian Kent Date: Mon, 15 May 2006 09:43:51 -0700 Subject: [PATCH] autofs4: NFY_NONE wait race fix This patch fixes two problems. First, the comparison of entries in the waitq.c was incorrect. Second, the NFY_NONE check was incorrect. The test of whether the dentry is mounted if ineffective, for example, if an expire fails then we could wait forever on a non existant expire. The bug was identified by Jeff Moyer. The patch changes autofs4 to wait on expires only as this is all that's needed. If there is no existing wait when autofs4_wait is call with a type of NFY_NONE it delays until either a wait appears or the the expire flag is cleared. Signed-off-by: Ian Kent Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/autofs4/autofs_i.h | 5 ++-- fs/autofs4/root.c | 10 ++----- fs/autofs4/waitq.c | 77 +++++++++++++++++++++++++++++++++++---------------- 3 files changed, 58 insertions(+), 34 deletions(-) diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h index 57c4903614e5..d6603d02304c 100644 --- a/fs/autofs4/autofs_i.h +++ b/fs/autofs4/autofs_i.h @@ -74,8 +74,8 @@ struct autofs_wait_queue { struct autofs_wait_queue *next; autofs_wqt_t wait_queue_token; /* We use the following to see what we are waiting for */ - int hash; - int len; + unsigned int hash; + unsigned int len; char *name; u32 dev; u64 ino; @@ -85,7 +85,6 @@ struct autofs_wait_queue { pid_t tgid; /* This is for status reporting upon return */ int status; - atomic_t notify; atomic_t wait_ctr; }; diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index 84e030c8ddd0..5100f984783f 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c @@ -327,6 +327,7 @@ static int try_to_fill_dentry(struct dentry *dentry, int flags) static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd) { struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); + struct autofs_info *ino = autofs4_dentry_ino(dentry); int oz_mode = autofs4_oz_mode(sbi); unsigned int lookup_type; int status; @@ -340,13 +341,8 @@ static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd) if (oz_mode || !lookup_type) goto done; - /* - * If a request is pending wait for it. - * If it's a mount then it won't be expired till at least - * a liitle later and if it's an expire then we might need - * to mount it again. - */ - if (autofs4_ispending(dentry)) { + /* If an expire request is pending wait for it. */ + if (ino && (ino->flags & AUTOFS_INF_EXPIRING)) { DPRINTK("waiting for active request %p name=%.*s", dentry, dentry->d_name.len, dentry->d_name.name); diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c index 142ab6aa2aa1..ce103e7b0bc3 100644 --- a/fs/autofs4/waitq.c +++ b/fs/autofs4/waitq.c @@ -189,14 +189,30 @@ static int autofs4_getpath(struct autofs_sb_info *sbi, return len; } +static struct autofs_wait_queue * +autofs4_find_wait(struct autofs_sb_info *sbi, + char *name, unsigned int hash, unsigned int len) +{ + struct autofs_wait_queue *wq; + + for (wq = sbi->queues; wq; wq = wq->next) { + if (wq->hash == hash && + wq->len == len && + wq->name && !memcmp(wq->name, name, len)) + break; + } + return wq; +} + int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry, enum autofs_notify notify) { + struct autofs_info *ino; struct autofs_wait_queue *wq; char *name; unsigned int len = 0; unsigned int hash = 0; - int status; + int status, type; /* In catatonic mode, we don't wait for nobody */ if (sbi->catatonic) @@ -223,21 +239,41 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry, return -EINTR; } - for (wq = sbi->queues ; wq ; wq = wq->next) { - if (wq->hash == dentry->d_name.hash && - wq->len == len && - wq->name && !memcmp(wq->name, name, len)) - break; - } + wq = autofs4_find_wait(sbi, name, hash, len); + ino = autofs4_dentry_ino(dentry); + if (!wq && ino && notify == NFY_NONE) { + /* + * Either we've betean the pending expire to post it's + * wait or it finished while we waited on the mutex. + * So we need to wait till either, the wait appears + * or the expire finishes. + */ + + while (ino->flags & AUTOFS_INF_EXPIRING) { + mutex_unlock(&sbi->wq_mutex); + schedule_timeout_interruptible(HZ/10); + if (mutex_lock_interruptible(&sbi->wq_mutex)) { + kfree(name); + return -EINTR; + } + wq = autofs4_find_wait(sbi, name, hash, len); + if (wq) + break; + } - if (!wq) { - /* Can't wait for an expire if there's no mount */ - if (notify == NFY_NONE && !d_mountpoint(dentry)) { + /* + * Not ideal but the status has already gone. Of the two + * cases where we wait on NFY_NONE neither depend on the + * return status of the wait. + */ + if (!wq) { kfree(name); mutex_unlock(&sbi->wq_mutex); - return -ENOENT; + return 0; } + } + if (!wq) { /* Create a new wait queue */ wq = kmalloc(sizeof(struct autofs_wait_queue),GFP_KERNEL); if (!wq) { @@ -263,20 +299,7 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry, wq->tgid = current->tgid; wq->status = -EINTR; /* Status return if interrupted */ atomic_set(&wq->wait_ctr, 2); - atomic_set(&wq->notify, 1); - mutex_unlock(&sbi->wq_mutex); - } else { - atomic_inc(&wq->wait_ctr); mutex_unlock(&sbi->wq_mutex); - kfree(name); - DPRINTK("existing wait id = 0x%08lx, name = %.*s, nfy=%d", - (unsigned long) wq->wait_queue_token, wq->len, wq->name, notify); - } - - if (notify != NFY_NONE && atomic_read(&wq->notify)) { - int type; - - atomic_dec(&wq->notify); if (sbi->version < 5) { if (notify == NFY_MOUNT) @@ -299,6 +322,12 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry, /* autofs4_notify_daemon() may block */ autofs4_notify_daemon(sbi, wq, type); + } else { + atomic_inc(&wq->wait_ctr); + mutex_unlock(&sbi->wq_mutex); + kfree(name); + DPRINTK("existing wait id = 0x%08lx, name = %.*s, nfy=%d", + (unsigned long) wq->wait_queue_token, wq->len, wq->name, notify); } /* wq->name is NULL if and only if the lock is already released */ -- cgit v1.2.3-70-g09d2 From 90d5ede5985f3b172cc3ccd89bf8c52a209088a5 Mon Sep 17 00:00:00 2001 From: Stefan Schweizer Date: Mon, 15 May 2006 09:43:52 -0700 Subject: [PATCH] Fix capi reload by unregistering the correct major I am having the bug FATAL: Error inserting capi ([..]/capi.ko): Device or resource busy when I try to reload capi after loading it. in dmesg: capi20: unable to get major 68 Fix the issue which is caused by setting the major to zero when registering the chrdev succeeded. (akpm: this means that we can again not use `major=0' (dynamic major allocation) for this driver). Cc: Karsten Keil Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/isdn/capi/capi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index 9b493f0becc4..173c899a1fb4 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c @@ -1499,7 +1499,6 @@ static int __init capi_init(void) printk(KERN_ERR "capi20: unable to get major %d\n", capi_major); return major_ret; } - capi_major = major_ret; capi_class = class_create(THIS_MODULE, "capi"); if (IS_ERR(capi_class)) { unregister_chrdev(capi_major, "capi20"); -- cgit v1.2.3-70-g09d2 From 94585136606e0598a93ec145d9a899c8ec9b2208 Mon Sep 17 00:00:00 2001 From: Kylene Jo Hall Date: Mon, 15 May 2006 09:43:53 -0700 Subject: [PATCH] tpm: update module dependencies The TIS driver is dependent upon information from the ACPI table for device discovery thus it compiles but does no actual work without this dependency. Signed-off-by: Kylene Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index 1efde3b27619..fe00c7dfb649 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig @@ -22,7 +22,7 @@ config TCG_TPM config TCG_TIS tristate "TPM Interface Specification 1.2 Interface" - depends on TCG_TPM + depends on TCG_TPM && PNPACPI ---help--- If you have a TPM security chip that is compliant with the TCG TIS 1.2 TPM specification say Yes and it will be accessible -- cgit v1.2.3-70-g09d2 From 73d58588091e81e5ee4266488e2fb09a410f1512 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 15 May 2006 09:43:53 -0700 Subject: [PATCH] pcmcia Oopses fixes Fix some NULL dereferences in the pcmcia code when using old userland tools. Signed-off-by: Benjamin Herrenschmidt Acked-by: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pcmcia/pcmcia_ioctl.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c index c53db7ceda5e..738b1ef595a3 100644 --- a/drivers/pcmcia/pcmcia_ioctl.c +++ b/drivers/pcmcia/pcmcia_ioctl.c @@ -426,7 +426,7 @@ static int ds_open(struct inode *inode, struct file *file) if (!warning_printed) { printk(KERN_INFO "pcmcia: Detected deprecated PCMCIA ioctl " - "usage.\n"); + "usage from process: %s.\n", current->comm); printk(KERN_INFO "pcmcia: This interface will soon be removed from " "the kernel; please expect breakage unless you upgrade " "to new tools.\n"); @@ -601,8 +601,12 @@ static int ds_ioctl(struct inode * inode, struct file * file, ret = CS_BAD_ARGS; else { struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->config.Function); - ret = pccard_get_configuration_info(s, p_dev, &buf->config); - pcmcia_put_dev(p_dev); + if (p_dev == NULL) + ret = CS_BAD_ARGS; + else { + ret = pccard_get_configuration_info(s, p_dev, &buf->config); + pcmcia_put_dev(p_dev); + } } break; case DS_GET_FIRST_TUPLE: @@ -632,8 +636,12 @@ static int ds_ioctl(struct inode * inode, struct file * file, ret = CS_BAD_ARGS; else { struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->status.Function); - ret = pccard_get_status(s, p_dev, &buf->status); - pcmcia_put_dev(p_dev); + if (p_dev == NULL) + ret = CS_BAD_ARGS; + else { + ret = pccard_get_status(s, p_dev, &buf->status); + pcmcia_put_dev(p_dev); + } } break; case DS_VALIDATE_CIS: @@ -665,9 +673,10 @@ static int ds_ioctl(struct inode * inode, struct file * file, if (!(buf->conf_reg.Function && (buf->conf_reg.Function >= s->functions))) { struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->conf_reg.Function); - if (p_dev) + if (p_dev) { ret = pcmcia_access_configuration_register(p_dev, &buf->conf_reg); - pcmcia_put_dev(p_dev); + pcmcia_put_dev(p_dev); + } } break; case DS_GET_FIRST_REGION: -- cgit v1.2.3-70-g09d2 From a7b862f663d81858531dfccc0537bc9d8a2a4121 Mon Sep 17 00:00:00 2001 From: Chris Wedgwood Date: Mon, 15 May 2006 09:43:55 -0700 Subject: [PATCH] VIA quirk fixup, additional PCI IDs An earlier commit (75cf7456dd87335f574dcd53c4ae616a2ad71a11) changed an overly-zealous PCI quirk to only poke those VIA devices that need it. However, some PCI devices were not included in what I hope is now the full list. Consequently we're failing to run the quirk on all machines which need it, causing IRQ routing failures. This should I hope correct this. Thanks to Masoud Sharbiani for pointing this out and testing the fix. Signed-off-by: Chris Wedgwood Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pci/quirks.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 19e2b174d33c..0d36d5040880 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -634,6 +634,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_vi * non-x86 architectures (yes Via exists on PPC among other places), * we must mask the PCI_INTERRUPT_LINE value versus 0xf to get * interrupts delivered properly. + * + * Some of the on-chip devices are actually '586 devices' so they are + * listed here. */ static void quirk_via_irq(struct pci_dev *dev) { @@ -648,6 +651,10 @@ static void quirk_via_irq(struct pci_dev *dev) pci_write_config_byte(dev, PCI_INTERRUPT_LINE, new_irq); } } +DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, quirk_via_irq); +DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1, quirk_via_irq); +DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_2, quirk_via_irq); +DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_via_irq); DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, quirk_via_irq); DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_via_irq); DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_5, quirk_via_irq); -- cgit v1.2.3-70-g09d2 From 3b7c8108273bed41a2fc04533cc9f2026ff38c8e Mon Sep 17 00:00:00 2001 From: Olaf Kirch Date: Mon, 15 May 2006 09:43:57 -0700 Subject: [PATCH] smbfs chroot issue (CVE-2006-1864) Mark Moseley reported that a chroot environment on a SMB share can be left via "cd ..\\". Similar to CVE-2006-1863 issue with cifs, this fix is for smbfs. Steven French wrote: Looks fine to me. This should catch the slash on lookup or equivalent, which will be all obvious paths of interest. Signed-off-by: Chris Wright Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/smbfs/dir.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fs/smbfs/dir.c b/fs/smbfs/dir.c index 34c7a11d91f0..70d9c5a37f5a 100644 --- a/fs/smbfs/dir.c +++ b/fs/smbfs/dir.c @@ -434,6 +434,11 @@ smb_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) if (dentry->d_name.len > SMB_MAXNAMELEN) goto out; + /* Do not allow lookup of names with backslashes in */ + error = -EINVAL; + if (memchr(dentry->d_name.name, '\\', dentry->d_name.len)) + goto out; + lock_kernel(); error = smb_proc_getattr(dentry, &finfo); #ifdef SMBFS_PARANOIA -- cgit v1.2.3-70-g09d2 From 986733e01d258c26107f1da9d8d47c718349ad2f Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 15 May 2006 09:43:58 -0700 Subject: [PATCH] RCU: introduce rcu_needs_cpu() interface With "Paul E. McKenney" Introduce rcu_needs_cpu() interface. This can be used to tell if there will be a new rcu batch on a cpu soon by looking at the curlist pointer. This can be used to avoid to enter a tickless idle state where the cpu would miss that a new batch is ready when rcu_start_batch would be called on a different cpu. Signed-off-by: Heiko Carstens Cc: "Paul E. McKenney" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/rcupdate.h | 1 + kernel/rcupdate.c | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 5673008b61e1..970284f571a6 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -132,6 +132,7 @@ static inline void rcu_bh_qsctr_inc(int cpu) } extern int rcu_pending(int cpu); +extern int rcu_needs_cpu(int cpu); /** * rcu_read_lock - mark the beginning of an RCU read-side critical section. diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c index 6d32ff26f948..2058f88c7bbb 100644 --- a/kernel/rcupdate.c +++ b/kernel/rcupdate.c @@ -479,12 +479,31 @@ static int __rcu_pending(struct rcu_ctrlblk *rcp, struct rcu_data *rdp) return 0; } +/* + * Check to see if there is any immediate RCU-related work to be done + * by the current CPU, returning 1 if so. This function is part of the + * RCU implementation; it is -not- an exported member of the RCU API. + */ int rcu_pending(int cpu) { return __rcu_pending(&rcu_ctrlblk, &per_cpu(rcu_data, cpu)) || __rcu_pending(&rcu_bh_ctrlblk, &per_cpu(rcu_bh_data, cpu)); } +/* + * Check to see if any future RCU-related work will need to be done + * by the current CPU, even if none need be done immediately, returning + * 1 if so. This function is part of the RCU implementation; it is -not- + * an exported member of the RCU API. + */ +int rcu_needs_cpu(int cpu) +{ + struct rcu_data *rdp = &per_cpu(rcu_data, cpu); + struct rcu_data *rdp_bh = &per_cpu(rcu_bh_data, cpu); + + return (!!rdp->curlist || !!rdp_bh->curlist || rcu_pending(cpu)); +} + void rcu_check_callbacks(int cpu, int user) { if (user || -- cgit v1.2.3-70-g09d2 From 5afdbd6e84c7fbdaa7cfde4cbee0d3a5f4f56da2 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 15 May 2006 09:43:59 -0700 Subject: [PATCH] s390: exploit rcu_needs_cpu() interface Exploit rcu_needs_cpu() interface to keep the cpu 'ticking' if necessary. Signed-off-by: Heiko Carstens Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/s390/kernel/time.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index fea043b69b91..029f09901b85 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -249,18 +249,19 @@ static inline void stop_hz_timer(void) unsigned long flags; unsigned long seq, next; __u64 timer, todval; + int cpu = smp_processor_id(); if (sysctl_hz_timer != 0) return; - cpu_set(smp_processor_id(), nohz_cpu_mask); + cpu_set(cpu, nohz_cpu_mask); /* * Leave the clock comparator set up for the next timer * tick if either rcu or a softirq is pending. */ - if (rcu_pending(smp_processor_id()) || local_softirq_pending()) { - cpu_clear(smp_processor_id(), nohz_cpu_mask); + if (rcu_needs_cpu(cpu) || local_softirq_pending()) { + cpu_clear(cpu, nohz_cpu_mask); return; } -- cgit v1.2.3-70-g09d2 From ac924c6034d9095f95ee889f7e31bbb9145da0c2 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 15 May 2006 09:43:59 -0700 Subject: [PATCH] setup_per_zone_pages_min() overflow fix As pointed out in http://bugzilla.kernel.org/show_bug.cgi?id=6490, this function can experience overflows on 32-bit machines, causing our response to changed values of min_free_kbytes to go whacky. Fixing it efficiently is all too hard, so fix it with 64-bit math instead. Cc: Ake Sandgren Cc: Martin Bligh Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/page_alloc.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index ea77c999047e..813b4ec1298a 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -39,6 +39,7 @@ #include #include +#include #include "internal.h" /* @@ -2566,9 +2567,11 @@ void setup_per_zone_pages_min(void) } for_each_zone(zone) { - unsigned long tmp; + u64 tmp; + spin_lock_irqsave(&zone->lru_lock, flags); - tmp = (pages_min * zone->present_pages) / lowmem_pages; + tmp = (u64)pages_min * zone->present_pages; + do_div(tmp, lowmem_pages); if (is_highmem(zone)) { /* * __GFP_HIGH and PF_MEMALLOC allocations usually don't @@ -2595,8 +2598,8 @@ void setup_per_zone_pages_min(void) zone->pages_min = tmp; } - zone->pages_low = zone->pages_min + tmp / 4; - zone->pages_high = zone->pages_min + tmp / 2; + zone->pages_low = zone->pages_min + (tmp >> 2); + zone->pages_high = zone->pages_min + (tmp >> 1); spin_unlock_irqrestore(&zone->lru_lock, flags); } -- cgit v1.2.3-70-g09d2 From 698d070746770aaaec78ab4ffa3ab1f1d5c6abe8 Mon Sep 17 00:00:00 2001 From: Greg Smith Date: Mon, 15 May 2006 09:44:02 -0700 Subject: [PATCH] s390: lcs incorrect test While debugging why our LCS emulator is having some problems I noticed the following weirdness in drivers/s390/net/lcs.c routine lcs_irq. The `if' statement is always true since SCHN_STAT_PCI is defined as 0x80. Cc: Martin Schwidefsky Cc: Heiko Carstens Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/s390/net/lcs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index 5d6b7a57b02f..e65da921a827 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -1348,7 +1348,7 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) index = (struct ccw1 *) __va((addr_t) irb->scsw.cpa) - channel->ccws; if ((irb->scsw.actl & SCSW_ACTL_SUSPENDED) || - (irb->scsw.cstat | SCHN_STAT_PCI)) + (irb->scsw.cstat & SCHN_STAT_PCI)) /* Bloody io subsystem tells us lies about cpa... */ index = (index - 1) & (LCS_NUM_BUFFS - 1); while (channel->io_idx != index) { -- cgit v1.2.3-70-g09d2 From 6a050da45b5d855b48b057446847ff1542977b52 Mon Sep 17 00:00:00 2001 From: Mark Huang Date: Mon, 15 May 2006 09:44:03 -0700 Subject: [PATCH] initramfs: fix CPIO hardlink check Copy the filenames of hardlinks when inserting them into the hash, since the "name" pointer may point to scratch space (name_buf). Not doing so results in corruption if the scratch space is later overwritten: the wrong file may be hardlinked, or, if the scratch space contains garbage, the link will fail and a 0-byte file will be created instead. Signed-off-by: Mark Huang Acked-by: Al Viro Cc: "H. Peter Anvin" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- init/initramfs.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/init/initramfs.c b/init/initramfs.c index 679d870d991b..f81cfa40a719 100644 --- a/init/initramfs.c +++ b/init/initramfs.c @@ -26,10 +26,12 @@ static void __init free(void *where) /* link hash */ +#define N_ALIGN(len) ((((len) + 1) & ~3) + 2) + static __initdata struct hash { int ino, minor, major; struct hash *next; - char *name; + char name[N_ALIGN(PATH_MAX)]; } *head[32]; static inline int hash(int major, int minor, int ino) @@ -57,7 +59,7 @@ static char __init *find_link(int major, int minor, int ino, char *name) q->ino = ino; q->minor = minor; q->major = major; - q->name = name; + strcpy(q->name, name); q->next = NULL; *p = q; return NULL; @@ -133,8 +135,6 @@ static inline void eat(unsigned n) count -= n; } -#define N_ALIGN(len) ((((len) + 1) & ~3) + 2) - static __initdata char *collected; static __initdata int remains; static __initdata char *collect; -- cgit v1.2.3-70-g09d2 From 0159677857c5ada0a0a2c03a4dd59312382b73d0 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Mon, 15 May 2006 09:44:05 -0700 Subject: [PATCH] s390: add vmsplice system call Add new vmsplice system call and add missing __NR_xxx defines for sys_set_robust_list, sys_get_robust_list, sys_splice, sys_sync_file_range and sys_tee. Signed-off-by: Martin Schwidefsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/s390/kernel/compat_wrapper.S | 8 ++++++++ arch/s390/kernel/syscalls.S | 1 + include/asm-s390/unistd.h | 8 +++++++- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S index ef5b9c44b86b..4d53b2739357 100644 --- a/arch/s390/kernel/compat_wrapper.S +++ b/arch/s390/kernel/compat_wrapper.S @@ -1650,3 +1650,11 @@ sys_tee_wrapper: llgfr %r4,%r4 # size_t llgfr %r5,%r5 # unsigned int jg sys_tee + + .globl compat_sys_vmsplice_wrapper +compat_sys_vmsplice_wrapper: + lgfr %r2,%r2 # int + llgtr %r3,%r3 # compat_iovec * + llgfr %r4,%r4 # unsigned int + llgfr %r5,%r5 # unsigned int + jg compat_sys_vmsplice diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S index fc2c0767202b..93be1d56c036 100644 --- a/arch/s390/kernel/syscalls.S +++ b/arch/s390/kernel/syscalls.S @@ -317,3 +317,4 @@ SYSCALL(sys_get_robust_list,sys_get_robust_list,compat_sys_get_robust_list_wrapp SYSCALL(sys_splice,sys_splice,sys_splice_wrapper) SYSCALL(sys_sync_file_range,sys_sync_file_range,sys_sync_file_range_wrapper) SYSCALL(sys_tee,sys_tee,sys_tee_wrapper) +SYSCALL(sys_vmsplice,sys_vmsplice,compat_sys_vmsplice_wrapper) diff --git a/include/asm-s390/unistd.h b/include/asm-s390/unistd.h index 657d582e8149..41c2792ff6b0 100644 --- a/include/asm-s390/unistd.h +++ b/include/asm-s390/unistd.h @@ -296,8 +296,14 @@ #define __NR_pselect6 301 #define __NR_ppoll 302 #define __NR_unshare 303 +#define __NR_set_robust_list 304 +#define __NR_get_robust_list 305 +#define __NR_splice 306 +#define __NR_sync_file_range 307 +#define __NR_tee 308 +#define __NR_vmsplice 309 -#define NR_syscalls 304 +#define NR_syscalls 310 /* * There are some system calls that are not present on 64 bit, some -- cgit v1.2.3-70-g09d2 From 5e376613899076396d0c97de67ad072587267370 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Mon, 15 May 2006 09:44:06 -0700 Subject: [PATCH] symbol_put_addr() locks kernel Even since a previous patch: Fix race between CONFIG_DEBUG_SLABALLOC and modules Sun, 27 Jun 2004 17:55:19 +0000 (17:55 +0000) http://www.kernel.org/git/?p=linux/kernel/git/torvalds/old-2.6-bkcvs.git;a=commit;h=92b3db26d31cf21b70e3c1eadc56c179506d8fbe The function symbol_put_addr() will deadlock the kernel. symbol_put_addr() would acquire modlist_lock, then while holding the lock call two functions kernel_text_address() and module_text_address() which also try to acquire the same lock. This deadlocks the kernel of course. This patch changes symbol_put_addr() to not acquire the modlist_lock, it doesn't need it since it never looks at the module list directly. Also, it now uses core_kernel_text() instead of kernel_text_address(). The latter has an additional check for addr inside a module, but we don't need to do that since we call module_text_address() (the same function kernel_text_address uses) ourselves. Signed-off-by: Trent Piepho Cc: Zwane Mwaikambo Acked-by: Rusty Russell Cc: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/kernel.h | 1 + kernel/extable.c | 2 +- kernel/module.c | 12 ++++++------ 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/include/linux/kernel.h b/include/linux/kernel.h index e1bd0842f6a1..f4fc576ed4c4 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -124,6 +124,7 @@ extern int get_option(char **str, int *pint); extern char *get_options(const char *str, int nints, int *ints); extern unsigned long long memparse(char *ptr, char **retptr); +extern int core_kernel_text(unsigned long addr); extern int __kernel_text_address(unsigned long addr); extern int kernel_text_address(unsigned long addr); extern int session_of_pgrp(int pgrp); diff --git a/kernel/extable.c b/kernel/extable.c index 7501b531ceed..7fe262855317 100644 --- a/kernel/extable.c +++ b/kernel/extable.c @@ -40,7 +40,7 @@ const struct exception_table_entry *search_exception_tables(unsigned long addr) return e; } -static int core_kernel_text(unsigned long addr) +int core_kernel_text(unsigned long addr) { if (addr >= (unsigned long)_stext && addr <= (unsigned long)_etext) diff --git a/kernel/module.c b/kernel/module.c index d24deb0dbbc9..bbe04862e1b0 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -705,14 +705,14 @@ EXPORT_SYMBOL(__symbol_put); void symbol_put_addr(void *addr) { - unsigned long flags; + struct module *modaddr; - spin_lock_irqsave(&modlist_lock, flags); - if (!kernel_text_address((unsigned long)addr)) - BUG(); + if (core_kernel_text((unsigned long)addr)) + return; - module_put(module_text_address((unsigned long)addr)); - spin_unlock_irqrestore(&modlist_lock, flags); + if (!(modaddr = module_text_address((unsigned long)addr))) + BUG(); + module_put(modaddr); } EXPORT_SYMBOL_GPL(symbol_put_addr); -- cgit v1.2.3-70-g09d2 From 2e367a82fc2da335455984a7722c721dd3fa782b Mon Sep 17 00:00:00 2001 From: Marcelo Tosatti Date: Mon, 15 May 2006 09:44:08 -0700 Subject: [PATCH] Marcelo has moved Signed-off-by: Marcelo Tosatti Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- CREDITS | 9 ++------- MAINTAINERS | 2 +- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/CREDITS b/CREDITS index 6f50be37fa0f..9bf714a1c7d9 100644 --- a/CREDITS +++ b/CREDITS @@ -3241,14 +3241,9 @@ S: 12725 SW Millikan Way, Suite 400 S: Beaverton, Oregon 97005 S: USA -N: Marcelo W. Tosatti -E: marcelo.tosatti@cyclades.com -D: Miscellaneous kernel hacker +N: Marcelo Tosatti +E: marcelo@kvack.org D: v2.4 kernel maintainer -D: Current pc300/cyclades maintainer -S: Cyclades Corporation -S: Av Cristovao Colombo, 462. Floresta. -S: Porto Alegre S: Brazil N: Stefan Traby diff --git a/MAINTAINERS b/MAINTAINERS index 5e3355871416..cf147aed8df1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1662,7 +1662,7 @@ S: Maintained LINUX FOR POWERPC EMBEDDED PPC8XX P: Marcelo Tosatti -M: marcelo.tosatti@cyclades.com +M: marcelo@kvack.org W: http://www.penguinppc.org/ L: linuxppc-embedded@ozlabs.org S: Maintained -- cgit v1.2.3-70-g09d2 From 48564e628bd7662d7a0b3ac81c41cd0e4cc36dae Mon Sep 17 00:00:00 2001 From: Jan Niehusmann Date: Mon, 15 May 2006 09:44:12 -0700 Subject: [PATCH] smbfs: Fix slab corruption in samba error path Yesterday, I got the following error with 2.6.16.13 during a file copy from a smb filesystem over a wireless link. I guess there was some error on the wireless link, which in turn caused an error condition for the smb filesystem. In the log, smb_file_read reports error=4294966784 (0xfffffe00), which also shows up in the slab dumps, and also is -ERESTARTSYS. Error code 27499 corresponds to 0x6b6b, so the rq_errno field seems to be the only one being set after freeing the slab. In smb_add_request (which is the only place in smbfs where I found ERESTARTSYS), I found the following: if (!timeleft || signal_pending(current)) { /* * On timeout or on interrupt we want to try and remove the * request from the recvq/xmitq. */ smb_lock_server(server); if (!(req->rq_flags & SMB_REQ_RECEIVED)) { list_del_init(&req->rq_queue); smb_rput(req); } smb_unlock_server(server); } [...] if (signal_pending(current)) req->rq_errno = -ERESTARTSYS; I guess that some codepath like smbiod_flush() caused the request to be removed from the queue, and smb_rput(req) be called, without SMB_REQ_RECEIVED being set. This violates an asumption made by the quoted code. Then, the above code calls smb_rput(req) again, the req gets freed, and req->rq_errno = -ERESTARTSYS writes into the already freed slab. As list_del_init doesn't cause an error if called multiple times, that does cause the observed behaviour (freed slab with rq_errno=-ERESTARTSYS). If this observation is correct, the following patch should fix it. I wonder why the smb code uses list_del_init everywhere - using list_del instead would catch such situations by poisoning the next and prev pointers. May 4 23:29:21 knautsch kernel: [17180085.456000] ipw2200: Firmware error detected. Restarting. May 4 23:29:21 knautsch kernel: [17180085.456000] ipw2200: Sysfs 'error' log captured. May 4 23:33:02 knautsch kernel: [17180306.316000] ipw2200: Firmware error detected. Restarting. May 4 23:33:02 knautsch kernel: [17180306.316000] ipw2200: Sysfs 'error' log already exists. May 4 23:33:02 knautsch kernel: [17180306.968000] smb_file_read: //some_file validation failed, error=4294966784 May 4 23:34:18 knautsch kernel: [17180383.256000] smb_file_read: //some_file validation failed, error=4294966784 May 4 23:34:18 knautsch kernel: [17180383.284000] SMB connection re-established (-5) May 4 23:37:19 knautsch kernel: [17180563.956000] smb_file_read: //some_file validation failed, error=4294966784 May 4 23:40:09 knautsch kernel: [17180733.636000] smb_file_read: //some_file validation failed, error=4294966784 May 4 23:40:26 knautsch kernel: [17180750.700000] smb_file_read: //some_file validation failed, error=4294966784 May 4 23:43:02 knautsch kernel: [17180907.304000] smb_file_read: //some_file validation failed, error=4294966784 May 4 23:43:08 knautsch kernel: [17180912.324000] smb_file_read: //some_file validation failed, error=4294966784 May 4 23:43:34 knautsch kernel: [17180938.416000] smb_errno: class Unknown, code 27499 from command 0x6b May 4 23:43:34 knautsch kernel: [17180938.416000] Slab corruption: start=c4ebe09c, len=244 May 4 23:43:34 knautsch kernel: [17180938.416000] Redzone: 0x5a2cf071/0x5a2cf071. May 4 23:43:34 knautsch kernel: [17180938.416000] Last user: [](smb_rput+0x53/0x90 [smbfs]) May 4 23:43:34 knautsch kernel: [17180938.416000] 000: 6b 6b 6b 6b 6b 6b 6b 6b 6a 6b 6b 6b 6b 6b 6b 6b May 4 23:43:34 knautsch kernel: [17180938.416000] 0f0: 00 fe ff ff May 4 23:43:34 knautsch kernel: [17180938.416000] Next obj: start=c4ebe19c, len=244 May 4 23:43:34 knautsch kernel: [17180938.416000] Redzone: 0x5a2cf071/0x5a2cf071. May 4 23:43:34 knautsch kernel: [17180938.416000] Last user: [<00000000>](_stext+0x3feffde0/0x30) May 4 23:43:34 knautsch kernel: [17180938.416000] 000: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b May 4 23:43:34 knautsch kernel: [17180938.416000] 010: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b May 4 23:43:34 knautsch kernel: [17180938.460000] SMB connection re-established (-5) May 4 23:43:42 knautsch kernel: [17180946.292000] ipw2200: Firmware error detected. Restarting. May 4 23:43:42 knautsch kernel: [17180946.292000] ipw2200: Sysfs 'error' log already exists. May 4 23:45:04 knautsch kernel: [17181028.752000] ipw2200: Firmware error detected. Restarting. May 4 23:45:04 knautsch kernel: [17181028.752000] ipw2200: Sysfs 'error' log already exists. May 4 23:45:05 knautsch kernel: [17181029.868000] smb_file_read: //some_file validation failed, error=4294966784 May 4 23:45:36 knautsch kernel: [17181060.984000] smb_errno: class Unknown, code 27499 from command 0x6b May 4 23:45:36 knautsch kernel: [17181060.984000] Slab corruption: start=c4ebe09c, len=244 May 4 23:45:36 knautsch kernel: [17181060.984000] Redzone: 0x5a2cf071/0x5a2cf071. May 4 23:45:36 knautsch kernel: [17181060.984000] Last user: [](smb_rput+0x53/0x90 [smbfs]) May 4 23:45:36 knautsch kernel: [17181060.984000] 000: 6b 6b 6b 6b 6b 6b 6b 6b 6a 6b 6b 6b 6b 6b 6b 6b May 4 23:45:36 knautsch kernel: [17181060.984000] 0f0: 00 fe ff ff May 4 23:45:36 knautsch kernel: [17181060.984000] Next obj: start=c4ebe19c, len=244 May 4 23:45:36 knautsch kernel: [17181060.984000] Redzone: 0x5a2cf071/0x5a2cf071. May 4 23:45:36 knautsch kernel: [17181060.984000] Last user: [<00000000>](_stext+0x3feffde0/0x30) May 4 23:45:36 knautsch kernel: [17181060.984000] 000: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b May 4 23:45:36 knautsch kernel: [17181060.984000] 010: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b May 4 23:45:36 knautsch kernel: [17181061.024000] SMB connection re-established (-5) May 4 23:46:17 knautsch kernel: [17181102.132000] smb_file_read: //some_file validation failed, error=4294966784 May 4 23:47:46 knautsch kernel: [17181190.468000] smb_errno: class Unknown, code 27499 from command 0x6b May 4 23:47:46 knautsch kernel: [17181190.468000] Slab corruption: start=c4ebe09c, len=244 May 4 23:47:46 knautsch kernel: [17181190.468000] Redzone: 0x5a2cf071/0x5a2cf071. May 4 23:47:46 knautsch kernel: [17181190.468000] Last user: [](smb_rput+0x53/0x90 [smbfs]) May 4 23:47:46 knautsch kernel: [17181190.468000] 000: 6b 6b 6b 6b 6b 6b 6b 6b 6a 6b 6b 6b 6b 6b 6b 6b May 4 23:47:46 knautsch kernel: [17181190.468000] 0f0: 00 fe ff ff May 4 23:47:46 knautsch kernel: [17181190.468000] Next obj: start=c4ebe19c, len=244 May 4 23:47:46 knautsch kernel: [17181190.468000] Redzone: 0x5a2cf071/0x5a2cf071. May 4 23:47:46 knautsch kernel: [17181190.468000] Last user: [<00000000>](_stext+0x3feffde0/0x30) May 4 23:47:46 knautsch kernel: [17181190.468000] 000: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b May 4 23:47:46 knautsch kernel: [17181190.468000] 010: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b May 4 23:47:46 knautsch kernel: [17181190.492000] SMB connection re-established (-5) May 4 23:49:20 knautsch kernel: [17181284.828000] smb_file_read: //some_file validation failed, error=4294966784 May 4 23:49:39 knautsch kernel: [17181303.896000] smb_file_read: //some_file validation failed, error=4294966784 Signed-off-by: Jan Niehusmann Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/smbfs/request.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/smbfs/request.c b/fs/smbfs/request.c index c71c375863cc..c71dd2760d32 100644 --- a/fs/smbfs/request.c +++ b/fs/smbfs/request.c @@ -339,9 +339,11 @@ int smb_add_request(struct smb_request *req) /* * On timeout or on interrupt we want to try and remove the * request from the recvq/xmitq. + * First check if the request is still part of a queue. (May + * have been removed by some error condition) */ smb_lock_server(server); - if (!(req->rq_flags & SMB_REQ_RECEIVED)) { + if (!list_empty(&req->rq_queue)) { list_del_init(&req->rq_queue); smb_rput(req); } -- cgit v1.2.3-70-g09d2 From 39d24e64263cd3211705d3b61ea4171c65030921 Mon Sep 17 00:00:00 2001 From: Mike Kravetz Date: Mon, 15 May 2006 09:44:13 -0700 Subject: [PATCH] add slab_is_available() routine for boot code slab_is_available() indicates slab based allocators are available for use. SPARSEMEM code needs to know this as it can be called at various times during the boot process. Signed-off-by: Mike Kravetz Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/slab.h | 1 + mm/slab.c | 8 ++++++++ mm/sparse.c | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/include/linux/slab.h b/include/linux/slab.h index 3af03b19c983..2d985d59c7b8 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -150,6 +150,7 @@ static inline void *kcalloc(size_t n, size_t size, gfp_t flags) extern void kfree(const void *); extern unsigned int ksize(const void *); +extern int slab_is_available(void); #ifdef CONFIG_NUMA extern void *kmem_cache_alloc_node(kmem_cache_t *, gfp_t flags, int node); diff --git a/mm/slab.c b/mm/slab.c index c32af7e7581e..b1d643b5238d 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -700,6 +700,14 @@ static enum { FULL } g_cpucache_up; +/* + * used by boot code to determine if it can use slab based allocator + */ +int slab_is_available(void) +{ + return g_cpucache_up == FULL; +} + static DEFINE_PER_CPU(struct work_struct, reap_work); static void free_block(struct kmem_cache *cachep, void **objpp, int len, diff --git a/mm/sparse.c b/mm/sparse.c index d7c32de99ee8..c5e89eb9ac8f 100644 --- a/mm/sparse.c +++ b/mm/sparse.c @@ -32,7 +32,7 @@ static struct mem_section *sparse_index_alloc(int nid) unsigned long array_size = SECTIONS_PER_ROOT * sizeof(struct mem_section); - if (system_state == SYSTEM_RUNNING) + if (slab_is_available()) section = kmalloc_node(array_size, GFP_KERNEL, nid); else section = alloc_bootmem_node(NODE_DATA(nid), array_size); -- cgit v1.2.3-70-g09d2 From a8d2e7d95229db9999682113bfac40b49978f212 Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Mon, 15 May 2006 09:44:14 -0700 Subject: [PATCH] LED: Improve Kconfig information Improve the NEW_LEDS Kconfig information to say what it does as well as what it doesn't. Signed-off-by: Richard Purdie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/leds/Kconfig | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 3f5b64794542..626506234b76 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -4,8 +4,11 @@ menu "LED devices" config NEW_LEDS bool "LED Support" help - Say Y to enable Linux LED support. This is not related to standard - keyboard LEDs which are controlled via the input system. + Say Y to enable Linux LED support. This allows control of supported + LEDs from both userspace and optionally, by kernel events (triggers). + + This is not related to standard keyboard LEDs which are controlled + via the input system. config LEDS_CLASS tristate "LED Class Support" -- cgit v1.2.3-70-g09d2 From 68673afd443c5eeb4cebfb9026e3675f43d79f2b Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Mon, 15 May 2006 09:44:15 -0700 Subject: [PATCH] Backlight/LCD Class: Fix sysfs _store error handling The backlight and LCD class _store functions currently accept values like "34 some random strings" without error. This corrects them to return -EINVAL if the value is not numeric with an optional byte of trailing whitespace. Signed-off-by: Richard Purdie Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/backlight/backlight.c | 18 ++++++++++++------ drivers/video/backlight/lcd.c | 32 ++++++++++++++++---------------- 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c index 334b1db1bd7c..27597c576eff 100644 --- a/drivers/video/backlight/backlight.c +++ b/drivers/video/backlight/backlight.c @@ -29,12 +29,15 @@ static ssize_t backlight_show_power(struct class_device *cdev, char *buf) static ssize_t backlight_store_power(struct class_device *cdev, const char *buf, size_t count) { - int rc = -ENXIO, power; + int rc = -ENXIO; char *endp; struct backlight_device *bd = to_backlight_device(cdev); + int power = simple_strtoul(buf, &endp, 0); + size_t size = endp - buf; - power = simple_strtoul(buf, &endp, 0); - if (*endp && !isspace(*endp)) + if (*endp && isspace(*endp)) + size++; + if (size != count) return -EINVAL; down(&bd->sem); @@ -65,12 +68,15 @@ static ssize_t backlight_show_brightness(struct class_device *cdev, char *buf) static ssize_t backlight_store_brightness(struct class_device *cdev, const char *buf, size_t count) { - int rc = -ENXIO, brightness; + int rc = -ENXIO; char *endp; struct backlight_device *bd = to_backlight_device(cdev); + int brightness = simple_strtoul(buf, &endp, 0); + size_t size = endp - buf; - brightness = simple_strtoul(buf, &endp, 0); - if (*endp && !isspace(*endp)) + if (*endp && isspace(*endp)) + size++; + if (size != count) return -EINVAL; down(&bd->sem); diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c index 86908a60c630..bc8ab005a3fb 100644 --- a/drivers/video/backlight/lcd.c +++ b/drivers/video/backlight/lcd.c @@ -31,12 +31,15 @@ static ssize_t lcd_show_power(struct class_device *cdev, char *buf) static ssize_t lcd_store_power(struct class_device *cdev, const char *buf, size_t count) { - int rc, power; + int rc = -ENXIO; char *endp; struct lcd_device *ld = to_lcd_device(cdev); + int power = simple_strtoul(buf, &endp, 0); + size_t size = endp - buf; - power = simple_strtoul(buf, &endp, 0); - if (*endp && !isspace(*endp)) + if (*endp && isspace(*endp)) + size++; + if (size != count) return -EINVAL; down(&ld->sem); @@ -44,8 +47,7 @@ static ssize_t lcd_store_power(struct class_device *cdev, const char *buf, size_ pr_debug("lcd: set power to %d\n", power); ld->props->set_power(ld, power); rc = count; - } else - rc = -ENXIO; + } up(&ld->sem); return rc; @@ -53,14 +55,12 @@ static ssize_t lcd_store_power(struct class_device *cdev, const char *buf, size_ static ssize_t lcd_show_contrast(struct class_device *cdev, char *buf) { - int rc; + int rc = -ENXIO; struct lcd_device *ld = to_lcd_device(cdev); down(&ld->sem); if (likely(ld->props && ld->props->get_contrast)) rc = sprintf(buf, "%d\n", ld->props->get_contrast(ld)); - else - rc = -ENXIO; up(&ld->sem); return rc; @@ -68,12 +68,15 @@ static ssize_t lcd_show_contrast(struct class_device *cdev, char *buf) static ssize_t lcd_store_contrast(struct class_device *cdev, const char *buf, size_t count) { - int rc, contrast; + int rc = -ENXIO; char *endp; struct lcd_device *ld = to_lcd_device(cdev); + int contrast = simple_strtoul(buf, &endp, 0); + size_t size = endp - buf; - contrast = simple_strtoul(buf, &endp, 0); - if (*endp && !isspace(*endp)) + if (*endp && isspace(*endp)) + size++; + if (size != count) return -EINVAL; down(&ld->sem); @@ -81,8 +84,7 @@ static ssize_t lcd_store_contrast(struct class_device *cdev, const char *buf, si pr_debug("lcd: set contrast to %d\n", contrast); ld->props->set_contrast(ld, contrast); rc = count; - } else - rc = -ENXIO; + } up(&ld->sem); return rc; @@ -90,14 +92,12 @@ static ssize_t lcd_store_contrast(struct class_device *cdev, const char *buf, si static ssize_t lcd_show_max_contrast(struct class_device *cdev, char *buf) { - int rc; + int rc = -ENXIO; struct lcd_device *ld = to_lcd_device(cdev); down(&ld->sem); if (likely(ld->props)) rc = sprintf(buf, "%d\n", ld->props->max_contrast); - else - rc = -ENXIO; up(&ld->sem); return rc; -- cgit v1.2.3-70-g09d2 From 263de9b582b0f9b6ad5a0651b7df884fe80d6c3c Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Mon, 15 May 2006 09:44:16 -0700 Subject: [PATCH] LED: Add maintainer entry for the LED subsystem Add a MAINTAINERS entry for the LED subsystem. Signed-off-by: Richard Purdie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- MAINTAINERS | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index cf147aed8df1..246153dee7f1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1603,6 +1603,11 @@ M: James.Bottomley@HansenPartnership.com L: linux-scsi@vger.kernel.org S: Maintained +LED SUBSYSTEM +P: Richard Purdie +M: rpurdie@rpsys.net +S: Maintained + LEGO USB Tower driver P: Juergen Stuber M: starblue@users.sourceforge.net -- cgit v1.2.3-70-g09d2 From 3dc7b82ea7649356bf027fba50c16ca50cec31e2 Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Mon, 15 May 2006 09:44:17 -0700 Subject: [PATCH] LED: Fix sysfs store function error handling Fix the error handling of some LED _store functions. This corrects them to return -EINVAL if the value is not numeric with an optional byte of trailing whitespace. Signed-off-by: Richard Purdie Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/leds/led-class.c | 9 +++++++-- drivers/leds/ledtrig-timer.c | 17 +++++++++++++---- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index b0b5d05fadd6..c75d0ef1609c 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include "leds.h" @@ -43,9 +44,13 @@ static ssize_t led_brightness_store(struct class_device *dev, ssize_t ret = -EINVAL; char *after; unsigned long state = simple_strtoul(buf, &after, 10); + size_t count = after - buf; - if (after - buf > 0) { - ret = after - buf; + if (*after && isspace(*after)) + count++; + + if (count == size) { + ret = count; led_set_brightness(led_cdev, state); } diff --git a/drivers/leds/ledtrig-timer.c b/drivers/leds/ledtrig-timer.c index f484b5d6dbf8..fbf141ef46ec 100644 --- a/drivers/leds/ledtrig-timer.c +++ b/drivers/leds/ledtrig-timer.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "leds.h" @@ -69,11 +70,15 @@ static ssize_t led_delay_on_store(struct class_device *dev, const char *buf, int ret = -EINVAL; char *after; unsigned long state = simple_strtoul(buf, &after, 10); + size_t count = after - buf; - if (after - buf > 0) { + if (*after && isspace(*after)) + count++; + + if (count == size) { timer_data->delay_on = state; mod_timer(&timer_data->timer, jiffies + 1); - ret = after - buf; + ret = count; } return ret; @@ -97,11 +102,15 @@ static ssize_t led_delay_off_store(struct class_device *dev, const char *buf, int ret = -EINVAL; char *after; unsigned long state = simple_strtoul(buf, &after, 10); + size_t count = after - buf; + + if (*after && isspace(*after)) + count++; - if (after - buf > 0) { + if (count == size) { timer_data->delay_off = state; mod_timer(&timer_data->timer, jiffies + 1); - ret = after - buf; + ret = count; } return ret; -- cgit v1.2.3-70-g09d2 From 343f1fe6f2e3fb4912db241e639b0721c2e14f2e Mon Sep 17 00:00:00 2001 From: Latchesar Ionkov Date: Mon, 15 May 2006 09:44:18 -0700 Subject: [PATCH] v9fs: Twalk memory leak v9fs leaks memory if the file server responds with Rerror to a Twalk message. The patch fixes the leak. Signed-off-by: Latchesar Ionkov Cc: Eric Van Hensbergen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/9p/fcall.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/fs/9p/fcall.c b/fs/9p/fcall.c index 71742ba150c4..6f2617820a4e 100644 --- a/fs/9p/fcall.c +++ b/fs/9p/fcall.c @@ -98,23 +98,20 @@ v9fs_t_attach(struct v9fs_session_info *v9ses, char *uname, char *aname, static void v9fs_t_clunk_cb(void *a, struct v9fs_fcall *tc, struct v9fs_fcall *rc, int err) { - int fid; + int fid, id; struct v9fs_session_info *v9ses; - if (err) - return; - + id = 0; fid = tc->params.tclunk.fid; - kfree(tc); - - if (!rc) - return; - - v9ses = a; - if (rc->id == RCLUNK) - v9fs_put_idpool(fid, &v9ses->fidpool); + if (rc) + id = rc->id; + kfree(tc); kfree(rc); + if (id == RCLUNK) { + v9ses = a; + v9fs_put_idpool(fid, &v9ses->fidpool); + } } /** -- cgit v1.2.3-70-g09d2 From 41e5a6ac80c600e1f8bda0a4871f0b797e097d78 Mon Sep 17 00:00:00 2001 From: Latchesar Ionkov Date: Mon, 15 May 2006 09:44:21 -0700 Subject: [PATCH] v9fs: signal handling fixes Multiple races can happen when v9fs is interrupted by a signal and Tflush message is sent to the server. After v9fs sends Tflush it doesn't wait until it receives Rflush, and possibly the response of the original message. This behavior may confuse v9fs what fids are allocated by the file server. This patch fixes the races and the fid allocation. Signed-off-by: Latchesar Ionkov Cc: Eric Van Hensbergen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/9p/mux.c | 222 ++++++++++++++++++++++++++++++++---------------------- fs/9p/mux.h | 4 +- fs/9p/vfs_file.c | 13 +++- fs/9p/vfs_inode.c | 19 ++++- 4 files changed, 158 insertions(+), 100 deletions(-) diff --git a/fs/9p/mux.c b/fs/9p/mux.c index 3e5b124a7212..f4407eb276c7 100644 --- a/fs/9p/mux.c +++ b/fs/9p/mux.c @@ -50,15 +50,23 @@ enum { Wpending = 8, /* can write */ }; +enum { + None, + Flushing, + Flushed, +}; + struct v9fs_mux_poll_task; struct v9fs_req { + spinlock_t lock; int tag; struct v9fs_fcall *tcall; struct v9fs_fcall *rcall; int err; v9fs_mux_req_callback cb; void *cba; + int flush; struct list_head req_list; }; @@ -96,8 +104,8 @@ struct v9fs_mux_poll_task { struct v9fs_mux_rpc { struct v9fs_mux_data *m; - struct v9fs_req *req; int err; + struct v9fs_fcall *tcall; struct v9fs_fcall *rcall; wait_queue_head_t wqueue; }; @@ -524,10 +532,9 @@ again: static void process_request(struct v9fs_mux_data *m, struct v9fs_req *req) { - int ecode, tag; + int ecode; struct v9fs_str *ename; - tag = req->tag; if (!req->err && req->rcall->id == RERROR) { ecode = req->rcall->params.rerror.errno; ename = &req->rcall->params.rerror.error; @@ -553,23 +560,6 @@ static void process_request(struct v9fs_mux_data *m, struct v9fs_req *req) if (!req->err) req->err = -EIO; } - - if (req->err == ERREQFLUSH) - return; - - if (req->cb) { - dprintk(DEBUG_MUX, "calling callback tcall %p rcall %p\n", - req->tcall, req->rcall); - - (*req->cb) (req->cba, req->tcall, req->rcall, req->err); - req->cb = NULL; - } else - kfree(req->rcall); - - v9fs_mux_put_tag(m, tag); - - wake_up(&m->equeue); - kfree(req); } /** @@ -669,17 +659,26 @@ static void v9fs_read_work(void *a) list_for_each_entry_safe(rreq, rptr, &m->req_list, req_list) { if (rreq->tag == rcall->tag) { req = rreq; - req->rcall = rcall; - list_del(&req->req_list); - spin_unlock(&m->lock); - process_request(m, req); + if (req->flush != Flushing) + list_del(&req->req_list); break; } - } + spin_unlock(&m->lock); - if (!req) { - spin_unlock(&m->lock); + if (req) { + req->rcall = rcall; + process_request(m, req); + + if (req->flush != Flushing) { + if (req->cb) + (*req->cb) (req, req->cba); + else + kfree(req->rcall); + + wake_up(&m->equeue); + } + } else { if (err >= 0 && rcall->id != RFLUSH) dprintk(DEBUG_ERROR, "unexpected response mux %p id %d tag %d\n", @@ -746,7 +745,6 @@ static struct v9fs_req *v9fs_send_request(struct v9fs_mux_data *m, return ERR_PTR(-ENOMEM); v9fs_set_tag(tc, n); - if ((v9fs_debug_level&DEBUG_FCALL) == DEBUG_FCALL) { char buf[150]; @@ -754,12 +752,14 @@ static struct v9fs_req *v9fs_send_request(struct v9fs_mux_data *m, printk(KERN_NOTICE "<<< %p %s\n", m, buf); } + spin_lock_init(&req->lock); req->tag = n; req->tcall = tc; req->rcall = NULL; req->err = 0; req->cb = cb; req->cba = cba; + req->flush = None; spin_lock(&m->lock); list_add_tail(&req->req_list, &m->unsent_req_list); @@ -776,72 +776,108 @@ static struct v9fs_req *v9fs_send_request(struct v9fs_mux_data *m, return req; } -static void v9fs_mux_flush_cb(void *a, struct v9fs_fcall *tc, - struct v9fs_fcall *rc, int err) +static void v9fs_mux_free_request(struct v9fs_mux_data *m, struct v9fs_req *req) +{ + v9fs_mux_put_tag(m, req->tag); + kfree(req); +} + +static void v9fs_mux_flush_cb(struct v9fs_req *freq, void *a) { v9fs_mux_req_callback cb; int tag; struct v9fs_mux_data *m; - struct v9fs_req *req, *rptr; + struct v9fs_req *req, *rreq, *rptr; m = a; - dprintk(DEBUG_MUX, "mux %p tc %p rc %p err %d oldtag %d\n", m, tc, - rc, err, tc->params.tflush.oldtag); + dprintk(DEBUG_MUX, "mux %p tc %p rc %p err %d oldtag %d\n", m, + freq->tcall, freq->rcall, freq->err, + freq->tcall->params.tflush.oldtag); spin_lock(&m->lock); cb = NULL; - tag = tc->params.tflush.oldtag; - list_for_each_entry_safe(req, rptr, &m->req_list, req_list) { - if (req->tag == tag) { + tag = freq->tcall->params.tflush.oldtag; + req = NULL; + list_for_each_entry_safe(rreq, rptr, &m->req_list, req_list) { + if (rreq->tag == tag) { + req = rreq; list_del(&req->req_list); - if (req->cb) { - cb = req->cb; - req->cb = NULL; - spin_unlock(&m->lock); - (*cb) (req->cba, req->tcall, req->rcall, - req->err); - } - kfree(req); - wake_up(&m->equeue); break; } } + spin_unlock(&m->lock); - if (!cb) - spin_unlock(&m->lock); + if (req) { + spin_lock(&req->lock); + req->flush = Flushed; + spin_unlock(&req->lock); + + if (req->cb) + (*req->cb) (req, req->cba); + else + kfree(req->rcall); + + wake_up(&m->equeue); + } - v9fs_mux_put_tag(m, tag); - kfree(tc); - kfree(rc); + kfree(freq->tcall); + kfree(freq->rcall); + v9fs_mux_free_request(m, freq); } -static void +static int v9fs_mux_flush_request(struct v9fs_mux_data *m, struct v9fs_req *req) { struct v9fs_fcall *fc; + struct v9fs_req *rreq, *rptr; dprintk(DEBUG_MUX, "mux %p req %p tag %d\n", m, req, req->tag); + /* if a response was received for a request, do nothing */ + spin_lock(&req->lock); + if (req->rcall || req->err) { + spin_unlock(&req->lock); + dprintk(DEBUG_MUX, "mux %p req %p response already received\n", m, req); + return 0; + } + + req->flush = Flushing; + spin_unlock(&req->lock); + + spin_lock(&m->lock); + /* if the request is not sent yet, just remove it from the list */ + list_for_each_entry_safe(rreq, rptr, &m->unsent_req_list, req_list) { + if (rreq->tag == req->tag) { + dprintk(DEBUG_MUX, "mux %p req %p request is not sent yet\n", m, req); + list_del(&rreq->req_list); + req->flush = Flushed; + spin_unlock(&m->lock); + if (req->cb) + (*req->cb) (req, req->cba); + return 0; + } + } + spin_unlock(&m->lock); + + clear_thread_flag(TIF_SIGPENDING); fc = v9fs_create_tflush(req->tag); v9fs_send_request(m, fc, v9fs_mux_flush_cb, m); + return 1; } static void -v9fs_mux_rpc_cb(void *a, struct v9fs_fcall *tc, struct v9fs_fcall *rc, int err) +v9fs_mux_rpc_cb(struct v9fs_req *req, void *a) { struct v9fs_mux_rpc *r; - if (err == ERREQFLUSH) { - kfree(rc); - dprintk(DEBUG_MUX, "err req flush\n"); - return; - } - + dprintk(DEBUG_MUX, "req %p r %p\n", req, a); r = a; - dprintk(DEBUG_MUX, "mux %p req %p tc %p rc %p err %d\n", r->m, r->req, - tc, rc, err); - r->rcall = rc; - r->err = err; + r->rcall = req->rcall; + r->err = req->err; + + if (req->flush!=None && !req->err) + r->err = -ERESTARTSYS; + wake_up(&r->wqueue); } @@ -856,12 +892,13 @@ int v9fs_mux_rpc(struct v9fs_mux_data *m, struct v9fs_fcall *tc, struct v9fs_fcall **rc) { - int err; + int err, sigpending; unsigned long flags; struct v9fs_req *req; struct v9fs_mux_rpc r; r.err = 0; + r.tcall = tc; r.rcall = NULL; r.m = m; init_waitqueue_head(&r.wqueue); @@ -869,48 +906,50 @@ v9fs_mux_rpc(struct v9fs_mux_data *m, struct v9fs_fcall *tc, if (rc) *rc = NULL; + sigpending = 0; + if (signal_pending(current)) { + sigpending = 1; + clear_thread_flag(TIF_SIGPENDING); + } + req = v9fs_send_request(m, tc, v9fs_mux_rpc_cb, &r); if (IS_ERR(req)) { err = PTR_ERR(req); dprintk(DEBUG_MUX, "error %d\n", err); - return PTR_ERR(req); + return err; } - r.req = req; - dprintk(DEBUG_MUX, "mux %p tc %p tag %d rpc %p req %p\n", m, tc, - req->tag, &r, req); err = wait_event_interruptible(r.wqueue, r.rcall != NULL || r.err < 0); if (r.err < 0) err = r.err; if (err == -ERESTARTSYS && m->trans->status == Connected && m->err == 0) { - spin_lock(&m->lock); - req->tcall = NULL; - req->err = ERREQFLUSH; - spin_unlock(&m->lock); + if (v9fs_mux_flush_request(m, req)) { + /* wait until we get response of the flush message */ + do { + clear_thread_flag(TIF_SIGPENDING); + err = wait_event_interruptible(r.wqueue, + r.rcall || r.err); + } while (!r.rcall && !r.err && err==-ERESTARTSYS && + m->trans->status==Connected && !m->err); + } + sigpending = 1; + } - clear_thread_flag(TIF_SIGPENDING); - v9fs_mux_flush_request(m, req); + if (sigpending) { spin_lock_irqsave(¤t->sighand->siglock, flags); recalc_sigpending(); spin_unlock_irqrestore(¤t->sighand->siglock, flags); } - if (!err) { - if (r.rcall) - dprintk(DEBUG_MUX, "got response id %d tag %d\n", - r.rcall->id, r.rcall->tag); - - if (rc) - *rc = r.rcall; - else - kfree(r.rcall); - } else { + if (rc) + *rc = r.rcall; + else kfree(r.rcall); - dprintk(DEBUG_MUX, "got error %d\n", err); - if (err > 0) - err = -EIO; - } + + v9fs_mux_free_request(m, req); + if (err > 0) + err = -EIO; return err; } @@ -951,12 +990,15 @@ void v9fs_mux_cancel(struct v9fs_mux_data *m, int err) struct v9fs_req *req, *rtmp; LIST_HEAD(cancel_list); - dprintk(DEBUG_MUX, "mux %p err %d\n", m, err); + dprintk(DEBUG_ERROR, "mux %p err %d\n", m, err); m->err = err; spin_lock(&m->lock); list_for_each_entry_safe(req, rtmp, &m->req_list, req_list) { list_move(&req->req_list, &cancel_list); } + list_for_each_entry_safe(req, rtmp, &m->unsent_req_list, req_list) { + list_move(&req->req_list, &cancel_list); + } spin_unlock(&m->lock); list_for_each_entry_safe(req, rtmp, &cancel_list, req_list) { @@ -965,11 +1007,9 @@ void v9fs_mux_cancel(struct v9fs_mux_data *m, int err) req->err = err; if (req->cb) - (*req->cb) (req->cba, req->tcall, req->rcall, req->err); + (*req->cb) (req, req->cba); else kfree(req->rcall); - - kfree(req); } wake_up(&m->equeue); diff --git a/fs/9p/mux.h b/fs/9p/mux.h index e90bfd32ea42..fb10c50186a1 100644 --- a/fs/9p/mux.h +++ b/fs/9p/mux.h @@ -24,6 +24,7 @@ */ struct v9fs_mux_data; +struct v9fs_req; /** * v9fs_mux_req_callback - callback function that is called when the @@ -36,8 +37,7 @@ struct v9fs_mux_data; * @rc - response call * @err - error code (non-zero if error occured) */ -typedef void (*v9fs_mux_req_callback)(void *a, struct v9fs_fcall *tc, - struct v9fs_fcall *rc, int err); +typedef void (*v9fs_mux_req_callback)(struct v9fs_req *req, void *a); int v9fs_mux_global_init(void); void v9fs_mux_global_exit(void); diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index 083dcfcd158e..1a8e46084f0e 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c @@ -72,11 +72,17 @@ int v9fs_file_open(struct inode *inode, struct file *file) return -ENOSPC; } - err = v9fs_t_walk(v9ses, vfid->fid, fid, NULL, NULL); + err = v9fs_t_walk(v9ses, vfid->fid, fid, NULL, &fcall); if (err < 0) { dprintk(DEBUG_ERROR, "rewalk didn't work\n"); - goto put_fid; + if (fcall && fcall->id == RWALK) + goto clunk_fid; + else { + v9fs_put_idpool(fid, &v9ses->fidpool); + goto free_fcall; + } } + kfree(fcall); /* TODO: do special things for O_EXCL, O_NOFOLLOW, O_SYNC */ /* translate open mode appropriately */ @@ -109,8 +115,7 @@ int v9fs_file_open(struct inode *inode, struct file *file) clunk_fid: v9fs_t_clunk(v9ses, fid); -put_fid: - v9fs_put_idpool(fid, &v9ses->fidpool); +free_fcall: kfree(fcall); return err; diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 133db366d306..2cb87ba4b1c1 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -270,7 +270,10 @@ v9fs_create(struct v9fs_session_info *v9ses, u32 pfid, char *name, u32 perm, err = v9fs_t_walk(v9ses, pfid, fid, NULL, &fcall); if (err < 0) { PRINT_FCALL_ERROR("clone error", fcall); - goto put_fid; + if (fcall && fcall->id == RWALK) + goto clunk_fid; + else + goto put_fid; } kfree(fcall); @@ -322,6 +325,9 @@ v9fs_clone_walk(struct v9fs_session_info *v9ses, u32 fid, struct dentry *dentry) &fcall); if (err < 0) { + if (fcall && fcall->id == RWALK) + goto clunk_fid; + PRINT_FCALL_ERROR("walk error", fcall); v9fs_put_idpool(nfid, &v9ses->fidpool); goto error; @@ -640,19 +646,26 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, } result = v9fs_t_walk(v9ses, dirfidnum, newfid, - (char *)dentry->d_name.name, NULL); + (char *)dentry->d_name.name, &fcall); + if (result < 0) { - v9fs_put_idpool(newfid, &v9ses->fidpool); + if (fcall && fcall->id == RWALK) + v9fs_t_clunk(v9ses, newfid); + else + v9fs_put_idpool(newfid, &v9ses->fidpool); + if (result == -ENOENT) { d_add(dentry, NULL); dprintk(DEBUG_VFS, "Return negative dentry %p count %d\n", dentry, atomic_read(&dentry->d_count)); + kfree(fcall); return NULL; } dprintk(DEBUG_ERROR, "walk error:%d\n", result); goto FreeFcall; } + kfree(fcall); result = v9fs_t_stat(v9ses, newfid, &fcall); if (result < 0) { -- cgit v1.2.3-70-g09d2 From e6333fd4ddf7a583480017f535b9ea53c116ab81 Mon Sep 17 00:00:00 2001 From: Hua Zhong Date: Mon, 15 May 2006 09:44:22 -0700 Subject: [PATCH] fix can_share_swap_page() when !CONFIG_SWAP can_share_swap_page() is used to check if the page has the last reference. This avoids allocating a new page for COW if it's the last page. However, if CONFIG_SWAP is not set, can_share_swap_page() is defined as 0, thus always causes a copy for the last COW page. The below simple patch fixes it. Signed-off-by: Hua Zhong Cc: David Howells Cc: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/swap.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/swap.h b/include/linux/swap.h index 5b1fdf1cff4f..f03c24719302 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -296,7 +296,7 @@ static inline void disable_swap_token(void) #define read_swap_cache_async(swp,vma,addr) NULL #define lookup_swap_cache(swp) NULL #define valid_swaphandles(swp, off) 0 -#define can_share_swap_page(p) 0 +#define can_share_swap_page(p) (page_mapcount(p) == 1) #define move_to_swap_cache(p, swp) 1 #define move_from_swap_cache(p, i, m) 1 #define __delete_from_swap_cache(p) /*NOTHING*/ -- cgit v1.2.3-70-g09d2 From 64471ebe534dc6cedd72849b2324b52cb5249eb9 Mon Sep 17 00:00:00 2001 From: Benjamin LaHaise Date: Mon, 15 May 2006 09:44:24 -0700 Subject: [PATCH] Add Core Solo and Core Duo support to oprofile Add support to oprofile for the Intel Core Solo and Core Duo processors. See also the patch to add support to oprofile-0.9.1-8.1.1 at http://www.kvack.org/~bcrl/patches/oprofile/oprofile-core-0.9.1.diff . Signed-off-by: Benjamin LaHaise Cc: Philippe Elie Cc: John Levon Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/oprofile/nmi_int.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/i386/oprofile/nmi_int.c b/arch/i386/oprofile/nmi_int.c index 1a2076ce6f6a..ec0fd3cfa774 100644 --- a/arch/i386/oprofile/nmi_int.c +++ b/arch/i386/oprofile/nmi_int.c @@ -332,10 +332,11 @@ static int __init ppro_init(char ** cpu_type) { __u8 cpu_model = boot_cpu_data.x86_model; - if (cpu_model > 0xd) + if (cpu_model == 14) + *cpu_type = "i386/core"; + else if (cpu_model > 0xd) return 0; - - if (cpu_model == 9) { + else if (cpu_model == 9) { *cpu_type = "i386/p6_mobile"; } else if (cpu_model > 5) { *cpu_type = "i386/piii"; -- cgit v1.2.3-70-g09d2 From 2a7362f52a17e8dbeab57c00c3c45fcfeb0dff54 Mon Sep 17 00:00:00 2001 From: Kylene Jo Hall Date: Mon, 15 May 2006 09:44:25 -0700 Subject: [PATCH] tpm: fix constant Fix the constant used for the base address when it cannot be determined from ACPI. It was off by one order of magnitude. Signed-off-by: Kylene Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm_tis.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index b9cae9a238bb..f621168f38ae 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -55,7 +55,7 @@ enum tis_int_flags { }; enum tis_defaults { - TIS_MEM_BASE = 0xFED4000, + TIS_MEM_BASE = 0xFED40000, TIS_MEM_LEN = 0x5000, TIS_SHORT_TIMEOUT = 750, /* ms */ TIS_LONG_TIMEOUT = 2000, /* 2 sec */ -- cgit v1.2.3-70-g09d2 From 655fdeab809a5612b0eab6aee873b00d26404ca7 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 15 May 2006 09:44:26 -0700 Subject: [PATCH] Final rio polish Signed-off-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/Kconfig | 2 +- drivers/char/rio/host.h | 9 -------- drivers/char/rio/rioboot.c | 1 + drivers/char/rio/rioctrl.c | 43 ++++++++++++++++++++++------------ drivers/char/rio/rioioctl.h | 56 ++++----------------------------------------- 5 files changed, 35 insertions(+), 76 deletions(-) diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 402296670d3a..78d928f9d9f1 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -291,7 +291,7 @@ config SX config RIO tristate "Specialix RIO system support" - depends on SERIAL_NONSTANDARD && !64BIT + depends on SERIAL_NONSTANDARD help This is a driver for the Specialix RIO, a smart serial card which drives an outboard box that can support up to 128 ports. Product diff --git a/drivers/char/rio/host.h b/drivers/char/rio/host.h index 3ec73d1a279a..179cdbea712b 100644 --- a/drivers/char/rio/host.h +++ b/drivers/char/rio/host.h @@ -33,12 +33,6 @@ #ifndef __rio_host_h__ #define __rio_host_h__ -#ifdef SCCS_LABELS -#ifndef lint -static char *_host_h_sccs_ = "@(#)host.h 1.2"; -#endif -#endif - /* ** the host structure - one per host card in the system. */ @@ -77,9 +71,6 @@ struct Host { #define RC_STARTUP 1 #define RC_RUNNING 2 #define RC_STUFFED 3 -#define RC_SOMETHING 4 -#define RC_SOMETHING_NEW 5 -#define RC_SOMETHING_ELSE 6 #define RC_READY 7 #define RUN_STATE 7 /* diff --git a/drivers/char/rio/rioboot.c b/drivers/char/rio/rioboot.c index acda9326c2ef..290143addd34 100644 --- a/drivers/char/rio/rioboot.c +++ b/drivers/char/rio/rioboot.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/char/rio/rioctrl.c b/drivers/char/rio/rioctrl.c index d31aba62bb7f..75b2557c37ec 100644 --- a/drivers/char/rio/rioctrl.c +++ b/drivers/char/rio/rioctrl.c @@ -1394,14 +1394,17 @@ int RIOPreemptiveCmd(struct rio_info *p, struct Port *PortP, u8 Cmd) return RIO_FAIL; } - if (((int) ((char) PortP->InUse) == -1) || !(CmdBlkP = RIOGetCmdBlk())) { - rio_dprintk(RIO_DEBUG_CTRL, "Cannot allocate command block for command %d on port %d\n", Cmd, PortP->PortNum); + if ((PortP->InUse == (typeof(PortP->InUse))-1) || + !(CmdBlkP = RIOGetCmdBlk())) { + rio_dprintk(RIO_DEBUG_CTRL, "Cannot allocate command block " + "for command %d on port %d\n", Cmd, PortP->PortNum); return RIO_FAIL; } - rio_dprintk(RIO_DEBUG_CTRL, "Command blk %p - InUse now %d\n", CmdBlkP, PortP->InUse); + rio_dprintk(RIO_DEBUG_CTRL, "Command blk %p - InUse now %d\n", + CmdBlkP, PortP->InUse); - PktCmdP = (struct PktCmd_M *) &CmdBlkP->Packet.data[0]; + PktCmdP = (struct PktCmd_M *)&CmdBlkP->Packet.data[0]; CmdBlkP->Packet.src_unit = 0; if (PortP->SecondBlock) @@ -1425,38 +1428,46 @@ int RIOPreemptiveCmd(struct rio_info *p, struct Port *PortP, u8 Cmd) switch (Cmd) { case MEMDUMP: - rio_dprintk(RIO_DEBUG_CTRL, "Queue MEMDUMP command blk %p (addr 0x%x)\n", CmdBlkP, (int) SubCmd.Addr); + rio_dprintk(RIO_DEBUG_CTRL, "Queue MEMDUMP command blk %p " + "(addr 0x%x)\n", CmdBlkP, (int) SubCmd.Addr); PktCmdP->SubCommand = MEMDUMP; PktCmdP->SubAddr = SubCmd.Addr; break; case FCLOSE: - rio_dprintk(RIO_DEBUG_CTRL, "Queue FCLOSE command blk %p\n", CmdBlkP); + rio_dprintk(RIO_DEBUG_CTRL, "Queue FCLOSE command blk %p\n", + CmdBlkP); break; case READ_REGISTER: - rio_dprintk(RIO_DEBUG_CTRL, "Queue READ_REGISTER (0x%x) command blk %p\n", (int) SubCmd.Addr, CmdBlkP); + rio_dprintk(RIO_DEBUG_CTRL, "Queue READ_REGISTER (0x%x) " + "command blk %p\n", (int) SubCmd.Addr, CmdBlkP); PktCmdP->SubCommand = READ_REGISTER; PktCmdP->SubAddr = SubCmd.Addr; break; case RESUME: - rio_dprintk(RIO_DEBUG_CTRL, "Queue RESUME command blk %p\n", CmdBlkP); + rio_dprintk(RIO_DEBUG_CTRL, "Queue RESUME command blk %p\n", + CmdBlkP); break; case RFLUSH: - rio_dprintk(RIO_DEBUG_CTRL, "Queue RFLUSH command blk %p\n", CmdBlkP); + rio_dprintk(RIO_DEBUG_CTRL, "Queue RFLUSH command blk %p\n", + CmdBlkP); CmdBlkP->PostFuncP = RIORFlushEnable; break; case SUSPEND: - rio_dprintk(RIO_DEBUG_CTRL, "Queue SUSPEND command blk %p\n", CmdBlkP); + rio_dprintk(RIO_DEBUG_CTRL, "Queue SUSPEND command blk %p\n", + CmdBlkP); break; case MGET: - rio_dprintk(RIO_DEBUG_CTRL, "Queue MGET command blk %p\n", CmdBlkP); + rio_dprintk(RIO_DEBUG_CTRL, "Queue MGET command blk %p\n", + CmdBlkP); break; case MSET: case MBIC: case MBIS: CmdBlkP->Packet.data[4] = (char) PortP->ModemLines; - rio_dprintk(RIO_DEBUG_CTRL, "Queue MSET/MBIC/MBIS command blk %p\n", CmdBlkP); + rio_dprintk(RIO_DEBUG_CTRL, "Queue MSET/MBIC/MBIS command " + "blk %p\n", CmdBlkP); break; case WFLUSH: @@ -1465,12 +1476,14 @@ int RIOPreemptiveCmd(struct rio_info *p, struct Port *PortP, u8 Cmd) ** allowed then we should not bother sending any more to the ** RTA. */ - if ((int) ((char) PortP->WflushFlag) == (int) -1) { - rio_dprintk(RIO_DEBUG_CTRL, "Trashed WFLUSH, WflushFlag about to wrap!"); + if (PortP->WflushFlag == (typeof(PortP->WflushFlag))-1) { + rio_dprintk(RIO_DEBUG_CTRL, "Trashed WFLUSH, " + "WflushFlag about to wrap!"); RIOFreeCmdBlk(CmdBlkP); return (RIO_FAIL); } else { - rio_dprintk(RIO_DEBUG_CTRL, "Queue WFLUSH command blk %p\n", CmdBlkP); + rio_dprintk(RIO_DEBUG_CTRL, "Queue WFLUSH command " + "blk %p\n", CmdBlkP); CmdBlkP->PostFuncP = RIOWFlushMark; } break; diff --git a/drivers/char/rio/rioioctl.h b/drivers/char/rio/rioioctl.h index 14b83fae75c8..e8af5b30519e 100644 --- a/drivers/char/rio/rioioctl.h +++ b/drivers/char/rio/rioioctl.h @@ -33,10 +33,6 @@ #ifndef __rioioctl_h__ #define __rioioctl_h__ -#ifdef SCCS_LABELS -static char *_rioioctl_h_sccs_ = "@(#)rioioctl.h 1.2"; -#endif - /* ** RIO device driver - user ioctls and associated structures. */ @@ -44,55 +40,13 @@ static char *_rioioctl_h_sccs_ = "@(#)rioioctl.h 1.2"; struct portStats { int port; int gather; - ulong txchars; - ulong rxchars; - ulong opens; - ulong closes; - ulong ioctls; + unsigned long txchars; + unsigned long rxchars; + unsigned long opens; + unsigned long closes; + unsigned long ioctls; }; - -#define rIOC ('r'<<8) -#define TCRIOSTATE (rIOC | 1) -#define TCRIOXPON (rIOC | 2) -#define TCRIOXPOFF (rIOC | 3) -#define TCRIOXPCPS (rIOC | 4) -#define TCRIOXPRINT (rIOC | 5) -#define TCRIOIXANYON (rIOC | 6) -#define TCRIOIXANYOFF (rIOC | 7) -#define TCRIOIXONON (rIOC | 8) -#define TCRIOIXONOFF (rIOC | 9) -#define TCRIOMBIS (rIOC | 10) -#define TCRIOMBIC (rIOC | 11) -#define TCRIOTRIAD (rIOC | 12) -#define TCRIOTSTATE (rIOC | 13) - -/* -** 15.10.1998 ARG - ESIL 0761 part fix -** Add RIO ioctls for manipulating RTS and CTS flow control, (as LynxOS -** appears to not support hardware flow control). -*/ -#define TCRIOCTSFLOWEN (rIOC | 14) /* enable CTS flow control */ -#define TCRIOCTSFLOWDIS (rIOC | 15) /* disable CTS flow control */ -#define TCRIORTSFLOWEN (rIOC | 16) /* enable RTS flow control */ -#define TCRIORTSFLOWDIS (rIOC | 17) /* disable RTS flow control */ - -/* -** 09.12.1998 ARG - ESIL 0776 part fix -** Definition for 'RIOC' also appears in daemon.h, so we'd better do a -** #ifndef here first. -** 'RIO_QUICK_CHECK' also #define'd here as this ioctl is now -** allowed to be used by customers. -** -** 05.02.1999 ARG - -** This is what I've decied to do with ioctls etc., which are intended to be -** invoked from users applications : -** Anything that needs to be defined here will be removed from daemon.h, that -** way it won't end up having to be defined/maintained in two places. The only -** consequence of this is that this file should now be #include'd by daemon.h -** -** 'stats' ioctls now #define'd here as they are to be used by customers. -*/ #define RIOC ('R'<<8)|('i'<<16)|('o'<<24) #define RIO_QUICK_CHECK (RIOC | 105) -- cgit v1.2.3-70-g09d2 From bb53a76116a8af13ee2581c85c02fe40e0c1a599 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Mon, 15 May 2006 09:44:27 -0700 Subject: [PATCH] tpm_register_hardware gcc 4.1 warning fix drivers/char/tpm/tpm.c: In function 'tpm_register_hardware': drivers/char/tpm/tpm.c:1157: warning: assignment from incompatible pointer type Signed-off-by: Daniel Walker Acked-by: Kylene Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 54a4c804e25f..050ced247f68 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -140,7 +140,7 @@ extern int tpm_pm_resume(struct device *); extern struct dentry ** tpm_bios_log_setup(char *); extern void tpm_bios_log_teardown(struct dentry **); #else -static inline struct dentry* tpm_bios_log_setup(char *name) +static inline struct dentry ** tpm_bios_log_setup(char *name) { return NULL; } -- cgit v1.2.3-70-g09d2 From 3835a9bd07778d87dea37fbf190f70883515e8fc Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Mon, 15 May 2006 09:44:27 -0700 Subject: [PATCH] fs/compat.c: fix 'if (a |= b )' typo Mentioned by Mark Armbrust somewhere on Usenet. Signed-off-by: Alexey Dobriyan Cc: David Woodhouse Cc: Ulrich Drepper Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/compat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/compat.c b/fs/compat.c index 970888aad843..01f39f87f372 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -1913,7 +1913,7 @@ asmlinkage long compat_sys_ppoll(struct pollfd __user *ufds, } if (sigmask) { - if (sigsetsize |= sizeof(compat_sigset_t)) + if (sigsetsize != sizeof(compat_sigset_t)) return -EINVAL; if (copy_from_user(&ss32, sigmask, sizeof(ss32))) return -EFAULT; -- cgit v1.2.3-70-g09d2 From be6e028b6422878df2e799a74609a03a553c7dad Mon Sep 17 00:00:00 2001 From: Andy Whitcroft Date: Mon, 15 May 2006 09:44:29 -0700 Subject: [PATCH] root mount failure: emit filesystems attempted When we fail to mount from a valid root device list out the filesystems we have tried to mount it with. This gives the user vital diagnostics as to what is missing from their kernel. For example in the fragment below the kernel does not have CRAMFS compiled into the kernel and yet appears to recognise it at the RAMDISK detect stage. Later the mount fails as we don't have the filesystem. RAMDISK: cramfs filesystem found at block 0 RAMDISK: Loading 1604KiB [1 disk] into ram disk... done. XFS: bad magic number XFS: SB validate failed No filesystem could mount root, tried: reiserfs ext3 ext2 msdos vfat iso9660 jfs xfs Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(8,1) Signed-off-by: Andy Whitcroft Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- init/do_mounts.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/init/do_mounts.c b/init/do_mounts.c index adb7cad3e6ee..f4b7b9d278cd 100644 --- a/init/do_mounts.c +++ b/init/do_mounts.c @@ -310,6 +310,11 @@ retry: panic("VFS: Unable to mount root fs on %s", b); } + + printk("No filesystem could mount root, tried: "); + for (p = fs_names; *p; p += strlen(p)+1) + printk(" %s", p); + printk("\n"); panic("VFS: Unable to mount root fs on %s", __bdevname(ROOT_DEV, b)); out: putname(fs_names); -- cgit v1.2.3-70-g09d2 From eee391a66d774e644bf3cbb35403562e09d88bb2 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 15 May 2006 09:44:30 -0700 Subject: [PATCH] revert "vfs: propagate mnt_flags into do_loopback/vfsmount" Revert commit f6422f17d3a480f21917a3895e2a46b968f56a08, due to Valdis.Kletnieks@vt.edu wrote: > > There seems to have been a bug introduced in this changeset: > > Am running 2.6.17-rc3-mm1. When this changeset is applied, 'mount --bind' > misbehaves: > > > # mkdir /foo > > # mount -t tmpfs -o rw,nosuid,nodev,noexec,noatime,nodiratime none /foo > > # mkdir /foo/bar > > # mount --bind /foo/bar /foo > > # tail -2 /proc/mounts > > none /foo tmpfs rw,nosuid,nodev,noexec,noatime,nodiratime 0 0 > > none /foo tmpfs rw 0 0 > > Reverting this changeset causes both mounts to have the same options. > > (Thanks to Stephen Smalley for tracking down the changeset...) > Cc: Herbert Poetzl Cc: Christoph Hellwig Cc: Cc: Stephen Smalley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/namespace.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/fs/namespace.c b/fs/namespace.c index 2c5f1f80bdc2..bf478addb852 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -899,13 +899,11 @@ static int do_change_type(struct nameidata *nd, int flag) /* * do loopback mount. */ -static int do_loopback(struct nameidata *nd, char *old_name, unsigned long flags, int mnt_flags) +static int do_loopback(struct nameidata *nd, char *old_name, int recurse) { struct nameidata old_nd; struct vfsmount *mnt = NULL; - int recurse = flags & MS_REC; int err = mount_is_safe(nd); - if (err) return err; if (!old_name || !*old_name) @@ -939,7 +937,6 @@ static int do_loopback(struct nameidata *nd, char *old_name, unsigned long flags spin_unlock(&vfsmount_lock); release_mounts(&umount_list); } - mnt->mnt_flags = mnt_flags; out: up_write(&namespace_sem); @@ -1353,7 +1350,7 @@ long do_mount(char *dev_name, char *dir_name, char *type_page, retval = do_remount(&nd, flags & ~MS_REMOUNT, mnt_flags, data_page); else if (flags & MS_BIND) - retval = do_loopback(&nd, dev_name, flags, mnt_flags); + retval = do_loopback(&nd, dev_name, flags & MS_REC); else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE)) retval = do_change_type(&nd, flags); else if (flags & MS_MOVE) -- cgit v1.2.3-70-g09d2 From ce007ea59729d627f62bb5fa8c1a81e25653a0ad Mon Sep 17 00:00:00 2001 From: Carl-Daniel Hailfinger Date: Mon, 15 May 2006 09:44:33 -0700 Subject: [PATCH] smbus unhiding kills thermal management Do not enable the SMBus device on Asus boards if suspend is used. We do not reenable the device on resume, leading to all sorts of undesirable effects, the worst being a total fan failure after resume on Samsung P35 laptop. Signed-off-by: Carl-Daniel Hailfinger Signed-off-by: Pavel Machek Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pci/quirks.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 0d36d5040880..d378478612fb 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -902,6 +902,7 @@ static void __init k8t_sound_hostbridge(struct pci_dev *dev) } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, k8t_sound_hostbridge); +#ifndef CONFIG_ACPI_SLEEP /* * On ASUS P4B boards, the SMBus PCI Device within the ICH2/4 southbridge * is not activated. The myth is that Asus said that they do not want the @@ -913,8 +914,12 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, k8t_sound_ho * bridge. Unfortunately, this device has no subvendor/subdevice ID. So it * becomes necessary to do this tweak in two steps -- I've chosen the Host * bridge as trigger. + * + * Actually, leaving it unhidden and not redoing the quirk over suspend2ram + * will cause thermal management to break down, and causing machine to + * overheat. */ -static int __initdata asus_hides_smbus = 0; +static int __initdata asus_hides_smbus; static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev) { @@ -1057,6 +1062,8 @@ static void __init asus_hides_smbus_lpc_ich6(struct pci_dev *dev) } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, asus_hides_smbus_lpc_ich6 ); +#endif + /* * SiS 96x south bridge: BIOS typically hides SMBus device... */ -- cgit v1.2.3-70-g09d2 From b2d596d8e08099b47e0a75aa4b7f82aae780e851 Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Mon, 15 May 2006 09:44:34 -0700 Subject: [PATCH] fix hotplug kconfig help HOTPLUG_CPU entry says "Say Y..." then "Say N.". Slightly ugly, so I fixed it up, and added remark about suspend on SMP as a bonus. Signed-off-by: Pavel Machek Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/Kconfig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig index c6fe99e57a05..8dfa3054f10f 100644 --- a/arch/i386/Kconfig +++ b/arch/i386/Kconfig @@ -758,10 +758,10 @@ config HOTPLUG_CPU bool "Support for hot-pluggable CPUs (EXPERIMENTAL)" depends on SMP && HOTPLUG && EXPERIMENTAL && !X86_VOYAGER ---help--- - Say Y here to experiment with turning CPUs off and on. CPUs - can be controlled through /sys/devices/system/cpu. + Say Y here to experiment with turning CPUs off and on, and to + enable suspend on SMP systems. CPUs can be controlled through + /sys/devices/system/cpu. - Say N. endmenu -- cgit v1.2.3-70-g09d2 From bfe2e9349f318883c036607c64b6205d573a28ff Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Mon, 15 May 2006 09:44:35 -0700 Subject: [PATCH] gigaset: endian fix Signed-off-by: Alexey Dobriyan Cc: Hansjoerg Lipp Cc: Tilman Schmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/isdn/gigaset/usb-gigaset.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c index bfb73fd5077e..d86ab68114b0 100644 --- a/drivers/isdn/gigaset/usb-gigaset.c +++ b/drivers/isdn/gigaset/usb-gigaset.c @@ -710,8 +710,8 @@ static int gigaset_probe(struct usb_interface *interface, retval = -ENODEV; //FIXME /* See if the device offered us matches what we can accept */ - if ((le16_to_cpu(udev->descriptor.idVendor != USB_M105_VENDOR_ID)) || - (le16_to_cpu(udev->descriptor.idProduct != USB_M105_PRODUCT_ID))) + if ((le16_to_cpu(udev->descriptor.idVendor) != USB_M105_VENDOR_ID) || + (le16_to_cpu(udev->descriptor.idProduct) != USB_M105_PRODUCT_ID)) return -ENODEV; /* this starts to become ascii art... */ -- cgit v1.2.3-70-g09d2 From 79afecfaabbe42e2a8a7e28880517f1721f2f3a7 Mon Sep 17 00:00:00 2001 From: Aneesh Kumar Date: Mon, 15 May 2006 09:44:36 -0700 Subject: [PATCH] Fix typos in Documentation/memory-barriers.txt Fix some typos in Documentation/memory-barriers.txt Signed-off-by: Aneesh Kumar K.V Cc: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/memory-barriers.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt index 92f0056d928c..c61d8b876fdb 100644 --- a/Documentation/memory-barriers.txt +++ b/Documentation/memory-barriers.txt @@ -1031,7 +1031,7 @@ conflict on any particular lock. LOCKS VS MEMORY ACCESSES ------------------------ -Consider the following: the system has a pair of spinlocks (N) and (Q), and +Consider the following: the system has a pair of spinlocks (M) and (Q), and three CPUs; then should the following sequence of events occur: CPU 1 CPU 2 @@ -1678,7 +1678,7 @@ CPU's caches by some other cache event: smp_wmb(); - p = &b; q = p; + p = &v; q = p; -- cgit v1.2.3-70-g09d2 From 264a341231e8af2c2e35ac15d26de76f1198525b Mon Sep 17 00:00:00 2001 From: Thomas Kleffel Date: Mon, 15 May 2006 09:44:37 -0700 Subject: [PATCH] ide_cs: Add IBM microdrive to known IDs Add the IBM microdrive to the known PCMCIA IDs for ide_cs. Signed-off-by: Thomas Kleffel Cc: Bartlomiej Zolnierkiewicz Cc: Alan Cox Cc: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/ide/legacy/ide-cs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c index 4961f1e764a7..602797a44208 100644 --- a/drivers/ide/legacy/ide-cs.c +++ b/drivers/ide/legacy/ide-cs.c @@ -392,6 +392,7 @@ static struct pcmcia_device_id ide_ids[] = { PCMCIA_DEVICE_PROD_ID12("FREECOM", "PCCARD-IDE", 0x5714cbf7, 0x48e0ab8e), PCMCIA_DEVICE_PROD_ID12("HITACHI", "FLASH", 0xf4f43949, 0x9eb86aae), PCMCIA_DEVICE_PROD_ID12("HITACHI", "microdrive", 0xf4f43949, 0xa6d76178), + PCMCIA_DEVICE_PROD_ID12("IBM", "microdrive", 0xb569a6e5, 0xa6d76178), PCMCIA_DEVICE_PROD_ID12("IBM", "IBM17JSSFP20", 0xb569a6e5, 0xf2508753), PCMCIA_DEVICE_PROD_ID12("IO DATA", "CBIDE2 ", 0x547e66dc, 0x8671043b), PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDE", 0x547e66dc, 0x5c5ab149), -- cgit v1.2.3-70-g09d2 From d3779e7989cfdba854b843fe605f8df9e991cd18 Mon Sep 17 00:00:00 2001 From: Peter Osterlund Date: Mon, 15 May 2006 09:44:40 -0700 Subject: [PATCH] devices.txt: remove pktcdvd entry Changing the driver to use dynamic device numbers was one of the many changes that were made in order to have the driver accepted into the mainline kernel. Therefore I would say that the entry in devices.txt is obsolete. This patch removes it. Signed-off-by: Peter Osterlund Cc: Torben Mathiasen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/devices.txt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Documentation/devices.txt b/Documentation/devices.txt index 3c406acd4dfa..b369a8c46a73 100644 --- a/Documentation/devices.txt +++ b/Documentation/devices.txt @@ -1721,11 +1721,6 @@ Your cooperation is appreciated. These devices support the same API as the generic SCSI devices. - 97 block Packet writing for CD/DVD devices - 0 = /dev/pktcdvd0 First packet-writing module - 1 = /dev/pktcdvd1 Second packet-writing module - ... - 98 char Control and Measurement Device (comedi) 0 = /dev/comedi0 First comedi device 1 = /dev/comedi1 Second comedi device -- cgit v1.2.3-70-g09d2 From 194a61b8e09ac526c33777a688ee2a1504d7fbc3 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 15 May 2006 09:44:42 -0700 Subject: [PATCH] jffs2 warning fixes fs/jffs2/nodelist.c: In function `check_node_data': fs/jffs2/nodelist.c:441: warning: unsigned int format, different type arg (arg 4) fs/jffs2/nodelist.c:464: warning: int format, different type arg (arg 5) Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/jffs2/nodelist.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c index d4d0c41490cd..1d46677afd17 100644 --- a/fs/jffs2/nodelist.c +++ b/fs/jffs2/nodelist.c @@ -438,7 +438,8 @@ static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info if (c->mtd->point) { err = c->mtd->point(c->mtd, ofs, len, &retlen, &buffer); if (!err && retlen < tn->csize) { - JFFS2_WARNING("MTD point returned len too short: %u instead of %u.\n", retlen, tn->csize); + JFFS2_WARNING("MTD point returned len too short: %zu " + "instead of %u.\n", retlen, tn->csize); c->mtd->unpoint(c->mtd, buffer, ofs, len); } else if (err) JFFS2_WARNING("MTD point failed: error code %d.\n", err); @@ -461,7 +462,8 @@ static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info } if (retlen != len) { - JFFS2_ERROR("short read at %#08x: %d instead of %d.\n", ofs, retlen, len); + JFFS2_ERROR("short read at %#08x: %zd instead of %d.\n", + ofs, retlen, len); err = -EIO; goto free_out; } -- cgit v1.2.3-70-g09d2 From c4694c76ce28dd7e415b4f3014d8c6e580b5f3d2 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 15 May 2006 09:44:43 -0700 Subject: [PATCH] dl2k needs dma-mapping.h On alpha: drivers/net/dl2k.c: In function `rio_free_tx': drivers/net/dl2k.c:768: error: `DMA_48BIT_MASK' undeclared (first use in this function) drivers/net/dl2k.c:768: error: (Each undeclared identifier is reported only once drivers/net/dl2k.c:768: error: for each function it appears in.) drivers/net/dl2k.c: In function `receive_packet': drivers/net/dl2k.c:896: error: `DMA_48BIT_MASK' undeclared (first use in this function) drivers/net/dl2k.c: In function `rio_close': drivers/net/dl2k.c:1803: error: `DMA_48BIT_MASK' undeclared (first use in this function) Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/dl2k.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c index 1ddefd281213..038447fb5c5e 100644 --- a/drivers/net/dl2k.c +++ b/drivers/net/dl2k.c @@ -53,6 +53,7 @@ #define DRV_VERSION "v1.17b" #define DRV_RELDATE "2006/03/10" #include "dl2k.h" +#include static char version[] __devinitdata = KERN_INFO DRV_NAME " " DRV_VERSION " " DRV_RELDATE "\n"; -- cgit v1.2.3-70-g09d2 From 5b5ffbc1e6d62d89747f3f59c09b2e488a7d7fce Mon Sep 17 00:00:00 2001 From: Florin Malita Date: Mon, 15 May 2006 23:42:31 +0100 Subject: [PATCH] jffs2: memory leak in jffs2_scan_medium() If jffs2_scan_eraseblock() fails and the exit path is taken, 's' is not being deallocated. Reported by Coverity, CID: 1258. Signed-off-by: Florin Malita Signed-off-by: David Woodhouse --- fs/jffs2/scan.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index cf55b221fc2b..eca0996def60 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -222,9 +222,6 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) } } - if (jffs2_sum_active() && s) - kfree(s); - /* Nextblock dirty is always seen as wasted, because we cannot recycle it now */ if (c->nextblock && (c->nextblock->dirty_size)) { c->nextblock->wasted_size += c->nextblock->dirty_size; @@ -266,6 +263,9 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) else c->mtd->unpoint(c->mtd, flashbuf, 0, c->mtd->size); #endif + if (s) + kfree(s); + return ret; } -- cgit v1.2.3-70-g09d2 From f41a5f804a5862e9b87cf2d4cca1d6a7db7a9e82 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 16 May 2006 13:11:47 +0100 Subject: [MTD] Add help text for MTD_NAND_CS553X option. Signed-off-by: David Woodhouse --- drivers/mtd/nand/Kconfig | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index b4a7086b219c..b1f807980b79 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -192,12 +192,21 @@ config MTD_NAND_SHARPSL config MTD_NAND_CS553X tristate "NAND support for CS5535/CS5536 (AMD Geode companion chip)" depends on MTD_NAND && X86_PC && PCI - + help + The CS553x companion chips for the AMD Geode processor + include NAND flash controllers with built-in hardware ECC + capabilities; enabling this option will allow you to use + these. The driver will check the MSRs to verify that the + controller is enabled for NAND, and currently requires that + the controller be in MMIO mode. + + If you say "m", the module will be called "cs553x_nand.ko". + config MTD_NAND_NANDSIM tristate "Support for NAND Flash Simulator" depends on MTD_NAND && MTD_PARTITIONS help - The simulator may simulate verious NAND flash chips for the + The simulator may simulate various NAND flash chips for the MTD nand layer. endmenu -- cgit v1.2.3-70-g09d2 From ce589a0328866228412ea0df2c834688da8f4700 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 16 May 2006 13:46:44 +0200 Subject: drivers/mtd/devices/docprobe.c: correct #if's On Mon, May 15, 2006 at 12:56:37AM -0700, Andrew Morton wrote: >... > Changes since 2.6.17-rc3-mm1: >... > git-mtd.patch >... > git trees >... If we correct the names of the config options, the code might actually work as intended... Signed-off-by: Adrian Bunk Signed-off-by: David Woodhouse --- drivers/mtd/devices/docprobe.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/devices/docprobe.c b/drivers/mtd/devices/docprobe.c index 32f1d332f5b5..42ec08416a60 100644 --- a/drivers/mtd/devices/docprobe.c +++ b/drivers/mtd/devices/docprobe.c @@ -231,21 +231,21 @@ static inline int __init doccheck(void __iomem *potential, unsigned long physadr static int docfound; -#ifdef CONFIG_DOC2000 +#ifdef CONFIG_MTD_DOC2000 extern void DoC2k_init(struct mtd_info *); #define doc2k_initfunc (&DoC2k_init) #else #define doc2k_initfunc NULL #endif -#ifdef CONFIG_DOC2001 +#ifdef CONFIG_MTD_DOC2001 extern void DoCMil_init(struct mtd_info *); #define docmil_initfunc (&DoCMil_init) #else #define docmil_initfunc NULL #endif -#ifdef CONFIG_DOC2001PLUS +#ifdef CONFIG_MTD_DOC2001PLUS extern void DoCMilPlus_init(struct mtd_info *); #define docmplus_initfunc (&DoCMilPlus_init) #else -- cgit v1.2.3-70-g09d2 From cead4dbc03ba6eb2e35bac04439b76a0cc2286ce Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 16 May 2006 13:54:50 +0100 Subject: [MTD NAND] Make various initfuncs static, remove #ifdef MODULE from exitfuncs We all inherited the same error from the original NAND board driver which got copied and changed. Fix them all at once... Signed-off-by: David Woodhouse --- drivers/mtd/nand/au1550nd.c | 4 +--- drivers/mtd/nand/autcpu12.c | 4 +--- drivers/mtd/nand/cs553x_nand.c | 2 +- drivers/mtd/nand/rtc_from4.c | 4 +--- drivers/mtd/nand/sharpsl.c | 4 +--- drivers/mtd/nand/spia.c | 4 +--- drivers/mtd/nand/toto.c | 2 +- 7 files changed, 7 insertions(+), 17 deletions(-) diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c index 87d34351a86d..861fb961d942 100644 --- a/drivers/mtd/nand/au1550nd.c +++ b/drivers/mtd/nand/au1550nd.c @@ -321,7 +321,7 @@ int au1550_device_ready(struct mtd_info *mtd) /* * Main initialization routine */ -int __init au1xxx_nand_init(void) +static int __init au1xxx_nand_init(void) { struct nand_chip *this; u16 boot_swapboot = 0; /* default value */ @@ -480,7 +480,6 @@ module_init(au1xxx_nand_init); /* * Clean up routine */ -#ifdef MODULE static void __exit au1550_cleanup(void) { struct nand_chip *this = (struct nand_chip *)&au1550_mtd[1]; @@ -496,7 +495,6 @@ static void __exit au1550_cleanup(void) } module_exit(au1550_cleanup); -#endif MODULE_LICENSE("GPL"); MODULE_AUTHOR("Embedded Edge, LLC"); diff --git a/drivers/mtd/nand/autcpu12.c b/drivers/mtd/nand/autcpu12.c index 330deb032217..43b296040d7f 100644 --- a/drivers/mtd/nand/autcpu12.c +++ b/drivers/mtd/nand/autcpu12.c @@ -124,7 +124,7 @@ int autcpu12_device_ready(struct mtd_info *mtd) /* * Main initialization routine */ -int __init autcpu12_init(void) +static int __init autcpu12_init(void) { struct nand_chip *this; int err = 0; @@ -203,7 +203,6 @@ module_init(autcpu12_init); /* * Clean up routine */ -#ifdef MODULE static void __exit autcpu12_cleanup(void) { /* Release resources, unregister device */ @@ -217,7 +216,6 @@ static void __exit autcpu12_cleanup(void) } module_exit(autcpu12_cleanup); -#endif MODULE_LICENSE("GPL"); MODULE_AUTHOR("Thomas Gleixner "); diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c index d5b05514bb8b..bf251253ea1f 100644 --- a/drivers/mtd/nand/cs553x_nand.c +++ b/drivers/mtd/nand/cs553x_nand.c @@ -267,7 +267,7 @@ out: return err; } -int __init cs553x_init(void) +static int __init cs553x_init(void) { int err = -ENXIO; int i; diff --git a/drivers/mtd/nand/rtc_from4.c b/drivers/mtd/nand/rtc_from4.c index 0c56a6629128..bc9d849fbd5d 100644 --- a/drivers/mtd/nand/rtc_from4.c +++ b/drivers/mtd/nand/rtc_from4.c @@ -516,7 +516,7 @@ static int rtc_from4_errstat(struct mtd_info *mtd, struct nand_chip *this, int s /* * Main initialization routine */ -int __init rtc_from4_init(void) +static int __init rtc_from4_init(void) { struct nand_chip *this; unsigned short bcr1, bcr2, wcr2; @@ -637,7 +637,6 @@ module_init(rtc_from4_init); /* * Clean up routine */ -#ifdef MODULE static void __exit rtc_from4_cleanup(void) { /* Release resource, unregister partitions */ @@ -655,7 +654,6 @@ static void __exit rtc_from4_cleanup(void) } module_exit(rtc_from4_cleanup); -#endif MODULE_LICENSE("GPL"); MODULE_AUTHOR("d.marlin "); diff --git a/drivers/mtd/nand/spia.c b/drivers/mtd/nand/spia.c index b06aada31f79..9737f1d67c3c 100644 --- a/drivers/mtd/nand/spia.c +++ b/drivers/mtd/nand/spia.c @@ -101,7 +101,7 @@ static void spia_hwcontrol(struct mtd_info *mtd, int cmd) /* * Main initialization routine */ -int __init spia_init(void) +static int __init spia_init(void) { struct nand_chip *this; @@ -155,7 +155,6 @@ module_init(spia_init); /* * Clean up routine */ -#ifdef MODULE static void __exit spia_cleanup(void) { /* Release resources, unregister device */ @@ -166,7 +165,6 @@ static void __exit spia_cleanup(void) } module_exit(spia_cleanup); -#endif MODULE_LICENSE("GPL"); MODULE_AUTHOR("Steven J. Hill Date: Tue, 16 May 2006 16:08:10 +0100 Subject: [JFFS2] Fix section mismatch warnings in JFFS2. Mark certain functions with __init and __exit appropriately. Signed-off-by: David Brownell Signed-off-by: David Woodhouse --- fs/jffs2/compr.c | 4 ++-- fs/jffs2/compr_zlib.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/jffs2/compr.c b/fs/jffs2/compr.c index e7944e665b9f..5f45e01d71ed 100644 --- a/fs/jffs2/compr.c +++ b/fs/jffs2/compr.c @@ -412,7 +412,7 @@ void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig) kfree(comprbuf); } -int jffs2_compressors_init(void) +int __init jffs2_compressors_init(void) { /* Registering compressors */ #ifdef CONFIG_JFFS2_ZLIB @@ -440,7 +440,7 @@ int jffs2_compressors_init(void) return 0; } -int jffs2_compressors_exit(void) +int __exit jffs2_compressors_exit(void) { /* Unregistering compressors */ #ifdef CONFIG_JFFS2_RUBIN diff --git a/fs/jffs2/compr_zlib.c b/fs/jffs2/compr_zlib.c index 5c63e0cdcf4c..d43cbac4fb9b 100644 --- a/fs/jffs2/compr_zlib.c +++ b/fs/jffs2/compr_zlib.c @@ -60,7 +60,7 @@ static int __init alloc_workspaces(void) return 0; } -static void free_workspaces(void) +static void __exit free_workspaces(void) { vfree(def_strm.workspace); vfree(inf_strm.workspace); @@ -216,7 +216,7 @@ int __init jffs2_zlib_init(void) return ret; } -void jffs2_zlib_exit(void) +void __exit jffs2_zlib_exit(void) { jffs2_unregister_compressor(&jffs2_zlib_comp); free_workspaces(); -- cgit v1.2.3-70-g09d2 From c41ff6e5f38b02ff927d0d510e28dc1392bb4690 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 16 May 2006 17:05:33 +0100 Subject: [JFFS2] Fix printk format in jffs2_sum_write_data() error message. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fs/jffs2/summary.c: In function ‘jffs2_sum_write_data’: fs/jffs2/summary.c:658: warning: format ‘%zd’ expects type ‘signed size_t’, but argument 4 has type ‘uint32_t’ Signed-off-by: David Woodhouse --- fs/jffs2/summary.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index 7b0ed77a4c35..48293c197f13 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -655,7 +655,7 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock if (ret || (retlen != infosize)) { - JFFS2_WARNING("Write of %d bytes at 0x%08x failed. returned %d, retlen %zu\n", + JFFS2_WARNING("Write of %u bytes at 0x%08x failed. returned %d, retlen %zd\n", infosize, jeb->offset + c->sector_size - jeb->free_size, ret, retlen); c->summary->sum_size = JFFS2_SUMMARY_NOSUM_SIZE; -- cgit v1.2.3-70-g09d2 From 155285c4775b7027b01a5b744c721ae43cced798 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Tue, 16 May 2006 20:16:41 +0400 Subject: NAND: AMD Au1550 driver reads write-only register During the last cleanup of the AMD Au1550 NAND driver the old buglet was reintroduced: as the MEM_STNDCTL register is write-only and seem to always read as 0x31, read-modify-write to it done in au1xxx_nand_init() will have the side effect of enabling -RCS0/1 pin override (via bits 4/5 of this reg.), thus possibly causing a contention on the static bus when the NOR flash (using -RCS0) or board control status registers (using -RCS2) are read. Luckily, this goes away with a first NAND access, since au1550_hwcontrol() doesn't try to read this register before writing anymore. Signed-off-by: Sergei Shtylyov Signed-off-by: David Woodhouse --- drivers/mtd/nand/au1550nd.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c index 861fb961d942..839b35a386b6 100644 --- a/drivers/mtd/nand/au1550nd.c +++ b/drivers/mtd/nand/au1550nd.c @@ -347,11 +347,9 @@ static int __init au1xxx_nand_init(void) au1550_mtd->priv = this; au1550_mtd->owner = THIS_MODULE; - /* disable interrupts */ - au_writel(au_readl(MEM_STNDCTL) & ~(1 << 8), MEM_STNDCTL); - /* disable NAND boot */ - au_writel(au_readl(MEM_STNDCTL) & ~(1 << 0), MEM_STNDCTL); + /* MEM_STNDCTL: disable ints, disable nand boot */ + au_writel(0, MEM_STNDCTL); #ifdef CONFIG_MIPS_PB1550 /* set gpio206 high */ -- cgit v1.2.3-70-g09d2 From b020bb7d3b3a8e3568a16eaf98c033bb9ee474eb Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 16 May 2006 17:31:15 +0100 Subject: [MTD] Fix build warnings in RedBoot MTD partition parser. Fix build warnings from drivers/mtd/redboot.c due to use of `unsigned long` in `struct fis_image_desc` for fields being passed to swab32s() which expects __u32 * Change the entries to uint32_t to make them compatible with the swab32s() function Signed-off-by: Ben Dooks Signed-off-by: David Woodhouse --- drivers/mtd/redboot.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/mtd/redboot.c b/drivers/mtd/redboot.c index c077d2ec9cdd..5b58523e4d4e 100644 --- a/drivers/mtd/redboot.c +++ b/drivers/mtd/redboot.c @@ -1,5 +1,5 @@ /* - * $Id: redboot.c,v 1.19 2005/12/01 10:03:51 dwmw2 Exp $ + * $Id: redboot.c,v 1.21 2006/03/30 18:34:37 bjd Exp $ * * Parse RedBoot-style Flash Image System (FIS) tables and * produce a Linux partition array to match. @@ -15,14 +15,14 @@ struct fis_image_desc { unsigned char name[16]; // Null terminated name - unsigned long flash_base; // Address within FLASH of image - unsigned long mem_base; // Address in memory where it executes - unsigned long size; // Length of image - unsigned long entry_point; // Execution entry point - unsigned long data_length; // Length of actual data - unsigned char _pad[256-(16+7*sizeof(unsigned long))]; - unsigned long desc_cksum; // Checksum over image descriptor - unsigned long file_cksum; // Checksum over image data + uint32_t flash_base; // Address within FLASH of image + uint32_t mem_base; // Address in memory where it executes + uint32_t size; // Length of image + uint32_t entry_point; // Execution entry point + uint32_t data_length; // Length of actual data + unsigned char _pad[256-(16+7*sizeof(uint32_t))]; + uint32_t desc_cksum; // Checksum over image descriptor + uint32_t file_cksum; // Checksum over image data }; struct fis_list { -- cgit v1.2.3-70-g09d2 From 35af68b53a62c98bf551aaae7be179bde248eb34 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Tue, 16 May 2006 20:52:06 +0400 Subject: NAND: Fix NAND ECC errors on AMD Au1550 On AMD Au1550 the static bus controller fails to keep -CE asserted during chip ready delay on read commands and the NAND chip being used requires this. So, the current driver allows nand_base.c to drive -CE manually during the entire sector read. When the PCMCIA driver is enabled however, occasionally the ECC errors occur on NAND reads. This happens because the PCMCIA driver polls sockets periodically and reads one of the board's control/status regs (BCSRs) which are on the same static bus as the NAND flash, and just use another chip select (and the NOR flash also resides on that bus), so as the NAND driver forces NAND chip select asserted and the -RE signal is shared, a contention occurs on the static bus when BCSR or NOR flash is read while we're reading from NAND. So, we either can't keep interrupts enabled during the whole NAND sector read (which is hardly acceptable), or have to implement some interlocking scheme between multiple drivers (which is painful, and makes me shudder :-). There's a third way which has proven to work: to force -CE asserted only while we're waiting for a NAND chip to become ready after a read command, disabling interrupts for a maximum of 25 microseconds (according to Toshiba TC58DVM92A1FT00 datasheet -- this chip is mentioned in the board schematics); for Samsung NAND chip which seems to be actually used this delay is even less, 12 us. Signed-off-by: Konstantin Baydarov Signed-off-by: Sergei Shtylyov Signed-off-by: David Woodhouse --- drivers/mtd/nand/au1550nd.c | 139 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c index 839b35a386b6..d9a0143e1d3a 100644 --- a/drivers/mtd/nand/au1550nd.c +++ b/drivers/mtd/nand/au1550nd.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -318,6 +319,141 @@ int au1550_device_ready(struct mtd_info *mtd) return ret; } +/** + * au1550_select_chip - control -CE line + * Forbid driving -CE manually permitting the NAND controller to do this. + * Keeping -CE asserted during the whole sector reads interferes with the + * NOR flash and PCMCIA drivers as it causes contention on the static bus. + * We only have to hold -CE low for the NAND read commands since the flash + * chip needs it to be asserted during chip not ready time but the NAND + * controller keeps it released. + * + * @mtd: MTD device structure + * @chip: chipnumber to select, -1 for deselect + */ +static void au1550_select_chip(struct mtd_info *mtd, int chip) +{ +} + +/** + * au1550_command - Send command to NAND device + * @mtd: MTD device structure + * @command: the command to be sent + * @column: the column address for this command, -1 if none + * @page_addr: the page address for this command, -1 if none + */ +static void au1550_command(struct mtd_info *mtd, unsigned command, int column, int page_addr) +{ + register struct nand_chip *this = mtd->priv; + int ce_override = 0, i; + ulong flags; + + /* Begin command latch cycle */ + this->hwcontrol(mtd, NAND_CTL_SETCLE); + /* + * Write out the command to the device. + */ + if (command == NAND_CMD_SEQIN) { + int readcmd; + + if (column >= mtd->oobblock) { + /* OOB area */ + column -= mtd->oobblock; + readcmd = NAND_CMD_READOOB; + } else if (column < 256) { + /* First 256 bytes --> READ0 */ + readcmd = NAND_CMD_READ0; + } else { + column -= 256; + readcmd = NAND_CMD_READ1; + } + this->write_byte(mtd, readcmd); + } + this->write_byte(mtd, command); + + /* Set ALE and clear CLE to start address cycle */ + this->hwcontrol(mtd, NAND_CTL_CLRCLE); + + if (column != -1 || page_addr != -1) { + this->hwcontrol(mtd, NAND_CTL_SETALE); + + /* Serially input address */ + if (column != -1) { + /* Adjust columns for 16 bit buswidth */ + if (this->options & NAND_BUSWIDTH_16) + column >>= 1; + this->write_byte(mtd, column); + } + if (page_addr != -1) { + this->write_byte(mtd, (u8)(page_addr & 0xff)); + + if (command == NAND_CMD_READ0 || + command == NAND_CMD_READ1 || + command == NAND_CMD_READOOB) { + /* + * NAND controller will release -CE after + * the last address byte is written, so we'll + * have to forcibly assert it. No interrupts + * are allowed while we do this as we don't + * want the NOR flash or PCMCIA drivers to + * steal our precious bytes of data... + */ + ce_override = 1; + local_irq_save(flags); + this->hwcontrol(mtd, NAND_CTL_SETNCE); + } + + this->write_byte(mtd, (u8)(page_addr >> 8)); + + /* One more address cycle for devices > 32MiB */ + if (this->chipsize > (32 << 20)) + this->write_byte(mtd, (u8)((page_addr >> 16) & 0x0f)); + } + /* Latch in address */ + this->hwcontrol(mtd, NAND_CTL_CLRALE); + } + + /* + * Program and erase have their own busy handlers. + * Status and sequential in need no delay. + */ + switch (command) { + + case NAND_CMD_PAGEPROG: + case NAND_CMD_ERASE1: + case NAND_CMD_ERASE2: + case NAND_CMD_SEQIN: + case NAND_CMD_STATUS: + return; + + case NAND_CMD_RESET: + break; + + case NAND_CMD_READ0: + case NAND_CMD_READ1: + case NAND_CMD_READOOB: + /* Check if we're really driving -CE low (just in case) */ + if (unlikely(!ce_override)) + break; + + /* Apply a short delay always to ensure that we do wait tWB. */ + ndelay(100); + /* Wait for a chip to become ready... */ + for (i = this->chip_delay; !this->dev_ready(mtd) && i > 0; --i) + udelay(1); + + /* Release -CE and re-enable interrupts. */ + this->hwcontrol(mtd, NAND_CTL_CLRNCE); + local_irq_restore(flags); + return; + } + /* Apply this short delay always to ensure that we do wait tWB. */ + ndelay(100); + + while(!this->dev_ready(mtd)); +} + + /* * Main initialization routine */ @@ -437,6 +573,9 @@ static int __init au1xxx_nand_init(void) /* Set address of hardware control function */ this->hwcontrol = au1550_hwcontrol; this->dev_ready = au1550_device_ready; + this->select_chip = au1550_select_chip; + this->cmdfunc = au1550_command; + /* 30 us command delay time */ this->chip_delay = 30; this->eccmode = NAND_ECC_SOFT; -- cgit v1.2.3-70-g09d2 From ba9627b85fcb5ed67285ca0711f0f4d1e965746e Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 16 May 2006 23:03:08 +0100 Subject: [JFFS2] Repack some on-medium structures. ARM is weirder than I thought. We have to pack at least the jint16_t structure, because otherwise it'll be four bytes in size. Thankfully, we can do that and _not_ pack the actual node structures, and the compiler still doesn't emit stupid code. Signed-off-by: David Woodhouse --- include/linux/jffs2.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/linux/jffs2.h b/include/linux/jffs2.h index 228ad72f7dd8..a26fbd498c79 100644 --- a/include/linux/jffs2.h +++ b/include/linux/jffs2.h @@ -82,15 +82,15 @@ typedef struct { uint32_t v32; -} jint32_t; +} __attribute__((packed)) jint32_t; typedef struct { uint32_t m; -} jmode_t; +} __attribute__((packed)) jmode_t; typedef struct { uint16_t v16; -} jint16_t; +} __attribute__((packed)) jint16_t; struct jffs2_unknown_node { -- cgit v1.2.3-70-g09d2 From df54b52c411befdcf1d0989f939a49163570ad29 Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Tue, 6 Dec 2005 17:28:19 +0000 Subject: CHIPS: Fix potential starvation in cfi_cmdset_0001 The patch below fixes a potential starvation issue that can arise when there is contention on a chip during a period when a process is currently writing to it. The starvation is avoided by conditionally rescheduling when the chip is left in a state usable by other processes. Signed-off-by: Josh Boyer Signed-off-by: Tom Gall Signed-off-by: David Woodhouse --- drivers/mtd/chips/cfi_cmdset_0001.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index 898c321ab86d..e797752f7c0b 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -1691,6 +1691,11 @@ static int cfi_intelext_writev (struct mtd_info *mtd, const struct kvec *vecs, if (chipnum == cfi->numchips) return 0; } + + /* Be nice and reschedule with the chip in a usable state for other + processes. */ + cond_resched(); + } while (len); return 0; -- cgit v1.2.3-70-g09d2 From 6e7a6809c555aeb7cb98544df4d446fbd6f123ec Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Wed, 29 Mar 2006 23:31:42 +0100 Subject: cfi-cmdset-0001: always update the chip status ... otherwise xip_enable() won't do the right thing. Signed-off-by: Nicolas Pitre Signed-off-by: David Woodhouse --- drivers/mtd/chips/cfi_cmdset_0001.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index e797752f7c0b..ab3888f5e464 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -1479,8 +1479,10 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, [...], the device will not accept any more Write to Buffer commands". So we must check here and reset those bits if they're set. Otherwise we're just pissing in the wind */ - if (chip->state != FL_STATUS) + if (chip->state != FL_STATUS) { map_write(map, CMD(0x70), cmd_adr); + chip->state = FL_STATUS; + } status = map_read(map, cmd_adr); if (map_word_bitsset(map, status, CMD(0x30))) { xip_enable(map, chip, cmd_adr); -- cgit v1.2.3-70-g09d2 From c172471b78255a5cf6d05383d9ebbf0c6683167a Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Thu, 30 Mar 2006 15:52:41 +0100 Subject: cfi_cmdset_0001: factorize code to wait for flash status This allows for much better abstraction and separation of the XIP and non-XIP cases with their own specific implementations. This fixes the case where a timeout was tripped on in the XIP case by the code that was meant for the non-XIP case only. This also makes for a nice code reduction. Signed-off-by: Nicolas Pitre CC: "Alexey, Korolev" Signed-off-by: David Woodhouse --- drivers/mtd/chips/cfi_cmdset_0001.c | 421 ++++++++++++++---------------------- 1 file changed, 157 insertions(+), 264 deletions(-) diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index ab3888f5e464..d0d5e521b564 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -399,7 +399,7 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary) for (i=0; i< cfi->numchips; i++) { cfi->chips[i].word_write_time = 1<cfiq->WordWriteTimeoutTyp; cfi->chips[i].buffer_write_time = 1<cfiq->BufWriteTimeoutTyp; - cfi->chips[i].erase_time = 1<cfiq->BlockEraseTimeoutTyp; + cfi->chips[i].erase_time = 1000<cfiq->BlockEraseTimeoutTyp; cfi->chips[i].ref_point_counter = 0; init_waitqueue_head(&(cfi->chips[i].wq)); } @@ -894,26 +894,33 @@ static void __xipram xip_enable(struct map_info *map, struct flchip *chip, /* * When a delay is required for the flash operation to complete, the - * xip_udelay() function is polling for both the given timeout and pending - * (but still masked) hardware interrupts. Whenever there is an interrupt - * pending then the flash erase or write operation is suspended, array mode - * restored and interrupts unmasked. Task scheduling might also happen at that - * point. The CPU eventually returns from the interrupt or the call to - * schedule() and the suspended flash operation is resumed for the remaining - * of the delay period. + * xip_wait_for_operation() function is polling for both the given timeout + * and pending (but still masked) hardware interrupts. Whenever there is an + * interrupt pending then the flash erase or write operation is suspended, + * array mode restored and interrupts unmasked. Task scheduling might also + * happen at that point. The CPU eventually returns from the interrupt or + * the call to schedule() and the suspended flash operation is resumed for + * the remaining of the delay period. * * Warning: this function _will_ fool interrupt latency tracing tools. */ -static void __xipram xip_udelay(struct map_info *map, struct flchip *chip, - unsigned long adr, int usec) +static int __xipram xip_wait_for_operation( + struct map_info *map, struct flchip *chip, + unsigned long adr, int *chip_op_time ) { struct cfi_private *cfi = map->fldrv_priv; struct cfi_pri_intelext *cfip = cfi->cmdset_priv; map_word status, OK = CMD(0x80); - unsigned long suspended, start = xip_currtime(); + unsigned long usec, suspended, start, done; flstate_t oldstate, newstate; + start = xip_currtime(); + usec = *chip_op_time * 8; + if (usec == 0) + usec = 500000; + done = 0; + do { cpu_relax(); if (xip_irqpending() && cfip && @@ -930,9 +937,9 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip, * we resume the whole thing at once). Yes, it * can happen! */ + usec -= done; map_write(map, CMD(0xb0), adr); map_write(map, CMD(0x70), adr); - usec -= xip_elapsed_since(start); suspended = xip_currtime(); do { if (xip_elapsed_since(suspended) > 100000) { @@ -942,7 +949,7 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip, * This is a critical error but there * is not much we can do here. */ - return; + return -EIO; } status = map_read(map, adr); } while (!map_word_andequal(map, status, OK, OK)); @@ -1002,65 +1009,107 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip, xip_cpu_idle(); } status = map_read(map, adr); + done = xip_elapsed_since(start); } while (!map_word_andequal(map, status, OK, OK) - && xip_elapsed_since(start) < usec); -} + && done < usec); -#define UDELAY(map, chip, adr, usec) xip_udelay(map, chip, adr, usec) + return (done >= usec) ? -ETIME : 0; +} /* * The INVALIDATE_CACHED_RANGE() macro is normally used in parallel while * the flash is actively programming or erasing since we have to poll for * the operation to complete anyway. We can't do that in a generic way with * a XIP setup so do it before the actual flash operation in this case - * and stub it out from INVALIDATE_CACHE_UDELAY. + * and stub it out from INVAL_CACHE_AND_WAIT. */ #define XIP_INVAL_CACHED_RANGE(map, from, size) \ INVALIDATE_CACHED_RANGE(map, from, size) -#define INVALIDATE_CACHE_UDELAY(map, chip, cmd_adr, adr, len, usec) \ - UDELAY(map, chip, cmd_adr, usec) - -/* - * Extra notes: - * - * Activating this XIP support changes the way the code works a bit. For - * example the code to suspend the current process when concurrent access - * happens is never executed because xip_udelay() will always return with the - * same chip state as it was entered with. This is why there is no care for - * the presence of add_wait_queue() or schedule() calls from within a couple - * xip_disable()'d areas of code, like in do_erase_oneblock for example. - * The queueing and scheduling are always happening within xip_udelay(). - * - * Similarly, get_chip() and put_chip() just happen to always be executed - * with chip->state set to FL_READY (or FL_XIP_WHILE_*) where flash state - * is in array mode, therefore never executing many cases therein and not - * causing any problem with XIP. - */ +#define INVAL_CACHE_AND_WAIT(map, chip, cmd_adr, inval_adr, inval_len, p_usec) \ + xip_wait_for_operation(map, chip, cmd_adr, p_usec) #else #define xip_disable(map, chip, adr) #define xip_enable(map, chip, adr) #define XIP_INVAL_CACHED_RANGE(x...) +#define INVAL_CACHE_AND_WAIT inval_cache_and_wait_for_operation + +static int inval_cache_and_wait_for_operation( + struct map_info *map, struct flchip *chip, + unsigned long cmd_adr, unsigned long inval_adr, int inval_len, + int *chip_op_time ) +{ + struct cfi_private *cfi = map->fldrv_priv; + map_word status, status_OK = CMD(0x80); + int z, chip_state = chip->state; + unsigned long timeo; + + spin_unlock(chip->mutex); + if (inval_len) + INVALIDATE_CACHED_RANGE(map, inval_adr, inval_len); + if (*chip_op_time) + cfi_udelay(*chip_op_time); + spin_lock(chip->mutex); + + timeo = *chip_op_time * 8 * HZ / 1000000; + if (timeo < HZ/2) + timeo = HZ/2; + timeo += jiffies; + + z = 0; + for (;;) { + if (chip->state != chip_state) { + /* Someone's suspended the operation: sleep */ + DECLARE_WAITQUEUE(wait, current); + + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&chip->wq, &wait); + spin_unlock(chip->mutex); + schedule(); + remove_wait_queue(&chip->wq, &wait); + timeo = jiffies + (HZ / 2); /* FIXME */ + spin_lock(chip->mutex); + continue; + } + + status = map_read(map, cmd_adr); + if (map_word_andequal(map, status, status_OK, status_OK)) + break; -#define UDELAY(map, chip, adr, usec) \ -do { \ - spin_unlock(chip->mutex); \ - cfi_udelay(usec); \ - spin_lock(chip->mutex); \ -} while (0) - -#define INVALIDATE_CACHE_UDELAY(map, chip, cmd_adr, adr, len, usec) \ -do { \ - spin_unlock(chip->mutex); \ - INVALIDATE_CACHED_RANGE(map, adr, len); \ - cfi_udelay(usec); \ - spin_lock(chip->mutex); \ -} while (0) + /* OK Still waiting */ + if (time_after(jiffies, timeo)) { + map_write(map, CMD(0x70), cmd_adr); + chip->state = FL_STATUS; + return -ETIME; + } + + /* Latency issues. Drop the lock, wait a while and retry */ + z++; + spin_unlock(chip->mutex); + cfi_udelay(1); + spin_lock(chip->mutex); + } + + if (!z) { + if (!--(*chip_op_time)) + *chip_op_time = 1; + } else if (z > 1) + ++(*chip_op_time); + + /* Done and happy. */ + chip->state = FL_STATUS; + return 0; +} #endif +#define WAIT_TIMEOUT(map, chip, adr, udelay) \ + ({ int __udelay = (udelay); \ + INVAL_CACHE_AND_WAIT(map, chip, adr, 0, 0, &__udelay); }) + + static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t adr, size_t len) { unsigned long cmd_addr; @@ -1250,14 +1299,11 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, map_word datum, int mode) { struct cfi_private *cfi = map->fldrv_priv; - map_word status, status_OK, write_cmd; - unsigned long timeo; - int z, ret=0; + map_word status, write_cmd; + int ret=0; adr += chip->start; - /* Let's determine those according to the interleave only once */ - status_OK = CMD(0x80); switch (mode) { case FL_WRITING: write_cmd = (cfi->cfiq->P_ID != 0x0200) ? CMD(0x40) : CMD(0x41); @@ -1283,57 +1329,17 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, map_write(map, datum, adr); chip->state = mode; - INVALIDATE_CACHE_UDELAY(map, chip, adr, - adr, map_bankwidth(map), - chip->word_write_time); - - timeo = jiffies + (HZ/2); - z = 0; - for (;;) { - if (chip->state != mode) { - /* Someone's suspended the write. Sleep */ - DECLARE_WAITQUEUE(wait, current); - - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&chip->wq, &wait); - spin_unlock(chip->mutex); - schedule(); - remove_wait_queue(&chip->wq, &wait); - timeo = jiffies + (HZ / 2); /* FIXME */ - spin_lock(chip->mutex); - continue; - } - - status = map_read(map, adr); - if (map_word_andequal(map, status, status_OK, status_OK)) - break; - - /* OK Still waiting */ - if (time_after(jiffies, timeo)) { - map_write(map, CMD(0x70), adr); - chip->state = FL_STATUS; - xip_enable(map, chip, adr); - printk(KERN_ERR "%s: word write error (status timeout)\n", map->name); - ret = -EIO; - goto out; - } - - /* Latency issues. Drop the lock, wait a while and retry */ - z++; - UDELAY(map, chip, adr, 1); - } - if (!z) { - chip->word_write_time--; - if (!chip->word_write_time) - chip->word_write_time = 1; + ret = INVAL_CACHE_AND_WAIT(map, chip, adr, + adr, map_bankwidth(map), + &chip->word_write_time); + if (ret) { + xip_enable(map, chip, adr); + printk(KERN_ERR "%s: word write error (status timeout)\n", map->name); + goto out; } - if (z > 1) - chip->word_write_time++; - - /* Done and happy. */ - chip->state = FL_STATUS; /* check for errors */ + status = map_read(map, adr); if (map_word_bitsset(map, status, CMD(0x1a))) { unsigned long chipstatus = MERGESTATUS(status); @@ -1450,9 +1456,9 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, unsigned long *pvec_seek, int len) { struct cfi_private *cfi = map->fldrv_priv; - map_word status, status_OK, write_cmd, datum; - unsigned long cmd_adr, timeo; - int wbufsize, z, ret=0, word_gap, words; + map_word status, write_cmd, datum; + unsigned long cmd_adr; + int ret, wbufsize, word_gap, words; const struct kvec *vec; unsigned long vec_seek; @@ -1461,7 +1467,6 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, cmd_adr = adr & ~(wbufsize-1); /* Let's determine this according to the interleave only once */ - status_OK = CMD(0x80); write_cmd = (cfi->cfiq->P_ID != 0x0200) ? CMD(0xe8) : CMD(0xe9); spin_lock(chip->mutex); @@ -1493,32 +1498,20 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, } chip->state = FL_WRITING_TO_BUFFER; - - z = 0; - for (;;) { - map_write(map, write_cmd, cmd_adr); - + map_write(map, write_cmd, cmd_adr); + ret = WAIT_TIMEOUT(map, chip, cmd_adr, 0); + if (ret) { + /* Argh. Not ready for write to buffer */ + map_word Xstatus = map_read(map, cmd_adr); + map_write(map, CMD(0x70), cmd_adr); + chip->state = FL_STATUS; status = map_read(map, cmd_adr); - if (map_word_andequal(map, status, status_OK, status_OK)) - break; - - UDELAY(map, chip, cmd_adr, 1); - - if (++z > 20) { - /* Argh. Not ready for write to buffer */ - map_word Xstatus; - map_write(map, CMD(0x70), cmd_adr); - chip->state = FL_STATUS; - Xstatus = map_read(map, cmd_adr); - /* Odd. Clear status bits */ - map_write(map, CMD(0x50), cmd_adr); - map_write(map, CMD(0x70), cmd_adr); - xip_enable(map, chip, cmd_adr); - printk(KERN_ERR "%s: Chip not ready for buffer write. status = %lx, Xstatus = %lx\n", - map->name, status.x[0], Xstatus.x[0]); - ret = -EIO; - goto out; - } + map_write(map, CMD(0x50), cmd_adr); + map_write(map, CMD(0x70), cmd_adr); + xip_enable(map, chip, cmd_adr); + printk(KERN_ERR "%s: Chip not ready for buffer write. Xstatus = %lx, status = %lx\n", + map->name, Xstatus.x[0], status.x[0]); + goto out; } /* Figure out the number of words to write */ @@ -1573,56 +1566,19 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, map_write(map, CMD(0xd0), cmd_adr); chip->state = FL_WRITING; - INVALIDATE_CACHE_UDELAY(map, chip, cmd_adr, - adr, len, - chip->buffer_write_time); - - timeo = jiffies + (HZ/2); - z = 0; - for (;;) { - if (chip->state != FL_WRITING) { - /* Someone's suspended the write. Sleep */ - DECLARE_WAITQUEUE(wait, current); - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&chip->wq, &wait); - spin_unlock(chip->mutex); - schedule(); - remove_wait_queue(&chip->wq, &wait); - timeo = jiffies + (HZ / 2); /* FIXME */ - spin_lock(chip->mutex); - continue; - } - - status = map_read(map, cmd_adr); - if (map_word_andequal(map, status, status_OK, status_OK)) - break; - - /* OK Still waiting */ - if (time_after(jiffies, timeo)) { - map_write(map, CMD(0x70), cmd_adr); - chip->state = FL_STATUS; - xip_enable(map, chip, cmd_adr); - printk(KERN_ERR "%s: buffer write error (status timeout)\n", map->name); - ret = -EIO; - goto out; - } - - /* Latency issues. Drop the lock, wait a while and retry */ - z++; - UDELAY(map, chip, cmd_adr, 1); - } - if (!z) { - chip->buffer_write_time--; - if (!chip->buffer_write_time) - chip->buffer_write_time = 1; + ret = INVAL_CACHE_AND_WAIT(map, chip, cmd_adr, + adr, len, + &chip->buffer_write_time); + if (ret) { + map_write(map, CMD(0x70), cmd_adr); + chip->state = FL_STATUS; + xip_enable(map, chip, cmd_adr); + printk(KERN_ERR "%s: buffer write error (status timeout)\n", map->name); + goto out; } - if (z > 1) - chip->buffer_write_time++; - - /* Done and happy. */ - chip->state = FL_STATUS; /* check for errors */ + status = map_read(map, cmd_adr); if (map_word_bitsset(map, status, CMD(0x1a))) { unsigned long chipstatus = MERGESTATUS(status); @@ -1718,17 +1674,12 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, int len, void *thunk) { struct cfi_private *cfi = map->fldrv_priv; - map_word status, status_OK; - unsigned long timeo; + map_word status; int retries = 3; - DECLARE_WAITQUEUE(wait, current); - int ret = 0; + int ret; adr += chip->start; - /* Let's determine this according to the interleave only once */ - status_OK = CMD(0x80); - retry: spin_lock(chip->mutex); ret = get_chip(map, chip, adr, FL_ERASING); @@ -1750,48 +1701,15 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, chip->state = FL_ERASING; chip->erase_suspended = 0; - INVALIDATE_CACHE_UDELAY(map, chip, adr, - adr, len, - chip->erase_time*1000/2); - - /* FIXME. Use a timer to check this, and return immediately. */ - /* Once the state machine's known to be working I'll do that */ - - timeo = jiffies + (HZ*20); - for (;;) { - if (chip->state != FL_ERASING) { - /* Someone's suspended the erase. Sleep */ - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&chip->wq, &wait); - spin_unlock(chip->mutex); - schedule(); - remove_wait_queue(&chip->wq, &wait); - spin_lock(chip->mutex); - continue; - } - if (chip->erase_suspended) { - /* This erase was suspended and resumed. - Adjust the timeout */ - timeo = jiffies + (HZ*20); /* FIXME */ - chip->erase_suspended = 0; - } - - status = map_read(map, adr); - if (map_word_andequal(map, status, status_OK, status_OK)) - break; - - /* OK Still waiting */ - if (time_after(jiffies, timeo)) { - map_write(map, CMD(0x70), adr); - chip->state = FL_STATUS; - xip_enable(map, chip, adr); - printk(KERN_ERR "%s: block erase error: (status timeout)\n", map->name); - ret = -EIO; - goto out; - } - - /* Latency issues. Drop the lock, wait a while and retry */ - UDELAY(map, chip, adr, 1000000/HZ); + ret = INVAL_CACHE_AND_WAIT(map, chip, adr, + adr, len, + &chip->erase_time); + if (ret) { + map_write(map, CMD(0x70), adr); + chip->state = FL_STATUS; + xip_enable(map, chip, adr); + printk(KERN_ERR "%s: block erase error: (status timeout)\n", map->name); + goto out; } /* We've broken this before. It doesn't hurt to be safe */ @@ -1820,7 +1738,6 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, ret = -EIO; } else if (chipstatus & 0x20 && retries--) { printk(KERN_DEBUG "block erase failed at 0x%08lx: status 0x%lx. Retrying...\n", adr, chipstatus); - timeo = jiffies + HZ; put_chip(map, chip, adr); spin_unlock(chip->mutex); goto retry; @@ -1926,15 +1843,11 @@ static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip { struct cfi_private *cfi = map->fldrv_priv; struct cfi_pri_intelext *extp = cfi->cmdset_priv; - map_word status, status_OK; - unsigned long timeo = jiffies + HZ; + int udelay; int ret; adr += chip->start; - /* Let's determine this according to the interleave only once */ - status_OK = CMD(0x80); - spin_lock(chip->mutex); ret = get_chip(map, chip, adr, FL_LOCKING); if (ret) { @@ -1959,41 +1872,21 @@ static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip * If Instant Individual Block Locking supported then no need * to delay. */ + udelay = (!extp || !(extp->FeatureSupport & (1 << 5))) ? 1000000/HZ : 0; - if (!extp || !(extp->FeatureSupport & (1 << 5))) - UDELAY(map, chip, adr, 1000000/HZ); - - /* FIXME. Use a timer to check this, and return immediately. */ - /* Once the state machine's known to be working I'll do that */ - - timeo = jiffies + (HZ*20); - for (;;) { - - status = map_read(map, adr); - if (map_word_andequal(map, status, status_OK, status_OK)) - break; - - /* OK Still waiting */ - if (time_after(jiffies, timeo)) { - map_write(map, CMD(0x70), adr); - chip->state = FL_STATUS; - xip_enable(map, chip, adr); - printk(KERN_ERR "%s: block unlock error: (status timeout)\n", map->name); - put_chip(map, chip, adr); - spin_unlock(chip->mutex); - return -EIO; - } - - /* Latency issues. Drop the lock, wait a while and retry */ - UDELAY(map, chip, adr, 1); + ret = WAIT_TIMEOUT(map, chip, adr, udelay); + if (ret) { + map_write(map, CMD(0x70), adr); + chip->state = FL_STATUS; + xip_enable(map, chip, adr); + printk(KERN_ERR "%s: block unlock error: (status timeout)\n", map->name); + goto out; } - /* Done and happy. */ - chip->state = FL_STATUS; xip_enable(map, chip, adr); - put_chip(map, chip, adr); +out: put_chip(map, chip, adr); spin_unlock(chip->mutex); - return 0; + return ret; } static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len) -- cgit v1.2.3-70-g09d2 From 599fb3298b70d75c12dbdc4dd30f52c5cf04ea2f Mon Sep 17 00:00:00 2001 From: Sean Young Date: Wed, 17 May 2006 11:47:48 +0100 Subject: [PCMCIA MTD] Fix leak and crash on reboot Signed-off-by: Sean Young Signed-off-by: David Woodhouse --- drivers/mtd/maps/pcmciamtd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c index d27f4129afd3..c861134cbc48 100644 --- a/drivers/mtd/maps/pcmciamtd.c +++ b/drivers/mtd/maps/pcmciamtd.c @@ -713,6 +713,7 @@ static void pcmciamtd_detach(struct pcmcia_device *link) if(dev->mtd_info) { del_mtd_device(dev->mtd_info); + map_destroy(dev->mtd_info); info("mtd%d: Removed", dev->mtd_info->index); } -- cgit v1.2.3-70-g09d2 From ae282d497d5631ce31539717131c760e3872c539 Mon Sep 17 00:00:00 2001 From: Vitaly Wool Date: Wed, 17 May 2006 12:34:27 +0100 Subject: [MTD] generic: propagate oobavail to MTD partitions 'oobavail' parameter of mtd_info structure is now propagated to the MTD partitions Signed-off-by: Vitaly Wool Signed-off-by: David Woodhouse --- drivers/mtd/mtdpart.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 99395911d26f..29ed5abe70c4 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -400,6 +400,7 @@ int add_mtd_partitions(struct mtd_info *master, slave->mtd.size = parts[i].size; slave->mtd.oobblock = master->oobblock; slave->mtd.oobsize = master->oobsize; + slave->mtd.oobavail = master->oobavail; slave->mtd.ecctype = master->ecctype; slave->mtd.eccsize = master->eccsize; -- cgit v1.2.3-70-g09d2 From 683b30c8e78ab363dc8d8c94bdb61b64d1f6f5e2 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Wed, 17 May 2006 12:45:34 +0100 Subject: [MTD] RFD FTL: Be noisier, and don't assume block without RFD magic are erased Signed-off-by: Sean Young Signed-off-by: David Woodhouse --- drivers/mtd/rfd_ftl.c | 48 +++++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/drivers/mtd/rfd_ftl.c b/drivers/mtd/rfd_ftl.c index a3e00a4635a5..fa4362fb4dd8 100644 --- a/drivers/mtd/rfd_ftl.c +++ b/drivers/mtd/rfd_ftl.c @@ -3,7 +3,7 @@ * * Copyright (C) 2005 Sean Young * - * $Id: rfd_ftl.c,v 1.5 2005/11/07 11:14:21 gleixner Exp $ + * $Id: rfd_ftl.c,v 1.8 2006/01/15 12:51:44 sean Exp $ * * This type of flash translation layer (FTL) is used by the Embedded BIOS * by General Software. It is known as the Resident Flash Disk (RFD), see: @@ -61,6 +61,7 @@ struct block { BLOCK_OK, BLOCK_ERASING, BLOCK_ERASED, + BLOCK_UNUSED, BLOCK_FAILED } state; int free_sectors; @@ -99,10 +100,8 @@ static int build_block_map(struct partition *part, int block_no) block->offset = part->block_size * block_no; if (le16_to_cpu(part->header_cache[0]) != RFD_MAGIC) { - block->state = BLOCK_ERASED; /* assumption */ - block->free_sectors = part->data_sectors_per_block; - part->reserved_block = block_no; - return 1; + block->state = BLOCK_UNUSED; + return -ENOENT; } block->state = BLOCK_OK; @@ -124,7 +123,7 @@ static int build_block_map(struct partition *part, int block_no) entry = 0; if (entry >= part->sector_count) { - printk(KERN_NOTICE PREFIX + printk(KERN_WARNING PREFIX "'%s': unit #%d: entry %d corrupt, " "sector %d out of range\n", part->mbd.mtd->name, block_no, i, entry); @@ -132,7 +131,7 @@ static int build_block_map(struct partition *part, int block_no) } if (part->sector_map[entry] != -1) { - printk(KERN_NOTICE PREFIX + printk(KERN_WARNING PREFIX "'%s': more than one entry for sector %d\n", part->mbd.mtd->name, entry); part->errors = 1; @@ -167,7 +166,7 @@ static int scan_header(struct partition *part) /* each erase block has three bytes header, followed by the map */ part->header_sectors_per_block = ((HEADER_MAP_OFFSET + sectors_per_block) * - sizeof(u16) + SECTOR_SIZE - 1) / SECTOR_SIZE; + sizeof(u16) + SECTOR_SIZE - 1) / SECTOR_SIZE; part->data_sectors_per_block = sectors_per_block - part->header_sectors_per_block; @@ -226,7 +225,7 @@ static int scan_header(struct partition *part) } if (part->reserved_block == -1) { - printk(KERN_NOTICE PREFIX "'%s': no empty erase unit found\n", + printk(KERN_WARNING PREFIX "'%s': no empty erase unit found\n", part->mbd.mtd->name); part->errors = 1; @@ -315,7 +314,7 @@ static void erase_callback(struct erase_info *erase) rc = -EIO; if (rc) { - printk(KERN_NOTICE PREFIX "'%s': unable to write RFD " + printk(KERN_ERR PREFIX "'%s': unable to write RFD " "header at 0x%lx\n", part->mbd.mtd->name, part->blocks[i].offset); @@ -348,7 +347,7 @@ static int erase_block(struct partition *part, int block) rc = part->mbd.mtd->erase(part->mbd.mtd, erase); if (rc) { - printk(KERN_WARNING PREFIX "erase of region %x,%x on '%s' " + printk(KERN_ERR PREFIX "erase of region %x,%x on '%s' " "failed\n", erase->addr, erase->len, part->mbd.mtd->name); kfree(erase); @@ -383,7 +382,7 @@ static int move_block_contents(struct partition *part, int block_no, u_long *old rc = -EIO; if (rc) { - printk(KERN_NOTICE PREFIX "error reading '%s' at " + printk(KERN_ERR PREFIX "error reading '%s' at " "0x%lx\n", part->mbd.mtd->name, part->blocks[block_no].offset); @@ -423,7 +422,7 @@ static int move_block_contents(struct partition *part, int block_no, u_long *old rc = -EIO; if (rc) { - printk(KERN_NOTICE PREFIX "'%s': Unable to " + printk(KERN_ERR PREFIX "'%s': Unable to " "read sector for relocation\n", part->mbd.mtd->name); @@ -520,7 +519,7 @@ static int reclaim_block(struct partition *part, u_long *old_sector) * because if we fill that one up first it'll have the most chance of having * the least live sectors at reclaim. */ -static int find_free_block(const struct partition *part) +static int find_free_block(struct partition *part) { int block, stop; @@ -533,6 +532,9 @@ static int find_free_block(const struct partition *part) block != part->reserved_block) return block; + if (part->blocks[block].state == BLOCK_UNUSED) + erase_block(part, block); + if (++block >= part->total_blocks) block = 0; @@ -541,7 +543,7 @@ static int find_free_block(const struct partition *part) return -1; } -static int find_writeable_block(struct partition *part, u_long *old_sector) +static int find_writable_block(struct partition *part, u_long *old_sector) { int rc, block; size_t retlen; @@ -570,7 +572,7 @@ static int find_writeable_block(struct partition *part, u_long *old_sector) rc = -EIO; if (rc) { - printk(KERN_NOTICE PREFIX "'%s': unable to read header at " + printk(KERN_ERR PREFIX "'%s': unable to read header at " "0x%lx\n", part->mbd.mtd->name, part->blocks[block].offset); goto err; @@ -602,7 +604,7 @@ static int mark_sector_deleted(struct partition *part, u_long old_addr) rc = -EIO; if (rc) { - printk(KERN_WARNING PREFIX "error writing '%s' at " + printk(KERN_ERR PREFIX "error writing '%s' at " "0x%lx\n", part->mbd.mtd->name, addr); if (rc) goto err; @@ -652,7 +654,7 @@ static int do_writesect(struct mtd_blktrans_dev *dev, u_long sector, char *buf, if (part->current_block == -1 || !part->blocks[part->current_block].free_sectors) { - rc = find_writeable_block(part, old_addr); + rc = find_writable_block(part, old_addr); if (rc) goto err; } @@ -675,7 +677,7 @@ static int do_writesect(struct mtd_blktrans_dev *dev, u_long sector, char *buf, rc = -EIO; if (rc) { - printk(KERN_WARNING PREFIX "error writing '%s' at 0x%lx\n", + printk(KERN_ERR PREFIX "error writing '%s' at 0x%lx\n", part->mbd.mtd->name, addr); if (rc) goto err; @@ -695,7 +697,7 @@ static int do_writesect(struct mtd_blktrans_dev *dev, u_long sector, char *buf, rc = -EIO; if (rc) { - printk(KERN_WARNING PREFIX "error writing '%s' at 0x%lx\n", + printk(KERN_ERR PREFIX "error writing '%s' at 0x%lx\n", part->mbd.mtd->name, addr); if (rc) goto err; @@ -776,7 +778,7 @@ static void rfd_ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) part->block_size = block_size; else { if (!mtd->erasesize) { - printk(KERN_NOTICE PREFIX "please provide block_size"); + printk(KERN_WARNING PREFIX "please provide block_size"); return; } else @@ -791,8 +793,8 @@ static void rfd_ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) if (!(mtd->flags & MTD_WRITEABLE)) part->mbd.readonly = 1; else if (part->errors) { - printk(KERN_NOTICE PREFIX "'%s': errors found, " - "setting read-only", mtd->name); + printk(KERN_WARNING PREFIX "'%s': errors found, " + "setting read-only\n", mtd->name); part->mbd.readonly = 1; } -- cgit v1.2.3-70-g09d2 From be21ce119716f821c595552917ce7c05a3997b6b Mon Sep 17 00:00:00 2001 From: Martin Michlmayr Date: Mon, 20 Mar 2006 04:40:26 +0000 Subject: Re-add module description for ms02-nv to Kconfig In an unrelated MTD commit, a description about the ms02-nv module got removed from Kconfig. While I personally agree with this removal, the module maintainer (Maciej W. Rozycki) would like to see it added back. In the absense of any consistency regarding Kconfig descriptions his wish should be followed. Signed-off-by: Martin Michlmayr Acked-by: Maciej W. Rozycki Signed-off-by: David Woodhouse --- drivers/mtd/devices/Kconfig | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig index 6e9f880e2f98..16c02b5ccf7e 100644 --- a/drivers/mtd/devices/Kconfig +++ b/drivers/mtd/devices/Kconfig @@ -47,6 +47,11 @@ config MTD_MS02NV accelerator. Say Y here if you have a DECstation 5000/2x0 or a DECsystem 5900 equipped with such a module. + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read . The module will + be called ms02-nv.o. + config MTD_DATAFLASH tristate "Support for AT45xxx DataFlash" depends on MTD && SPI_MASTER && EXPERIMENTAL -- cgit v1.2.3-70-g09d2 From ceb31db11f78935c666c50fe9c99d4560d592fde Mon Sep 17 00:00:00 2001 From: Martin Michlmayr Date: Mon, 20 Mar 2006 04:40:46 +0000 Subject: LASAT depends on MTD_CFI The following difference was found between the mainline and linux-mips kernel. LASAT depends on MTD_CFI. Signed-off-by: Martin Michlmayr Signed-off-by: David Woodhouse --- drivers/mtd/maps/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index 4e2bd37b3d8a..6bdaacc6d6f9 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -200,8 +200,8 @@ config MTD_TSUNAMI Support for the flash chip on Tsunami TIG bus. config MTD_LASAT - tristate "Flash chips on LASAT board" - depends on LASAT + tristate "LASAT flash device" + depends on LASAT && MTD_CFI help Support for the flash chips on the Lasat 100 and 200 boards. -- cgit v1.2.3-70-g09d2 From e8d32937d9f2022c31871ef357a4883f78da1b7f Mon Sep 17 00:00:00 2001 From: Alexander Belyakov Date: Wed, 17 May 2006 19:11:16 +0400 Subject: MTD: mtdconcat NAND/Sibley support (rev.2) There is a second revision of "mtdconcat NAND/Sibley" patch. I hope the patch will not get damaged as I'm posting it from gmail account, thanks to Jorn. The patch adds previously missing concat_writev(), concat_writev_ecc(), concat_block_isbad(), concat_block_markbad() functions to make concatenation layer compatible with Sibley and NAND chips. Patch has been cleared from whitespaces, fixed some lines of code as requested. Also I have added code for alignment check that should support Jorn's "writesize" patch. Signed-off-by: Alexander Belyakov Signed-off-by: David Woodhouse --- drivers/mtd/mtdconcat.c | 169 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 164 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index 9af840364a74..da4c9c190bb3 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c @@ -250,6 +250,106 @@ concat_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, return err; } +static int +concat_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, + unsigned long count, loff_t to, size_t * retlen, + u_char *eccbuf, struct nand_oobinfo *oobsel) +{ + struct mtd_concat *concat = CONCAT(mtd); + struct kvec *vecs_copy; + unsigned long entry_low, entry_high; + size_t total_len = 0; + int i; + int err = -EINVAL; + + if (!(mtd->flags & MTD_WRITEABLE)) + return -EROFS; + + *retlen = 0; + + /* Calculate total length of data */ + for (i = 0; i < count; i++) + total_len += vecs[i].iov_len; + + /* Do not allow write past end of device */ + if ((to + total_len) > mtd->size) + return -EINVAL; + + /* Check alignment */ + if (mtd->writesize > 1) + if ((to % mtd->writesize) || (total_len % mtd->writesize)) + return -EINVAL; + + /* make a copy of vecs */ + vecs_copy = kmalloc(sizeof(struct kvec) * count, GFP_KERNEL); + if (!vecs_copy) + return -ENOMEM; + memcpy(vecs_copy, vecs, sizeof(struct kvec) * count); + + entry_low = 0; + for (i = 0; i < concat->num_subdev; i++) { + struct mtd_info *subdev = concat->subdev[i]; + size_t size, wsize, retsize, old_iov_len; + + if (to >= subdev->size) { + to -= subdev->size; + continue; + } + + size = min(total_len, (size_t)(subdev->size - to)); + wsize = size; /* store for future use */ + + entry_high = entry_low; + while (entry_high < count) { + if (size <= vecs_copy[entry_high].iov_len) + break; + size -= vecs_copy[entry_high++].iov_len; + } + + old_iov_len = vecs_copy[entry_high].iov_len; + vecs_copy[entry_high].iov_len = size; + + if (!(subdev->flags & MTD_WRITEABLE)) + err = -EROFS; + else if (eccbuf) + err = subdev->writev_ecc(subdev, &vecs_copy[entry_low], + entry_high - entry_low + 1, to, &retsize, + eccbuf, oobsel); + else + err = subdev->writev(subdev, &vecs_copy[entry_low], + entry_high - entry_low + 1, to, &retsize); + + vecs_copy[entry_high].iov_len = old_iov_len - size; + vecs_copy[entry_high].iov_base += size; + + entry_low = entry_high; + + if (err) + break; + + *retlen += retsize; + total_len -= wsize; + if (concat->mtd.type == MTD_NANDFLASH && eccbuf) + eccbuf += mtd->oobavail * (wsize / mtd->oobblock); + + if (total_len == 0) + break; + + err = -EINVAL; + to = 0; + } + + kfree(vecs_copy); + return err; +} + +static int +concat_writev(struct mtd_info *mtd, const struct kvec *vecs, + unsigned long count, loff_t to, size_t * retlen) +{ + return concat_writev_ecc(mtd, vecs, count, to, retlen, NULL, NULL); +} + static int concat_read_oob(struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf) @@ -636,6 +736,58 @@ static void concat_resume(struct mtd_info *mtd) } } +static int concat_block_isbad(struct mtd_info *mtd, loff_t ofs) +{ + struct mtd_concat *concat = CONCAT(mtd); + int i, res = 0; + + if (!concat->subdev[0]->block_isbad) + return res; + + if (ofs > mtd->size) + return -EINVAL; + + for (i = 0; i < concat->num_subdev; i++) { + struct mtd_info *subdev = concat->subdev[i]; + + if (ofs >= subdev->size) { + ofs -= subdev->size; + continue; + } + + res = subdev->block_isbad(subdev, ofs); + break; + } + + return res; +} + +static int concat_block_markbad(struct mtd_info *mtd, loff_t ofs) +{ + struct mtd_concat *concat = CONCAT(mtd); + int i, err = -EINVAL; + + if (!concat->subdev[0]->block_markbad) + return 0; + + if (ofs > mtd->size) + return -EINVAL; + + for (i = 0; i < concat->num_subdev; i++) { + struct mtd_info *subdev = concat->subdev[i]; + + if (ofs >= subdev->size) { + ofs -= subdev->size; + continue; + } + + err = subdev->block_markbad(subdev, ofs); + break; + } + + return err; +} + /* * This function constructs a virtual MTD device by concatenating * num_devs MTD devices. A pointer to the new device object is @@ -685,10 +837,18 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c concat->mtd.read_ecc = concat_read_ecc; if (subdev[0]->write_ecc) concat->mtd.write_ecc = concat_write_ecc; + if (subdev[0]->writev) + concat->mtd.writev = concat_writev; + if (subdev[0]->writev_ecc) + concat->mtd.writev_ecc = concat_writev_ecc; if (subdev[0]->read_oob) concat->mtd.read_oob = concat_read_oob; if (subdev[0]->write_oob) concat->mtd.write_oob = concat_write_oob; + if (subdev[0]->block_isbad) + concat->mtd.block_isbad = concat_block_isbad; + if (subdev[0]->block_markbad) + concat->mtd.block_markbad = concat_block_markbad; concat->subdev[0] = subdev[0]; @@ -734,14 +894,13 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c } + if(concat->mtd.type == MTD_NANDFLASH) + memcpy(&concat->mtd.oobinfo, &subdev[0]->oobinfo, + sizeof(struct nand_oobinfo)); + concat->num_subdev = num_devs; concat->mtd.name = name; - /* - * NOTE: for now, we do not provide any readv()/writev() methods - * because they are messy to implement and they are not - * used to a great extent anyway. - */ concat->mtd.erase = concat_erase; concat->mtd.read = concat_read; concat->mtd.write = concat_write; -- cgit v1.2.3-70-g09d2 From fd0e5187458041c82fea616575104698397d68d3 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Wed, 17 May 2006 21:53:58 +0100 Subject: [MTD] Fix mtdconcat build. We didn't introduce mtd->writesize yet. Signed-off-by: David Woodhouse --- drivers/mtd/mtdconcat.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index da4c9c190bb3..b7de90845c2d 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c @@ -276,8 +276,8 @@ concat_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, return -EINVAL; /* Check alignment */ - if (mtd->writesize > 1) - if ((to % mtd->writesize) || (total_len % mtd->writesize)) + if (mtd->oobblock > 1) + if ((to % mtd->oobblock) || (total_len % mtd->oobblock)) return -EINVAL; /* make a copy of vecs */ -- cgit v1.2.3-70-g09d2 From f6a673b3f4f93c1c50e1b18f29254b0531b722a8 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Wed, 17 May 2006 22:03:10 +0100 Subject: [MTD] Fix printk format error in gen_probe.c Signed-off-by: David Woodhouse --- drivers/mtd/chips/gen_probe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/chips/gen_probe.c b/drivers/mtd/chips/gen_probe.c index b2d30525c04c..52d59d35091d 100644 --- a/drivers/mtd/chips/gen_probe.c +++ b/drivers/mtd/chips/gen_probe.c @@ -39,7 +39,7 @@ struct mtd_info *mtd_do_chip_probe(struct map_info *map, struct chip_probe *cp) if (mtd) { if (mtd->size > map->size) { - printk(KERN_WARNING "Reducing visibility of %lKiB chip to %lKiB\n", + printk(KERN_WARNING "Reducing visibility of %ldKiB chip to %ldKiB\n", (unsigned long)mtd->size >> 10, (unsigned long)map->size >> 10); mtd->size = map->size; -- cgit v1.2.3-70-g09d2