From 312f7da2824c82800ee78d6190f12854456957af Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Tue, 27 Sep 2005 17:38:03 +0800 Subject: [PATCH] libata: interrupt driven pio for libata-core - add PIO_ST_FIRST for the state before sending ATAPI CDB or sending "ATA PIO data out" first data block. - add ATA_TFLAG_POLLING and ATA_DFLAG_CDB_INTR flags - remove the ATA_FLAG_NOINTR flag since the interrupt handler is now aware of the states - modify ata_pio_sector() and atapi_pio_bytes() to work in the interrupt context - modify the ata_host_intr() to handle PIO interrupts - modify ata_qc_issue_prot() to initialize states - atapi_packet_task() changed to handle "ATA PIO data out" first data block - support the pre-ATA4 ATAPI device which raise interrupt when ready to receive CDB Signed-off-by: Albert Lee Signed-off-by: Jeff Garzik --- include/linux/ata.h | 3 +++ include/linux/libata.h | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/ata.h b/include/linux/ata.h index a5b74efab067..6fec2f6f2d59 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -181,6 +181,7 @@ enum { ATA_TFLAG_ISADDR = (1 << 1), /* enable r/w to nsect/lba regs */ ATA_TFLAG_DEVICE = (1 << 2), /* enable r/w to device reg */ ATA_TFLAG_WRITE = (1 << 3), /* data dir: host->dev==1 (write) */ + ATA_TFLAG_POLLING = (1 << 4), /* set nIEN to 1 and use polling */ }; enum ata_tf_protocols { @@ -250,6 +251,8 @@ struct ata_taskfile { ((u64) (id)[(n) + 1] << 16) | \ ((u64) (id)[(n) + 0]) ) +#define ata_id_cdb_intr(id) (((id)[0] & 0x60) == 0x20) + static inline int atapi_cdb_len(u16 *dev_id) { u16 tmp = dev_id[0] & 0x3; diff --git a/include/linux/libata.h b/include/linux/libata.h index bb2d916bce44..9ac2b69df3c1 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -97,6 +97,7 @@ enum { ATA_DFLAG_LBA48 = (1 << 0), /* device supports LBA48 */ ATA_DFLAG_PIO = (1 << 1), /* device currently in PIO mode */ ATA_DFLAG_LOCK_SECTORS = (1 << 2), /* don't adjust max_sectors */ + ATA_DFLAG_CDB_INTR = (1 << 3), /* device asserts INTRQ when ready for CDB */ ATA_DEV_UNKNOWN = 0, /* unknown device */ ATA_DEV_ATA = 1, /* ATA device */ @@ -115,8 +116,6 @@ enum { ATA_FLAG_MMIO = (1 << 6), /* use MMIO, not PIO */ ATA_FLAG_SATA_RESET = (1 << 7), /* use COMRESET */ ATA_FLAG_PIO_DMA = (1 << 8), /* PIO cmds via DMA */ - ATA_FLAG_NOINTR = (1 << 9), /* FIXME: Remove this once - * proper HSM is in place. */ ATA_QCFLAG_ACTIVE = (1 << 1), /* cmd not yet ack'd to scsi lyer */ ATA_QCFLAG_SG = (1 << 3), /* have s/g table? */ @@ -165,6 +164,7 @@ enum hsm_task_states { HSM_ST_LAST, HSM_ST_LAST_POLL, HSM_ST_ERR, + HSM_ST_FIRST, }; /* forward declarations */ -- cgit v1.2.3 From e50362eccd8809a224cda5f71714a088ba37b2ab Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Tue, 27 Sep 2005 17:39:50 +0800 Subject: [PATCH] libata: interrupt driven pio for LLD libata.h: libata-core: Add ATA_FLAG_PIO_POLLING flag for LLDs that expect interrupt for command completion only. sata_nv.c: sata_vsc.c: irq handler is wrapper around ata_host_intr(), can handle PIO interrupts. sata_promise.c: sata_sx4.c: sata_qstor.c: sata_mv.c: Private irq handler. Polling mode ATA_FLAG_PIO_POLLING used for compatibility. Signed-off-by: Albert Lee Signed-off-by: Jeff Garzik --- drivers/scsi/libata-core.c | 19 +++++++++++++++++++ drivers/scsi/sata_mv.c | 7 +++++-- drivers/scsi/sata_nv.c | 4 ++-- drivers/scsi/sata_promise.c | 13 ++++++++----- drivers/scsi/sata_qstor.c | 11 +++++------ drivers/scsi/sata_sx4.c | 7 ++++--- drivers/scsi/sata_vsc.c | 6 +++--- include/linux/libata.h | 2 ++ 8 files changed, 48 insertions(+), 21 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index cc2d1308826e..f8a590e59f10 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -3356,6 +3356,25 @@ int ata_qc_issue_prot(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; + /* Use polling pio if the LLD doesn't handle + * interrupt driven pio and atapi CDB interrupt. + */ + if (ap->flags & ATA_FLAG_PIO_POLLING) { + switch (qc->tf.protocol) { + case ATA_PROT_PIO: + case ATA_PROT_ATAPI: + case ATA_PROT_ATAPI_NODATA: + qc->tf.flags |= ATA_TFLAG_POLLING; + break; + case ATA_PROT_ATAPI_DMA: + if (qc->dev->flags & ATA_DFLAG_CDB_INTR) + BUG(); + break; + default: + break; + } + } + /* select the device */ ata_dev_select(ap, qc->dev->devno, 1, 0); diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c index ea76fe44585e..b8f1f6963179 100644 --- a/drivers/scsi/sata_mv.c +++ b/drivers/scsi/sata_mv.c @@ -241,7 +241,8 @@ static struct ata_port_info mv_port_info[] = { { /* chip_504x */ .sht = &mv_sht, .host_flags = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO), + ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO | + ATA_FLAG_PIO_POLLING), .pio_mask = 0x1f, /* pio4-0 */ .udma_mask = 0, /* 0x7f (udma6-0 disabled for now) */ .port_ops = &mv_ops, @@ -250,7 +251,7 @@ static struct ata_port_info mv_port_info[] = { .sht = &mv_sht, .host_flags = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO | - MV_FLAG_DUAL_HC), + ATA_FLAG_PIO_POLLING | MV_FLAG_DUAL_HC), .pio_mask = 0x1f, /* pio4-0 */ .udma_mask = 0, /* 0x7f (udma6-0 disabled for now) */ .port_ops = &mv_ops, @@ -259,6 +260,7 @@ static struct ata_port_info mv_port_info[] = { .sht = &mv_sht, .host_flags = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO | + ATA_FLAG_PIO_POLLING | MV_FLAG_IRQ_COALESCE | MV_FLAG_BDMA), .pio_mask = 0x1f, /* pio4-0 */ .udma_mask = 0, /* 0x7f (udma6-0 disabled for now) */ @@ -268,6 +270,7 @@ static struct ata_port_info mv_port_info[] = { .sht = &mv_sht, .host_flags = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO | + ATA_FLAG_PIO_POLLING | MV_FLAG_IRQ_COALESCE | MV_FLAG_DUAL_HC | MV_FLAG_BDMA), .pio_mask = 0x1f, /* pio4-0 */ diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c index c05653c7779d..8b7e871ea0bf 100644 --- a/drivers/scsi/sata_nv.c +++ b/drivers/scsi/sata_nv.c @@ -304,11 +304,11 @@ static irqreturn_t nv_interrupt (int irq, void *dev_instance, ap = host_set->ports[i]; if (ap && - !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) { + !(ap->flags & ATA_FLAG_PORT_DISABLED)) { struct ata_queued_cmd *qc; qc = ata_qc_from_tag(ap, ap->active_tag); - if (qc && (!(qc->tf.ctl & ATA_NIEN))) + if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) handled += ata_host_intr(ap, qc); } diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c index def7e0d9dacb..f67deb0a55c9 100644 --- a/drivers/scsi/sata_promise.c +++ b/drivers/scsi/sata_promise.c @@ -162,7 +162,8 @@ static struct ata_port_info pdc_port_info[] = { { .sht = &pdc_ata_sht, .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_SRST | ATA_FLAG_MMIO, + ATA_FLAG_SRST | ATA_FLAG_MMIO | + ATA_FLAG_PIO_POLLING, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ @@ -173,7 +174,8 @@ static struct ata_port_info pdc_port_info[] = { { .sht = &pdc_ata_sht, .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_SRST | ATA_FLAG_MMIO, + ATA_FLAG_SRST | ATA_FLAG_MMIO | + ATA_FLAG_PIO_POLLING, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ @@ -184,7 +186,8 @@ static struct ata_port_info pdc_port_info[] = { { .sht = &pdc_ata_sht, .host_flags = ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST | - ATA_FLAG_MMIO | ATA_FLAG_SLAVE_POSS, + ATA_FLAG_MMIO | ATA_FLAG_SLAVE_POSS | + ATA_FLAG_PIO_POLLING, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ @@ -493,11 +496,11 @@ static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *r ap = host_set->ports[i]; tmp = mask & (1 << (i + 1)); if (tmp && ap && - !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) { + !(ap->flags & ATA_FLAG_PORT_DISABLED)) { struct ata_queued_cmd *qc; qc = ata_qc_from_tag(ap, ap->active_tag); - if (qc && (!(qc->tf.ctl & ATA_NIEN))) + if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) handled += pdc_host_intr(ap, qc); } } diff --git a/drivers/scsi/sata_qstor.c b/drivers/scsi/sata_qstor.c index ffcdeb68641c..a604afafaecc 100644 --- a/drivers/scsi/sata_qstor.c +++ b/drivers/scsi/sata_qstor.c @@ -175,7 +175,7 @@ static struct ata_port_info qs_port_info[] = { .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SATA_RESET | //FIXME ATA_FLAG_SRST | - ATA_FLAG_MMIO, + ATA_FLAG_MMIO | ATA_FLAG_PIO_POLLING, .pio_mask = 0x10, /* pio4 */ .udma_mask = 0x7f, /* udma0-6 */ .port_ops = &qs_ata_ops, @@ -389,14 +389,13 @@ static inline unsigned int qs_intr_pkt(struct ata_host_set *host_set) DPRINTK("SFF=%08x%08x: sCHAN=%u sHST=%d sDST=%02x\n", sff1, sff0, port_no, sHST, sDST); handled = 1; - if (ap && !(ap->flags & - (ATA_FLAG_PORT_DISABLED|ATA_FLAG_NOINTR))) { + if (ap && !(ap->flags & ATA_FLAG_PORT_DISABLED)) { struct ata_queued_cmd *qc; struct qs_port_priv *pp = ap->private_data; if (!pp || pp->state != qs_state_pkt) continue; qc = ata_qc_from_tag(ap, ap->active_tag); - if (qc && (!(qc->tf.ctl & ATA_NIEN))) { + if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) { switch (sHST) { case 0: /* sucessful CPB */ case 3: /* device error */ @@ -422,13 +421,13 @@ static inline unsigned int qs_intr_mmio(struct ata_host_set *host_set) struct ata_port *ap; ap = host_set->ports[port_no]; if (ap && - !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) { + !(ap->flags & ATA_FLAG_PORT_DISABLED)) { struct ata_queued_cmd *qc; struct qs_port_priv *pp = ap->private_data; if (!pp || pp->state != qs_state_mmio) continue; qc = ata_qc_from_tag(ap, ap->active_tag); - if (qc && (!(qc->tf.ctl & ATA_NIEN))) { + if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) { /* check main status, clearing INTRQ */ u8 status = ata_chk_status(ap); diff --git a/drivers/scsi/sata_sx4.c b/drivers/scsi/sata_sx4.c index 540a85191172..a9f9f7685a59 100644 --- a/drivers/scsi/sata_sx4.c +++ b/drivers/scsi/sata_sx4.c @@ -219,7 +219,8 @@ static struct ata_port_info pdc_port_info[] = { { .sht = &pdc_sata_sht, .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_SRST | ATA_FLAG_MMIO, + ATA_FLAG_SRST | ATA_FLAG_MMIO | + ATA_FLAG_PIO_POLLING, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ @@ -832,11 +833,11 @@ static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_re tmp = mask & (1 << i); VPRINTK("seq %u, port_no %u, ap %p, tmp %x\n", i, port_no, ap, tmp); if (tmp && ap && - !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) { + !(ap->flags & ATA_FLAG_PORT_DISABLED)) { struct ata_queued_cmd *qc; qc = ata_qc_from_tag(ap, ap->active_tag); - if (qc && (!(qc->tf.ctl & ATA_NIEN))) + if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) handled += pdc20621_host_intr(ap, qc, (i > 4), mmio_base); } diff --git a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c index cf94e0158a8d..92378d768c86 100644 --- a/drivers/scsi/sata_vsc.c +++ b/drivers/scsi/sata_vsc.c @@ -193,12 +193,12 @@ static irqreturn_t vsc_sata_interrupt (int irq, void *dev_instance, struct ata_port *ap; ap = host_set->ports[i]; - if (ap && !(ap->flags & - (ATA_FLAG_PORT_DISABLED|ATA_FLAG_NOINTR))) { + if (ap && + !(ap->flags & ATA_FLAG_PORT_DISABLED)) { struct ata_queued_cmd *qc; qc = ata_qc_from_tag(ap, ap->active_tag); - if (qc && (!(qc->tf.ctl & ATA_NIEN))) + if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) handled += ata_host_intr(ap, qc); } } diff --git a/include/linux/libata.h b/include/linux/libata.h index 9ac2b69df3c1..ea8ab29aa92e 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -116,6 +116,8 @@ enum { ATA_FLAG_MMIO = (1 << 6), /* use MMIO, not PIO */ ATA_FLAG_SATA_RESET = (1 << 7), /* use COMRESET */ ATA_FLAG_PIO_DMA = (1 << 8), /* PIO cmds via DMA */ + ATA_FLAG_PIO_POLLING = (1 << 9), /* use polling PIO if LLD + * doesn't handle PIO interrupts */ ATA_QCFLAG_ACTIVE = (1 << 1), /* cmd not yet ack'd to scsi lyer */ ATA_QCFLAG_SG = (1 << 3), /* have s/g table? */ -- cgit v1.2.3 From c56b14d2a3e32695e13cd49b417da889da744d1c Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Fri, 30 Sep 2005 19:07:39 +0800 Subject: [PATCH] libata irq-pio: add comments and cleanup Signed-off-by: Albert Lee Signed-off-by: Jeff Garzik --- drivers/scsi/libata-core.c | 12 ------------ include/linux/libata.h | 19 ++++++++++--------- 2 files changed, 10 insertions(+), 21 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index f8a590e59f10..617836a313f0 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -3430,18 +3430,6 @@ int ata_qc_issue_prot(struct ata_queued_cmd *qc) break; case ATA_PROT_ATAPI: - if (qc->tf.flags & ATA_TFLAG_POLLING) - ata_qc_set_polling(qc); - - ata_tf_to_host_nolock(ap, &qc->tf); - ap->hsm_task_state = HSM_ST_FIRST; - - /* send cdb by polling if no cdb interrupt */ - if ((!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) || - (qc->tf.flags & ATA_TFLAG_POLLING)) - queue_work(ata_wq, &ap->packet_task); - break; - case ATA_PROT_ATAPI_NODATA: if (qc->tf.flags & ATA_TFLAG_POLLING) ata_qc_set_polling(qc); diff --git a/include/linux/libata.h b/include/linux/libata.h index ea8ab29aa92e..1fcd0ef9e1c9 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -158,15 +158,16 @@ enum { }; enum hsm_task_states { - HSM_ST_UNKNOWN, - HSM_ST_IDLE, - HSM_ST_POLL, - HSM_ST_TMOUT, - HSM_ST, - HSM_ST_LAST, - HSM_ST_LAST_POLL, - HSM_ST_ERR, - HSM_ST_FIRST, + HSM_ST_UNKNOWN, /* state unknown */ + HSM_ST_IDLE, /* no command on going */ + HSM_ST_POLL, /* same as HSM_ST, waits longer */ + HSM_ST_TMOUT, /* timeout */ + HSM_ST, /* (waiting the device to) transfer data */ + HSM_ST_LAST, /* (waiting the device to) complete command */ + HSM_ST_LAST_POLL, /* same as HSM_ST_LAST, waits longer */ + HSM_ST_ERR, /* error */ + HSM_ST_FIRST, /* (waiting the device to) + write CDB or first data block */ }; /* forward declarations */ -- cgit v1.2.3 From f9997be974be40e884e9e8157ded2f2f9aed454c Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Fri, 30 Sep 2005 19:09:31 +0800 Subject: [PATCH] libata irq-pio: rename atapi_packet_task() and comments Signed-off-by: Albert Lee Signed-off-by: Jeff Garzik --- drivers/scsi/libata-core.c | 25 +++++++++++++------------ include/linux/libata.h | 6 +++--- 2 files changed, 16 insertions(+), 15 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 617836a313f0..a63758da4892 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -3416,7 +3416,7 @@ int ata_qc_issue_prot(struct ata_queued_cmd *qc) if (qc->tf.flags & ATA_TFLAG_WRITE) { /* PIO data out protocol */ ap->hsm_task_state = HSM_ST_FIRST; - queue_work(ata_wq, &ap->packet_task); + queue_work(ata_wq, &ap->dataout_task); /* send first data block by polling */ } else { @@ -3440,7 +3440,7 @@ int ata_qc_issue_prot(struct ata_queued_cmd *qc) /* send cdb by polling if no cdb interrupt */ if ((!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) || (qc->tf.flags & ATA_TFLAG_POLLING)) - queue_work(ata_wq, &ap->packet_task); + queue_work(ata_wq, &ap->dataout_task); break; case ATA_PROT_ATAPI_DMA: @@ -3452,7 +3452,7 @@ int ata_qc_issue_prot(struct ata_queued_cmd *qc) /* send cdb by polling if no cdb interrupt */ if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) - queue_work(ata_wq, &ap->packet_task); + queue_work(ata_wq, &ap->dataout_task); break; default: @@ -3952,20 +3952,21 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs) } /** - * atapi_packet_task - Write CDB bytes to hardware - * @_data: Port to which ATAPI device is attached. + * ata_dataout_task - Write first data block to hardware + * @_data: Port to which ATA/ATAPI device is attached. * * When device has indicated its readiness to accept - * a CDB, this function is called. Send the CDB. - * If DMA is to be performed, exit immediately. - * Otherwise, we are in polling mode, so poll - * status under operation succeeds or fails. + * the data, this function sends out the CDB or + * the first data block by PIO. + * After this, + * - If polling, ata_pio_task() handles the rest. + * - Otherwise, interrupt handler takes over. * * LOCKING: * Kernel thread context (may sleep) */ -static void atapi_packet_task(void *_data) +static void ata_dataout_task(void *_data) { struct ata_port *ap = _data; struct ata_queued_cmd *qc; @@ -3978,7 +3979,7 @@ static void atapi_packet_task(void *_data) /* sleep-wait for BSY to clear */ DPRINTK("busy wait\n"); - if (ata_busy_sleep(ap, ATA_TMOUT_CDB_QUICK, ATA_TMOUT_CDB)) + if (ata_busy_sleep(ap, ATA_TMOUT_DATAOUT_QUICK, ATA_TMOUT_DATAOUT)) goto err_out; /* make sure DRQ is set */ @@ -4141,7 +4142,7 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host, ap->active_tag = ATA_TAG_POISON; ap->last_ctl = 0xFF; - INIT_WORK(&ap->packet_task, atapi_packet_task, ap); + INIT_WORK(&ap->dataout_task, ata_dataout_task, ap); INIT_WORK(&ap->pio_task, ata_pio_task, ap); for (i = 0; i < ATA_MAX_DEVICES; i++) diff --git a/include/linux/libata.h b/include/linux/libata.h index 1fcd0ef9e1c9..7e6feb97406e 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -129,8 +129,8 @@ enum { ATA_TMOUT_PIO = 30 * HZ, ATA_TMOUT_BOOT = 30 * HZ, /* hueristic */ ATA_TMOUT_BOOT_QUICK = 7 * HZ, /* hueristic */ - ATA_TMOUT_CDB = 30 * HZ, - ATA_TMOUT_CDB_QUICK = 5 * HZ, + ATA_TMOUT_DATAOUT = 30 * HZ, + ATA_TMOUT_DATAOUT_QUICK = 5 * HZ, /* ATA bus states */ BUS_UNKNOWN = 0, @@ -319,7 +319,7 @@ struct ata_port { struct ata_host_stats stats; struct ata_host_set *host_set; - struct work_struct packet_task; + struct work_struct dataout_task; struct work_struct pio_task; unsigned int hsm_task_state; -- cgit v1.2.3 From e27486db89ef04d5df1727c52362fa3d50cff241 Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Tue, 1 Nov 2005 19:24:49 +0800 Subject: [PATCH] libata irq-pio: merge the ata_dataout_task workqueue with ata_pio_task workqueue - remove ap->dataout_task from struct ata_port - let ata_pio_task() handle the HSM_ST_FIRST state. - rename ata_dataout_task() to ata_pio_first_block() - replace the ata_dataout_task workqueue with ata_pio_task workqueue Signed-off-by: Albert Lee ======== Signed-off-by: Jeff Garzik --- drivers/scsi/libata-core.c | 20 +++++++++++--------- include/linux/libata.h | 2 -- 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 15736e3313f0..96b8bbaa7631 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -3056,8 +3056,8 @@ static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc) } /** - * ata_dataout_task - Write first data block to hardware - * @_data: Port to which ATA/ATAPI device is attached. + * ata_pio_first_block - Write first data block to hardware + * @ap: Port to which ATA/ATAPI device is attached. * * When device has indicated its readiness to accept * the data, this function sends out the CDB or @@ -3070,9 +3070,8 @@ static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc) * Kernel thread context (may sleep) */ -static void ata_dataout_task(void *_data) +static void ata_pio_first_block(struct ata_port *ap) { - struct ata_port *ap = _data; struct ata_queued_cmd *qc; u8 status; unsigned long flags; @@ -3346,6 +3345,10 @@ fsm_start: qc_completed = 0; switch (ap->hsm_task_state) { + case HSM_ST_FIRST: + ata_pio_first_block(ap); + return; + case HSM_ST: ata_pio_block(ap); break; @@ -3796,10 +3799,10 @@ int ata_qc_issue_prot(struct ata_queued_cmd *qc) if (qc->tf.flags & ATA_TFLAG_WRITE) { /* PIO data out protocol */ ap->hsm_task_state = HSM_ST_FIRST; - queue_work(ata_wq, &ap->dataout_task); + queue_work(ata_wq, &ap->pio_task); /* always send first data block using - * the ata_dataout_task() codepath. + * the ata_pio_task() codepath. */ } else { /* PIO data in protocol */ @@ -3826,7 +3829,7 @@ int ata_qc_issue_prot(struct ata_queued_cmd *qc) /* send cdb by polling if no cdb interrupt */ if ((!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) || (qc->tf.flags & ATA_TFLAG_POLLING)) - queue_work(ata_wq, &ap->dataout_task); + queue_work(ata_wq, &ap->pio_task); break; case ATA_PROT_ATAPI_DMA: @@ -3838,7 +3841,7 @@ int ata_qc_issue_prot(struct ata_queued_cmd *qc) /* send cdb by polling if no cdb interrupt */ if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) - queue_work(ata_wq, &ap->dataout_task); + queue_work(ata_wq, &ap->pio_task); break; default: @@ -4426,7 +4429,6 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host, ap->active_tag = ATA_TAG_POISON; ap->last_ctl = 0xFF; - INIT_WORK(&ap->dataout_task, ata_dataout_task, ap); INIT_WORK(&ap->pio_task, ata_pio_task, ap); for (i = 0; i < ATA_MAX_DEVICES; i++) diff --git a/include/linux/libata.h b/include/linux/libata.h index ad0451dfee15..70ae140dbf23 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -346,8 +346,6 @@ struct ata_port { struct ata_host_stats stats; struct ata_host_set *host_set; - struct work_struct dataout_task; - struct work_struct pio_task; unsigned int hsm_task_state; unsigned long pio_task_timeout; -- cgit v1.2.3 From 07f6f7d074e68d56d82e7cc5c65096033ac8dc56 Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Tue, 1 Nov 2005 19:33:20 +0800 Subject: [PATCH] libata irq-pio: add read/write multiple support - add is_multi_taskfile() to ata.h - initialize ata_device->multi_count with device identify data - use ata_pio_sectors() to support r/w multiple commands Signed-off-by: Albert Lee ======== Signed-off-by: Jeff Garzik --- drivers/scsi/libata-core.c | 44 ++++++++++++++++++++++++++++++++++++++------ include/linux/ata.h | 8 ++++++++ 2 files changed, 46 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 2e0e6cca327c..59a4a26bc13f 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -1261,6 +1261,12 @@ retry: } + if (dev->id[59] & 0x100) { + dev->multi_count = dev->id[59] & 0xff; + DPRINTK("ata%u: dev %u multi count %u\n", + ap->id, device, dev->multi_count); + } + ap->host->max_cmd_len = 16; } @@ -2804,7 +2810,7 @@ static int ata_pio_complete (struct ata_port *ap) * we enter, BSY will be cleared in a chk-status or two. If not, * the drive is probably seeking or something. Snooze for a couple * msecs, then chk-status again. If still busy, fall back to - * HSM_ST_POLL state. + * HSM_ST_LAST_POLL state. */ drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 10); if (drv_stat & (ATA_BUSY | ATA_DRQ)) { @@ -3020,6 +3026,32 @@ static void ata_pio_sector(struct ata_queued_cmd *qc) } } +/** + * ata_pio_sectors - Transfer one or many 512-byte sectors. + * @qc: Command on going + * + * Transfer one or many ATA_SECT_SIZE of data from/to the + * ATA device for the DRQ request. + * + * LOCKING: + * Inherited from caller. + */ + +static void ata_pio_sectors(struct ata_queued_cmd *qc) +{ + if (is_multi_taskfile(&qc->tf)) { + /* READ/WRITE MULTIPLE */ + unsigned int nsect; + + assert(qc->dev->multi_count); + + nsect = min(qc->nsect - qc->cursect, qc->dev->multi_count); + while (nsect--) + ata_pio_sector(qc); + } else + ata_pio_sector(qc); +} + /** * atapi_send_cdb - Write CDB bytes to hardware * @ap: Port to which ATAPI device is attached. @@ -3118,11 +3150,11 @@ static int ata_pio_first_block(struct ata_port *ap) * send first data block. */ - /* ata_pio_sector() might change the state to HSM_ST_LAST. - * so, the state is changed here before ata_pio_sector(). + /* ata_pio_sectors() might change the state to HSM_ST_LAST. + * so, the state is changed here before ata_pio_sectors(). */ ap->hsm_task_state = HSM_ST; - ata_pio_sector(qc); + ata_pio_sectors(qc); ata_altstatus(ap); /* flush */ } else /* send CDB */ @@ -3327,7 +3359,7 @@ static void ata_pio_block(struct ata_port *ap) return; } - ata_pio_sector(qc); + ata_pio_sectors(qc); } ata_altstatus(ap); /* flush */ @@ -4213,7 +4245,7 @@ fsm_start: goto fsm_start; } - ata_pio_sector(qc); + ata_pio_sectors(qc); if (ap->hsm_task_state == HSM_ST_LAST && (!(qc->tf.flags & ATA_TFLAG_WRITE))) { diff --git a/include/linux/ata.h b/include/linux/ata.h index d54da3306d2c..f512104a1a3f 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -293,6 +293,14 @@ static inline int is_atapi_taskfile(const struct ata_taskfile *tf) (tf->protocol == ATA_PROT_ATAPI_DMA); } +static inline int is_multi_taskfile(struct ata_taskfile *tf) +{ + return (tf->command == ATA_CMD_READ_MULTI) || + (tf->command == ATA_CMD_WRITE_MULTI) || + (tf->command == ATA_CMD_READ_MULTI_EXT) || + (tf->command == ATA_CMD_WRITE_MULTI_EXT); +} + static inline int ata_ok(u8 status) { return ((status & (ATA_BUSY | ATA_DRDY | ATA_DF | ATA_DRQ | ATA_ERR)) -- cgit v1.2.3 From ffd642e748c867a7339b57225b8bf8b9a0dcd9c5 Mon Sep 17 00:00:00 2001 From: David Shaohua Li Date: Wed, 8 Feb 2006 17:35:00 -0500 Subject: [ACPI] enable SMP C-states on x86_64 http://bugzilla.kernel.org/show_bug.cgi?id=5653 Signed-off-by: David Shaohua Li Signed-off-by: Len Brown --- arch/x86_64/kernel/acpi/Makefile | 1 + arch/x86_64/kernel/acpi/processor.c | 72 ------------------------------------- include/asm-x86_64/acpi.h | 2 ++ 3 files changed, 3 insertions(+), 72 deletions(-) delete mode 100644 arch/x86_64/kernel/acpi/processor.c (limited to 'include') diff --git a/arch/x86_64/kernel/acpi/Makefile b/arch/x86_64/kernel/acpi/Makefile index 4fe97071f297..080b9963f1bc 100644 --- a/arch/x86_64/kernel/acpi/Makefile +++ b/arch/x86_64/kernel/acpi/Makefile @@ -4,5 +4,6 @@ obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup.o ifneq ($(CONFIG_ACPI_PROCESSOR),) obj-y += processor.o +processor-y := ../../../i386/kernel/acpi/processor.o ../../../i386/kernel/acpi/cstate.o endif diff --git a/arch/x86_64/kernel/acpi/processor.c b/arch/x86_64/kernel/acpi/processor.c deleted file mode 100644 index 3bdc2baa5bb1..000000000000 --- a/arch/x86_64/kernel/acpi/processor.c +++ /dev/null @@ -1,72 +0,0 @@ -/* - * arch/x86_64/kernel/acpi/processor.c - * - * Copyright (C) 2005 Intel Corporation - * Venkatesh Pallipadi - * - Added _PDC for platforms with Intel CPUs - */ - -#include -#include -#include -#include - -#include -#include - -static void init_intel_pdc(struct acpi_processor *pr, struct cpuinfo_x86 *c) -{ - struct acpi_object_list *obj_list; - union acpi_object *obj; - u32 *buf; - - /* allocate and initialize pdc. It will be used later. */ - obj_list = kmalloc(sizeof(struct acpi_object_list), GFP_KERNEL); - if (!obj_list) { - printk(KERN_ERR "Memory allocation error\n"); - return; - } - - obj = kmalloc(sizeof(union acpi_object), GFP_KERNEL); - if (!obj) { - printk(KERN_ERR "Memory allocation error\n"); - kfree(obj_list); - return; - } - - buf = kmalloc(12, GFP_KERNEL); - if (!buf) { - printk(KERN_ERR "Memory allocation error\n"); - kfree(obj); - kfree(obj_list); - return; - } - - buf[0] = ACPI_PDC_REVISION_ID; - buf[1] = 1; - buf[2] = ACPI_PDC_EST_CAPABILITY_SMP; - - obj->type = ACPI_TYPE_BUFFER; - obj->buffer.length = 12; - obj->buffer.pointer = (u8 *) buf; - obj_list->count = 1; - obj_list->pointer = obj; - pr->pdc = obj_list; - - return; -} - -/* Initialize _PDC data based on the CPU vendor */ -void arch_acpi_processor_init_pdc(struct acpi_processor *pr) -{ - unsigned int cpu = pr->id; - struct cpuinfo_x86 *c = cpu_data + cpu; - - pr->pdc = NULL; - if (c->x86_vendor == X86_VENDOR_INTEL && cpu_has(c, X86_FEATURE_EST)) - init_intel_pdc(pr, c); - - return; -} - -EXPORT_SYMBOL(arch_acpi_processor_init_pdc); diff --git a/include/asm-x86_64/acpi.h b/include/asm-x86_64/acpi.h index aa1c7b2e438c..2c95a319c056 100644 --- a/include/asm-x86_64/acpi.h +++ b/include/asm-x86_64/acpi.h @@ -162,6 +162,8 @@ extern int acpi_pci_disabled; extern u8 x86_acpiid_to_apicid[]; +#define ARCH_HAS_POWER_INIT 1 + extern int acpi_skip_timer_override; #endif /*__KERNEL__*/ -- cgit v1.2.3 From 3b2d99429e3386b6e2ac949fc72486509c8bbe36 Mon Sep 17 00:00:00 2001 From: Venkatesh Pallipadi Date: Wed, 14 Dec 2005 15:05:00 -0500 Subject: P-state software coordination for ACPI core http://bugzilla.kernel.org/show_bug.cgi?id=5737 Signed-off-by: Venkatesh Pallipadi Signed-off-by: Len Brown --- drivers/acpi/processor_perflib.c | 228 +++++++++++++++++++++++++++++++++++++++ include/acpi/processor.h | 27 ++++- include/linux/cpufreq.h | 4 + 3 files changed, 258 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index abbdb37a7f5f..ffc5280334c8 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -553,6 +553,234 @@ static void acpi_cpufreq_remove_file(struct acpi_processor *pr) } #endif /* CONFIG_X86_ACPI_CPUFREQ_PROC_INTF */ +static int acpi_processor_get_psd(struct acpi_processor *pr) +{ + int result = 0; + acpi_status status = AE_OK; + struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; + struct acpi_buffer format = {sizeof("NNNNN"), "NNNNN"}; + struct acpi_buffer state = {0, NULL}; + union acpi_object *psd = NULL; + struct acpi_psd_package *pdomain; + + ACPI_FUNCTION_TRACE("acpi_processor_get_psd"); + + status = acpi_evaluate_object(pr->handle, "_PSD", NULL, &buffer); + if (ACPI_FAILURE(status)) { + return_VALUE(-ENODEV); + } + + psd = (union acpi_object *) buffer.pointer; + if (!psd || (psd->type != ACPI_TYPE_PACKAGE)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n")); + result = -EFAULT; + goto end; + } + + if (psd->package.count != 1) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n")); + result = -EFAULT; + goto end; + } + + pdomain = &(pr->performance->domain_info); + + state.length = sizeof(struct acpi_psd_package); + state.pointer = pdomain; + + status = acpi_extract_package(&(psd->package.elements[0]), + &format, &state); + if (ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n")); + result = -EFAULT; + goto end; + } + + if (pdomain->num_entries != ACPI_PSD_REV0_ENTRIES) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _PSD:num_entries\n")); + result = -EFAULT; + goto end; + } + + if (pdomain->revision != ACPI_PSD_REV0_REVISION) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _PSD:revision\n")); + result = -EFAULT; + goto end; + } + +end: + acpi_os_free(buffer.pointer); + return_VALUE(result); +} + +int acpi_processor_preregister_performance( + struct acpi_processor_performance **performance) +{ + int count, count_target; + int retval = 0; + unsigned int i, j; + cpumask_t covered_cpus; + struct acpi_processor *pr; + struct acpi_psd_package *pdomain; + struct acpi_processor *match_pr; + struct acpi_psd_package *match_pdomain; + + ACPI_FUNCTION_TRACE("acpi_processor_preregister_performance"); + + down(&performance_sem); + + retval = 0; + + /* Call _PSD for all CPUs */ + for_each_cpu(i) { + pr = processors[i]; + if (!pr) { + /* Look only at processors in ACPI namespace */ + continue; + } + + if (pr->performance) { + retval = -EBUSY; + continue; + } + + if (!performance || !performance[i]) { + retval = -EINVAL; + continue; + } + + pr->performance = performance[i]; + cpu_set(i, pr->performance->shared_cpu_map); + if (acpi_processor_get_psd(pr)) { + retval = -EINVAL; + continue; + } + } + if (retval) + goto err_ret; + + /* + * Now that we have _PSD data from all CPUs, lets setup P-state + * domain info. + */ + for_each_cpu(i) { + pr = processors[i]; + if (!pr) + continue; + + /* Basic validity check for domain info */ + pdomain = &(pr->performance->domain_info); + if ((pdomain->revision != ACPI_PSD_REV0_REVISION) || + (pdomain->num_entries != ACPI_PSD_REV0_ENTRIES)) { + retval = -EINVAL; + goto err_ret; + } + if (pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ALL && + pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ANY && + pdomain->coord_type != DOMAIN_COORD_TYPE_HW_ALL) { + retval = -EINVAL; + goto err_ret; + } + } + + cpus_clear(covered_cpus); + for_each_cpu(i) { + pr = processors[i]; + if (!pr) + continue; + + if (cpu_isset(i, covered_cpus)) + continue; + + pdomain = &(pr->performance->domain_info); + cpu_set(i, pr->performance->shared_cpu_map); + cpu_set(i, covered_cpus); + if (pdomain->num_processors <= 1) + continue; + + /* Validate the Domain info */ + count_target = pdomain->num_processors; + count = 1; + if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ALL || + pdomain->coord_type == DOMAIN_COORD_TYPE_HW_ALL) { + pr->performance->shared_type = CPUFREQ_SHARED_TYPE_ALL; + } else if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ANY) { + pr->performance->shared_type = CPUFREQ_SHARED_TYPE_ANY; + } + + for_each_cpu(j) { + if (i == j) + continue; + + match_pr = processors[j]; + if (!match_pr) + continue; + + match_pdomain = &(match_pr->performance->domain_info); + if (match_pdomain->domain != pdomain->domain) + continue; + + /* Here i and j are in the same domain */ + + if (match_pdomain->num_processors != count_target) { + retval = -EINVAL; + goto err_ret; + } + + if (pdomain->coord_type != match_pdomain->coord_type) { + retval = -EINVAL; + goto err_ret; + } + + cpu_set(j, covered_cpus); + cpu_set(j, pr->performance->shared_cpu_map); + count++; + } + + for_each_cpu(j) { + if (i == j) + continue; + + match_pr = processors[j]; + if (!match_pr) + continue; + + match_pdomain = &(match_pr->performance->domain_info); + if (match_pdomain->domain != pdomain->domain) + continue; + + match_pr->performance->shared_type = + pr->performance->shared_type; + match_pr->performance->shared_cpu_map = + pr->performance->shared_cpu_map; + } + } + +err_ret: + if (retval) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error while parsing _PSD domain information. Assuming no coordination\n")); + } + + for_each_cpu(i) { + pr = processors[i]; + if (!pr || !pr->performance) + continue; + + /* Assume no coordination on any error parsing domain info */ + if (retval) { + cpus_clear(pr->performance->shared_cpu_map); + cpu_set(i, pr->performance->shared_cpu_map); + pr->performance->shared_type = CPUFREQ_SHARED_TYPE_ALL; + } + pr->performance = NULL; /* Will be set for real in register */ + } + + up(&performance_sem); + return_VALUE(retval); +} +EXPORT_SYMBOL(acpi_processor_preregister_performance); + + int acpi_processor_register_performance(struct acpi_processor_performance *performance, unsigned int cpu) diff --git a/include/acpi/processor.h b/include/acpi/processor.h index badf0277b1be..0c46d1b3dda2 100644 --- a/include/acpi/processor.h +++ b/include/acpi/processor.h @@ -3,6 +3,7 @@ #include #include +#include #include @@ -18,6 +19,17 @@ #define ACPI_PDC_REVISION_ID 0x1 +#define ACPI_PSD_REV0_REVISION 0 /* Support for _PSD as in ACPI 3.0 */ +#define ACPI_PSD_REV0_ENTRIES 5 + +/* + * Types of coordination defined in ACPI 3.0. Same macros can be used across + * P, C and T states + */ +#define DOMAIN_COORD_TYPE_SW_ALL 0xfc +#define DOMAIN_COORD_TYPE_SW_ANY 0xfd +#define DOMAIN_COORD_TYPE_HW_ALL 0xfe + /* Power Management */ struct acpi_processor_cx; @@ -66,6 +78,14 @@ struct acpi_processor_power { /* Performance Management */ +struct acpi_psd_package { + acpi_integer num_entries; + acpi_integer revision; + acpi_integer domain; + acpi_integer coord_type; + acpi_integer num_processors; +} __attribute__ ((packed)); + struct acpi_pct_register { u8 descriptor; u16 length; @@ -92,7 +112,9 @@ struct acpi_processor_performance { struct acpi_pct_register status_register; unsigned int state_count; struct acpi_processor_px *states; - + struct acpi_psd_package domain_info; + cpumask_t shared_cpu_map; + unsigned int shared_type; }; /* Throttling Control */ @@ -161,6 +183,9 @@ struct acpi_processor_errata { } piix4; }; +extern int acpi_processor_preregister_performance( + struct acpi_processor_performance **performance); + extern int acpi_processor_register_performance(struct acpi_processor_performance *performance, unsigned int cpu); extern void acpi_processor_unregister_performance(struct diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 17866d7e2b71..f7d988366941 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -73,6 +73,8 @@ struct cpufreq_real_policy { struct cpufreq_policy { cpumask_t cpus; /* affected CPUs */ + unsigned int shared_type; /* ANY or ALL affected CPUs + should set cpufreq */ unsigned int cpu; /* cpu nr of registered CPU */ struct cpufreq_cpuinfo cpuinfo;/* see above */ @@ -99,6 +101,8 @@ struct cpufreq_policy { #define CPUFREQ_INCOMPATIBLE (1) #define CPUFREQ_NOTIFY (2) +#define CPUFREQ_SHARED_TYPE_ALL (0) /* All dependent CPUs should set freq */ +#define CPUFREQ_SHARED_TYPE_ANY (1) /* Freq can be set from any dependent CPU */ /******************** cpufreq transition notifiers *******************/ -- cgit v1.2.3 From d52bb94d56676acd9bdac8e097257a87b4b1b2e1 Mon Sep 17 00:00:00 2001 From: Venkatesh Pallipadi Date: Wed, 14 Dec 2005 15:05:00 -0500 Subject: Enable P-state software coordination via _PDC http://bugzilla.kernel.org/show_bug.cgi?id=5737 Signed-off-by: Venkatesh Pallipadi Signed-off-by: Len Brown --- arch/i386/kernel/acpi/processor.c | 2 +- arch/x86_64/kernel/acpi/processor.c | 2 +- include/acpi/pdc_intel.h | 5 +++++ 3 files changed, 7 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/arch/i386/kernel/acpi/processor.c b/arch/i386/kernel/acpi/processor.c index 9f4cc02717ec..b54fded49834 100644 --- a/arch/i386/kernel/acpi/processor.c +++ b/arch/i386/kernel/acpi/processor.c @@ -47,7 +47,7 @@ static void init_intel_pdc(struct acpi_processor *pr, struct cpuinfo_x86 *c) buf[2] = ACPI_PDC_C_CAPABILITY_SMP; if (cpu_has(c, X86_FEATURE_EST)) - buf[2] |= ACPI_PDC_EST_CAPABILITY_SMP; + buf[2] |= ACPI_PDC_EST_CAPABILITY_SWSMP; obj->type = ACPI_TYPE_BUFFER; obj->buffer.length = 12; diff --git a/arch/x86_64/kernel/acpi/processor.c b/arch/x86_64/kernel/acpi/processor.c index 3bdc2baa5bb1..81fcb3f869f2 100644 --- a/arch/x86_64/kernel/acpi/processor.c +++ b/arch/x86_64/kernel/acpi/processor.c @@ -44,7 +44,7 @@ static void init_intel_pdc(struct acpi_processor *pr, struct cpuinfo_x86 *c) buf[0] = ACPI_PDC_REVISION_ID; buf[1] = 1; - buf[2] = ACPI_PDC_EST_CAPABILITY_SMP; + buf[2] = ACPI_PDC_EST_CAPABILITY_SWSMP; obj->type = ACPI_TYPE_BUFFER; obj->buffer.length = 12; diff --git a/include/acpi/pdc_intel.h b/include/acpi/pdc_intel.h index 3fa81d55cd0c..c5472be6f3a2 100644 --- a/include/acpi/pdc_intel.h +++ b/include/acpi/pdc_intel.h @@ -18,6 +18,11 @@ ACPI_PDC_C_C1_HALT | \ ACPI_PDC_P_FFH) +#define ACPI_PDC_EST_CAPABILITY_SWSMP (ACPI_PDC_SMP_C1PT | \ + ACPI_PDC_C_C1_HALT | \ + ACPI_PDC_SMP_P_SWCOORD | \ + ACPI_PDC_P_FFH) + #define ACPI_PDC_C_CAPABILITY_SMP (ACPI_PDC_SMP_C2C3 | \ ACPI_PDC_SMP_C1PT | \ ACPI_PDC_C_C1_HALT) -- cgit v1.2.3 From c2956a3b0d1c17b38da369811a6ce93eb7a01a04 Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Fri, 3 Mar 2006 10:34:05 +0800 Subject: [PATCH] libata-dev: recognize WRITE_MULTI_FUA_EXT for r/w multiple Recognize ATA_CMD_WRITE_MULTI_FUA_EXT as r/w multiple commands. Signed-off-by: Albert Lee Signed-off-by: Jeff Garzik --- include/linux/ata.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/ata.h b/include/linux/ata.h index 469952366ed4..e7b0c21f6cd4 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -314,7 +314,8 @@ static inline int is_multi_taskfile(struct ata_taskfile *tf) return (tf->command == ATA_CMD_READ_MULTI) || (tf->command == ATA_CMD_WRITE_MULTI) || (tf->command == ATA_CMD_READ_MULTI_EXT) || - (tf->command == ATA_CMD_WRITE_MULTI_EXT); + (tf->command == ATA_CMD_WRITE_MULTI_EXT) || + (tf->command == ATA_CMD_WRITE_MULTI_FUA_EXT); } static inline int ata_ok(u8 status) -- cgit v1.2.3 From 200d5a7684cc49ef4be40e832daf3f217e70dfbb Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 15 Feb 2006 16:24:49 +0900 Subject: [PATCH] libata: increase LBA48 max sectors to 65535 max_hw_sectors/max_sectors separation patch made into the tree, increase max_sectors to its hardware limit. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/scsi/libata-scsi.c | 2 +- include/linux/libata.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index dd954a23b357..b53ef494a206 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -678,7 +678,7 @@ static void ata_scsi_dev_config(struct scsi_device *sdev, */ max_sectors = ATA_MAX_SECTORS; if (dev->flags & ATA_DFLAG_LBA48) - max_sectors = 2048; + max_sectors = ATA_MAX_SECTORS_LBA48; if (dev->max_sectors) max_sectors = dev->max_sectors; diff --git a/include/linux/libata.h b/include/linux/libata.h index d81cecdda4f3..4dff3cf9d389 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -110,6 +110,7 @@ enum { ATA_DEF_QUEUE = 1, ATA_MAX_QUEUE = 1, ATA_MAX_SECTORS = 200, /* FIXME */ + ATA_MAX_SECTORS_LBA48 = 65535, ATA_MAX_BUS = 2, ATA_DEF_BUSY_WAIT = 10000, ATA_SHORT_PAUSE = (HZ >> 6) + 1, -- cgit v1.2.3 From 27cdadef6dfe0d0614653919a110fc75ab1650ce Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Sat, 25 Mar 2006 17:53:57 +0800 Subject: [PATCH] libata-dev: Cleanup unused enums/functions Cleanup the following unused functions: - ata_pio_poll() - ata_pio_complete() - ata_pio_first_block() - ata_pio_block() - ata_pio_error() ap->pio_task_timeout and other enums. Signed-off-by: Albert Lee Signed-off-by: Jeff Garzik --- drivers/scsi/libata-core.c | 279 --------------------------------------------- include/linux/libata.h | 9 -- 2 files changed, 288 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index eeeeda0481a2..ef0d0dd90e17 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -67,7 +67,6 @@ static void ata_set_mode(struct ata_port *ap); static unsigned int ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev); static void ata_dev_xfermask(struct ata_port *ap, struct ata_device *dev); -static void ata_pio_error(struct ata_port *ap); static unsigned int ata_unique_id = 1; static struct workqueue_struct *ata_wq; @@ -3131,114 +3130,6 @@ void ata_poll_qc_complete(struct ata_queued_cmd *qc) spin_unlock_irqrestore(&ap->host_set->lock, flags); } -/** - * ata_pio_poll - poll using PIO, depending on current state - * @ap: the target ata_port - * - * LOCKING: - * None. (executing in kernel thread context) - * - * RETURNS: - * timeout value to use - */ - -static unsigned long ata_pio_poll(struct ata_port *ap) -{ - struct ata_queued_cmd *qc; - u8 status; - unsigned int poll_state = HSM_ST_UNKNOWN; - unsigned int reg_state = HSM_ST_UNKNOWN; - - qc = ata_qc_from_tag(ap, ap->active_tag); - WARN_ON(qc == NULL); - - switch (ap->hsm_task_state) { - case HSM_ST: - case HSM_ST_POLL: - poll_state = HSM_ST_POLL; - reg_state = HSM_ST; - break; - case HSM_ST_LAST: - case HSM_ST_LAST_POLL: - poll_state = HSM_ST_LAST_POLL; - reg_state = HSM_ST_LAST; - break; - default: - BUG(); - break; - } - - status = ata_chk_status(ap); - if (status & ATA_BUSY) { - if (time_after(jiffies, ap->pio_task_timeout)) { - qc->err_mask |= AC_ERR_TIMEOUT; - ap->hsm_task_state = HSM_ST_TMOUT; - return 0; - } - ap->hsm_task_state = poll_state; - return ATA_SHORT_PAUSE; - } - - ap->hsm_task_state = reg_state; - return 0; -} - -/** - * ata_pio_complete - check if drive is busy or idle - * @ap: the target ata_port - * - * LOCKING: - * None. (executing in kernel thread context) - * - * RETURNS: - * Zero if qc completed. - * Non-zero if has next. - */ - -static int ata_pio_complete (struct ata_port *ap) -{ - struct ata_queued_cmd *qc; - u8 drv_stat; - - /* - * This is purely heuristic. This is a fast path. Sometimes when - * we enter, BSY will be cleared in a chk-status or two. If not, - * the drive is probably seeking or something. Snooze for a couple - * msecs, then chk-status again. If still busy, fall back to - * HSM_ST_LAST_POLL state. - */ - drv_stat = ata_busy_wait(ap, ATA_BUSY, 10); - if (drv_stat & ATA_BUSY) { - msleep(2); - drv_stat = ata_busy_wait(ap, ATA_BUSY, 10); - if (drv_stat & ATA_BUSY) { - ap->hsm_task_state = HSM_ST_LAST_POLL; - ap->pio_task_timeout = jiffies + ATA_TMOUT_PIO; - return 1; - } - } - - qc = ata_qc_from_tag(ap, ap->active_tag); - WARN_ON(qc == NULL); - - drv_stat = ata_wait_idle(ap); - if (!ata_ok(drv_stat)) { - qc->err_mask |= __ac_err_mask(drv_stat); - ap->hsm_task_state = HSM_ST_ERR; - return 1; - } - - ap->hsm_task_state = HSM_ST_IDLE; - - WARN_ON(qc->err_mask); - ata_poll_qc_complete(qc); - - /* another command may start at this point */ - - return 0; -} - - /** * swap_buf_le16 - swap halves of 16-bit words in place * @buf: Buffer to swap @@ -3496,91 +3387,6 @@ static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc) } } -/** - * ata_pio_first_block - Write first data block to hardware - * @ap: Port to which ATA/ATAPI device is attached. - * - * When device has indicated its readiness to accept - * the data, this function sends out the CDB or - * the first data block by PIO. - * After this, - * - If polling, ata_pio_task() handles the rest. - * - Otherwise, interrupt handler takes over. - * - * LOCKING: - * Kernel thread context (may sleep) - * - * RETURNS: - * Zero if irq handler takes over - * Non-zero if has next (polling). - */ - -static int ata_pio_first_block(struct ata_port *ap) -{ - struct ata_queued_cmd *qc; - u8 status; - unsigned long flags; - int has_next; - - qc = ata_qc_from_tag(ap, ap->active_tag); - WARN_ON(qc == NULL); - WARN_ON((qc->flags & ATA_QCFLAG_ACTIVE) == 0); - - /* if polling, we will stay in the work queue after sending the data. - * otherwise, interrupt handler takes over after sending the data. - */ - has_next = (qc->tf.flags & ATA_TFLAG_POLLING); - - /* sleep-wait for BSY to clear */ - DPRINTK("busy wait\n"); - if (ata_busy_sleep(ap, ATA_TMOUT_DATAOUT_QUICK, ATA_TMOUT_DATAOUT)) { - qc->err_mask |= AC_ERR_TIMEOUT; - ap->hsm_task_state = HSM_ST_TMOUT; - goto err_out; - } - - /* make sure DRQ is set */ - status = ata_chk_status(ap); - if ((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ) { - /* device status error */ - qc->err_mask |= AC_ERR_HSM; - ap->hsm_task_state = HSM_ST_ERR; - goto err_out; - } - - /* Send the CDB (atapi) or the first data block (ata pio out). - * During the state transition, interrupt handler shouldn't - * be invoked before the data transfer is complete and - * hsm_task_state is changed. Hence, the following locking. - */ - spin_lock_irqsave(&ap->host_set->lock, flags); - - if (qc->tf.protocol == ATA_PROT_PIO) { - /* PIO data out protocol. - * send first data block. - */ - - /* ata_pio_sectors() might change the state to HSM_ST_LAST. - * so, the state is changed here before ata_pio_sectors(). - */ - ap->hsm_task_state = HSM_ST; - ata_pio_sectors(qc); - ata_altstatus(ap); /* flush */ - } else - /* send CDB */ - atapi_send_cdb(ap, qc); - - spin_unlock_irqrestore(&ap->host_set->lock, flags); - - /* if polling, ata_pio_task() handles the rest. - * otherwise, interrupt handler takes over from here. - */ - return has_next; - -err_out: - return 1; /* has next */ -} - /** * __atapi_pio_bytes - Transfer data from/to the ATAPI device. * @qc: Command on going @@ -3720,91 +3526,6 @@ err_out: ap->hsm_task_state = HSM_ST_ERR; } -/** - * ata_pio_block - start PIO on a block - * @ap: the target ata_port - * - * LOCKING: - * None. (executing in kernel thread context) - */ - -static void ata_pio_block(struct ata_port *ap) -{ - struct ata_queued_cmd *qc; - u8 status; - - /* - * This is purely heuristic. This is a fast path. - * Sometimes when we enter, BSY will be cleared in - * a chk-status or two. If not, the drive is probably seeking - * or something. Snooze for a couple msecs, then - * chk-status again. If still busy, fall back to - * HSM_ST_POLL state. - */ - status = ata_busy_wait(ap, ATA_BUSY, 5); - if (status & ATA_BUSY) { - msleep(2); - status = ata_busy_wait(ap, ATA_BUSY, 10); - if (status & ATA_BUSY) { - ap->hsm_task_state = HSM_ST_POLL; - ap->pio_task_timeout = jiffies + ATA_TMOUT_PIO; - return; - } - } - - qc = ata_qc_from_tag(ap, ap->active_tag); - WARN_ON(qc == NULL); - - /* check error */ - if (status & (ATA_ERR | ATA_DF)) { - qc->err_mask |= AC_ERR_DEV; - ap->hsm_task_state = HSM_ST_ERR; - return; - } - - /* transfer data if any */ - if (is_atapi_taskfile(&qc->tf)) { - /* DRQ=0 means no more data to transfer */ - if ((status & ATA_DRQ) == 0) { - ap->hsm_task_state = HSM_ST_LAST; - return; - } - - atapi_pio_bytes(qc); - } else { - /* handle BSY=0, DRQ=0 as error */ - if ((status & ATA_DRQ) == 0) { - qc->err_mask |= AC_ERR_HSM; - ap->hsm_task_state = HSM_ST_ERR; - return; - } - - ata_pio_sectors(qc); - } - - ata_altstatus(ap); /* flush */ -} - -static void ata_pio_error(struct ata_port *ap) -{ - struct ata_queued_cmd *qc; - - qc = ata_qc_from_tag(ap, ap->active_tag); - WARN_ON(qc == NULL); - - if (qc->tf.command != ATA_CMD_PACKET) - printk(KERN_WARNING "ata%u: PIO error\n", ap->id); - - /* make sure qc->err_mask is available to - * know what's wrong and recover - */ - WARN_ON(qc->err_mask == 0); - - ap->hsm_task_state = HSM_ST_IDLE; - - ata_poll_qc_complete(qc); -} - /** * ata_hsm_move - move the HSM to the next state. * @ap: the target ata_port diff --git a/include/linux/libata.h b/include/linux/libata.h index 70ca99bbc6c7..0eb71c1773a1 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -162,13 +162,8 @@ enum { ATA_QCFLAG_EH_SCHEDULED = (1 << 5), /* EH scheduled */ /* various lengths of time */ - ATA_TMOUT_PIO = 30 * HZ, ATA_TMOUT_BOOT = 30 * HZ, /* heuristic */ ATA_TMOUT_BOOT_QUICK = 7 * HZ, /* heuristic */ - ATA_TMOUT_DATAOUT = 30 * HZ, - ATA_TMOUT_DATAOUT_QUICK = 5 * HZ, - ATA_TMOUT_CDB = 30 * HZ, - ATA_TMOUT_CDB_QUICK = 5 * HZ, ATA_TMOUT_INTERNAL = 30 * HZ, ATA_TMOUT_INTERNAL_QUICK = 5 * HZ, @@ -216,11 +211,8 @@ enum { enum hsm_task_states { HSM_ST_UNKNOWN, /* state unknown */ HSM_ST_IDLE, /* no command on going */ - HSM_ST_POLL, /* same as HSM_ST, waits longer */ - HSM_ST_TMOUT, /* timeout */ HSM_ST, /* (waiting the device to) transfer data */ HSM_ST_LAST, /* (waiting the device to) complete command */ - HSM_ST_LAST_POLL, /* same as HSM_ST_LAST, waits longer */ HSM_ST_ERR, /* error */ HSM_ST_FIRST, /* (waiting the device to) write CDB or first data block */ @@ -409,7 +401,6 @@ struct ata_port { struct work_struct port_task; unsigned int hsm_task_state; - unsigned long pio_task_timeout; u32 msg_enable; struct list_head eh_done_q; -- cgit v1.2.3 From 52fc0b026e99b5d5d585095148d997d5634bbc25 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Mon, 2 Oct 2006 00:00:00 -0400 Subject: [ACPI] ACPICA 20060210 Removed a couple of extraneous ACPI_ERROR messages that appeared during normal execution. These became apparent after the conversion from ACPI_DEBUG_PRINT. Fixed a problem where the CreateField operator could hang if the BitIndex or NumBits parameter referred to a named object. From Valery Podrezov. http://bugzilla.kernel.org/show_bug.cgi?id=5359 Fixed a problem where a DeRefOf operation on a buffer object incorrectly failed with an exception. This also fixes a couple of related RefOf and DeRefOf issues. From Valery Podrezov. http://bugzilla.kernel.org/show_bug.cgi?id=5360 http://bugzilla.kernel.org/show_bug.cgi?id=5387 http://bugzilla.kernel.org/show_bug.cgi?id=5392 Fixed a problem where the AE_BUFFER_LIMIT exception was returned instead of AE_STRING_LIMIT on an out-of-bounds Index() operation. From Valery Podrezov. http://bugzilla.kernel.org/show_bug.cgi?id=5480 Implemented a memory cleanup at the end of the execution of each iteration of an AML While() loop, preventing the accumulation of outstanding objects. From Valery Podrezov. http://bugzilla.kernel.org/show_bug.cgi?id=5427 Eliminated a chunk of duplicate code in the object resolution code. From Valery Podrezov. http://bugzilla.kernel.org/show_bug.cgi?id=5336 Fixed several warnings during the 64-bit code generation. Signed-off-by: Bob Moore Signed-off-by: Len Brown --- drivers/acpi/dispatcher/dsfield.c | 1 + drivers/acpi/dispatcher/dsmethod.c | 5 +++ drivers/acpi/dispatcher/dsmthdat.c | 1 + drivers/acpi/dispatcher/dsobject.c | 6 +++ drivers/acpi/dispatcher/dsopcode.c | 4 ++ drivers/acpi/dispatcher/dsutils.c | 7 +++- drivers/acpi/dispatcher/dswexec.c | 3 ++ drivers/acpi/dispatcher/dswload.c | 9 +++++ drivers/acpi/dispatcher/dswscope.c | 2 + drivers/acpi/dispatcher/dswstate.c | 5 +++ drivers/acpi/events/evevent.c | 2 + drivers/acpi/events/evgpe.c | 5 +++ drivers/acpi/events/evgpeblk.c | 13 +++++++ drivers/acpi/events/evmisc.c | 6 +++ drivers/acpi/events/evregion.c | 10 +++++ drivers/acpi/events/evrgnini.c | 6 +++ drivers/acpi/events/evxface.c | 3 ++ drivers/acpi/events/evxfevnt.c | 1 + drivers/acpi/events/evxfregn.c | 2 + drivers/acpi/executer/exconfig.c | 5 +++ drivers/acpi/executer/exconvrt.c | 2 + drivers/acpi/executer/exdump.c | 2 + drivers/acpi/executer/exfield.c | 2 + drivers/acpi/executer/exfldio.c | 5 +++ drivers/acpi/executer/exmisc.c | 1 + drivers/acpi/executer/exmutex.c | 3 ++ drivers/acpi/executer/exnames.c | 6 +++ drivers/acpi/executer/exoparg1.c | 44 ++++++++++++++++++---- drivers/acpi/executer/exoparg2.c | 77 ++++++++++++++++++++++++-------------- drivers/acpi/executer/exoparg3.c | 2 + drivers/acpi/executer/exoparg6.c | 1 + drivers/acpi/executer/exregion.c | 1 + drivers/acpi/executer/exresnte.c | 5 +++ drivers/acpi/executer/exresolv.c | 43 +++++---------------- drivers/acpi/executer/exresop.c | 4 ++ drivers/acpi/executer/exstore.c | 2 + drivers/acpi/executer/exstoren.c | 3 ++ drivers/acpi/executer/exstorob.c | 3 ++ drivers/acpi/executer/exsystem.c | 2 + drivers/acpi/executer/exutils.c | 3 ++ drivers/acpi/hardware/hwgpe.c | 2 + drivers/acpi/hardware/hwregs.c | 1 + drivers/acpi/hardware/hwsleep.c | 1 + drivers/acpi/hardware/hwtimer.c | 1 + drivers/acpi/namespace/nsaccess.c | 7 ++++ drivers/acpi/namespace/nsalloc.c | 8 ++++ drivers/acpi/namespace/nsdump.c | 4 ++ drivers/acpi/namespace/nseval.c | 1 + drivers/acpi/namespace/nsinit.c | 5 +++ drivers/acpi/namespace/nsload.c | 3 ++ drivers/acpi/namespace/nsobject.c | 3 ++ drivers/acpi/namespace/nssearch.c | 3 ++ drivers/acpi/namespace/nsutils.c | 6 +++ drivers/acpi/namespace/nswalk.c | 4 ++ drivers/acpi/namespace/nsxfeval.c | 46 ++++++++++++----------- drivers/acpi/namespace/nsxfname.c | 1 + drivers/acpi/namespace/nsxfobj.c | 1 + drivers/acpi/parser/psargs.c | 7 ++++ drivers/acpi/parser/psloop.c | 6 +++ drivers/acpi/parser/psopcode.c | 2 + drivers/acpi/parser/psparse.c | 8 ++++ drivers/acpi/parser/psscope.c | 1 + drivers/acpi/parser/pstree.c | 7 ++++ drivers/acpi/parser/psutils.c | 1 + drivers/acpi/parser/pswalk.c | 3 ++ drivers/acpi/parser/psxface.c | 2 + drivers/acpi/resources/rscalc.c | 16 +++++--- drivers/acpi/resources/rslist.c | 3 ++ drivers/acpi/resources/rsmisc.c | 6 ++- drivers/acpi/resources/rsutils.c | 46 +++++++++++++---------- drivers/acpi/resources/rsxface.c | 2 + drivers/acpi/tables/tbconvrt.c | 3 ++ drivers/acpi/tables/tbget.c | 9 +++++ drivers/acpi/tables/tbgetall.c | 1 + drivers/acpi/tables/tbinstal.c | 1 + drivers/acpi/tables/tbrsdt.c | 1 + drivers/acpi/tables/tbutils.c | 2 + drivers/acpi/tables/tbxface.c | 3 ++ drivers/acpi/tables/tbxfroot.c | 11 ++++++ drivers/acpi/utilities/utalloc.c | 5 +++ drivers/acpi/utilities/utcache.c | 2 + drivers/acpi/utilities/utcopy.c | 1 + drivers/acpi/utilities/utdebug.c | 4 ++ drivers/acpi/utilities/utdelete.c | 3 ++ drivers/acpi/utilities/uteval.c | 4 ++ drivers/acpi/utilities/utglobal.c | 2 + drivers/acpi/utilities/utmisc.c | 31 +++------------ drivers/acpi/utilities/utobject.c | 2 + drivers/acpi/utilities/utresrc.c | 4 ++ drivers/acpi/utilities/utstate.c | 2 + include/acpi/acconfig.h | 2 +- include/acpi/acdisasm.h | 1 + include/acpi/acutils.h | 2 - 93 files changed, 466 insertions(+), 144 deletions(-) (limited to 'include') diff --git a/drivers/acpi/dispatcher/dsfield.c b/drivers/acpi/dispatcher/dsfield.c index 76bc0463f6de..3d33bcc98678 100644 --- a/drivers/acpi/dispatcher/dsfield.c +++ b/drivers/acpi/dispatcher/dsfield.c @@ -425,6 +425,7 @@ acpi_ds_init_field_objects(union acpi_parse_object *op, * Walk the list of entries in the field_list */ while (arg) { + /* Ignore OFFSET and ACCESSAS terms here */ if (arg->common.aml_opcode == AML_INT_NAMEDFIELD_OP) { diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c index c475546535b6..238916ce5412 100644 --- a/drivers/acpi/dispatcher/dsmethod.c +++ b/drivers/acpi/dispatcher/dsmethod.c @@ -81,6 +81,7 @@ acpi_ds_method_error(acpi_status status, struct acpi_walk_state *walk_state) /* Invoke the global exception handler */ if (acpi_gbl_exception_handler) { + /* Exit the interpreter, allow handler to execute methods */ acpi_ex_exit_interpreter(); @@ -100,6 +101,7 @@ acpi_ds_method_error(acpi_status status, struct acpi_walk_state *walk_state) } #ifdef ACPI_DISASSEMBLER if (ACPI_FAILURE(status)) { + /* Display method locals/args if disassembler is present */ acpi_dm_dump_method_info(status, walk_state, walk_state->op); @@ -249,6 +251,7 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread, } if (!(obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY)) { + /* 1) Parse: Create a new walk state for the preempting walk */ next_walk_state = @@ -378,9 +381,11 @@ acpi_ds_restart_control_method(struct acpi_walk_state *walk_state, /* Did the called method return a value? */ if (return_desc) { + /* Are we actually going to use the return value? */ if (walk_state->return_used) { + /* Save the return value from the previous method */ status = acpi_ds_result_push(return_desc, walk_state); diff --git a/drivers/acpi/dispatcher/dsmthdat.c b/drivers/acpi/dispatcher/dsmthdat.c index c025674f938b..f7cb5170aa11 100644 --- a/drivers/acpi/dispatcher/dsmthdat.c +++ b/drivers/acpi/dispatcher/dsmthdat.c @@ -701,6 +701,7 @@ acpi_ds_method_data_get_type(u16 opcode, object = acpi_ns_get_attached_object(node); if (!object) { + /* Uninitialized local/arg, return TYPE_ANY */ return_VALUE(ACPI_TYPE_ANY); diff --git a/drivers/acpi/dispatcher/dsobject.c b/drivers/acpi/dispatcher/dsobject.c index 8b21f0f9e517..1f2d0c6ef36c 100644 --- a/drivers/acpi/dispatcher/dsobject.c +++ b/drivers/acpi/dispatcher/dsobject.c @@ -103,6 +103,7 @@ acpi_ds_build_internal_object(struct acpi_walk_state *walk_state, common. node))); if (ACPI_FAILURE(status)) { + /* Check if we are resolving a named reference within a package */ if ((status == AE_NOT_FOUND) @@ -195,6 +196,7 @@ acpi_ds_build_internal_buffer_obj(struct acpi_walk_state *walk_state, */ obj_desc = *obj_desc_ptr; if (!obj_desc) { + /* Create a new buffer object */ obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_BUFFER); @@ -355,6 +357,7 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state, arg = arg->common.next; for (i = 0; arg; i++) { if (arg->common.aml_opcode == AML_INT_RETURN_VALUE_OP) { + /* Object (package or buffer) is already built */ obj_desc->package.elements[i] = @@ -408,6 +411,7 @@ acpi_ds_create_node(struct acpi_walk_state *walk_state, } if (!op->common.value.arg) { + /* No arguments, there is nothing to do */ return_ACPI_STATUS(AE_OK); @@ -469,6 +473,7 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state, obj_desc = *ret_obj_desc; op_info = acpi_ps_get_opcode_info(opcode); if (op_info->class == AML_CLASS_UNKNOWN) { + /* Unknown opcode */ return_ACPI_STATUS(AE_TYPE); @@ -626,6 +631,7 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state, default: /* Other literals, etc.. */ if (op->common.aml_opcode == AML_INT_NAMEPATH_OP) { + /* Node was saved in Op */ obj_desc->reference.node = op->common.node; diff --git a/drivers/acpi/dispatcher/dsopcode.c b/drivers/acpi/dispatcher/dsopcode.c index 6229c10674e1..8a690a9963f2 100644 --- a/drivers/acpi/dispatcher/dsopcode.c +++ b/drivers/acpi/dispatcher/dsopcode.c @@ -640,6 +640,7 @@ acpi_ds_eval_buffer_field_operands(struct acpi_walk_state *walk_state, /* Initialize the Buffer Field */ if (op->common.aml_opcode == AML_CREATE_FIELD_OP) { + /* NOTE: Slightly different operands for this opcode */ status = @@ -984,6 +985,7 @@ acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state, ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "[WHILE_OP] Op=%p\n", op)); if (walk_state->control_state->common.value) { + /* Predicate was true, go back and evaluate it again! */ status = AE_CTRL_PENDING; @@ -1014,6 +1016,7 @@ acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state, * has been bubbled up the tree */ if (op->common.value.arg) { + /* Since we have a real Return(), delete any implicit return */ acpi_ds_clear_implicit_return(walk_state); @@ -1047,6 +1050,7 @@ acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state, walk_state->return_desc = walk_state->operands[0]; } else if ((walk_state->results) && (walk_state->results->results.num_results > 0)) { + /* Since we have a real Return(), delete any implicit return */ acpi_ds_clear_implicit_return(walk_state); diff --git a/drivers/acpi/dispatcher/dsutils.c b/drivers/acpi/dispatcher/dsutils.c index 53356a591ac1..3fbe17ebef5a 100644 --- a/drivers/acpi/dispatcher/dsutils.c +++ b/drivers/acpi/dispatcher/dsutils.c @@ -202,6 +202,7 @@ acpi_ds_is_result_used(union acpi_parse_object * op, */ if ((!op->common.parent) || (op->common.parent->common.aml_opcode == AML_SCOPE_OP)) { + /* No parent, the return value cannot possibly be used */ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, @@ -352,6 +353,7 @@ acpi_ds_delete_result_if_not_used(union acpi_parse_object *op, } if (!acpi_ds_is_result_used(op, walk_state)) { + /* Must pop the result stack (obj_desc should be equal to result_obj) */ status = acpi_ds_result_pop(&obj_desc, walk_state); @@ -498,7 +500,9 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state, */ if ((walk_state->deferred_node) && (walk_state->deferred_node->type == ACPI_TYPE_BUFFER_FIELD) - && (arg_index != 0)) { + && (arg_index == + (u32) ((walk_state->opcode == + AML_CREATE_FIELD_OP) ? 3 : 2))) { obj_desc = ACPI_CAST_PTR(union acpi_operand_object, walk_state->deferred_node); @@ -521,6 +525,7 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state, && (parent_op->common.aml_opcode != AML_REGION_OP) && (parent_op->common.aml_opcode != AML_INT_NAMEPATH_OP)) { + /* Enter name into namespace if not found */ interpreter_mode = ACPI_IMODE_LOAD_PASS2; diff --git a/drivers/acpi/dispatcher/dswexec.c b/drivers/acpi/dispatcher/dswexec.c index f1af655ff113..198949f41048 100644 --- a/drivers/acpi/dispatcher/dswexec.c +++ b/drivers/acpi/dispatcher/dswexec.c @@ -409,6 +409,7 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state) * being the object_type and size_of operators. */ if (!(walk_state->op_info->flags & AML_NO_OPERAND_RESOLVE)) { + /* Resolve all operands */ status = acpi_ex_resolve_operands(walk_state->opcode, @@ -548,6 +549,7 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state) */ status = acpi_ds_resolve_operands(walk_state); if (ACPI_FAILURE(status)) { + /* On error, clear all resolved operands */ acpi_ds_clear_operands(walk_state); @@ -722,6 +724,7 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state) cleanup: if (walk_state->result_obj) { + /* Break to debugger to display result */ ACPI_DEBUGGER_EXEC(acpi_db_display_result_object diff --git a/drivers/acpi/dispatcher/dswload.c b/drivers/acpi/dispatcher/dswload.c index d3d24da31c81..02b03126e14e 100644 --- a/drivers/acpi/dispatcher/dswload.c +++ b/drivers/acpi/dispatcher/dswload.c @@ -261,6 +261,7 @@ acpi_ds_load1_begin_op(struct acpi_walk_state * walk_state, */ if (walk_state->deferred_node) { + /* This name is already in the namespace, get the node */ node = walk_state->deferred_node; @@ -311,6 +312,7 @@ acpi_ds_load1_begin_op(struct acpi_walk_state * walk_state, /* Common exit */ if (!op) { + /* Create a new op */ op = acpi_ps_alloc_op(walk_state->opcode); @@ -413,6 +415,7 @@ acpi_status acpi_ds_load1_end_op(struct acpi_walk_state *walk_state) #endif if (op->common.aml_opcode == AML_NAME_OP) { + /* For Name opcode, get the object type from the argument */ if (op->common.value.arg) { @@ -521,6 +524,7 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state, if ((walk_state->control_state) && (walk_state->control_state->common.state == ACPI_CONTROL_CONDITIONAL_EXECUTING)) { + /* We are executing a while loop outside of a method */ status = acpi_ds_exec_begin_op(walk_state, out_op); @@ -554,10 +558,12 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state, /* Get the name we are going to enter or lookup in the namespace */ if (walk_state->opcode == AML_INT_NAMEPATH_OP) { + /* For Namepath op, get the path string */ buffer_ptr = op->common.value.string; if (!buffer_ptr) { + /* No name, just exit */ return_ACPI_STATUS(AE_OK); @@ -680,6 +686,7 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state, /* All other opcodes */ if (op && op->common.node) { + /* This op/node was previously entered into the namespace */ node = op->common.node; @@ -705,6 +712,7 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state, * Note: Name may already exist if we are executing a deferred opcode. */ if (walk_state->deferred_node) { + /* This name is already in the namespace, get the node */ node = walk_state->deferred_node; @@ -727,6 +735,7 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state, } if (!op) { + /* Create a new op */ op = acpi_ps_alloc_op(walk_state->opcode); diff --git a/drivers/acpi/dispatcher/dswscope.c b/drivers/acpi/dispatcher/dswscope.c index ada21ef4a174..e2954fff8c5e 100644 --- a/drivers/acpi/dispatcher/dswscope.c +++ b/drivers/acpi/dispatcher/dswscope.c @@ -66,6 +66,7 @@ void acpi_ds_scope_stack_clear(struct acpi_walk_state *walk_state) ACPI_FUNCTION_NAME("ds_scope_stack_clear"); while (walk_state->scope_info) { + /* Pop a scope off the stack */ scope_info = walk_state->scope_info; @@ -105,6 +106,7 @@ acpi_ds_scope_stack_push(struct acpi_namespace_node *node, ACPI_FUNCTION_TRACE("ds_scope_stack_push"); if (!node) { + /* Invalid scope */ ACPI_ERROR((AE_INFO, "Null scope parameter")); diff --git a/drivers/acpi/dispatcher/dswstate.c b/drivers/acpi/dispatcher/dswstate.c index fa78cb74ee36..5bc340b1b286 100644 --- a/drivers/acpi/dispatcher/dswstate.c +++ b/drivers/acpi/dispatcher/dswstate.c @@ -170,6 +170,7 @@ acpi_ds_result_pop(union acpi_operand_object ** object, state->results.num_results--; for (index = ACPI_OBJ_NUM_OPERANDS; index; index--) { + /* Check for a valid result object */ if (state->results.obj_desc[index - 1]) { @@ -448,6 +449,7 @@ acpi_ds_obj_stack_pop(u32 pop_count, struct acpi_walk_state * walk_state) ACPI_FUNCTION_NAME("ds_obj_stack_pop"); for (i = 0; i < pop_count; i++) { + /* Check for stack underflow */ if (walk_state->num_operands == 0) { @@ -494,6 +496,7 @@ acpi_ds_obj_stack_pop_and_delete(u32 pop_count, ACPI_FUNCTION_NAME("ds_obj_stack_pop_and_delete"); for (i = 0; i < pop_count; i++) { + /* Check for stack underflow */ if (walk_state->num_operands == 0) { @@ -598,6 +601,7 @@ struct acpi_walk_state *acpi_ds_pop_walk_state(struct acpi_thread_state *thread) walk_state = thread->walk_state_list; if (walk_state) { + /* Next walk state becomes the current walk state */ thread->walk_state_list = walk_state->next; @@ -778,6 +782,7 @@ acpi_ds_init_aml_walk(struct acpi_walk_state *walk_state, } if (parser_state->start_node) { + /* Push start scope on scope stack and make it current */ status = diff --git a/drivers/acpi/events/evevent.c b/drivers/acpi/events/evevent.c index c9ac05c4685f..c8d9752e3128 100644 --- a/drivers/acpi/events/evevent.c +++ b/drivers/acpi/events/evevent.c @@ -260,12 +260,14 @@ u32 acpi_ev_fixed_event_detect(void) * Check for all possible Fixed Events and dispatch those that are active */ for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) { + /* Both the status and enable bits must be on for this event */ if ((fixed_status & acpi_gbl_fixed_event_info[i]. status_bit_mask) && (fixed_enable & acpi_gbl_fixed_event_info[i]. enable_bit_mask)) { + /* Found an active (signalled) event */ int_status |= acpi_ev_fixed_event_dispatch((u32) i); diff --git a/drivers/acpi/events/evgpe.c b/drivers/acpi/events/evgpe.c index f64f977dd3d5..7d7b81af972e 100644 --- a/drivers/acpi/events/evgpe.c +++ b/drivers/acpi/events/evgpe.c @@ -207,6 +207,7 @@ acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info, ACPI_SET_BIT(gpe_event_info->flags, ACPI_GPE_RUN_ENABLED); if (write_to_hardware) { + /* Clear the GPE (of stale events), then enable it */ status = acpi_hw_clear_gpe(gpe_event_info); @@ -313,6 +314,7 @@ struct acpi_gpe_event_info *acpi_ev_get_gpe_event_info(acpi_handle gpe_device, /* A NULL gpe_block means use the FADT-defined GPE block(s) */ if (!gpe_device) { + /* Examine GPE Block 0 and 1 (These blocks are permanent) */ for (i = 0; i < ACPI_MAX_GPE_BLOCKS; i++) { @@ -402,6 +404,7 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list) * Find all currently active GP events. */ for (i = 0; i < gpe_block->register_count; i++) { + /* Get the next status/enable pair */ gpe_register_info = &gpe_block->register_info[i]; @@ -437,6 +440,7 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list) enabled_status_byte = (u8) (status_reg & enable_reg); if (!enabled_status_byte) { + /* No active GPEs in this register, move on */ continue; @@ -445,6 +449,7 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list) /* Now look at the individual GPEs in this byte register */ for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) { + /* Examine one GPE bit */ if (enabled_status_byte & diff --git a/drivers/acpi/events/evgpeblk.c b/drivers/acpi/events/evgpeblk.c index 0fd00b5ad650..87e77a138fff 100644 --- a/drivers/acpi/events/evgpeblk.c +++ b/drivers/acpi/events/evgpeblk.c @@ -146,10 +146,12 @@ acpi_status acpi_ev_walk_gpe_list(ACPI_GPE_CALLBACK gpe_walk_callback) gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head; while (gpe_xrupt_info) { + /* Walk all Gpe Blocks attached to this interrupt level */ gpe_block = gpe_xrupt_info->gpe_block_list_head; while (gpe_block) { + /* One callback per GPE block */ status = gpe_walk_callback(gpe_xrupt_info, gpe_block); @@ -195,6 +197,7 @@ acpi_ev_delete_gpe_handlers(struct acpi_gpe_xrupt_info *gpe_xrupt_info, /* Examine each GPE Register within the block */ for (i = 0; i < gpe_block->register_count; i++) { + /* Now look at the individual GPEs in this byte register */ for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) { @@ -289,6 +292,7 @@ acpi_ev_save_method_info(acpi_handle obj_handle, gpe_number = ACPI_STRTOUL(&name[2], NULL, 16); if (gpe_number == ACPI_UINT32_MAX) { + /* Conversion failed; invalid method, just ignore it */ ACPI_ERROR((AE_INFO, @@ -371,6 +375,7 @@ acpi_ev_match_prw_and_gpe(acpi_handle obj_handle, status = acpi_ut_evaluate_object(obj_handle, METHOD_NAME__PRW, ACPI_BTYPE_PACKAGE, &pkg_desc); if (ACPI_FAILURE(status)) { + /* Ignore all errors from _PRW, we don't want to abort the subsystem */ return_ACPI_STATUS(AE_OK); @@ -394,6 +399,7 @@ acpi_ev_match_prw_and_gpe(acpi_handle obj_handle, obj_desc = pkg_desc->package.elements[0]; if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_INTEGER) { + /* Use FADT-defined GPE device (from definition of _PRW) */ target_gpe_device = acpi_gbl_fadt_gpe_device; @@ -402,6 +408,7 @@ acpi_ev_match_prw_and_gpe(acpi_handle obj_handle, gpe_number = (u32) obj_desc->integer.value; } else if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_PACKAGE) { + /* Package contains a GPE reference and GPE number within a GPE block */ if ((obj_desc->package.count < 2) || @@ -679,6 +686,7 @@ acpi_status acpi_ev_delete_gpe_block(struct acpi_gpe_block_info *gpe_block) status = acpi_hw_disable_gpe_block(gpe_block->xrupt_block, gpe_block); if (!gpe_block->previous && !gpe_block->next) { + /* This is the last gpe_block on this interrupt */ status = acpi_ev_delete_gpe_xrupt(gpe_block->xrupt_block); @@ -780,6 +788,7 @@ acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block) this_event = gpe_event_info; for (i = 0; i < gpe_block->register_count; i++) { + /* Init the register_info for this GPE register (8 GPEs) */ this_register->base_gpe_number = @@ -1013,6 +1022,7 @@ acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device, for (i = 0; i < gpe_block->register_count; i++) { for (j = 0; j < 8; j++) { + /* Get the info block for this particular GPE */ gpe_event_info = @@ -1099,6 +1109,7 @@ acpi_status acpi_ev_gpe_initialize(void) * particular block is not supported. */ if (acpi_gbl_FADT->gpe0_blk_len && acpi_gbl_FADT->xgpe0_blk.address) { + /* GPE block 0 exists (has both length and address > 0) */ register_count0 = (u16) (acpi_gbl_FADT->gpe0_blk_len / 2); @@ -1121,6 +1132,7 @@ acpi_status acpi_ev_gpe_initialize(void) } if (acpi_gbl_FADT->gpe1_blk_len && acpi_gbl_FADT->xgpe1_blk.address) { + /* GPE block 1 exists (has both length and address > 0) */ register_count1 = (u16) (acpi_gbl_FADT->gpe1_blk_len / 2); @@ -1168,6 +1180,7 @@ acpi_status acpi_ev_gpe_initialize(void) /* Exit if there are no GPE registers */ if ((register_count0 + register_count1) == 0) { + /* GPEs are not required by ACPI, this is OK */ ACPI_DEBUG_PRINT((ACPI_DB_INIT, diff --git a/drivers/acpi/events/evmisc.c b/drivers/acpi/events/evmisc.c index 0909ba69577e..334407239f2f 100644 --- a/drivers/acpi/events/evmisc.c +++ b/drivers/acpi/events/evmisc.c @@ -150,6 +150,7 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node, obj_desc = acpi_ns_get_attached_object(node); if (obj_desc) { + /* We have the notify object, Get the right handler */ switch (node->type) { @@ -240,6 +241,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context) * to the device. */ if (notify_info->notify.value <= ACPI_MAX_SYS_NOTIFY) { + /* Global system notification handler */ if (acpi_gbl_system_notify.handler) { @@ -297,6 +299,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_global_lock_thread(void *context) /* Signal threads that are waiting for the lock */ if (acpi_gbl_global_lock_thread_count) { + /* Send sufficient units to the semaphore */ status = @@ -335,6 +338,7 @@ static u32 acpi_ev_global_lock_handler(void *context) */ ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_common_fACS.global_lock, acquired); if (acquired) { + /* Got the lock, now wake all threads waiting for it */ acpi_gbl_global_lock_acquired = TRUE; @@ -439,6 +443,7 @@ acpi_status acpi_ev_acquire_global_lock(u16 timeout) ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_common_fACS.global_lock, acquired); if (acquired) { + /* We got the lock */ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, @@ -492,6 +497,7 @@ acpi_status acpi_ev_release_global_lock(void) acpi_gbl_global_lock_thread_count--; if (acpi_gbl_global_lock_thread_count) { + /* There are still some threads holding the lock, cannot release */ return_ACPI_STATUS(AE_OK); diff --git a/drivers/acpi/events/evregion.c b/drivers/acpi/events/evregion.c index 6da58e776413..b831ec4bcae7 100644 --- a/drivers/acpi/events/evregion.c +++ b/drivers/acpi/events/evregion.c @@ -164,6 +164,7 @@ acpi_status acpi_ev_initialize_op_regions(void) * Run the _REG methods for op_regions in each default address space */ for (i = 0; i < ACPI_NUM_DEFAULT_SPACES; i++) { + /* TBD: Make sure handler is the DEFAULT handler, otherwise * _REG will have already been run. */ @@ -315,6 +316,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, */ region_setup = handler_desc->address_space.setup; if (!region_setup) { + /* No initialization routine, exit with error */ ACPI_ERROR((AE_INFO, @@ -361,6 +363,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, region_obj->region.flags |= AOPOBJ_SETUP_COMPLETE; if (region_obj2->extra.region_context) { + /* The handler for this region was already installed */ ACPI_MEM_FREE(region_context); @@ -463,6 +466,7 @@ acpi_ev_detach_region(union acpi_operand_object *region_obj, handler_obj = region_obj->region.handler; if (!handler_obj) { + /* This region has no handler, all done */ return_VOID; @@ -474,6 +478,7 @@ acpi_ev_detach_region(union acpi_operand_object *region_obj, last_obj_ptr = &handler_obj->address_space.region_list; while (obj_desc) { + /* Is this the correct Region? */ if (obj_desc == region_obj) { @@ -666,6 +671,7 @@ acpi_ev_install_handler(acpi_handle obj_handle, obj_desc = acpi_ns_get_attached_object(node); if (!obj_desc) { + /* No object, just exit */ return (AE_OK); @@ -674,10 +680,12 @@ acpi_ev_install_handler(acpi_handle obj_handle, /* Devices are handled different than regions */ if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_DEVICE) { + /* Check if this Device already has a handler for this address space */ next_handler_obj = obj_desc->device.handler; while (next_handler_obj) { + /* Found a handler, is it for the same address space? */ if (next_handler_obj->address_space.space_id == @@ -839,6 +847,7 @@ acpi_ev_install_space_handler(struct acpi_namespace_node * node, /* Walk the handler list for this device */ while (handler_obj) { + /* Same space_id indicates a handler already installed */ if (handler_obj->address_space.space_id == space_id) { @@ -1035,6 +1044,7 @@ acpi_ev_reg_run(acpi_handle obj_handle, obj_desc = acpi_ns_get_attached_object(node); if (!obj_desc) { + /* No object, just exit */ return (AE_OK); diff --git a/drivers/acpi/events/evrgnini.c b/drivers/acpi/events/evrgnini.c index baed8c1a1b9f..a0bffc2a0787 100644 --- a/drivers/acpi/events/evrgnini.c +++ b/drivers/acpi/events/evrgnini.c @@ -199,6 +199,7 @@ acpi_ev_pci_config_region_setup(acpi_handle handle, * handlers with that device. */ if (handler_obj->address_space.node == acpi_gbl_root_node) { + /* Start search from the parent object */ pci_root_node = parent_node; @@ -220,6 +221,7 @@ acpi_ev_pci_config_region_setup(acpi_handle handle, PCI_EXPRESS_ROOT_HID_STRING, sizeof(PCI_EXPRESS_ROOT_HID_STRING))))) { + /* Install a handler for this PCI root bridge */ status = @@ -478,11 +480,13 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj, * ie: acpi_gbl_root_node->parent_entry being set to NULL */ while (node) { + /* Check to see if a handler exists */ handler_obj = NULL; obj_desc = acpi_ns_get_attached_object(node); if (obj_desc) { + /* Can only be a handler if the object exists */ switch (node->type) { @@ -507,10 +511,12 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj, } while (handler_obj) { + /* Is this handler of the correct type? */ if (handler_obj->address_space.space_id == space_id) { + /* Found correct handler */ ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, diff --git a/drivers/acpi/events/evxface.c b/drivers/acpi/events/evxface.c index b38b39dde543..ba16fda3a158 100644 --- a/drivers/acpi/events/evxface.c +++ b/drivers/acpi/events/evxface.c @@ -275,6 +275,7 @@ acpi_install_notify_handler(acpi_handle device, * only one global handler can be regsitered (per notify type). */ if (device == ACPI_ROOT_OBJECT) { + /* Make sure the handler is not already installed */ if (((handler_type & ACPI_SYSTEM_NOTIFY) && @@ -317,6 +318,7 @@ acpi_install_notify_handler(acpi_handle device, obj_desc = acpi_ns_get_attached_object(node); if (obj_desc) { + /* Object exists - make sure there's no handler */ if (((handler_type & ACPI_SYSTEM_NOTIFY) && @@ -370,6 +372,7 @@ acpi_install_notify_handler(acpi_handle device, } if (handler_type == ACPI_ALL_NOTIFY) { + /* Extra ref if installed in both */ acpi_ut_add_reference(notify_obj); diff --git a/drivers/acpi/events/evxfevnt.c b/drivers/acpi/events/evxfevnt.c index ec9ce8429f15..babebb501405 100644 --- a/drivers/acpi/events/evxfevnt.c +++ b/drivers/acpi/events/evxfevnt.c @@ -636,6 +636,7 @@ acpi_install_gpe_block(acpi_handle gpe_device, obj_desc = acpi_ns_get_attached_object(node); if (!obj_desc) { + /* No object, create a new one */ obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_DEVICE); diff --git a/drivers/acpi/events/evxfregn.c b/drivers/acpi/events/evxfregn.c index abf5caca9ae5..368c8aa0094b 100644 --- a/drivers/acpi/events/evxfregn.c +++ b/drivers/acpi/events/evxfregn.c @@ -176,9 +176,11 @@ acpi_remove_address_space_handler(acpi_handle device, handler_obj = obj_desc->device.handler; last_obj_ptr = &obj_desc->device.handler; while (handler_obj) { + /* We have a handler, see if user requested this one */ if (handler_obj->address_space.space_id == space_id) { + /* Matched space_id, first dereference this in the Regions */ ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, diff --git a/drivers/acpi/executer/exconfig.c b/drivers/acpi/executer/exconfig.c index a29782fe3ecf..864530f754c3 100644 --- a/drivers/acpi/executer/exconfig.c +++ b/drivers/acpi/executer/exconfig.c @@ -110,6 +110,7 @@ acpi_ex_add_table(struct acpi_table_header *table, if (ACPI_FAILURE(status)) { if (status == AE_ALREADY_EXISTS) { + /* Table already exists, just return the handle */ return_ACPI_STATUS(AE_OK); @@ -121,6 +122,7 @@ acpi_ex_add_table(struct acpi_table_header *table, status = acpi_ns_load_table(table_info.installed_desc, parent_node); if (ACPI_FAILURE(status)) { + /* Uninstall table on error */ (void)acpi_tb_uninstall_table(table_info.installed_desc); @@ -169,6 +171,7 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state, */ status = acpi_tb_match_signature(operand[0]->string.pointer, NULL); if (status == AE_OK) { + /* Signature matched -- don't allow override */ return_ACPI_STATUS(AE_ALREADY_EXISTS); @@ -252,6 +255,7 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state, /* Parameter Data (optional) */ if (parameter_node) { + /* Store the parameter data into the optional parameter object */ status = acpi_ex_store(operand[5], @@ -424,6 +428,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, status = acpi_ex_add_table(table_ptr, acpi_gbl_root_node, &ddb_handle); if (ACPI_FAILURE(status)) { + /* On error, table_ptr was deallocated above */ return_ACPI_STATUS(status); diff --git a/drivers/acpi/executer/exconvrt.c b/drivers/acpi/executer/exconvrt.c index e6d52e12d77a..a2c93c9ba07c 100644 --- a/drivers/acpi/executer/exconvrt.c +++ b/drivers/acpi/executer/exconvrt.c @@ -319,6 +319,7 @@ acpi_ex_convert_to_ascii(acpi_integer integer, remainder = 0; for (i = decimal_length; i > 0; i--) { + /* Divide by nth factor of 10 */ digit = integer; @@ -346,6 +347,7 @@ acpi_ex_convert_to_ascii(acpi_integer integer, hex_length = (acpi_native_uint) ACPI_MUL_2(data_width); for (i = 0, j = (hex_length - 1); i < hex_length; i++, j--) { + /* Get one hex digit, most significant digits first */ string[k] = diff --git a/drivers/acpi/executer/exdump.c b/drivers/acpi/executer/exdump.c index a7cca8d4f855..0a53d31e09de 100644 --- a/drivers/acpi/executer/exdump.c +++ b/drivers/acpi/executer/exdump.c @@ -463,6 +463,7 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth) } if (!obj_desc) { + /* This could be a null element of a package */ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Null Object Descriptor\n")); @@ -532,6 +533,7 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth) obj_desc->reference.offset); if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_INTEGER) { + /* Value is an Integer */ acpi_os_printf(" value is [%8.8X%8.8x]", diff --git a/drivers/acpi/executer/exfield.c b/drivers/acpi/executer/exfield.c index e259201ce9a0..215783a33c2c 100644 --- a/drivers/acpi/executer/exfield.c +++ b/drivers/acpi/executer/exfield.c @@ -142,6 +142,7 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state, length = (acpi_size) ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->field.bit_length); if (length > acpi_gbl_integer_byte_width) { + /* Field is too large for an Integer, create a Buffer instead */ buffer_desc = acpi_ut_create_buffer_object(length); @@ -329,6 +330,7 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.bit_length); if (length < required_length) { + /* We need to create a new buffer */ new_buffer = ACPI_MEM_CALLOCATE(required_length); diff --git a/drivers/acpi/executer/exfldio.c b/drivers/acpi/executer/exfldio.c index bd1af35f7fcf..d5a4b2627c19 100644 --- a/drivers/acpi/executer/exfldio.c +++ b/drivers/acpi/executer/exfldio.c @@ -113,6 +113,7 @@ acpi_ex_setup_region(union acpi_operand_object *obj_desc, } if (rgn_desc->region.space_id == ACPI_ADR_SPACE_SMBUS) { + /* SMBus has a non-linear address space */ return_ACPI_STATUS(AE_OK); @@ -491,6 +492,7 @@ acpi_ex_field_datum_io(union acpi_operand_object *obj_desc, value)); if (read_write == ACPI_READ) { + /* Read the datum from the data_register */ status = @@ -568,6 +570,7 @@ acpi_ex_write_with_update_rule(union acpi_operand_object *obj_desc, /* If the mask is all ones, we don't need to worry about the update rule */ if (mask != ACPI_INTEGER_MAX) { + /* Decode the update rule */ switch (obj_desc->common_field. @@ -704,6 +707,7 @@ acpi_ex_extract_from_field(union acpi_operand_object *obj_desc, /* Read the rest of the field */ for (i = 1; i < field_datum_count; i++) { + /* Get next input datum from the field */ field_offset += obj_desc->common_field.access_byte_width; @@ -817,6 +821,7 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc, /* Write the entire field */ for (i = 1; i < field_datum_count; i++) { + /* Write merged datum to the target field */ merged_datum &= mask; diff --git a/drivers/acpi/executer/exmisc.c b/drivers/acpi/executer/exmisc.c index 48c18d29222a..74f2c1a9bdaf 100644 --- a/drivers/acpi/executer/exmisc.c +++ b/drivers/acpi/executer/exmisc.c @@ -649,6 +649,7 @@ acpi_ex_do_logical_op(u16 opcode, /* Length and all bytes must be equal */ if ((length0 == length1) && (compare == 0)) { + /* Length and all bytes match ==> TRUE */ local_result = TRUE; diff --git a/drivers/acpi/executer/exmutex.c b/drivers/acpi/executer/exmutex.c index f843b22e20b9..eaee1de5e90d 100644 --- a/drivers/acpi/executer/exmutex.c +++ b/drivers/acpi/executer/exmutex.c @@ -173,6 +173,7 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc, /* Support for multiple acquires by the owning thread */ if (obj_desc->mutex.owner_thread) { + /* Special case for Global Lock, allow all threads */ if ((obj_desc->mutex.owner_thread->thread_id == @@ -192,6 +193,7 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc, status = acpi_ex_system_acquire_mutex(time_desc, obj_desc); if (ACPI_FAILURE(status)) { + /* Includes failure from a timeout on time_desc */ return_ACPI_STATUS(status); @@ -286,6 +288,7 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, obj_desc->mutex.acquisition_depth--; if (obj_desc->mutex.acquisition_depth != 0) { + /* Just decrement the depth and return */ return_ACPI_STATUS(AE_OK); diff --git a/drivers/acpi/executer/exnames.c b/drivers/acpi/executer/exnames.c index 054fe5e1a314..f9bc81c1b78d 100644 --- a/drivers/acpi/executer/exnames.c +++ b/drivers/acpi/executer/exnames.c @@ -85,6 +85,7 @@ static char *acpi_ex_allocate_name_string(u32 prefix_count, u32 num_name_segs) * This may actually be somewhat longer than needed. */ if (prefix_count == ACPI_UINT32_MAX) { + /* Special case for root */ size_needed = 1 + (ACPI_NAME_SIZE * num_name_segs) + 2 + 1; @@ -119,11 +120,13 @@ static char *acpi_ex_allocate_name_string(u32 prefix_count, u32 num_name_segs) /* Set up Dual or Multi prefixes if needed */ if (num_name_segs > 2) { + /* Set up multi prefixes */ *temp_ptr++ = AML_MULTI_NAME_PREFIX_OP; *temp_ptr++ = (char)num_name_segs; } else if (2 == num_name_segs) { + /* Set up dual prefixes */ *temp_ptr++ = AML_DUAL_NAME_PREFIX; @@ -184,6 +187,7 @@ static acpi_status acpi_ex_name_segment(u8 ** in_aml_address, char *name_string) /* Valid name segment */ if (index == 4) { + /* Found 4 valid characters */ char_buf[4] = '\0'; @@ -254,6 +258,7 @@ acpi_ex_get_name_string(acpi_object_type data_type, if (ACPI_TYPE_LOCAL_REGION_FIELD == data_type || ACPI_TYPE_LOCAL_BANK_FIELD == data_type || ACPI_TYPE_LOCAL_INDEX_FIELD == data_type) { + /* Disallow prefixes for types associated with field_unit names */ name_string = acpi_ex_allocate_name_string(0, 1); @@ -410,6 +415,7 @@ acpi_ex_get_name_string(acpi_object_type data_type, } if (AE_CTRL_PENDING == status && has_prefix) { + /* Ran out of segments after processing a prefix */ ACPI_ERROR((AE_INFO, "Malformed Name at %p", name_string)); diff --git a/drivers/acpi/executer/exoparg1.c b/drivers/acpi/executer/exoparg1.c index 23d0823bcd5e..4f3627ee2b2b 100644 --- a/drivers/acpi/executer/exoparg1.c +++ b/drivers/acpi/executer/exoparg1.c @@ -342,6 +342,7 @@ acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state) for (i = 0; (i < acpi_gbl_integer_nybble_width) && (digit > 0); i++) { + /* Get the least significant 4-bit BCD digit */ temp32 = ((u32) digit) & 0xF; @@ -487,6 +488,7 @@ acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state) status = acpi_ex_convert_to_string(operand[0], &return_desc, ACPI_EXPLICIT_CONVERT_DECIMAL); if (return_desc == operand[0]) { + /* No conversion performed, add ref to handle return value */ acpi_ut_add_reference(return_desc); } @@ -497,6 +499,7 @@ acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state) status = acpi_ex_convert_to_string(operand[0], &return_desc, ACPI_EXPLICIT_CONVERT_HEX); if (return_desc == operand[0]) { + /* No conversion performed, add ref to handle return value */ acpi_ut_add_reference(return_desc); } @@ -506,6 +509,7 @@ acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state) status = acpi_ex_convert_to_buffer(operand[0], &return_desc); if (return_desc == operand[0]) { + /* No conversion performed, add ref to handle return value */ acpi_ut_add_reference(return_desc); } @@ -516,6 +520,7 @@ acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state) status = acpi_ex_convert_to_integer(operand[0], &return_desc, ACPI_ANY_BASE); if (return_desc == operand[0]) { + /* No conversion performed, add ref to handle return value */ acpi_ut_add_reference(return_desc); } @@ -541,6 +546,7 @@ acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state) } if (ACPI_SUCCESS(status)) { + /* Store the return value computed above into the target object */ status = acpi_ex_store(return_desc, operand[1], walk_state); @@ -625,6 +631,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state) temp_desc = operand[0]; if (ACPI_GET_DESCRIPTOR_TYPE(temp_desc) == ACPI_DESC_TYPE_OPERAND) { + /* Internal reference object - prevent deletion */ acpi_ut_add_reference(temp_desc); @@ -777,8 +784,25 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state) /* Check for a method local or argument, or standalone String */ - if (ACPI_GET_DESCRIPTOR_TYPE(operand[0]) != + if (ACPI_GET_DESCRIPTOR_TYPE(operand[0]) == ACPI_DESC_TYPE_NAMED) { + temp_desc = + acpi_ns_get_attached_object((struct + acpi_namespace_node *) + operand[0]); + if (temp_desc + && + ((ACPI_GET_OBJECT_TYPE(temp_desc) == + ACPI_TYPE_STRING) + || (ACPI_GET_OBJECT_TYPE(temp_desc) == + ACPI_TYPE_LOCAL_REFERENCE))) { + operand[0] = temp_desc; + acpi_ut_add_reference(temp_desc); + } else { + status = AE_AML_OPERAND_TYPE; + goto cleanup; + } + } else { switch (ACPI_GET_OBJECT_TYPE(operand[0])) { case ACPI_TYPE_LOCAL_REFERENCE: /* @@ -827,13 +851,24 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state) break; case ACPI_TYPE_STRING: + break; + default: + status = AE_AML_OPERAND_TYPE; + goto cleanup; + } + } + + if (ACPI_GET_DESCRIPTOR_TYPE(operand[0]) != + ACPI_DESC_TYPE_NAMED) { + if (ACPI_GET_OBJECT_TYPE(operand[0]) == + ACPI_TYPE_STRING) { /* * This is a deref_of (String). The string is a reference * to a named ACPI object. * * 1) Find the owning Node - * 2) Dereference the node to an actual object. Could be a + * 2) Dereference the node to an actual object. Could be a * Field, so we need to resolve the node to a value. */ status = @@ -857,11 +892,6 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state) (struct acpi_namespace_node, &return_desc), walk_state); goto cleanup; - - default: - - status = AE_AML_OPERAND_TYPE; - goto cleanup; } } diff --git a/drivers/acpi/executer/exoparg2.c b/drivers/acpi/executer/exoparg2.c index e263a5ddd405..5e1abb12c748 100644 --- a/drivers/acpi/executer/exoparg2.c +++ b/drivers/acpi/executer/exoparg2.c @@ -138,6 +138,7 @@ acpi_status acpi_ex_opcode_2A_0T_0R(struct acpi_walk_state *walk_state) acpi_ev_check_for_wake_only_gpe(walk_state-> gpe_event_info); if (ACPI_FAILURE(status)) { + /* AE_WAKE_ONLY_GPE only error, means ignore this notify */ return_ACPI_STATUS(AE_OK) @@ -252,6 +253,7 @@ acpi_status acpi_ex_opcode_2A_2T_1R(struct acpi_walk_state *walk_state) acpi_ut_remove_reference(return_desc2); if (ACPI_FAILURE(status)) { + /* Delete the return object */ acpi_ut_remove_reference(return_desc1); @@ -287,6 +289,7 @@ acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state) /* Execute the opcode */ if (walk_state->op_info->flags & AML_MATH) { + /* All simple math opcodes (add, etc.) */ return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); @@ -383,54 +386,70 @@ acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state) goto cleanup; } + /* Initialize the Index reference object */ + index = operand[1]->integer.value; + return_desc->reference.offset = (u32) index; + return_desc->reference.opcode = AML_INDEX_OP; + return_desc->reference.object = operand[0]; - /* At this point, the Source operand is a Package, Buffer, or String */ + /* + * At this point, the Source operand is a String, Buffer, or Package. + * Verify that the index is within range. + */ + switch (ACPI_GET_OBJECT_TYPE(operand[0])) { + case ACPI_TYPE_STRING: - if (ACPI_GET_OBJECT_TYPE(operand[0]) == ACPI_TYPE_PACKAGE) { - /* Object to be indexed is a Package */ + if (index >= operand[0]->string.length) { + status = AE_AML_STRING_LIMIT; + } + + return_desc->reference.target_type = + ACPI_TYPE_BUFFER_FIELD; + break; + + case ACPI_TYPE_BUFFER: + + if (index >= operand[0]->buffer.length) { + status = AE_AML_BUFFER_LIMIT; + } + + return_desc->reference.target_type = + ACPI_TYPE_BUFFER_FIELD; + break; + + case ACPI_TYPE_PACKAGE: if (index >= operand[0]->package.count) { - ACPI_ERROR((AE_INFO, - "Index value (%X%8.8X) beyond package end (%X)", - ACPI_FORMAT_UINT64(index), - operand[0]->package.count)); status = AE_AML_PACKAGE_LIMIT; - goto cleanup; } return_desc->reference.target_type = ACPI_TYPE_PACKAGE; - return_desc->reference.object = operand[0]; return_desc->reference.where = &operand[0]->package.elements[index]; - } else { - /* Object to be indexed is a Buffer/String */ + break; - if (index >= operand[0]->buffer.length) { - ACPI_ERROR((AE_INFO, - "Index value (%X%8.8X) beyond end of buffer (%X)", - ACPI_FORMAT_UINT64(index), - operand[0]->buffer.length)); - status = AE_AML_BUFFER_LIMIT; - goto cleanup; - } + default: - return_desc->reference.target_type = - ACPI_TYPE_BUFFER_FIELD; - return_desc->reference.object = operand[0]; + status = AE_AML_INTERNAL; + goto cleanup; + } + + /* Failure means that the Index was beyond the end of the object */ + + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, + "Index (%X%8.8X) is beyond end of object", + ACPI_FORMAT_UINT64(index))); + goto cleanup; } /* * Add a reference to the target package/buffer/string for the life - * of the index. + * of the index */ acpi_ut_add_reference(operand[0]); - /* Complete the Index reference object */ - - return_desc->reference.opcode = AML_INDEX_OP; - return_desc->reference.offset = (u32) index; - /* Store the reference to the Target */ status = acpi_ex_store(return_desc, operand[2], walk_state); @@ -509,6 +528,7 @@ acpi_status acpi_ex_opcode_2A_0T_1R(struct acpi_walk_state *walk_state) /* Execute the Opcode */ if (walk_state->op_info->flags & AML_LOGICAL_NUMERIC) { + /* logical_op (Operand0, Operand1) */ status = acpi_ex_do_logical_numeric_op(walk_state->opcode, @@ -518,6 +538,7 @@ acpi_status acpi_ex_opcode_2A_0T_1R(struct acpi_walk_state *walk_state) value, &logical_result); goto store_logical_result; } else if (walk_state->op_info->flags & AML_LOGICAL) { + /* logical_op (Operand0, Operand1) */ status = acpi_ex_do_logical_op(walk_state->opcode, operand[0], diff --git a/drivers/acpi/executer/exoparg3.c b/drivers/acpi/executer/exoparg3.c index 6a3a883cb8a3..8da794ec35b0 100644 --- a/drivers/acpi/executer/exoparg3.c +++ b/drivers/acpi/executer/exoparg3.c @@ -208,6 +208,7 @@ acpi_status acpi_ex_opcode_3A_1T_1R(struct acpi_walk_state *walk_state) /* If the requested length is zero, don't allocate a buffer */ if (length > 0) { + /* Allocate a new buffer for the Buffer */ buffer = ACPI_MEM_CALLOCATE(length); @@ -225,6 +226,7 @@ acpi_status acpi_ex_opcode_3A_1T_1R(struct acpi_walk_state *walk_state) } if (buffer) { + /* We have a buffer, copy the portion requested */ ACPI_MEMCPY(buffer, operand[0]->string.pointer + index, diff --git a/drivers/acpi/executer/exoparg6.c b/drivers/acpi/executer/exoparg6.c index e043d924444f..33e4fb1addce 100644 --- a/drivers/acpi/executer/exoparg6.c +++ b/drivers/acpi/executer/exoparg6.c @@ -276,6 +276,7 @@ acpi_status acpi_ex_opcode_6A_0T_1R(struct acpi_walk_state * walk_state) * match was found. */ for (; index < operand[0]->package.count; index++) { + /* Get the current package element */ this_element = operand[0]->package.elements[index]; diff --git a/drivers/acpi/executer/exregion.c b/drivers/acpi/executer/exregion.c index 6a4cfdff606d..9db68d19253e 100644 --- a/drivers/acpi/executer/exregion.c +++ b/drivers/acpi/executer/exregion.c @@ -135,6 +135,7 @@ acpi_ex_system_memory_space_handler(u32 function, * Delete the existing mapping and create a new one. */ if (mem_info->mapped_length) { + /* Valid mapping, delete it */ acpi_os_unmap_memory(mem_info->mapped_logical_address, diff --git a/drivers/acpi/executer/exresnte.c b/drivers/acpi/executer/exresnte.c index 01b26c80d22b..417d914d9e19 100644 --- a/drivers/acpi/executer/exresnte.c +++ b/drivers/acpi/executer/exresnte.c @@ -103,6 +103,7 @@ acpi_ex_resolve_node_to_value(struct acpi_namespace_node **object_ptr, if ((entry_type == ACPI_TYPE_LOCAL_ALIAS) || (entry_type == ACPI_TYPE_LOCAL_METHOD_ALIAS)) { + /* There is always exactly one level of indirection */ node = ACPI_CAST_PTR(struct acpi_namespace_node, node->object); @@ -141,6 +142,7 @@ acpi_ex_resolve_node_to_value(struct acpi_namespace_node **object_ptr, status = acpi_ds_get_package_arguments(source_desc); if (ACPI_SUCCESS(status)) { + /* Return an additional reference to the object */ obj_desc = source_desc; @@ -158,6 +160,7 @@ acpi_ex_resolve_node_to_value(struct acpi_namespace_node **object_ptr, status = acpi_ds_get_buffer_arguments(source_desc); if (ACPI_SUCCESS(status)) { + /* Return an additional reference to the object */ obj_desc = source_desc; @@ -240,6 +243,8 @@ acpi_ex_resolve_node_to_value(struct acpi_namespace_node **object_ptr, /* This is a ddb_handle */ /* Return an additional reference to the object */ + case AML_REF_OF_OP: + obj_desc = source_desc; acpi_ut_add_reference(obj_desc); break; diff --git a/drivers/acpi/executer/exresolv.c b/drivers/acpi/executer/exresolv.c index 1deed492fe88..22dabdd10604 100644 --- a/drivers/acpi/executer/exresolv.c +++ b/drivers/acpi/executer/exresolv.c @@ -382,10 +382,16 @@ acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state, while (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_LOCAL_REFERENCE) { switch (obj_desc->reference.opcode) { case AML_REF_OF_OP: + case AML_INT_NAMEPATH_OP: /* Dereference the reference pointer */ - node = obj_desc->reference.object; + if (obj_desc->reference.opcode == AML_REF_OF_OP) { + node = obj_desc->reference.object; + } else { /* AML_INT_NAMEPATH_OP */ + + node = obj_desc->reference.node; + } /* All "References" point to a NS node */ @@ -401,6 +407,7 @@ acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state, obj_desc = acpi_ns_get_attached_object(node); if (!obj_desc) { + /* No object, use the NS node type */ type = acpi_ns_get_type(node); @@ -432,6 +439,7 @@ acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state, */ obj_desc = *(obj_desc->reference.where); if (!obj_desc) { + /* NULL package elements are allowed */ type = 0; /* Uninitialized */ @@ -439,39 +447,6 @@ acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state, } break; - case AML_INT_NAMEPATH_OP: - - /* Dereference the reference pointer */ - - node = obj_desc->reference.node; - - /* All "References" point to a NS node */ - - if (ACPI_GET_DESCRIPTOR_TYPE(node) != - ACPI_DESC_TYPE_NAMED) { - ACPI_ERROR((AE_INFO, "Not a NS node %p [%s]", - node, - acpi_ut_get_descriptor_name(node))); - return_ACPI_STATUS(AE_AML_INTERNAL); - } - - /* Get the attached object */ - - obj_desc = acpi_ns_get_attached_object(node); - if (!obj_desc) { - /* No object, use the NS node type */ - - type = acpi_ns_get_type(node); - goto exit; - } - - /* Check for circular references */ - - if (obj_desc == operand) { - return_ACPI_STATUS(AE_AML_CIRCULAR_REFERENCE); - } - break; - case AML_LOCAL_OP: case AML_ARG_OP: diff --git a/drivers/acpi/executer/exresop.c b/drivers/acpi/executer/exresop.c index a1c000f5a415..42b9089dccc0 100644 --- a/drivers/acpi/executer/exresop.c +++ b/drivers/acpi/executer/exresop.c @@ -77,6 +77,7 @@ acpi_ex_check_object_type(acpi_object_type type_needed, ACPI_FUNCTION_ENTRY(); if (type_needed == ACPI_TYPE_ANY) { + /* All types OK, so we don't perform any typechecks */ return (AE_OK); @@ -224,6 +225,7 @@ acpi_ex_resolve_operands(u16 opcode, } if (object_type == (u8) ACPI_TYPE_LOCAL_REFERENCE) { + /* Decode the Reference */ op_info = acpi_ps_get_opcode_info(opcode); @@ -332,6 +334,7 @@ acpi_ex_resolve_operands(u16 opcode, } if (obj_desc->reference.opcode == AML_NAME_OP) { + /* Convert a named reference to the actual named object */ temp_node = obj_desc->reference.object; @@ -662,6 +665,7 @@ acpi_ex_resolve_operands(u16 opcode, } if (target_op == AML_DEBUG_OP) { + /* Allow store of any object to the Debug object */ break; diff --git a/drivers/acpi/executer/exstore.c b/drivers/acpi/executer/exstore.c index 3f020c0e2b95..287476f319f4 100644 --- a/drivers/acpi/executer/exstore.c +++ b/drivers/acpi/executer/exstore.c @@ -423,6 +423,7 @@ acpi_ex_store_object_to_index(union acpi_operand_object *source_desc, } if (obj_desc) { + /* Decrement reference count by the ref count of the parent package */ for (i = 0; i < ((union acpi_operand_object *) @@ -572,6 +573,7 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc, /* If no implicit conversion, drop into the default case below */ if ((!implicit_conversion) || (walk_state->opcode == AML_COPY_OP)) { + /* Force execution of default (no implicit conversion) */ target_type = ACPI_TYPE_ANY; diff --git a/drivers/acpi/executer/exstoren.c b/drivers/acpi/executer/exstoren.c index 42967baf760d..969f9cbbbeeb 100644 --- a/drivers/acpi/executer/exstoren.c +++ b/drivers/acpi/executer/exstoren.c @@ -97,6 +97,7 @@ acpi_ex_resolve_object(union acpi_operand_object **source_desc_ptr, */ if (ACPI_GET_OBJECT_TYPE(source_desc) == ACPI_TYPE_LOCAL_REFERENCE) { + /* Resolve a reference object first */ status = @@ -121,6 +122,7 @@ acpi_ex_resolve_object(union acpi_operand_object **source_desc_ptr, !((ACPI_GET_OBJECT_TYPE(source_desc) == ACPI_TYPE_LOCAL_REFERENCE) && (source_desc->reference.opcode == AML_LOAD_OP))) { + /* Conversion successful but still not a valid type */ ACPI_ERROR((AE_INFO, @@ -289,6 +291,7 @@ acpi_ex_store_object_to_object(union acpi_operand_object *source_desc, } if (actual_src_desc != source_desc) { + /* Delete the intermediate (temporary) source object */ acpi_ut_remove_reference(actual_src_desc); diff --git a/drivers/acpi/executer/exstorob.c b/drivers/acpi/executer/exstorob.c index 6ab707087750..41732d382bce 100644 --- a/drivers/acpi/executer/exstorob.c +++ b/drivers/acpi/executer/exstorob.c @@ -91,6 +91,7 @@ acpi_ex_store_buffer_to_buffer(union acpi_operand_object *source_desc, /* Copy source buffer to target buffer */ if (length <= target_desc->buffer.length) { + /* Clear existing buffer and copy in the new one */ ACPI_MEMSET(target_desc->buffer.pointer, 0, @@ -113,6 +114,7 @@ acpi_ex_store_buffer_to_buffer(union acpi_operand_object *source_desc, * copy must not truncate the original buffer. */ if (original_src_type == ACPI_TYPE_STRING) { + /* Set the new length of the target */ target_desc->buffer.length = length; @@ -183,6 +185,7 @@ acpi_ex_store_string_to_string(union acpi_operand_object *source_desc, */ if (target_desc->string.pointer && (!(target_desc->common.flags & AOPOBJ_STATIC_POINTER))) { + /* Only free if not a pointer into the DSDT */ ACPI_MEM_FREE(target_desc->string.pointer); diff --git a/drivers/acpi/executer/exsystem.c b/drivers/acpi/executer/exsystem.c index ea9144f42e1f..6a2e47a0e112 100644 --- a/drivers/acpi/executer/exsystem.c +++ b/drivers/acpi/executer/exsystem.c @@ -76,6 +76,7 @@ acpi_status acpi_ex_system_wait_semaphore(acpi_handle semaphore, u16 timeout) } if (status == AE_TIME) { + /* We must wait, so unlock the interpreter */ acpi_ex_exit_interpreter(); @@ -90,6 +91,7 @@ acpi_status acpi_ex_system_wait_semaphore(acpi_handle semaphore, u16 timeout) status2 = acpi_ex_enter_interpreter(); if (ACPI_FAILURE(status2)) { + /* Report fatal error, could not acquire interpreter */ return_ACPI_STATUS(status2); diff --git a/drivers/acpi/executer/exutils.c b/drivers/acpi/executer/exutils.c index f73a61aeb7ec..8543d1a0ed31 100644 --- a/drivers/acpi/executer/exutils.c +++ b/drivers/acpi/executer/exutils.c @@ -194,6 +194,7 @@ u8 acpi_ex_acquire_global_lock(u32 field_flags) /* Only attempt lock if the always_lock bit is set */ if (field_flags & AML_FIELD_LOCK_RULE_MASK) { + /* We should attempt to get the lock, wait forever */ status = acpi_ev_acquire_global_lock(ACPI_WAIT_FOREVER); @@ -230,10 +231,12 @@ void acpi_ex_release_global_lock(u8 locked_by_me) /* Only attempt unlock if the caller locked it */ if (locked_by_me) { + /* OK, now release the lock */ status = acpi_ev_release_global_lock(); if (ACPI_FAILURE(status)) { + /* Report the error, but there isn't much else we can do */ ACPI_EXCEPTION((AE_INFO, status, diff --git a/drivers/acpi/hardware/hwgpe.c b/drivers/acpi/hardware/hwgpe.c index d84942d22dd5..729b68eb3e35 100644 --- a/drivers/acpi/hardware/hwgpe.c +++ b/drivers/acpi/hardware/hwgpe.c @@ -214,6 +214,7 @@ acpi_hw_disable_gpe_block(struct acpi_gpe_xrupt_info * gpe_xrupt_info, /* Examine each GPE Register within the block */ for (i = 0; i < gpe_block->register_count; i++) { + /* Disable all GPEs in this register */ status = acpi_hw_low_level_write(8, 0x00, @@ -250,6 +251,7 @@ acpi_hw_clear_gpe_block(struct acpi_gpe_xrupt_info * gpe_xrupt_info, /* Examine each GPE Register within the block */ for (i = 0; i < gpe_block->register_count; i++) { + /* Clear status on all GPEs in this register */ status = acpi_hw_low_level_write(8, 0xFF, diff --git a/drivers/acpi/hardware/hwregs.c b/drivers/acpi/hardware/hwregs.c index e1fe75498415..95c4ccb3a378 100644 --- a/drivers/acpi/hardware/hwregs.c +++ b/drivers/acpi/hardware/hwregs.c @@ -295,6 +295,7 @@ acpi_status acpi_get_register(u32 register_id, u32 * return_value, u32 flags) } if (ACPI_SUCCESS(status)) { + /* Normalize the value that was read */ register_value = diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c index 89269272fd62..284a59ebcc2c 100644 --- a/drivers/acpi/hardware/hwsleep.c +++ b/drivers/acpi/hardware/hwsleep.c @@ -490,6 +490,7 @@ acpi_status acpi_leave_sleep_state(u8 sleep_state) ACPI_REGISTER_PM1_CONTROL, &PM1Acontrol); if (ACPI_SUCCESS(status)) { + /* Clear SLP_EN and SLP_TYP fields */ PM1Acontrol &= ~(sleep_type_reg_info->access_bit_mask | diff --git a/drivers/acpi/hardware/hwtimer.c b/drivers/acpi/hardware/hwtimer.c index fc10b7cb456f..ef7c98e293a9 100644 --- a/drivers/acpi/hardware/hwtimer.c +++ b/drivers/acpi/hardware/hwtimer.c @@ -155,6 +155,7 @@ acpi_get_timer_duration(u32 start_ticks, u32 end_ticks, u32 * time_elapsed) delta_ticks = end_ticks - start_ticks; } else if (start_ticks > end_ticks) { if (0 == acpi_gbl_FADT->tmr_val_ext) { + /* 24-bit Timer */ delta_ticks = diff --git a/drivers/acpi/namespace/nsaccess.c b/drivers/acpi/namespace/nsaccess.c index 1149bc18fb35..6bdad8bfcf0b 100644 --- a/drivers/acpi/namespace/nsaccess.c +++ b/drivers/acpi/namespace/nsaccess.c @@ -98,6 +98,7 @@ acpi_status acpi_ns_root_initialize(void) "Entering predefined entries into namespace\n")); for (init_val = acpi_gbl_pre_defined_names; init_val->name; init_val++) { + /* _OSI is optional for now, will be permanent later */ if (!ACPI_STRCMP(init_val->name, "_OSI") @@ -365,6 +366,7 @@ acpi_ns_lookup(union acpi_generic_state *scope_info, * Begin examination of the actual pathname */ if (!pathname) { + /* A Null name_path is allowed and refers to the root */ num_segments = 0; @@ -389,6 +391,7 @@ acpi_ns_lookup(union acpi_generic_state *scope_info, * to the current scope). */ if (*path == (u8) AML_ROOT_PREFIX) { + /* Pathname is fully qualified, start from the root */ this_node = acpi_gbl_root_node; @@ -416,6 +419,7 @@ acpi_ns_lookup(union acpi_generic_state *scope_info, this_node = prefix_node; num_carats = 0; while (*path == (u8) AML_PARENT_PREFIX) { + /* Name is fully qualified, no search rules apply */ search_parent_flag = ACPI_NS_NO_UPSEARCH; @@ -430,6 +434,7 @@ acpi_ns_lookup(union acpi_generic_state *scope_info, num_carats++; this_node = acpi_ns_get_parent_node(this_node); if (!this_node) { + /* Current scope has no parent scope */ ACPI_ERROR((AE_INFO, @@ -569,6 +574,7 @@ acpi_ns_lookup(union acpi_generic_state *scope_info, &this_node); if (ACPI_FAILURE(status)) { if (status == AE_NOT_FOUND) { + /* Name not found in ACPI namespace */ ACPI_DEBUG_PRINT((ACPI_DB_NAMES, @@ -602,6 +608,7 @@ acpi_ns_lookup(union acpi_generic_state *scope_info, (type_to_check_for != ACPI_TYPE_LOCAL_SCOPE) && (this_node->type != ACPI_TYPE_ANY) && (this_node->type != type_to_check_for)) { + /* Complain about a type mismatch */ ACPI_WARNING((AE_INFO, diff --git a/drivers/acpi/namespace/nsalloc.c b/drivers/acpi/namespace/nsalloc.c index 9b871f38b61b..cd26cb971a1c 100644 --- a/drivers/acpi/namespace/nsalloc.c +++ b/drivers/acpi/namespace/nsalloc.c @@ -115,6 +115,7 @@ void acpi_ns_delete_node(struct acpi_namespace_node *node) } if (prev_node) { + /* Node is not first child, unlink it */ prev_node->peer = next_node->peer; @@ -125,6 +126,7 @@ void acpi_ns_delete_node(struct acpi_namespace_node *node) /* Node is first child (has no previous peer) */ if (next_node->flags & ANOBJ_END_OF_PEER_LIST) { + /* No peers at all */ parent_node->child = NULL; @@ -264,6 +266,7 @@ void acpi_ns_delete_children(struct acpi_namespace_node *parent_node) * Deallocate all children at this level */ do { + /* Get the things we need */ next_node = child_node->peer; @@ -352,11 +355,13 @@ void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node) * to where we started. */ while (level > 0) { + /* Get the next node in this scope (NULL if none) */ child_node = acpi_ns_get_next_node(ACPI_TYPE_ANY, parent_node, child_node); if (child_node) { + /* Found a child node - detach any attached object */ acpi_ns_detach_object(child_node); @@ -427,6 +432,7 @@ static void acpi_ns_remove_reference(struct acpi_namespace_node *node) */ this_node = node; while (this_node) { + /* Prepare to move up to parent */ parent_node = acpi_ns_get_parent_node(this_node); @@ -438,6 +444,7 @@ static void acpi_ns_remove_reference(struct acpi_namespace_node *node) /* Delete the node if no more references */ if (!this_node->reference_count) { + /* Delete all children and delete the node */ acpi_ns_delete_children(this_node); @@ -500,6 +507,7 @@ void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id) if (child_node) { if (child_node->owner_id == owner_id) { + /* Found a matching child node - detach any attached object */ acpi_ns_detach_object(child_node); diff --git a/drivers/acpi/namespace/nsdump.c b/drivers/acpi/namespace/nsdump.c index a2807317a84b..e275373b1705 100644 --- a/drivers/acpi/namespace/nsdump.c +++ b/drivers/acpi/namespace/nsdump.c @@ -191,6 +191,7 @@ acpi_ns_dump_one_object(acpi_handle obj_handle, } if (!(info->display_type & ACPI_DISPLAY_SHORT)) { + /* Indent the object according to the level */ acpi_os_printf("%2d%*s", (u32) level - 1, (int)level * 2, " "); @@ -226,6 +227,7 @@ acpi_ns_dump_one_object(acpi_handle obj_handle, case ACPI_DISPLAY_SUMMARY: if (!obj_desc) { + /* No attached object, we are done */ acpi_os_printf("\n"); @@ -419,6 +421,7 @@ acpi_ns_dump_one_object(acpi_handle obj_handle, acpi_os_printf("O:%p", obj_desc); if (!obj_desc) { + /* No attached object, we are done */ acpi_os_printf("\n"); @@ -682,6 +685,7 @@ void acpi_ns_dump_tables(acpi_handle search_base, u32 max_depth) } if (ACPI_NS_ALL == search_base) { + /* Entire namespace */ search_handle = acpi_gbl_root_node; diff --git a/drivers/acpi/namespace/nseval.c b/drivers/acpi/namespace/nseval.c index 19d7b94d40c3..80ef95545636 100644 --- a/drivers/acpi/namespace/nseval.c +++ b/drivers/acpi/namespace/nseval.c @@ -326,6 +326,7 @@ acpi_status acpi_ns_evaluate_by_handle(struct acpi_parameter_info *info) * Check if there is a return value on the stack that must be dealt with */ if (status == AE_CTRL_RETURN_VALUE) { + /* Map AE_CTRL_RETURN_VALUE to AE_OK, we are done with it */ status = AE_OK; diff --git a/drivers/acpi/namespace/nsinit.c b/drivers/acpi/namespace/nsinit.c index 9f929e479fd8..9aa337c33887 100644 --- a/drivers/acpi/namespace/nsinit.c +++ b/drivers/acpi/namespace/nsinit.c @@ -366,6 +366,7 @@ acpi_ns_init_one_device(acpi_handle obj_handle, status = acpi_ns_search_node(*ACPI_CAST_PTR(u32, METHOD_NAME__INI), device_node, ACPI_TYPE_METHOD, &ini_node); if (ACPI_FAILURE(status)) { + /* No _INI method found - move on to next device */ return_ACPI_STATUS(AE_OK); @@ -386,6 +387,7 @@ acpi_ns_init_one_device(acpi_handle obj_handle, status = acpi_ut_execute_STA(pinfo.node, &flags); if (ACPI_FAILURE(status)) { + /* Ignore error and move on to next device */ return_ACPI_STATUS(AE_OK); @@ -396,6 +398,7 @@ acpi_ns_init_one_device(acpi_handle obj_handle, } if (!(flags & ACPI_STA_DEVICE_PRESENT)) { + /* Don't look at children of a not present device */ return_ACPI_STATUS(AE_CTRL_DEPTH); @@ -412,6 +415,7 @@ acpi_ns_init_one_device(acpi_handle obj_handle, pinfo.node = ini_node; status = acpi_ns_evaluate_by_handle(&pinfo); if (ACPI_FAILURE(status)) { + /* Ignore error and move on to next device */ #ifdef ACPI_DEBUG_OUTPUT @@ -435,6 +439,7 @@ acpi_ns_init_one_device(acpi_handle obj_handle, } if (acpi_gbl_init_handler) { + /* External initialization handler is present, call it */ status = diff --git a/drivers/acpi/namespace/nsload.c b/drivers/acpi/namespace/nsload.c index 4e0b0524c188..80acfd35f3ec 100644 --- a/drivers/acpi/namespace/nsload.c +++ b/drivers/acpi/namespace/nsload.c @@ -84,6 +84,7 @@ acpi_ns_load_table(struct acpi_table_desc *table_desc, if (! (acpi_gbl_table_data[table_desc->type]. flags & ACPI_TABLE_EXECUTABLE)) { + /* Just ignore this table */ return_ACPI_STATUS(AE_OK); @@ -325,6 +326,7 @@ static acpi_status acpi_ns_delete_subtree(acpi_handle start_handle) * to where we started. */ while (level > 0) { + /* Attempt to get the next object in this scope */ status = acpi_get_next_object(ACPI_TYPE_ANY, parent_handle, @@ -335,6 +337,7 @@ static acpi_status acpi_ns_delete_subtree(acpi_handle start_handle) /* Did we get a new object? */ if (ACPI_SUCCESS(status)) { + /* Check if this object has any children */ if (ACPI_SUCCESS diff --git a/drivers/acpi/namespace/nsobject.c b/drivers/acpi/namespace/nsobject.c index 10ae6292bca4..39dc87b228fc 100644 --- a/drivers/acpi/namespace/nsobject.c +++ b/drivers/acpi/namespace/nsobject.c @@ -82,6 +82,7 @@ acpi_ns_attach_object(struct acpi_namespace_node *node, * Parameter validation */ if (!node) { + /* Invalid handle */ ACPI_ERROR((AE_INFO, "Null named_obj handle")); @@ -89,6 +90,7 @@ acpi_ns_attach_object(struct acpi_namespace_node *node, } if (!object && (ACPI_TYPE_ANY != type)) { + /* Null object */ ACPI_ERROR((AE_INFO, @@ -97,6 +99,7 @@ acpi_ns_attach_object(struct acpi_namespace_node *node, } if (ACPI_GET_DESCRIPTOR_TYPE(node) != ACPI_DESC_TYPE_NAMED) { + /* Not a name handle */ ACPI_ERROR((AE_INFO, "Invalid handle %p [%s]", diff --git a/drivers/acpi/namespace/nssearch.c b/drivers/acpi/namespace/nssearch.c index d64b78952f24..f73a3d566168 100644 --- a/drivers/acpi/namespace/nssearch.c +++ b/drivers/acpi/namespace/nssearch.c @@ -114,9 +114,11 @@ acpi_ns_search_node(u32 target_name, */ next_node = node->child; while (next_node) { + /* Check for match against the name */ if (next_node->name.integer == target_name) { + /* Resolve a control method alias if any */ if (acpi_ns_get_type(next_node) == @@ -146,6 +148,7 @@ acpi_ns_search_node(u32 target_name, * so a flag is used to indicate the end-of-list */ if (next_node->flags & ANOBJ_END_OF_PEER_LIST) { + /* Searched entire list, we are done */ break; diff --git a/drivers/acpi/namespace/nsutils.c b/drivers/acpi/namespace/nsutils.c index 3e7cad549a38..e8c779114bec 100644 --- a/drivers/acpi/namespace/nsutils.c +++ b/drivers/acpi/namespace/nsutils.c @@ -83,6 +83,7 @@ acpi_ns_report_error(char *module_name, acpi_ut_report_error(module_name, line_number); if (lookup_status == AE_BAD_CHARACTER) { + /* There is a non-ascii character in the name */ acpi_os_printf("[0x%4.4X] (NON-ASCII)", @@ -267,6 +268,7 @@ u32 acpi_ns_local(acpi_object_type type) ACPI_FUNCTION_TRACE("ns_local"); if (!acpi_ut_valid_object_type(type)) { + /* Type code out of range */ ACPI_WARNING((AE_INFO, "Invalid Object Type %X", type)); @@ -411,6 +413,7 @@ acpi_status acpi_ns_build_internal_name(struct acpi_namestring_info *info) for (i = 0; i < ACPI_NAME_SIZE; i++) { if (acpi_ns_valid_path_separator(*external_name) || (*external_name == 0)) { + /* Pad the segment with underscore(s) if segment is short */ result[i] = '_'; @@ -795,6 +798,7 @@ u32 acpi_ns_opens_scope(acpi_object_type type) ACPI_FUNCTION_TRACE_STR("ns_opens_scope", acpi_ut_get_type_name(type)); if (!acpi_ut_valid_object_type(type)) { + /* type code out of range */ ACPI_WARNING((AE_INFO, "Invalid Object Type %X", type)); @@ -838,6 +842,7 @@ acpi_ns_get_node_by_path(char *pathname, ACPI_FUNCTION_TRACE_PTR("ns_get_node_by_path", pathname); if (pathname) { + /* Convert path to internal representation */ status = acpi_ns_internalize_name(pathname, &internal_path); @@ -963,6 +968,7 @@ acpi_name acpi_ns_find_parent_name(struct acpi_namespace_node * child_node) ACPI_FUNCTION_TRACE("ns_find_parent_name"); if (child_node) { + /* Valid entry. Get the parent Node */ parent_node = acpi_ns_get_parent_node(child_node); diff --git a/drivers/acpi/namespace/nswalk.c b/drivers/acpi/namespace/nswalk.c index fcab1e784b81..6bbc734bfee2 100644 --- a/drivers/acpi/namespace/nswalk.c +++ b/drivers/acpi/namespace/nswalk.c @@ -76,6 +76,7 @@ struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type, ACPI_FUNCTION_ENTRY(); if (!child_node) { + /* It's really the parent's _scope_ that we want */ if (parent_node->child) { @@ -92,6 +93,7 @@ struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type, /* If any type is OK, we are done */ if (type == ACPI_TYPE_ANY) { + /* next_node is NULL if we are at the end-of-list */ return (next_node); @@ -100,6 +102,7 @@ struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type, /* Must search for the node -- but within this scope only */ while (next_node) { + /* If type matches, we are done */ if (next_node->type == type) { @@ -182,6 +185,7 @@ acpi_ns_walk_namespace(acpi_object_type type, * bubbled up to (and passed) the original parent handle (start_entry) */ while (level > 0) { + /* Get the next node in this scope. Null if not found */ status = AE_OK; diff --git a/drivers/acpi/namespace/nsxfeval.c b/drivers/acpi/namespace/nsxfeval.c index a95f636dc35d..71e7769d7daf 100644 --- a/drivers/acpi/namespace/nsxfeval.c +++ b/drivers/acpi/namespace/nsxfeval.c @@ -110,6 +110,7 @@ acpi_evaluate_object_typed(acpi_handle handle, } if (return_buffer->length == 0) { + /* Error because caller specifically asked for a return value */ ACPI_ERROR((AE_INFO, "No return value")); @@ -131,6 +132,7 @@ acpi_evaluate_object_typed(acpi_handle handle, acpi_ut_get_type_name(return_type))); if (must_free) { + /* Caller used ACPI_ALLOCATE_BUFFER, free the return buffer */ acpi_os_free(return_buffer->pointer); @@ -224,9 +226,9 @@ acpi_evaluate_object(acpi_handle handle, * 3) Valid handle */ if ((pathname) && (acpi_ns_valid_root_prefix(pathname[0]))) { - /* - * The path is fully qualified, just evaluate by name - */ + + /* The path is fully qualified, just evaluate by name */ + status = acpi_ns_evaluate_by_name(pathname, &info); } else if (!handle) { /* @@ -235,11 +237,12 @@ acpi_evaluate_object(acpi_handle handle, * qualified names above, this is an error */ if (!pathname) { - ACPI_ERROR((AE_INFO, - "Both Handle and Pathname are NULL")); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Both Handle and Pathname are NULL")); } else { - ACPI_ERROR((AE_INFO, - "Handle is NULL and Pathname is relative")); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Null Handle with relative pathname [%s]", + pathname)); } status = AE_BAD_PARAMETER; @@ -256,9 +259,8 @@ acpi_evaluate_object(acpi_handle handle, */ status = acpi_ns_evaluate_by_handle(&info); } else { - /* - * Both a Handle and a relative Pathname - */ + /* Both a Handle and a relative Pathname */ + status = acpi_ns_evaluate_relative(pathname, &info); } } @@ -295,6 +297,7 @@ acpi_evaluate_object(acpi_handle handle, acpi_ut_get_object_size(info.return_object, &buffer_space_needed); if (ACPI_SUCCESS(status)) { + /* Validate/Allocate/Clear caller buffer */ status = @@ -303,7 +306,8 @@ acpi_evaluate_object(acpi_handle handle, buffer_space_needed); if (ACPI_FAILURE(status)) { /* - * Caller's buffer is too small or a new one can't be allocated + * Caller's buffer is too small or a new one can't + * be allocated */ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Needed buffer size %X, %s\n", @@ -312,9 +316,8 @@ acpi_evaluate_object(acpi_handle handle, acpi_format_exception (status))); } else { - /* - * We have enough space for the object, build it - */ + /* We have enough space for the object, build it */ + status = acpi_ut_copy_iobject_to_eobject (info.return_object, @@ -341,10 +344,10 @@ acpi_evaluate_object(acpi_handle handle, } } - /* - * Free the input parameter list (if we created one), - */ + /* Free the input parameter list (if we created one) */ + if (info.parameters) { + /* Free the allocated parameter block */ acpi_ut_delete_internal_object_list(info.parameters); @@ -473,6 +476,7 @@ acpi_ns_get_device_callback(acpi_handle obj_handle, } if (!(flags & ACPI_STA_DEVICE_PRESENT)) { + /* Don't examine children of the device if not present */ return (AE_CTRL_DEPTH); @@ -489,6 +493,7 @@ acpi_ns_get_device_callback(acpi_handle obj_handle, } if (ACPI_STRNCMP(hid.value, info->hid, sizeof(hid.value)) != 0) { + /* Get the list of Compatible IDs */ status = acpi_ut_execute_CID(node, &cid); @@ -563,9 +568,9 @@ acpi_get_devices(char *HID, * We're going to call their callback from OUR callback, so we need * to know what it is, and their context parameter. */ + info.hid = HID; info.context = context; info.user_function = user_function; - info.hid = HID; /* * Lock the namespace around the walk. @@ -578,9 +583,8 @@ acpi_get_devices(char *HID, return_ACPI_STATUS(status); } - status = acpi_ns_walk_namespace(ACPI_TYPE_DEVICE, - ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, - ACPI_NS_WALK_UNLOCK, + status = acpi_ns_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK, acpi_ns_get_device_callback, &info, return_value); diff --git a/drivers/acpi/namespace/nsxfname.c b/drivers/acpi/namespace/nsxfname.c index 8cd8675a47c0..55d26624ab9f 100644 --- a/drivers/acpi/namespace/nsxfname.c +++ b/drivers/acpi/namespace/nsxfname.c @@ -162,6 +162,7 @@ acpi_get_name(acpi_handle handle, u32 name_type, struct acpi_buffer * buffer) } if (name_type == ACPI_FULL_PATHNAME) { + /* Get the full pathname (From the namespace root) */ status = acpi_ns_handle_to_pathname(handle, buffer); diff --git a/drivers/acpi/namespace/nsxfobj.c b/drivers/acpi/namespace/nsxfobj.c index a0332595677a..9c5f3302799c 100644 --- a/drivers/acpi/namespace/nsxfobj.c +++ b/drivers/acpi/namespace/nsxfobj.c @@ -206,6 +206,7 @@ acpi_get_next_object(acpi_object_type type, /* If null handle, use the parent */ if (!child) { + /* Start search at the beginning of the specified scope */ parent_node = acpi_ns_map_handle_to_node(parent); diff --git a/drivers/acpi/parser/psargs.c b/drivers/acpi/parser/psargs.c index de573be52718..1c5934fe1853 100644 --- a/drivers/acpi/parser/psargs.c +++ b/drivers/acpi/parser/psargs.c @@ -275,6 +275,7 @@ acpi_ps_get_next_namepath(struct acpi_walk_state *walk_state, */ if (ACPI_SUCCESS(status) && possible_method_call && (node->type == ACPI_TYPE_METHOD)) { + /* This name is actually a control method invocation */ method_desc = acpi_ns_get_attached_object(node); @@ -319,6 +320,7 @@ acpi_ps_get_next_namepath(struct acpi_walk_state *walk_state, * some not_found cases are allowed */ if (status == AE_NOT_FOUND) { + /* 1) not_found is ok during load pass 1/2 (allow forward references) */ if ((walk_state->parse_flags & ACPI_PARSE_MODE_MASK) != @@ -354,6 +356,7 @@ acpi_ps_get_next_namepath(struct acpi_walk_state *walk_state, if ((walk_state->parse_flags & ACPI_PARSE_MODE_MASK) == ACPI_PARSE_EXECUTE) { + /* Report a control method execution error */ status = acpi_ds_method_error(status, walk_state); @@ -620,6 +623,7 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state, case ARGP_FIELDLIST: if (parser_state->aml < parser_state->pkg_end) { + /* Non-empty list */ while (parser_state->aml < parser_state->pkg_end) { @@ -645,6 +649,7 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state, case ARGP_BYTELIST: if (parser_state->aml < parser_state->pkg_end) { + /* Non-empty list */ arg = acpi_ps_alloc_op(AML_INT_BYTELIST_OP); @@ -673,6 +678,7 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state, if (subop == 0 || acpi_ps_is_leading_char(subop) || acpi_ps_is_prefix_char(subop)) { + /* null_name or name_string */ arg = acpi_ps_alloc_op(AML_INT_NAMEPATH_OP); @@ -703,6 +709,7 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state, case ARGP_OBJLIST: if (parser_state->aml < parser_state->pkg_end) { + /* Non-empty list of variable arguments, nothing returned */ walk_state->arg_count = ACPI_VAR_ARGS; diff --git a/drivers/acpi/parser/psloop.c b/drivers/acpi/parser/psloop.c index 00b072e15d19..42062d5abc9e 100644 --- a/drivers/acpi/parser/psloop.c +++ b/drivers/acpi/parser/psloop.c @@ -95,6 +95,7 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) #if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY)) if (walk_state->walk_type & ACPI_WALK_METHOD_RESTART) { + /* We are restarting a preempted control method */ if (acpi_ps_has_completed_scope(parser_state)) { @@ -143,6 +144,7 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "Popped scope, Op=%p\n", op)); } else if (walk_state->prev_op) { + /* We were in the middle of an op */ op = walk_state->prev_op; @@ -156,6 +158,7 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) while ((parser_state->aml < parser_state->aml_end) || (op)) { aml_op_start = parser_state->aml; if (!op) { + /* Get the next opcode from the AML stream */ walk_state->aml_offset = @@ -213,6 +216,7 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) /* Create Op structure and append to parent's argument list */ if (walk_state->op_info->flags & AML_NAMED) { + /* Allocate a new pre_op if necessary */ if (!pre_op) { @@ -388,6 +392,7 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) /* Are there any arguments that must be processed? */ if (walk_state->arg_types) { + /* Get arguments */ switch (op->common.aml_opcode) { @@ -853,6 +858,7 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) } else if (ACPI_FAILURE(status)) { + /* First error is most important */ (void) diff --git a/drivers/acpi/parser/psopcode.c b/drivers/acpi/parser/psopcode.c index 11d6351ab8b2..9eb8d0663886 100644 --- a/drivers/acpi/parser/psopcode.c +++ b/drivers/acpi/parser/psopcode.c @@ -731,6 +731,7 @@ const struct acpi_opcode_info *acpi_ps_get_opcode_info(u16 opcode) * Detect normal 8-bit opcode or extended 16-bit opcode */ if (!(opcode & 0xFF00)) { + /* Simple (8-bit) opcode: 0-255, can't index beyond table */ return (&acpi_gbl_aml_op_info @@ -739,6 +740,7 @@ const struct acpi_opcode_info *acpi_ps_get_opcode_info(u16 opcode) if (((opcode & 0xFF00) == AML_EXTENDED_OPCODE) && (((u8) opcode) <= MAX_EXTENDED_OPCODE)) { + /* Valid extended (16-bit) opcode */ return (&acpi_gbl_aml_op_info diff --git a/drivers/acpi/parser/psparse.c b/drivers/acpi/parser/psparse.c index a9f3229f4106..83d8916bc1af 100644 --- a/drivers/acpi/parser/psparse.c +++ b/drivers/acpi/parser/psparse.c @@ -106,6 +106,7 @@ u16 acpi_ps_peek_opcode(struct acpi_parse_state * parser_state) opcode = (u16) ACPI_GET8(aml); if (opcode == AML_EXTENDED_OP_PREFIX) { + /* Extended opcode, get the second opcode byte */ aml++; @@ -158,6 +159,7 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state, if (op->common.parent) { prev = op->common.parent->common.value.arg; if (!prev) { + /* Nothing more to do */ goto cleanup; @@ -245,6 +247,7 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state, /* We must unlink this op from the parent tree */ if (prev == op) { + /* This op is the first in the list */ if (replacement_op) { @@ -265,6 +268,7 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state, else while (prev) { + /* Traverse all siblings in the parent's argument list */ next = prev->common.next; @@ -510,6 +514,7 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state) } else if (status == AE_CTRL_TERMINATE) { status = AE_OK; } else if ((status != AE_OK) && (walk_state->method_desc)) { + /* Either the method parse or actual execution failed */ ACPI_ERROR_METHOD("Method parse/execution failed", @@ -551,6 +556,7 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state) if (((walk_state->parse_flags & ACPI_PARSE_MODE_MASK) == ACPI_PARSE_EXECUTE) || (ACPI_FAILURE(status))) { if (walk_state->method_desc) { + /* Decrement the thread count on the method parse tree */ if (walk_state->method_desc->method. @@ -633,12 +639,14 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state) } } else { if (previous_walk_state->return_desc) { + /* Caller doesn't want it, must delete it */ acpi_ut_remove_reference(previous_walk_state-> return_desc); } if (previous_walk_state->implicit_return_obj) { + /* Caller doesn't want it, must delete it */ acpi_ut_remove_reference(previous_walk_state-> diff --git a/drivers/acpi/parser/psscope.c b/drivers/acpi/parser/psscope.c index bc6047caccd9..edb7c9ba6ec2 100644 --- a/drivers/acpi/parser/psscope.c +++ b/drivers/acpi/parser/psscope.c @@ -165,6 +165,7 @@ acpi_ps_push_scope(struct acpi_parse_state *parser_state, acpi_ut_push_generic_state(&parser_state->scope, scope); if (arg_count == ACPI_VAR_ARGS) { + /* Multiple arguments */ scope->parse_scope.arg_end = parser_state->pkg_end; diff --git a/drivers/acpi/parser/pstree.c b/drivers/acpi/parser/pstree.c index dd6f16726fc4..6aa0012643ce 100644 --- a/drivers/acpi/parser/pstree.c +++ b/drivers/acpi/parser/pstree.c @@ -77,6 +77,7 @@ union acpi_parse_object *acpi_ps_get_arg(union acpi_parse_object *op, u32 argn) op_info = acpi_ps_get_opcode_info(op->common.aml_opcode); if (op_info->class == AML_CLASS_UNKNOWN) { + /* Invalid opcode or ASCII character */ return (NULL); @@ -85,6 +86,7 @@ union acpi_parse_object *acpi_ps_get_arg(union acpi_parse_object *op, u32 argn) /* Check if this opcode requires argument sub-objects */ if (!(op_info->flags & AML_HAS_ARGS)) { + /* Has no linked argument objects */ return (NULL); @@ -130,6 +132,7 @@ acpi_ps_append_arg(union acpi_parse_object *op, union acpi_parse_object *arg) op_info = acpi_ps_get_opcode_info(op->common.aml_opcode); if (op_info->class == AML_CLASS_UNKNOWN) { + /* Invalid opcode */ ACPI_ERROR((AE_INFO, "Invalid AML Opcode: 0x%2.2X", @@ -140,6 +143,7 @@ acpi_ps_append_arg(union acpi_parse_object *op, union acpi_parse_object *arg) /* Check if this opcode requires argument sub-objects */ if (!(op_info->flags & AML_HAS_ARGS)) { + /* Has no linked argument objects */ return; @@ -148,6 +152,7 @@ acpi_ps_append_arg(union acpi_parse_object *op, union acpi_parse_object *arg) /* Append the argument to the linked argument list */ if (op->common.value.arg) { + /* Append to existing argument list */ prev_arg = op->common.value.arg; @@ -222,12 +227,14 @@ union acpi_parse_object *acpi_ps_get_depth_next(union acpi_parse_object *origin, } if (arg == origin) { + /* Reached parent of origin, end search */ return (NULL); } if (parent->common.next) { + /* Found sibling of parent */ return (parent->common.next); diff --git a/drivers/acpi/parser/psutils.c b/drivers/acpi/parser/psutils.c index 3e07cb9cb748..a4c33a4bfe35 100644 --- a/drivers/acpi/parser/psutils.c +++ b/drivers/acpi/parser/psutils.c @@ -135,6 +135,7 @@ union acpi_parse_object *acpi_ps_alloc_op(u16 opcode) /* Allocate the minimum required size object */ if (flags == ACPI_PARSEOP_GENERIC) { + /* The generic op (default) is by far the most common (16 to 1) */ op = acpi_os_acquire_object(acpi_gbl_ps_node_cache); diff --git a/drivers/acpi/parser/pswalk.c b/drivers/acpi/parser/pswalk.c index 06f05bfd7612..3d08b8c6db41 100644 --- a/drivers/acpi/parser/pswalk.c +++ b/drivers/acpi/parser/pswalk.c @@ -69,13 +69,16 @@ void acpi_ps_delete_parse_tree(union acpi_parse_object *subtree_root) /* Visit all nodes in the subtree */ while (op) { + /* Check if we are not ascending */ if (op != parent) { + /* Look for an argument or child of the current op */ next = acpi_ps_get_arg(op, 0); if (next) { + /* Still going downward in tree (Op is not completed yet) */ op = next; diff --git a/drivers/acpi/parser/psxface.c b/drivers/acpi/parser/psxface.c index 2dd48cbb7c02..e09a820ee294 100644 --- a/drivers/acpi/parser/psxface.c +++ b/drivers/acpi/parser/psxface.c @@ -317,9 +317,11 @@ acpi_ps_update_parameter_list(struct acpi_parameter_info *info, u16 action) acpi_native_uint i; if ((info->parameter_type == ACPI_PARAM_ARGS) && (info->parameters)) { + /* Update reference count for each parameter */ for (i = 0; info->parameters[i]; i++) { + /* Ignore errors, just do them all */ (void)acpi_ut_update_object_reference(info-> diff --git a/drivers/acpi/resources/rscalc.c b/drivers/acpi/resources/rscalc.c index 7d6481d9fbec..223bdc493269 100644 --- a/drivers/acpi/resources/rscalc.c +++ b/drivers/acpi/resources/rscalc.c @@ -78,6 +78,7 @@ static u8 acpi_rs_count_set_bits(u16 bit_field) ACPI_FUNCTION_ENTRY(); for (bits_set = 0; bit_field; bits_set++) { + /* Zero the least significant bit that is set */ bit_field &= (bit_field - 1); @@ -154,6 +155,7 @@ acpi_rs_stream_option_length(u32 resource_length, * length, minus one byte for the resource_source_index itself. */ if (resource_length > minimum_aml_resource_length) { + /* Compute the length of the optional string */ string_length = @@ -162,7 +164,7 @@ acpi_rs_stream_option_length(u32 resource_length, /* Round up length to 32 bits for internal structure alignment */ - return (ACPI_ROUND_UP_to_32_bITS(string_length)); + return ((u32) ACPI_ROUND_UP_to_32_bITS(string_length)); } /******************************************************************************* @@ -191,6 +193,7 @@ acpi_rs_get_aml_length(struct acpi_resource * resource, acpi_size * size_needed) /* Traverse entire list of internal resource descriptors */ while (resource) { + /* Validate the descriptor type */ if (resource->type > ACPI_RESOURCE_TYPE_MAX) { @@ -214,6 +217,7 @@ acpi_rs_get_aml_length(struct acpi_resource * resource, acpi_size * size_needed) * is a Large Resource data type. */ if (resource->data.vendor.byte_length > 7) { + /* Base size of a Large resource descriptor */ total_size = @@ -346,6 +350,7 @@ acpi_rs_get_list_length(u8 * aml_buffer, /* Walk the list of AML resource descriptors */ while (aml_buffer < end_aml) { + /* Validate the Resource Type and Resource Length */ status = acpi_ut_validate_resource(aml_buffer, &resource_index); @@ -390,7 +395,7 @@ acpi_rs_get_list_length(u8 * aml_buffer, * Vendor Resource: * Ensure a 32-bit boundary for the structure */ - extra_struct_bytes = + extra_struct_bytes = (u32) ACPI_ROUND_UP_to_32_bITS(resource_length) - resource_length; break; @@ -407,7 +412,7 @@ acpi_rs_get_list_length(u8 * aml_buffer, * Vendor Resource: * Add vendor data and ensure a 32-bit boundary for the structure */ - extra_struct_bytes = + extra_struct_bytes = (u32) ACPI_ROUND_UP_to_32_bITS(resource_length) - resource_length; break; @@ -431,7 +436,7 @@ acpi_rs_get_list_length(u8 * aml_buffer, */ buffer++; - extra_struct_bytes = + extra_struct_bytes = (u32) /* * Add 4 bytes for each additional interrupt. Note: at * least one interrupt is required and is included in @@ -450,7 +455,7 @@ acpi_rs_get_list_length(u8 * aml_buffer, * Add the size of any optional data (resource_source) * Ensure a 64-bit boundary for the structure */ - extra_struct_bytes = + extra_struct_bytes = (u32) ACPI_ROUND_UP_to_64_bITS (acpi_rs_stream_option_length (resource_length, minimum_aml_resource_length)); @@ -525,6 +530,7 @@ acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object, top_object_list = package_object->package.elements; for (index = 0; index < number_of_elements; index++) { + /* Dereference the sub-package */ package_element = *top_object_list; diff --git a/drivers/acpi/resources/rslist.c b/drivers/acpi/resources/rslist.c index 1434e786477e..c27dca64d5d0 100644 --- a/drivers/acpi/resources/rslist.c +++ b/drivers/acpi/resources/rslist.c @@ -77,6 +77,7 @@ acpi_rs_convert_aml_to_resources(u8 * aml, u32 aml_length, u8 * output_buffer) /* Loop until end-of-buffer or an end_tag is found */ while (aml < end_aml) { + /* Validate the Resource Type and Resource Length */ status = acpi_ut_validate_resource(aml, &resource_index); @@ -155,6 +156,7 @@ acpi_rs_convert_resources_to_aml(struct acpi_resource *resource, /* Walk the resource descriptor list, convert each descriptor */ while (aml < end_aml) { + /* Validate the (internal) Resource Type */ if (resource->type > ACPI_RESOURCE_TYPE_MAX) { @@ -191,6 +193,7 @@ acpi_rs_convert_resources_to_aml(struct acpi_resource *resource, /* Check for end-of-list, normal exit */ if (resource->type == ACPI_RESOURCE_TYPE_END_TAG) { + /* An End Tag indicates the end of the input Resource Template */ return_ACPI_STATUS(AE_OK); diff --git a/drivers/acpi/resources/rsmisc.c b/drivers/acpi/resources/rsmisc.c index ed866cf1c6d2..095730196a8a 100644 --- a/drivers/acpi/resources/rsmisc.c +++ b/drivers/acpi/resources/rsmisc.c @@ -84,6 +84,7 @@ acpi_rs_convert_aml_to_resource(struct acpi_resource *resource, ACPI_FUNCTION_TRACE("rs_get_resource"); if (((acpi_native_uint) resource) & 0x3) { + /* Each internal resource struct is expected to be 32-bit aligned */ ACPI_WARNING((AE_INFO, @@ -295,9 +296,11 @@ acpi_rs_convert_aml_to_resource(struct acpi_resource *resource, exit: if (!flags_mode) { + /* Round the resource struct length up to the next 32-bit boundary */ - resource->length = ACPI_ROUND_UP_to_32_bITS(resource->length); + resource->length = + (u32) ACPI_ROUND_UP_to_32_bITS(resource->length); } return_ACPI_STATUS(AE_OK); } @@ -535,6 +538,7 @@ if (((aml->irq.flags & 0x09) == 0x00) || ((aml->irq.flags & 0x09) == 0x09)) { resource->data.extended_irq.interrupt_count = temp8; if (temp8 < 1) { + /* Must have at least one IRQ */ return_ACPI_STATUS(AE_AML_BAD_RESOURCE_LENGTH); diff --git a/drivers/acpi/resources/rsutils.c b/drivers/acpi/resources/rsutils.c index 25b5aedd6612..c5f7014929b4 100644 --- a/drivers/acpi/resources/rsutils.c +++ b/drivers/acpi/resources/rsutils.c @@ -205,6 +205,7 @@ acpi_rs_set_resource_length(acpi_rsdesc_size total_length, /* Length is stored differently for large and small descriptors */ if (aml->small_header.descriptor_type & ACPI_RESOURCE_NAME_LARGE) { + /* Large descriptor -- bytes 1-2 contain the 16-bit length */ ACPI_MOVE_16_TO_16(&aml->large_header.resource_length, @@ -328,6 +329,7 @@ acpi_rs_get_resource_source(acpi_rs_length resource_length, * we add 1 to the minimum length. */ if (total_length > (acpi_rsdesc_size) (minimum_length + 1)) { + /* Get the resource_source_index */ resource_source->index = aml_resource_source[0]; @@ -351,16 +353,20 @@ acpi_rs_get_resource_source(acpi_rs_length resource_length, * Zero the entire area of the buffer. */ total_length = + (u32) ACPI_ROUND_UP_to_32_bITS(ACPI_STRLEN - ((char *)&aml_resource_source[1]) + - 1); + (ACPI_CAST_PTR + (char, + &aml_resource_source[1])) + 1); + ACPI_MEMSET(resource_source->string_ptr, 0, total_length); /* Copy the resource_source string to the destination */ resource_source->string_length = acpi_rs_strcpy(resource_source->string_ptr, - (char *)&aml_resource_source[1]); + ACPI_CAST_PTR(char, + &aml_resource_source[1])); return ((acpi_rs_length) total_length); } @@ -405,6 +411,7 @@ acpi_rs_set_resource_source(union aml_resource * aml, /* Non-zero string length indicates presence of a resource_source */ if (resource_source->string_length) { + /* Point to the end of the AML descriptor */ aml_resource_source = ACPI_ADD_PTR(u8, aml, minimum_length); @@ -415,7 +422,7 @@ acpi_rs_set_resource_source(union aml_resource * aml, /* Copy the resource_source string */ - ACPI_STRCPY((char *)&aml_resource_source[1], + ACPI_STRCPY(ACPI_CAST_PTR(char, &aml_resource_source[1]), resource_source->string_ptr); /* @@ -435,9 +442,9 @@ acpi_rs_set_resource_source(union aml_resource * aml, * * FUNCTION: acpi_rs_get_prt_method_data * - * PARAMETERS: Handle - a handle to the containing object - * ret_buffer - a pointer to a buffer structure for the - * results + * PARAMETERS: Handle - Handle to the containing object + * ret_buffer - Pointer to a buffer structure for the + * results * * RETURN: Status * @@ -483,9 +490,9 @@ acpi_rs_get_prt_method_data(acpi_handle handle, struct acpi_buffer * ret_buffer) * * FUNCTION: acpi_rs_get_crs_method_data * - * PARAMETERS: Handle - a handle to the containing object - * ret_buffer - a pointer to a buffer structure for the - * results + * PARAMETERS: Handle - Handle to the containing object + * ret_buffer - Pointer to a buffer structure for the + * results * * RETURN: Status * @@ -532,9 +539,9 @@ acpi_rs_get_crs_method_data(acpi_handle handle, struct acpi_buffer *ret_buffer) * * FUNCTION: acpi_rs_get_prs_method_data * - * PARAMETERS: Handle - a handle to the containing object - * ret_buffer - a pointer to a buffer structure for the - * results + * PARAMETERS: Handle - Handle to the containing object + * ret_buffer - Pointer to a buffer structure for the + * results * * RETURN: Status * @@ -583,10 +590,10 @@ acpi_rs_get_prs_method_data(acpi_handle handle, struct acpi_buffer *ret_buffer) * * FUNCTION: acpi_rs_get_method_data * - * PARAMETERS: Handle - a handle to the containing object + * PARAMETERS: Handle - Handle to the containing object * Path - Path to method, relative to Handle - * ret_buffer - a pointer to a buffer structure for the - * results + * ret_buffer - Pointer to a buffer structure for the + * results * * RETURN: Status * @@ -634,9 +641,9 @@ acpi_rs_get_method_data(acpi_handle handle, * * FUNCTION: acpi_rs_set_srs_method_data * - * PARAMETERS: Handle - a handle to the containing object - * in_buffer - a pointer to a buffer structure of the - * parameter + * PARAMETERS: Handle - Handle to the containing object + * in_buffer - Pointer to a buffer structure of the + * parameter * * RETURN: Status * @@ -696,6 +703,7 @@ acpi_rs_set_srs_method_data(acpi_handle handle, struct acpi_buffer *in_buffer) status = acpi_ns_evaluate_relative(METHOD_NAME__SRS, &info); if (ACPI_SUCCESS(status)) { + /* Delete any return object (especially if implicit_return is enabled) */ if (info.return_object) { diff --git a/drivers/acpi/resources/rsxface.c b/drivers/acpi/resources/rsxface.c index 88b67077aeeb..2e1bc71acd94 100644 --- a/drivers/acpi/resources/rsxface.c +++ b/drivers/acpi/resources/rsxface.c @@ -279,6 +279,7 @@ acpi_walk_resources(acpi_handle device_handle, /* Walk the resource list until the end_tag is found (or buffer end) */ while (resource < resource_end) { + /* Sanity check the resource */ if (resource->type > ACPI_RESOURCE_TYPE_MAX) { @@ -291,6 +292,7 @@ acpi_walk_resources(acpi_handle device_handle, status = user_function(resource, context); if (ACPI_FAILURE(status)) { if (status == AE_CTRL_TERMINATE) { + /* This is an OK termination by the user function */ status = AE_OK; diff --git a/drivers/acpi/tables/tbconvrt.c b/drivers/acpi/tables/tbconvrt.c index 03b37d2223bc..254ebdbb7bef 100644 --- a/drivers/acpi/tables/tbconvrt.c +++ b/drivers/acpi/tables/tbconvrt.c @@ -147,6 +147,7 @@ acpi_status acpi_tb_convert_to_xsdt(struct acpi_table_desc *table_info) /* Copy the table pointers */ for (i = 0; i < acpi_gbl_rsdt_table_count; i++) { + /* RSDT pointers are 32 bits, XSDT pointers are 64 bits */ if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) { @@ -515,6 +516,7 @@ acpi_status acpi_tb_convert_table_fadt(void) if (acpi_gbl_FADT->revision >= FADT2_REVISION_ID) { if (acpi_gbl_FADT->length < sizeof(struct fadt_descriptor_rev2)) { + /* Length is too short to be a V2.0 table */ ACPI_WARNING((AE_INFO, @@ -603,6 +605,7 @@ acpi_status acpi_tb_build_common_facs(struct acpi_table_desc *table_info) if ((acpi_gbl_RSDP->revision < 2) || (acpi_gbl_FACS->length < 32) || (!(acpi_gbl_FACS->xfirmware_waking_vector))) { + /* ACPI 1.0 FACS or short table or optional X_ field is zero */ acpi_gbl_common_fACS.firmware_waking_vector = ACPI_CAST_PTR(u64, diff --git a/drivers/acpi/tables/tbget.c b/drivers/acpi/tables/tbget.c index 09b4ee6dfd60..4615e1afe8de 100644 --- a/drivers/acpi/tables/tbget.c +++ b/drivers/acpi/tables/tbget.c @@ -148,6 +148,10 @@ acpi_tb_get_table_header(struct acpi_pointer *address, sizeof(struct acpi_table_header), (void *)&header); if (ACPI_FAILURE(status)) { + ACPI_ERROR((AE_INFO, + "Could not map memory at %8.8X%8.8X for table header", + ACPI_FORMAT_UINT64(address->pointer. + physical))); return_ACPI_STATUS(status); } @@ -208,6 +212,7 @@ acpi_tb_get_table_body(struct acpi_pointer *address, status = acpi_tb_table_override(header, table_info); if (ACPI_SUCCESS(status)) { + /* Table was overridden by the host OS */ return_ACPI_STATUS(status); @@ -250,6 +255,7 @@ acpi_tb_table_override(struct acpi_table_header *header, */ status = acpi_os_table_override(header, &new_table); if (ACPI_FAILURE(status)) { + /* Some severe error from the OSL, but we basically ignore it */ ACPI_EXCEPTION((AE_INFO, status, @@ -258,6 +264,7 @@ acpi_tb_table_override(struct acpi_table_header *header, } if (!new_table) { + /* No table override */ return_ACPI_STATUS(AE_NO_ACPI_TABLES); @@ -381,6 +388,7 @@ acpi_tb_get_this_table(struct acpi_pointer *address, #if (!ACPI_CHECKSUM_ABORT) if (ACPI_FAILURE(status)) { + /* Ignore the error if configuration says so */ status = AE_OK; @@ -440,6 +448,7 @@ acpi_tb_get_table_ptr(acpi_table_type table_type, * instance is always in the list head. */ if (instance == 1) { + /* Get the first */ *table_ptr_loc = NULL; diff --git a/drivers/acpi/tables/tbgetall.c b/drivers/acpi/tables/tbgetall.c index 134e5dce0bc1..b4ec61d7cf06 100644 --- a/drivers/acpi/tables/tbgetall.c +++ b/drivers/acpi/tables/tbgetall.c @@ -223,6 +223,7 @@ acpi_status acpi_tb_get_required_tables(void) * any SSDTs. */ for (i = 0; i < acpi_gbl_rsdt_table_count; i++) { + /* Get the table address from the common internal XSDT */ address.pointer.value = acpi_gbl_XSDT->table_offset_entry[i]; diff --git a/drivers/acpi/tables/tbinstal.c b/drivers/acpi/tables/tbinstal.c index 7ffd0fddb4e5..ec2cb978b7c4 100644 --- a/drivers/acpi/tables/tbinstal.c +++ b/drivers/acpi/tables/tbinstal.c @@ -84,6 +84,7 @@ acpi_tb_match_signature(char *signature, if (!ACPI_STRNCMP(signature, acpi_gbl_table_data[i].signature, acpi_gbl_table_data[i].sig_length)) { + /* Found a signature match, return index if requested */ if (table_info) { diff --git a/drivers/acpi/tables/tbrsdt.c b/drivers/acpi/tables/tbrsdt.c index 4d308220225d..946d2f2d611d 100644 --- a/drivers/acpi/tables/tbrsdt.c +++ b/drivers/acpi/tables/tbrsdt.c @@ -190,6 +190,7 @@ acpi_status acpi_tb_validate_rsdt(struct acpi_table_header *table_ptr) } if (no_match) { + /* Invalid RSDT or XSDT signature */ ACPI_ERROR((AE_INFO, diff --git a/drivers/acpi/tables/tbutils.c b/drivers/acpi/tables/tbutils.c index bc571592f087..b463d4b88823 100644 --- a/drivers/acpi/tables/tbutils.c +++ b/drivers/acpi/tables/tbutils.c @@ -96,6 +96,7 @@ acpi_status acpi_tb_is_table_installed(struct acpi_table_desc *new_table_desc) (!ACPI_MEMCMP (table_desc->pointer, new_table_desc->pointer, new_table_desc->pointer->length))) { + /* Match: this table is already installed */ ACPI_DEBUG_PRINT((ACPI_DB_TABLES, @@ -249,6 +250,7 @@ u8 acpi_tb_generate_checksum(void *buffer, u32 length) u8 sum = 0; if (buffer && length) { + /* Buffer and Length are valid */ end_buffer = ACPI_ADD_PTR(u8, buffer, length); diff --git a/drivers/acpi/tables/tbxface.c b/drivers/acpi/tables/tbxface.c index 9fe53c9d5b9a..3e902cdb83e1 100644 --- a/drivers/acpi/tables/tbxface.c +++ b/drivers/acpi/tables/tbxface.c @@ -174,6 +174,7 @@ acpi_status acpi_load_table(struct acpi_table_header *table_ptr) status = acpi_tb_install_table(&table_info); if (ACPI_FAILURE(status)) { if (status == AE_ALREADY_EXISTS) { + /* Table already exists, no error */ status = AE_OK; @@ -208,6 +209,7 @@ acpi_status acpi_load_table(struct acpi_table_header *table_ptr) } if (ACPI_FAILURE(status)) { + /* Uninstall table and free the buffer */ (void)acpi_tb_uninstall_table(table_info.installed_desc); @@ -397,6 +399,7 @@ acpi_get_table(acpi_table_type table_type, /* Get the table length */ if (table_type == ACPI_TABLE_RSDP) { + /* RSD PTR is the only "table" without a header */ table_length = sizeof(struct rsdp_descriptor); diff --git a/drivers/acpi/tables/tbxfroot.c b/drivers/acpi/tables/tbxfroot.c index a62db6af83c9..7f68b759f15a 100644 --- a/drivers/acpi/tables/tbxfroot.c +++ b/drivers/acpi/tables/tbxfroot.c @@ -75,6 +75,7 @@ acpi_status acpi_tb_validate_rsdp(struct rsdp_descriptor *rsdp) * The signature and checksum must both be correct */ if (ACPI_STRNCMP((char *)rsdp, RSDP_SIG, sizeof(RSDP_SIG) - 1) != 0) { + /* Nope, BAD Signature */ return (AE_BAD_SIGNATURE); @@ -217,6 +218,7 @@ acpi_get_firmware_table(acpi_string signature, /* Ensure that we have a RSDP */ if (!acpi_gbl_RSDP) { + /* Get the RSDP */ status = acpi_os_get_root_pointer(flags, &address); @@ -327,10 +329,12 @@ acpi_get_firmware_table(acpi_string signature, /* Compare table signatures and table instance */ if (!ACPI_STRNCMP(header->signature, signature, ACPI_NAME_SIZE)) { + /* An instance of the table was found */ j++; if (j >= instance) { + /* Found the correct instance, get the entire table */ status = @@ -434,12 +438,14 @@ static u8 *acpi_tb_scan_memory_for_rsdp(u8 * start_address, u32 length) for (mem_rover = start_address; mem_rover < end_address; mem_rover += ACPI_RSDP_SCAN_STEP) { + /* The RSDP signature and checksum must both be correct */ status = acpi_tb_validate_rsdp(ACPI_CAST_PTR (struct rsdp_descriptor, mem_rover)); if (ACPI_SUCCESS(status)) { + /* Sig and checksum valid, we have found a real RSDP */ ACPI_DEBUG_PRINT((ACPI_DB_INFO, @@ -495,6 +501,7 @@ acpi_tb_find_rsdp(struct acpi_table_desc *table_info, u32 flags) * Scan supports either logical addressing or physical addressing */ if ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING) { + /* 1a) Get the location of the Extended BIOS Data Area (EBDA) */ status = acpi_os_map_memory((acpi_physical_address) @@ -542,6 +549,7 @@ acpi_tb_find_rsdp(struct acpi_table_desc *table_info, u32 flags) acpi_os_unmap_memory(table_ptr, ACPI_EBDA_WINDOW_SIZE); if (mem_rover) { + /* Return the physical address */ physical_address += @@ -576,6 +584,7 @@ acpi_tb_find_rsdp(struct acpi_table_desc *table_info, u32 flags) acpi_os_unmap_memory(table_ptr, ACPI_HI_RSDP_WINDOW_SIZE); if (mem_rover) { + /* Return the physical address */ physical_address = @@ -609,6 +618,7 @@ acpi_tb_find_rsdp(struct acpi_table_desc *table_info, u32 flags) (physical_address), ACPI_EBDA_WINDOW_SIZE); if (mem_rover) { + /* Return the physical address */ table_info->physical_address = @@ -624,6 +634,7 @@ acpi_tb_find_rsdp(struct acpi_table_desc *table_info, u32 flags) (ACPI_HI_RSDP_WINDOW_BASE), ACPI_HI_RSDP_WINDOW_SIZE); if (mem_rover) { + /* Found it, return the physical address */ table_info->physical_address = diff --git a/drivers/acpi/utilities/utalloc.c b/drivers/acpi/utilities/utalloc.c index 03b0044974c2..34de3791d4c2 100644 --- a/drivers/acpi/utilities/utalloc.c +++ b/drivers/acpi/utilities/utalloc.c @@ -308,6 +308,7 @@ void *acpi_ut_allocate(acpi_size size, u32 component, char *module, u32 line) allocation = acpi_os_allocate(size); if (!allocation) { + /* Report allocation error */ ACPI_ERROR((module, line, @@ -351,6 +352,7 @@ void *acpi_ut_callocate(acpi_size size, u32 component, char *module, u32 line) allocation = acpi_os_allocate(size); if (!allocation) { + /* Report allocation error */ ACPI_ERROR((module, line, @@ -477,6 +479,7 @@ void *acpi_ut_callocate_and_track(acpi_size size, acpi_ut_callocate(size + sizeof(struct acpi_debug_mem_header), component, module, line); if (!allocation) { + /* Report allocation error */ ACPI_ERROR((module, line, @@ -681,6 +684,7 @@ acpi_ut_remove_allocation(struct acpi_debug_mem_block *allocation, mem_list = acpi_gbl_global_list; if (NULL == mem_list->list_head) { + /* No allocations! */ ACPI_ERROR((module, line, @@ -807,6 +811,7 @@ void acpi_ut_dump_allocations(u32 component, char *module) if ((element->component & component) && ((module == NULL) || (0 == ACPI_STRCMP(module, element->module)))) { + /* Ignore allocated objects that are in a cache */ descriptor = diff --git a/drivers/acpi/utilities/utcache.c b/drivers/acpi/utilities/utcache.c index 2177cb1ef2c4..044c890e5b3c 100644 --- a/drivers/acpi/utilities/utcache.c +++ b/drivers/acpi/utilities/utcache.c @@ -118,6 +118,7 @@ acpi_status acpi_os_purge_cache(struct acpi_memory_list * cache) /* Walk the list of objects in this cache */ while (cache->list_head) { + /* Delete and unlink one cached state object */ next = *(ACPI_CAST_INDIRECT_PTR(char, @@ -259,6 +260,7 @@ void *acpi_os_acquire_object(struct acpi_memory_list *cache) /* Check the cache first */ if (cache->list_head) { + /* There is an object available, use it */ object = cache->list_head; diff --git a/drivers/acpi/utilities/utcopy.c b/drivers/acpi/utilities/utcopy.c index df2d32096b72..47875935c3f4 100644 --- a/drivers/acpi/utilities/utcopy.c +++ b/drivers/acpi/utilities/utcopy.c @@ -882,6 +882,7 @@ acpi_ut_copy_ipackage_to_ipackage(union acpi_operand_object *source_obj, acpi_ut_copy_ielement_to_ielement, walk_state); if (ACPI_FAILURE(status)) { + /* On failure, delete the destination package object */ acpi_ut_remove_reference(dest_obj); diff --git a/drivers/acpi/utilities/utdebug.c b/drivers/acpi/utilities/utdebug.c index 35f3d581e034..6e92b2a3c0fd 100644 --- a/drivers/acpi/utilities/utdebug.c +++ b/drivers/acpi/utilities/utdebug.c @@ -123,12 +123,14 @@ static const char *acpi_ut_trim_function_name(const char *function_name) /* All Function names are longer than 4 chars, check is safe */ if (*(ACPI_CAST_PTR(u32, function_name)) == ACPI_PREFIX_MIXED) { + /* This is the case where the original source has not been modified */ return (function_name + 4); } if (*(ACPI_CAST_PTR(u32, function_name)) == ACPI_PREFIX_LOWER) { + /* This is the case where the source has been 'linuxized' */ return (function_name + 5); @@ -545,6 +547,7 @@ void acpi_ut_dump_buffer(u8 * buffer, u32 count, u32 display, u32 component_id) /* Nasty little dump buffer routine! */ while (i < count) { + /* Print current offset */ acpi_os_printf("%6.4X: ", (u32) i); @@ -553,6 +556,7 @@ void acpi_ut_dump_buffer(u8 * buffer, u32 count, u32 display, u32 component_id) for (j = 0; j < 16;) { if (i + j >= count) { + /* Dump fill spaces */ acpi_os_printf("%*s", ((display * 2) + 1), " "); diff --git a/drivers/acpi/utilities/utdelete.c b/drivers/acpi/utilities/utdelete.c index 1db9695b0029..dbae72121cea 100644 --- a/drivers/acpi/utilities/utdelete.c +++ b/drivers/acpi/utilities/utdelete.c @@ -96,6 +96,7 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object) /* Free the actual string buffer */ if (!(object->common.flags & AOPOBJ_STATIC_POINTER)) { + /* But only if it is NOT a pointer into an ACPI table */ obj_pointer = object->string.pointer; @@ -111,6 +112,7 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object) /* Free the actual buffer */ if (!(object->common.flags & AOPOBJ_STATIC_POINTER)) { + /* But only if it is NOT a pointer into an ACPI table */ obj_pointer = object->buffer.pointer; @@ -415,6 +417,7 @@ acpi_ut_update_object_reference(union acpi_operand_object * object, u16 action) ACPI_FUNCTION_TRACE_PTR("ut_update_object_reference", object); while (object) { + /* Make sure that this isn't a namespace handle */ if (ACPI_GET_DESCRIPTOR_TYPE(object) == ACPI_DESC_TYPE_NAMED) { diff --git a/drivers/acpi/utilities/uteval.c b/drivers/acpi/utilities/uteval.c index 106cc97cb4af..952ffdea93aa 100644 --- a/drivers/acpi/utilities/uteval.c +++ b/drivers/acpi/utilities/uteval.c @@ -98,6 +98,7 @@ acpi_status acpi_ut_osi_implementation(struct acpi_walk_state *walk_state) ACPI_CAST_PTR(char, acpi_gbl_valid_osi_strings[i]))) { + /* This string is supported */ return_desc->integer.value = 0xFFFFFFFF; @@ -343,6 +344,7 @@ acpi_ut_execute_HID(struct acpi_namespace_node *device_node, } if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_INTEGER) { + /* Convert the Numeric HID to string */ acpi_ex_eisa_id_to_string((u32) obj_desc->integer.value, @@ -479,6 +481,7 @@ acpi_ut_execute_CID(struct acpi_namespace_node * device_node, /* The _CID object can be either a single CID or a package (list) of CIDs */ if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_PACKAGE) { + /* Translate each package element */ for (i = 0; i < count; i++) { @@ -543,6 +546,7 @@ acpi_ut_execute_UID(struct acpi_namespace_node *device_node, } if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_INTEGER) { + /* Convert the Numeric UID to string */ acpi_ex_unsigned_integer_to_string(obj_desc->integer.value, diff --git a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c index ffd13383a325..767c5e44a04b 100644 --- a/drivers/acpi/utilities/utglobal.c +++ b/drivers/acpi/utilities/utglobal.c @@ -119,6 +119,7 @@ const char *acpi_format_exception(acpi_status status) } if (!exception) { + /* Exception code was not recognized */ ACPI_ERROR((AE_INFO, @@ -747,6 +748,7 @@ u8 acpi_ut_valid_object_type(acpi_object_type type) { if (type > ACPI_TYPE_LOCAL_MAX) { + /* Note: Assumes all TYPEs are contiguous (external/local) */ return (FALSE); diff --git a/drivers/acpi/utilities/utmisc.c b/drivers/acpi/utilities/utmisc.c index 7364f5f8c9cd..60f36130663c 100644 --- a/drivers/acpi/utilities/utmisc.c +++ b/drivers/acpi/utilities/utmisc.c @@ -97,6 +97,7 @@ acpi_status acpi_ut_allocate_owner_id(acpi_owner_id * owner_id) for (k = acpi_gbl_next_owner_id_offset; k < 32; k++) { if (acpi_gbl_owner_id_mask[j] == ACPI_UINT32_MAX) { + /* There are no free IDs in this mask */ break; @@ -273,6 +274,7 @@ void acpi_ut_print_string(char *string, u8 max_length) acpi_os_printf("\""); for (i = 0; string[i] && (i < max_length); i++) { + /* Escape sequences */ switch (string[i]) { @@ -601,11 +603,13 @@ acpi_ut_strtoul64(char *string, u32 base, acpi_integer * ret_integer) while (*string) { if (ACPI_IS_DIGIT(*string)) { + /* Convert ASCII 0-9 to Decimal value */ this_digit = ((u8) * string) - '0'; } else { if (base == 10) { + /* Digit is out of range */ goto error_exit; @@ -613,6 +617,7 @@ acpi_ut_strtoul64(char *string, u32 base, acpi_integer * ret_integer) this_digit = (u8) ACPI_TOUPPER(*string); if (ACPI_IS_XDIGIT((char)this_digit)) { + /* Convert ASCII Hex char to value */ this_digit = this_digit - 'A' + 10; @@ -727,6 +732,7 @@ acpi_ut_walk_package_tree(union acpi_operand_object * source_object, } while (state) { + /* Get one element of the package */ this_index = state->pkg.index; @@ -812,31 +818,6 @@ acpi_ut_walk_package_tree(union acpi_operand_object * source_object, return_ACPI_STATUS(AE_AML_INTERNAL); } -/******************************************************************************* - * - * FUNCTION: acpi_ut_generate_checksum - * - * PARAMETERS: Buffer - Buffer to be scanned - * Length - number of bytes to examine - * - * RETURN: The generated checksum - * - * DESCRIPTION: Generate a checksum on a raw buffer - * - ******************************************************************************/ - -u8 acpi_ut_generate_checksum(u8 * buffer, u32 length) -{ - u32 i; - signed char sum = 0; - - for (i = 0; i < length; i++) { - sum = (signed char)(sum + buffer[i]); - } - - return ((u8) (0 - sum)); -} - /******************************************************************************* * * FUNCTION: acpi_ut_error, acpi_ut_warning, acpi_ut_info diff --git a/drivers/acpi/utilities/utobject.c b/drivers/acpi/utilities/utobject.c index 7ee2d1d98071..b1205a58028c 100644 --- a/drivers/acpi/utilities/utobject.c +++ b/drivers/acpi/utilities/utobject.c @@ -173,6 +173,7 @@ union acpi_operand_object *acpi_ut_create_buffer_object(acpi_size buffer_size) /* Create an actual buffer only if size > 0 */ if (buffer_size > 0) { + /* Allocate the actual buffer */ buffer = ACPI_MEM_CALLOCATE(buffer_size); @@ -397,6 +398,7 @@ acpi_ut_get_simple_object_size(union acpi_operand_object *internal_object, length = sizeof(union acpi_object); if (ACPI_GET_DESCRIPTOR_TYPE(internal_object) == ACPI_DESC_TYPE_NAMED) { + /* Object is a named object (reference), just return the length */ *obj_length = ACPI_ROUND_UP_TO_NATIVE_WORD(length); diff --git a/drivers/acpi/utilities/utresrc.c b/drivers/acpi/utilities/utresrc.c index 16461317113f..27158dd0f877 100644 --- a/drivers/acpi/utilities/utresrc.c +++ b/drivers/acpi/utilities/utresrc.c @@ -273,6 +273,7 @@ acpi_status acpi_ut_validate_resource(void *aml, u8 * return_index) * Examine the large/small bit in the resource header */ if (resource_type & ACPI_RESOURCE_NAME_LARGE) { + /* Verify the large resource type (name) against the max */ if (resource_type > ACPI_RESOURCE_NAME_LARGE_MAX) { @@ -376,6 +377,7 @@ u8 acpi_ut_get_resource_type(void *aml) * Examine the large/small bit in the resource header */ if (ACPI_GET8(aml) & ACPI_RESOURCE_NAME_LARGE) { + /* Large Resource Type -- bits 6:0 contain the name */ return (ACPI_GET8(aml)); @@ -411,6 +413,7 @@ u16 acpi_ut_get_resource_length(void *aml) * Examine the large/small bit in the resource header */ if (ACPI_GET8(aml) & ACPI_RESOURCE_NAME_LARGE) { + /* Large Resource type -- bytes 1-2 contain the 16-bit length */ ACPI_MOVE_16_TO_16(&resource_length, ACPI_ADD_PTR(u8, aml, 1)); @@ -515,6 +518,7 @@ acpi_ut_get_resource_end_tag(union acpi_operand_object * obj_desc, /* Walk the resource template, one descriptor per iteration */ while (aml < end_aml) { + /* Validate the Resource Type and Resource Length */ status = acpi_ut_validate_resource(aml, NULL); diff --git a/drivers/acpi/utilities/utstate.c b/drivers/acpi/utilities/utstate.c index 4b134a722907..69f2bfdc26ab 100644 --- a/drivers/acpi/utilities/utstate.c +++ b/drivers/acpi/utilities/utstate.c @@ -129,6 +129,7 @@ union acpi_generic_state *acpi_ut_pop_generic_state(union acpi_generic_state state = *list_head; if (state) { + /* Update the list head */ *list_head = state->common.next; @@ -158,6 +159,7 @@ union acpi_generic_state *acpi_ut_create_generic_state(void) state = acpi_os_acquire_object(acpi_gbl_state_cache); if (state) { + /* Initialize */ memset(state, 0, sizeof(union acpi_generic_state)); state->common.data_type = ACPI_DESC_TYPE_STATE; diff --git a/include/acpi/acconfig.h b/include/acpi/acconfig.h index e27dc8f29972..28a6a23c863a 100644 --- a/include/acpi/acconfig.h +++ b/include/acpi/acconfig.h @@ -63,7 +63,7 @@ /* Current ACPICA subsystem version in YYYYMMDD format */ -#define ACPI_CA_VERSION 0x20060127 +#define ACPI_CA_VERSION 0x20060210 /* * OS name, used for the _OS object. The _OS object is essentially obsolete, diff --git a/include/acpi/acdisasm.h b/include/acpi/acdisasm.h index 11a8fe39cb04..0727c132bd3c 100644 --- a/include/acpi/acdisasm.h +++ b/include/acpi/acdisasm.h @@ -70,6 +70,7 @@ extern const char *acpi_gbl_match_ops[ACPI_NUM_MATCH_OPS]; struct acpi_op_walk_info { u32 level; u32 bit_offset; + u32 flags; struct acpi_walk_state *walk_state; }; diff --git a/include/acpi/acutils.h b/include/acpi/acutils.h index 0927765df6aa..71ff78c75441 100644 --- a/include/acpi/acutils.h +++ b/include/acpi/acutils.h @@ -483,8 +483,6 @@ acpi_status acpi_ut_get_resource_end_tag(union acpi_operand_object *obj_desc, u8 ** end_tag); -u8 acpi_ut_generate_checksum(u8 * buffer, u32 length); - u32 acpi_ut_dword_byte_swap(u32 value); void acpi_ut_set_integer_width(u8 revision); -- cgit v1.2.3 From ea936b78f46cbe089a4ac363e1682dee7d427096 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Fri, 17 Feb 2006 00:00:00 -0500 Subject: ACPI: ACPICA 20060217 Implemented a change to the IndexField support to match the behavior of the Microsoft AML interpreter. The value written to the Index register is now a byte offset, no longer an index based upon the width of the Data register. This should fix IndexField problems seen on some machines where the Data register is not exactly one byte wide. The ACPI specification will be clarified on this point. Fixed a problem where several resource descriptor types could overrun the internal descriptor buffer due to size miscalculation: VendorShort, VendorLong, and Interrupt. This was noticed on IA64 machines, but could affect all platforms. Fixed a problem where individual resource descriptors were misaligned within the internal buffer, causing alignment faults on IA64 platforms. Signed-off-by: Bob Moore Signed-off-by: Len Brown --- drivers/acpi/executer/exprep.c | 17 +++++-- drivers/acpi/namespace/nsutils.c | 5 +- drivers/acpi/parser/psloop.c | 1 + drivers/acpi/resources/rscalc.c | 100 +++++++++++++++++--------------------- drivers/acpi/resources/rscreate.c | 2 +- drivers/acpi/resources/rslist.c | 15 ++++++ drivers/acpi/resources/rsmisc.c | 6 +-- drivers/acpi/resources/rsutils.c | 17 +++---- include/acpi/acconfig.h | 2 +- include/acpi/acmacros.h | 34 +++++++------ include/acpi/actypes.h | 10 ---- 11 files changed, 108 insertions(+), 101 deletions(-) (limited to 'include') diff --git a/drivers/acpi/executer/exprep.c b/drivers/acpi/executer/exprep.c index 7719ae5d4f16..916234bf811c 100644 --- a/drivers/acpi/executer/exprep.c +++ b/drivers/acpi/executer/exprep.c @@ -519,13 +519,20 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info) acpi_ut_add_reference(obj_desc->index_field.index_obj); /* + * February 2006: Changed to match MS behavior + * * The value written to the Index register is the byte offset of the - * target field - * Note: may change code to: ACPI_DIV_8 (Info->field_bit_position) + * target field. + * + * Previously, the value was calculated as an index in terms of the + * width of the Data register, as below: + * + * obj_desc->index_field.Value = (u32) + * (Info->field_bit_position / ACPI_MUL_8 ( + * obj_desc->Field.access_byte_width)); */ - obj_desc->index_field.value = (u32) - (info->field_bit_position / - ACPI_MUL_8(obj_desc->field.access_byte_width)); + obj_desc->index_field.value = + (u32) ACPI_DIV_8(info->field_bit_position); ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "index_field: bit_off %X, Off %X, Value %X, Gran %X, Index %p, Data %p\n", diff --git a/drivers/acpi/namespace/nsutils.c b/drivers/acpi/namespace/nsutils.c index e8c779114bec..123f454b14ab 100644 --- a/drivers/acpi/namespace/nsutils.c +++ b/drivers/acpi/namespace/nsutils.c @@ -78,6 +78,7 @@ acpi_ns_report_error(char *module_name, char *internal_name, acpi_status lookup_status) { acpi_status status; + u32 bad_name; char *name = NULL; acpi_ut_report_error(module_name, line_number); @@ -86,8 +87,8 @@ acpi_ns_report_error(char *module_name, /* There is a non-ascii character in the name */ - acpi_os_printf("[0x%4.4X] (NON-ASCII)", - *(ACPI_CAST_PTR(u32, internal_name))); + ACPI_MOVE_32_TO_32(&bad_name, internal_name); + acpi_os_printf("[0x%4.4X] (NON-ASCII)", bad_name); } else { /* Convert path to external format */ diff --git a/drivers/acpi/parser/psloop.c b/drivers/acpi/parser/psloop.c index 42062d5abc9e..14052cb648c1 100644 --- a/drivers/acpi/parser/psloop.c +++ b/drivers/acpi/parser/psloop.c @@ -767,6 +767,7 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) return_ACPI_STATUS(status2); } } + acpi_ps_pop_scope(parser_state, &op, &walk_state->arg_types, &walk_state->arg_count); diff --git a/drivers/acpi/resources/rscalc.c b/drivers/acpi/resources/rscalc.c index 223bdc493269..8e406d992f3b 100644 --- a/drivers/acpi/resources/rscalc.c +++ b/drivers/acpi/resources/rscalc.c @@ -162,9 +162,11 @@ acpi_rs_stream_option_length(u32 resource_length, resource_length - minimum_aml_resource_length - 1; } - /* Round up length to 32 bits for internal structure alignment */ - - return ((u32) ACPI_ROUND_UP_to_32_bITS(string_length)); + /* + * Round the length up to a multiple of the native word in order to + * guarantee that the entire resource descriptor is native word aligned + */ + return ((u32) ACPI_ROUND_UP_TO_NATIVE_WORD(string_length)); } /******************************************************************************* @@ -336,7 +338,7 @@ acpi_rs_get_list_length(u8 * aml_buffer, acpi_status status; u8 *end_aml; u8 *buffer; - u32 buffer_size = 0; + u32 buffer_size; u16 temp16; u16 resource_length; u32 extra_struct_bytes; @@ -345,6 +347,7 @@ acpi_rs_get_list_length(u8 * aml_buffer, ACPI_FUNCTION_TRACE("rs_get_list_length"); + *size_needed = 0; end_aml = aml_buffer + aml_buffer_length; /* Walk the list of AML resource descriptors */ @@ -391,37 +394,28 @@ acpi_rs_get_list_length(u8 * aml_buffer, break; case ACPI_RESOURCE_NAME_VENDOR_SMALL: + case ACPI_RESOURCE_NAME_VENDOR_LARGE: /* * Vendor Resource: - * Ensure a 32-bit boundary for the structure + * Get the number of vendor data bytes */ - extra_struct_bytes = (u32) - ACPI_ROUND_UP_to_32_bITS(resource_length) - - resource_length; + extra_struct_bytes = resource_length; break; case ACPI_RESOURCE_NAME_END_TAG: /* - * End Tag: This is the normal exit, add size of end_tag + * End Tag: + * This is the normal exit, add size of end_tag */ - *size_needed = buffer_size + ACPI_RS_SIZE_MIN; + *size_needed += ACPI_RS_SIZE_MIN; return_ACPI_STATUS(AE_OK); - case ACPI_RESOURCE_NAME_VENDOR_LARGE: - /* - * Vendor Resource: - * Add vendor data and ensure a 32-bit boundary for the structure - */ - extra_struct_bytes = (u32) - ACPI_ROUND_UP_to_32_bITS(resource_length) - - resource_length; - break; - case ACPI_RESOURCE_NAME_ADDRESS32: case ACPI_RESOURCE_NAME_ADDRESS16: + case ACPI_RESOURCE_NAME_ADDRESS64: /* - * 32-Bit or 16-bit Address Resource: - * Add the size of any optional data (resource_source) + * Address Resource: + * Add the size of the optional resource_source */ extra_struct_bytes = acpi_rs_stream_option_length(resource_length, @@ -430,50 +424,46 @@ acpi_rs_get_list_length(u8 * aml_buffer, case ACPI_RESOURCE_NAME_EXTENDED_IRQ: /* - * Extended IRQ: - * Point past the interrupt_vector_flags to get the - * interrupt_table_length. + * Extended IRQ Resource: + * Using the interrupt_table_length, add 4 bytes for each additional + * interrupt. Note: at least one interrupt is required and is + * included in the minimum descriptor size (reason for the -1) */ - buffer++; - - extra_struct_bytes = (u32) - /* - * Add 4 bytes for each additional interrupt. Note: at - * least one interrupt is required and is included in - * the minimum descriptor size - */ - ((*buffer - 1) * sizeof(u32)) + - /* Add the size of any optional data (resource_source) */ + extra_struct_bytes = (buffer[1] - 1) * sizeof(u32); + + /* Add the size of the optional resource_source */ + + extra_struct_bytes += acpi_rs_stream_option_length(resource_length - extra_struct_bytes, minimum_aml_resource_length); break; - case ACPI_RESOURCE_NAME_ADDRESS64: - /* - * 64-Bit Address Resource: - * Add the size of any optional data (resource_source) - * Ensure a 64-bit boundary for the structure - */ - extra_struct_bytes = (u32) - ACPI_ROUND_UP_to_64_bITS - (acpi_rs_stream_option_length - (resource_length, minimum_aml_resource_length)); - break; - default: break; } - /* Update the required buffer size for the internal descriptor structs */ + /* + * Update the required buffer size for the internal descriptor structs + * + * Important: Round the size up for the appropriate alignment. This + * is a requirement on IA64. + */ + buffer_size = acpi_gbl_resource_struct_sizes[resource_index] + + extra_struct_bytes; + buffer_size = ACPI_ROUND_UP_TO_NATIVE_WORD(buffer_size); + + *size_needed += buffer_size; - temp16 = (u16) (acpi_gbl_resource_struct_sizes[resource_index] + - extra_struct_bytes); - buffer_size += (u32) ACPI_ROUND_UP_TO_NATIVE_WORD(temp16); + ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, + "Type %.2X, Aml %.2X internal %.2X\n", + acpi_ut_get_resource_type(aml_buffer), + acpi_ut_get_descriptor_length(aml_buffer), + buffer_size)); /* - * Point to the next resource within the stream - * using the size of the header plus the length contained in the header + * Point to the next resource within the AML stream using the length + * contained in the resource descriptor header */ aml_buffer += acpi_ut_get_descriptor_length(aml_buffer); } @@ -589,7 +579,7 @@ acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object, /* Round up the size since each element must be aligned */ - temp_size_needed = ACPI_ROUND_UP_to_64_bITS(temp_size_needed); + temp_size_needed = ACPI_ROUND_UP_to_64_bIT(temp_size_needed); /* Point to the next union acpi_operand_object */ @@ -597,7 +587,7 @@ acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object, } /* - * Adding an extra element to the end of the list, essentially a + * Add an extra element to the end of the list, essentially a * NULL terminator */ *buffer_size_needed = diff --git a/drivers/acpi/resources/rscreate.c b/drivers/acpi/resources/rscreate.c index 8c128dea3252..67c052af7bbe 100644 --- a/drivers/acpi/resources/rscreate.c +++ b/drivers/acpi/resources/rscreate.c @@ -332,7 +332,7 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object, /* Now align the current length */ user_prt->length = - (u32) ACPI_ROUND_UP_to_64_bITS(user_prt->length); + (u32) ACPI_ROUND_UP_to_64_bIT(user_prt->length); /* 4) Fourth subobject: Dereference the PRT.source_index */ diff --git a/drivers/acpi/resources/rslist.c b/drivers/acpi/resources/rslist.c index c27dca64d5d0..6f2d8de39523 100644 --- a/drivers/acpi/resources/rslist.c +++ b/drivers/acpi/resources/rslist.c @@ -77,6 +77,15 @@ acpi_rs_convert_aml_to_resources(u8 * aml, u32 aml_length, u8 * output_buffer) /* Loop until end-of-buffer or an end_tag is found */ while (aml < end_aml) { + /* + * Check that the input buffer and all subsequent pointers into it + * are aligned on a native word boundary. Most important on IA64 + */ + if (ACPI_IS_MISALIGNED(resource)) { + ACPI_WARNING((AE_INFO, + "Misaligned resource pointer %p", + resource)); + } /* Validate the Resource Type and Resource Length */ @@ -101,6 +110,12 @@ acpi_rs_convert_aml_to_resources(u8 * aml, u32 aml_length, u8 * output_buffer) return_ACPI_STATUS(status); } + ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, + "Type %.2X, Aml %.2X internal %.2X\n", + acpi_ut_get_resource_type(aml), + acpi_ut_get_descriptor_length(aml), + resource->length)); + /* Normal exit on completion of an end_tag resource descriptor */ if (acpi_ut_get_resource_type(aml) == diff --git a/drivers/acpi/resources/rsmisc.c b/drivers/acpi/resources/rsmisc.c index 095730196a8a..6a731f4028d4 100644 --- a/drivers/acpi/resources/rsmisc.c +++ b/drivers/acpi/resources/rsmisc.c @@ -81,7 +81,7 @@ acpi_rs_convert_aml_to_resource(struct acpi_resource *resource, u16 item_count = 0; u16 temp16 = 0; - ACPI_FUNCTION_TRACE("rs_get_resource"); + ACPI_FUNCTION_TRACE("rs_convert_aml_to_resource"); if (((acpi_native_uint) resource) & 0x3) { @@ -297,10 +297,10 @@ acpi_rs_convert_aml_to_resource(struct acpi_resource *resource, exit: if (!flags_mode) { - /* Round the resource struct length up to the next 32-bit boundary */ + /* Round the resource struct length up to the next boundary (32 or 64) */ resource->length = - (u32) ACPI_ROUND_UP_to_32_bITS(resource->length); + (u32) ACPI_ROUND_UP_TO_NATIVE_WORD(resource->length); } return_ACPI_STATUS(AE_OK); } diff --git a/drivers/acpi/resources/rsutils.c b/drivers/acpi/resources/rsutils.c index c5f7014929b4..9bcf0b637d22 100644 --- a/drivers/acpi/resources/rsutils.c +++ b/drivers/acpi/resources/rsutils.c @@ -299,7 +299,8 @@ static u16 acpi_rs_strcpy(char *destination, char *source) * string_ptr - (optional) where to store the actual * resource_source string * - * RETURN: Length of the string plus NULL terminator, rounded up to 32 bit + * RETURN: Length of the string plus NULL terminator, rounded up to native + * word boundary * * DESCRIPTION: Copy the optional resource_source data from a raw AML descriptor * to an internal resource descriptor @@ -346,18 +347,16 @@ acpi_rs_get_resource_source(acpi_rs_length resource_length, } /* - * In order for the struct_size to fall on a 32-bit boundary, calculate - * the length of the string (+1 for the NULL terminator) and expand the - * struct_size to the next 32-bit boundary. + * In order for the Resource length to be a multiple of the native + * word, calculate the length of the string (+1 for NULL terminator) + * and expand to the next word multiple. * * Zero the entire area of the buffer. */ total_length = - (u32) - ACPI_ROUND_UP_to_32_bITS(ACPI_STRLEN - (ACPI_CAST_PTR - (char, - &aml_resource_source[1])) + 1); + ACPI_STRLEN(ACPI_CAST_PTR(char, &aml_resource_source[1])) + + 1; + total_length = (u32) ACPI_ROUND_UP_TO_NATIVE_WORD(total_length); ACPI_MEMSET(resource_source->string_ptr, 0, total_length); diff --git a/include/acpi/acconfig.h b/include/acpi/acconfig.h index 28a6a23c863a..788502256222 100644 --- a/include/acpi/acconfig.h +++ b/include/acpi/acconfig.h @@ -63,7 +63,7 @@ /* Current ACPICA subsystem version in YYYYMMDD format */ -#define ACPI_CA_VERSION 0x20060210 +#define ACPI_CA_VERSION 0x20060217 /* * OS name, used for the _OS object. The _OS object is essentially obsolete, diff --git a/include/acpi/acmacros.h b/include/acpi/acmacros.h index f2be2a881730..dd5644dbe946 100644 --- a/include/acpi/acmacros.h +++ b/include/acpi/acmacros.h @@ -341,29 +341,33 @@ /* * Rounding macros (Power of two boundaries only) */ -#define ACPI_ROUND_DOWN(value,boundary) (((acpi_native_uint)(value)) & \ +#define ACPI_ROUND_DOWN(value,boundary) (((acpi_native_uint)(value)) & \ (~(((acpi_native_uint) boundary)-1))) -#define ACPI_ROUND_UP(value,boundary) ((((acpi_native_uint)(value)) + \ +#define ACPI_ROUND_UP(value,boundary) ((((acpi_native_uint)(value)) + \ (((acpi_native_uint) boundary)-1)) & \ (~(((acpi_native_uint) boundary)-1))) -#define ACPI_ROUND_DOWN_TO_32_BITS(a) ACPI_ROUND_DOWN(a,4) -#define ACPI_ROUND_DOWN_TO_64_BITS(a) ACPI_ROUND_DOWN(a,8) -#define ACPI_ROUND_DOWN_TO_NATIVE_WORD(a) ACPI_ROUND_DOWN(a,ALIGNED_ADDRESS_BOUNDARY) +/* Note: sizeof(acpi_native_uint) evaluates to either 2, 4, or 8 */ -#define ACPI_ROUND_UP_to_32_bITS(a) ACPI_ROUND_UP(a,4) -#define ACPI_ROUND_UP_to_64_bITS(a) ACPI_ROUND_UP(a,8) -#define ACPI_ROUND_UP_TO_NATIVE_WORD(a) ACPI_ROUND_UP(a,ALIGNED_ADDRESS_BOUNDARY) +#define ACPI_ROUND_DOWN_to_32_bIT(a) ACPI_ROUND_DOWN(a,4) +#define ACPI_ROUND_DOWN_to_64_bIT(a) ACPI_ROUND_DOWN(a,8) +#define ACPI_ROUND_DOWN_TO_NATIVE_WORD(a) ACPI_ROUND_DOWN(a,sizeof(acpi_native_uint)) -#define ACPI_ROUND_BITS_UP_TO_BYTES(a) ACPI_DIV_8((a) + 7) -#define ACPI_ROUND_BITS_DOWN_TO_BYTES(a) ACPI_DIV_8((a)) +#define ACPI_ROUND_UP_to_32_bIT(a) ACPI_ROUND_UP(a,4) +#define ACPI_ROUND_UP_to_64_bIT(a) ACPI_ROUND_UP(a,8) +#define ACPI_ROUND_UP_TO_NATIVE_WORD(a) ACPI_ROUND_UP(a,sizeof(acpi_native_uint)) -#define ACPI_ROUND_UP_TO_1K(a) (((a) + 1023) >> 10) +#define ACPI_ROUND_BITS_UP_TO_BYTES(a) ACPI_DIV_8((a) + 7) +#define ACPI_ROUND_BITS_DOWN_TO_BYTES(a) ACPI_DIV_8((a)) + +#define ACPI_ROUND_UP_TO_1K(a) (((a) + 1023) >> 10) /* Generic (non-power-of-two) rounding */ -#define ACPI_ROUND_UP_TO(value,boundary) (((value) + ((boundary)-1)) / (boundary)) +#define ACPI_ROUND_UP_TO(value,boundary) (((value) + ((boundary)-1)) / (boundary)) + +#define ACPI_IS_MISALIGNED(value) (((acpi_native_uint)value) & (sizeof(acpi_native_uint)-1)) /* * Bitmask creation @@ -371,10 +375,10 @@ * MASK_BITS_ABOVE creates a mask starting AT the position and above * MASK_BITS_BELOW creates a mask starting one bit BELOW the position */ -#define ACPI_MASK_BITS_ABOVE(position) (~((ACPI_INTEGER_MAX) << ((u32) (position)))) -#define ACPI_MASK_BITS_BELOW(position) ((ACPI_INTEGER_MAX) << ((u32) (position))) +#define ACPI_MASK_BITS_ABOVE(position) (~((ACPI_INTEGER_MAX) << ((u32) (position)))) +#define ACPI_MASK_BITS_BELOW(position) ((ACPI_INTEGER_MAX) << ((u32) (position))) -#define ACPI_IS_OCTAL_DIGIT(d) (((char)(d) >= '0') && ((char)(d) <= '7')) +#define ACPI_IS_OCTAL_DIGIT(d) (((char)(d) >= '0') && ((char)(d) <= '7')) /* Bitfields within ACPI registers */ diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index 7ca89cde706e..95c3c8b6d618 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -154,7 +154,6 @@ typedef u64 acpi_physical_address; #define ACPI_MAX_PTR ACPI_UINT64_MAX #define ACPI_SIZE_MAX ACPI_UINT64_MAX -#define ALIGNED_ADDRESS_BOUNDARY 0x00000008 #define ACPI_USE_NATIVE_DIVIDE /* Has native 64-bit integer support */ /* @@ -195,8 +194,6 @@ typedef u64 acpi_physical_address; #define ACPI_MAX_PTR ACPI_UINT32_MAX #define ACPI_SIZE_MAX ACPI_UINT32_MAX -#define ALIGNED_ADDRESS_BOUNDARY 0x00000004 - /******************************************************************************* * * Types specific to 16-bit targets @@ -223,7 +220,6 @@ typedef char *acpi_physical_address; #define ACPI_MAX_PTR ACPI_UINT16_MAX #define ACPI_SIZE_MAX ACPI_UINT16_MAX -#define ALIGNED_ADDRESS_BOUNDARY 0x00000002 #define ACPI_USE_NATIVE_DIVIDE /* No 64-bit integers, ok to use native divide */ /* 64-bit integers cannot be supported */ @@ -1297,12 +1293,6 @@ struct acpi_resource { #define ACPI_NEXT_RESOURCE(res) (struct acpi_resource *)((u8 *) res + res->length) -#ifndef ACPI_MISALIGNMENT_NOT_SUPPORTED -#define ACPI_ALIGN_RESOURCE_SIZE(length) (length) -#else -#define ACPI_ALIGN_RESOURCE_SIZE(length) ACPI_ROUND_UP_TO_NATIVE_WORD(length) -#endif - /* * END: of definitions for Resource Attributes */ -- cgit v1.2.3 From 8313524a0d466f451a62709aaedf988d8257b21c Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 3 Oct 2006 00:00:00 -0400 Subject: ACPI: ACPICA 20060310 Tagged all external interfaces to the subsystem with the new ACPI_EXPORT_SYMBOL macro. This macro can be defined as necessary to assist kernel integration. For Linux, the macro resolves to the EXPORT_SYMBOL macro. The default definition is NULL. Added the ACPI_THREAD_ID type for the return value from acpi_os_get_thread_id(). This allows the host to define this as necessary to simplify kernel integration. The default definition is ACPI_NATIVE_UINT. Valery Podrezov fixed two interpreter problems related to error processing, the deletion of objects, and placing invalid pointers onto the internal operator result stack. http://bugzilla.kernel.org/show_bug.cgi?id=6028 http://bugzilla.kernel.org/show_bug.cgi?id=6151 Increased the reference count threshold where a warning is emitted for large reference counts in order to eliminate unnecessary warnings on systems with large namespaces (especially 64-bit.) Increased the value from 0x400 to 0x800. Due to universal disagreement as to the meaning of the 'c' in the calloc() function, the ACPI_MEM_CALLOCATE macro has been renamed to ACPI_ALLOCATE_ZEROED so that the purpose of the interface is 'clear'. ACPI_MEM_ALLOCATE and ACPI_MEM_FREE are renamed to ACPI_ALLOCATE and ACPI_FREE. Signed-off-by: Bob Moore Signed-off-by: Len Brown --- drivers/acpi/dispatcher/dsmthdat.c | 2 +- drivers/acpi/dispatcher/dsobject.c | 9 +++--- drivers/acpi/dispatcher/dsutils.c | 2 +- drivers/acpi/dispatcher/dswload.c | 1 - drivers/acpi/dispatcher/dswstate.c | 8 ++--- drivers/acpi/events/evgpeblk.c | 39 ++++++++++++------------ drivers/acpi/events/evregion.c | 2 +- drivers/acpi/events/evrgnini.c | 8 ++--- drivers/acpi/events/evxface.c | 32 ++++++++------------ drivers/acpi/events/evxfevnt.c | 40 ++++++++++++------------- drivers/acpi/events/evxfregn.c | 7 ++--- drivers/acpi/executer/exconfig.c | 4 +-- drivers/acpi/executer/exdump.c | 2 +- drivers/acpi/executer/exfield.c | 4 +-- drivers/acpi/executer/exnames.c | 4 +-- drivers/acpi/executer/exoparg1.c | 17 +++++++---- drivers/acpi/executer/exoparg2.c | 4 +-- drivers/acpi/executer/exoparg3.c | 9 +++--- drivers/acpi/executer/exregion.c | 10 +++---- drivers/acpi/executer/exstorob.c | 8 ++--- drivers/acpi/hardware/hwregs.c | 11 ++----- drivers/acpi/hardware/hwsleep.c | 18 ++++++----- drivers/acpi/hardware/hwtimer.c | 9 +++--- drivers/acpi/namespace/nsaccess.c | 19 +++++++----- drivers/acpi/namespace/nsalloc.c | 6 ++-- drivers/acpi/namespace/nsdumpdv.c | 2 +- drivers/acpi/namespace/nseval.c | 4 +-- drivers/acpi/namespace/nsinit.c | 2 +- drivers/acpi/namespace/nsnames.c | 10 ++----- drivers/acpi/namespace/nsparse.c | 2 +- drivers/acpi/namespace/nssearch.c | 2 +- drivers/acpi/namespace/nsutils.c | 12 ++++---- drivers/acpi/namespace/nsxfeval.c | 38 ++++++++++++------------ drivers/acpi/namespace/nsxfname.c | 16 ++++------ drivers/acpi/namespace/nsxfobj.c | 10 ++----- drivers/acpi/parser/pstree.c | 1 - drivers/acpi/resources/rsinfo.c | 1 + drivers/acpi/resources/rsxface.c | 29 ++++++++---------- drivers/acpi/tables/tbconvrt.c | 8 ++--- drivers/acpi/tables/tbget.c | 2 +- drivers/acpi/tables/tbinstal.c | 8 ++--- drivers/acpi/tables/tbxface.c | 15 +++++----- drivers/acpi/tables/tbxfroot.c | 22 ++++++-------- drivers/acpi/utilities/utalloc.c | 2 +- drivers/acpi/utilities/utcache.c | 8 ++--- drivers/acpi/utilities/utcopy.c | 24 +++++++-------- drivers/acpi/utilities/utdebug.c | 23 +++++--------- drivers/acpi/utilities/utdelete.c | 4 +-- drivers/acpi/utilities/uteval.c | 4 +-- drivers/acpi/utilities/utglobal.c | 6 ++-- drivers/acpi/utilities/utinit.c | 8 ++--- drivers/acpi/utilities/utmisc.c | 2 +- drivers/acpi/utilities/utmutex.c | 4 +-- drivers/acpi/utilities/utobject.c | 5 ++-- drivers/acpi/utilities/utxface.c | 24 ++++++++------- include/acpi/acconfig.h | 6 ++-- include/acpi/acdisasm.h | 23 ++++++++++++++ include/acpi/aclocal.h | 8 ++--- include/acpi/acmacros.h | 12 ++++---- include/acpi/acnamesp.h | 5 ++++ include/acpi/acpiosxf.h | 2 +- include/acpi/actypes.h | 15 ++++++++++ include/acpi/amlresrc.h | 61 +++++++++++++++++++------------------- include/acpi/platform/acenv.h | 6 ++-- include/acpi/platform/aclinux.h | 19 +++++------- 65 files changed, 367 insertions(+), 363 deletions(-) (limited to 'include') diff --git a/drivers/acpi/dispatcher/dsmthdat.c b/drivers/acpi/dispatcher/dsmthdat.c index f7cb5170aa11..2ed48439835d 100644 --- a/drivers/acpi/dispatcher/dsmthdat.c +++ b/drivers/acpi/dispatcher/dsmthdat.c @@ -81,7 +81,7 @@ acpi_ds_method_data_get_type(u16 opcode, * special data types. * * NOTES: walk_state fields are initialized to zero by the - * ACPI_MEM_CALLOCATE(). + * ACPI_ALLOCATE_ZEROED(). * * A pseudo-Namespace Node is assigned to each argument and local * so that ref_of() can return a pointer to the Node. diff --git a/drivers/acpi/dispatcher/dsobject.c b/drivers/acpi/dispatcher/dsobject.c index 1f2d0c6ef36c..ce54715f13ad 100644 --- a/drivers/acpi/dispatcher/dsobject.c +++ b/drivers/acpi/dispatcher/dsobject.c @@ -245,7 +245,7 @@ acpi_ds_build_internal_buffer_obj(struct acpi_walk_state *walk_state, "Buffer defined with zero length in AML, creating\n")); } else { obj_desc->buffer.pointer = - ACPI_MEM_CALLOCATE(obj_desc->buffer.length); + ACPI_ALLOCATE_ZEROED(obj_desc->buffer.length); if (!obj_desc->buffer.pointer) { acpi_ut_delete_object_desc(obj_desc); return_ACPI_STATUS(AE_NO_MEMORY); @@ -341,9 +341,10 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state, * individual objects). Add an extra pointer slot so * that the list is always null terminated. */ - obj_desc->package.elements = ACPI_MEM_CALLOCATE(((acpi_size) obj_desc-> - package.count + - 1) * sizeof(void *)); + obj_desc->package.elements = ACPI_ALLOCATE_ZEROED(((acpi_size) + obj_desc->package. + count + + 1) * sizeof(void *)); if (!obj_desc->package.elements) { acpi_ut_delete_object_desc(obj_desc); diff --git a/drivers/acpi/dispatcher/dsutils.c b/drivers/acpi/dispatcher/dsutils.c index 3fbe17ebef5a..ab24aa88e2fa 100644 --- a/drivers/acpi/dispatcher/dsutils.c +++ b/drivers/acpi/dispatcher/dsutils.c @@ -577,7 +577,7 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state, /* Free the namestring created above */ - ACPI_MEM_FREE(name_string); + ACPI_FREE(name_string); /* Check status from the lookup */ diff --git a/drivers/acpi/dispatcher/dswload.c b/drivers/acpi/dispatcher/dswload.c index 02b03126e14e..1ad7870101fb 100644 --- a/drivers/acpi/dispatcher/dswload.c +++ b/drivers/acpi/dispatcher/dswload.c @@ -1113,7 +1113,6 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state) ACPI_NS_DONT_OPEN_SCOPE, walk_state, &(new_node)); if (ACPI_SUCCESS(status)) { - /* * Make sure that what we found is indeed a method * We didn't search for a method on purpose, to see if the name diff --git a/drivers/acpi/dispatcher/dswstate.c b/drivers/acpi/dispatcher/dswstate.c index 5bc340b1b286..d2846ffc9773 100644 --- a/drivers/acpi/dispatcher/dswstate.c +++ b/drivers/acpi/dispatcher/dswstate.c @@ -66,7 +66,6 @@ void *acpi_ds_obj_stack_get_value(u32 index, #endif #ifdef ACPI_FUTURE_USAGE - /******************************************************************************* * * FUNCTION: acpi_ds_result_remove @@ -128,7 +127,6 @@ acpi_ds_result_remove(union acpi_operand_object **object, return (AE_OK); } - #endif /* ACPI_FUTURE_USAGE */ /******************************************************************************* @@ -645,7 +643,7 @@ struct acpi_walk_state *acpi_ds_create_walk_state(acpi_owner_id owner_id, ACPI_FUNCTION_TRACE("ds_create_walk_state"); - walk_state = ACPI_MEM_CALLOCATE(sizeof(struct acpi_walk_state)); + walk_state = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_walk_state)); if (!walk_state) { return_PTR(NULL); } @@ -668,7 +666,7 @@ struct acpi_walk_state *acpi_ds_create_walk_state(acpi_owner_id owner_id, status = acpi_ds_result_stack_push(walk_state); if (ACPI_FAILURE(status)) { - ACPI_MEM_FREE(walk_state); + ACPI_FREE(walk_state); return_PTR(NULL); } @@ -859,7 +857,7 @@ void acpi_ds_delete_walk_state(struct acpi_walk_state *walk_state) acpi_ut_delete_generic_state(state); } - ACPI_MEM_FREE(walk_state); + ACPI_FREE(walk_state); return_VOID; } diff --git a/drivers/acpi/events/evgpeblk.c b/drivers/acpi/events/evgpeblk.c index 87e77a138fff..e8e72986f0d6 100644 --- a/drivers/acpi/events/evgpeblk.c +++ b/drivers/acpi/events/evgpeblk.c @@ -207,7 +207,7 @@ acpi_ev_delete_gpe_handlers(struct acpi_gpe_xrupt_info *gpe_xrupt_info, if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == ACPI_GPE_DISPATCH_HANDLER) { - ACPI_MEM_FREE(gpe_event_info->dispatch.handler); + ACPI_FREE(gpe_event_info->dispatch.handler); gpe_event_info->dispatch.handler = NULL; gpe_event_info->flags &= ~ACPI_GPE_DISPATCH_MASK; @@ -504,7 +504,7 @@ static struct acpi_gpe_xrupt_info *acpi_ev_get_gpe_xrupt_block(u32 /* Not found, must allocate a new xrupt descriptor */ - gpe_xrupt = ACPI_MEM_CALLOCATE(sizeof(struct acpi_gpe_xrupt_info)); + gpe_xrupt = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_xrupt_info)); if (!gpe_xrupt) { return_PTR(NULL); } @@ -595,7 +595,7 @@ acpi_ev_delete_gpe_xrupt(struct acpi_gpe_xrupt_info *gpe_xrupt) /* Free the block */ - ACPI_MEM_FREE(gpe_xrupt); + ACPI_FREE(gpe_xrupt); return_ACPI_STATUS(AE_OK); } @@ -712,9 +712,9 @@ acpi_status acpi_ev_delete_gpe_block(struct acpi_gpe_block_info *gpe_block) /* Free the gpe_block */ - ACPI_MEM_FREE(gpe_block->register_info); - ACPI_MEM_FREE(gpe_block->event_info); - ACPI_MEM_FREE(gpe_block); + ACPI_FREE(gpe_block->register_info); + ACPI_FREE(gpe_block->event_info); + ACPI_FREE(gpe_block); unlock_and_exit: status = acpi_ut_release_mutex(ACPI_MTX_EVENTS); @@ -748,10 +748,10 @@ acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block) /* Allocate the GPE register information block */ - gpe_register_info = ACPI_MEM_CALLOCATE((acpi_size) gpe_block-> - register_count * - sizeof(struct - acpi_gpe_register_info)); + gpe_register_info = ACPI_ALLOCATE_ZEROED((acpi_size) gpe_block-> + register_count * + sizeof(struct + acpi_gpe_register_info)); if (!gpe_register_info) { ACPI_ERROR((AE_INFO, "Could not allocate the gpe_register_info table")); @@ -762,10 +762,11 @@ acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block) * Allocate the GPE event_info block. There are eight distinct GPEs * per register. Initialization to zeros is sufficient. */ - gpe_event_info = ACPI_MEM_CALLOCATE(((acpi_size) gpe_block-> - register_count * - ACPI_GPE_REGISTER_WIDTH) * - sizeof(struct acpi_gpe_event_info)); + gpe_event_info = ACPI_ALLOCATE_ZEROED(((acpi_size) gpe_block-> + register_count * + ACPI_GPE_REGISTER_WIDTH) * + sizeof(struct + acpi_gpe_event_info)); if (!gpe_event_info) { ACPI_ERROR((AE_INFO, "Could not allocate the gpe_event_info table")); @@ -848,10 +849,10 @@ acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block) error_exit: if (gpe_register_info) { - ACPI_MEM_FREE(gpe_register_info); + ACPI_FREE(gpe_register_info); } if (gpe_event_info) { - ACPI_MEM_FREE(gpe_event_info); + ACPI_FREE(gpe_event_info); } return_ACPI_STATUS(status); @@ -895,7 +896,7 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device, /* Allocate a new GPE block */ - gpe_block = ACPI_MEM_CALLOCATE(sizeof(struct acpi_gpe_block_info)); + gpe_block = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_block_info)); if (!gpe_block) { return_ACPI_STATUS(AE_NO_MEMORY); } @@ -915,7 +916,7 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device, */ status = acpi_ev_create_gpe_info_blocks(gpe_block); if (ACPI_FAILURE(status)) { - ACPI_MEM_FREE(gpe_block); + ACPI_FREE(gpe_block); return_ACPI_STATUS(status); } @@ -923,7 +924,7 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device, status = acpi_ev_install_gpe_block(gpe_block, interrupt_number); if (ACPI_FAILURE(status)) { - ACPI_MEM_FREE(gpe_block); + ACPI_FREE(gpe_block); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/events/evregion.c b/drivers/acpi/events/evregion.c index b831ec4bcae7..2b900ef05fa9 100644 --- a/drivers/acpi/events/evregion.c +++ b/drivers/acpi/events/evregion.c @@ -366,7 +366,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, /* The handler for this region was already installed */ - ACPI_MEM_FREE(region_context); + ACPI_FREE(region_context); } else { /* * Save the returned context for use in all accesses to diff --git a/drivers/acpi/events/evrgnini.c b/drivers/acpi/events/evrgnini.c index a0bffc2a0787..db98747fe54d 100644 --- a/drivers/acpi/events/evrgnini.c +++ b/drivers/acpi/events/evrgnini.c @@ -75,7 +75,7 @@ acpi_ev_system_memory_region_setup(acpi_handle handle, if (function == ACPI_REGION_DEACTIVATE) { if (*region_context) { - ACPI_MEM_FREE(*region_context); + ACPI_FREE(*region_context); *region_context = NULL; } return_ACPI_STATUS(AE_OK); @@ -84,7 +84,7 @@ acpi_ev_system_memory_region_setup(acpi_handle handle, /* Create a new context */ local_region_context = - ACPI_MEM_CALLOCATE(sizeof(struct acpi_mem_space_context)); + ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_mem_space_context)); if (!(local_region_context)) { return_ACPI_STATUS(AE_NO_MEMORY); } @@ -178,7 +178,7 @@ acpi_ev_pci_config_region_setup(acpi_handle handle, *region_context = NULL; if (function == ACPI_REGION_DEACTIVATE) { if (pci_id) { - ACPI_MEM_FREE(pci_id); + ACPI_FREE(pci_id); } return_ACPI_STATUS(status); } @@ -264,7 +264,7 @@ acpi_ev_pci_config_region_setup(acpi_handle handle, /* Region is still not initialized. Create a new context */ - pci_id = ACPI_MEM_CALLOCATE(sizeof(struct acpi_pci_id)); + pci_id = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_pci_id)); if (!pci_id) { return_ACPI_STATUS(AE_NO_MEMORY); } diff --git a/drivers/acpi/events/evxface.c b/drivers/acpi/events/evxface.c index ba16fda3a158..7d1cebc871f6 100644 --- a/drivers/acpi/events/evxface.c +++ b/drivers/acpi/events/evxface.c @@ -41,8 +41,6 @@ * POSSIBILITY OF SUCH DAMAGES. */ -#include - #include #include #include @@ -90,6 +88,8 @@ acpi_status acpi_install_exception_handler(acpi_exception_handler handler) (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); return_ACPI_STATUS(status); } + +ACPI_EXPORT_SYMBOL(acpi_install_exception_handler) #endif /* ACPI_FUTURE_USAGE */ /******************************************************************************* @@ -107,7 +107,6 @@ acpi_status acpi_install_exception_handler(acpi_exception_handler handler) * event. * ******************************************************************************/ - acpi_status acpi_install_fixed_event_handler(u32 event, acpi_event_handler handler, void *context) @@ -161,7 +160,7 @@ acpi_install_fixed_event_handler(u32 event, return_ACPI_STATUS(status); } -EXPORT_SYMBOL(acpi_install_fixed_event_handler); +ACPI_EXPORT_SYMBOL(acpi_install_fixed_event_handler) /******************************************************************************* * @@ -175,7 +174,6 @@ EXPORT_SYMBOL(acpi_install_fixed_event_handler); * DESCRIPTION: Disables the event and unregisters the event handler. * ******************************************************************************/ - acpi_status acpi_remove_fixed_event_handler(u32 event, acpi_event_handler handler) { @@ -216,7 +214,7 @@ acpi_remove_fixed_event_handler(u32 event, acpi_event_handler handler) return_ACPI_STATUS(status); } -EXPORT_SYMBOL(acpi_remove_fixed_event_handler); +ACPI_EXPORT_SYMBOL(acpi_remove_fixed_event_handler) /******************************************************************************* * @@ -235,7 +233,6 @@ EXPORT_SYMBOL(acpi_remove_fixed_event_handler); * DESCRIPTION: Install a handler for notifies on an ACPI device * ******************************************************************************/ - acpi_status acpi_install_notify_handler(acpi_handle device, u32 handler_type, @@ -384,7 +381,7 @@ acpi_install_notify_handler(acpi_handle device, return_ACPI_STATUS(status); } -EXPORT_SYMBOL(acpi_install_notify_handler); +ACPI_EXPORT_SYMBOL(acpi_install_notify_handler) /******************************************************************************* * @@ -402,7 +399,6 @@ EXPORT_SYMBOL(acpi_install_notify_handler); * DESCRIPTION: Remove a handler for notifies on an ACPI device * ******************************************************************************/ - acpi_status acpi_remove_notify_handler(acpi_handle device, u32 handler_type, acpi_notify_handler handler) @@ -538,7 +534,7 @@ acpi_remove_notify_handler(acpi_handle device, return_ACPI_STATUS(status); } -EXPORT_SYMBOL(acpi_remove_notify_handler); +ACPI_EXPORT_SYMBOL(acpi_remove_notify_handler) /******************************************************************************* * @@ -557,7 +553,6 @@ EXPORT_SYMBOL(acpi_remove_notify_handler); * DESCRIPTION: Install a handler for a General Purpose Event. * ******************************************************************************/ - acpi_status acpi_install_gpe_handler(acpi_handle gpe_device, u32 gpe_number, @@ -599,7 +594,7 @@ acpi_install_gpe_handler(acpi_handle gpe_device, /* Allocate and init handler object */ - handler = ACPI_MEM_CALLOCATE(sizeof(struct acpi_handler_info)); + handler = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_handler_info)); if (!handler) { status = AE_NO_MEMORY; goto unlock_and_exit; @@ -633,7 +628,7 @@ acpi_install_gpe_handler(acpi_handle gpe_device, return_ACPI_STATUS(status); } -EXPORT_SYMBOL(acpi_install_gpe_handler); +ACPI_EXPORT_SYMBOL(acpi_install_gpe_handler) /******************************************************************************* * @@ -649,7 +644,6 @@ EXPORT_SYMBOL(acpi_install_gpe_handler); * DESCRIPTION: Remove a handler for a General Purpose acpi_event. * ******************************************************************************/ - acpi_status acpi_remove_gpe_handler(acpi_handle gpe_device, u32 gpe_number, acpi_event_handler address) @@ -727,14 +721,14 @@ acpi_remove_gpe_handler(acpi_handle gpe_device, /* Now we can free the handler object */ - ACPI_MEM_FREE(handler); + ACPI_FREE(handler); unlock_and_exit: (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); return_ACPI_STATUS(status); } -EXPORT_SYMBOL(acpi_remove_gpe_handler); +ACPI_EXPORT_SYMBOL(acpi_remove_gpe_handler) /******************************************************************************* * @@ -749,7 +743,6 @@ EXPORT_SYMBOL(acpi_remove_gpe_handler); * DESCRIPTION: Acquire the ACPI Global Lock * ******************************************************************************/ - acpi_status acpi_acquire_global_lock(u16 timeout, u32 * handle) { acpi_status status; @@ -774,7 +767,7 @@ acpi_status acpi_acquire_global_lock(u16 timeout, u32 * handle) return (status); } -EXPORT_SYMBOL(acpi_acquire_global_lock); +ACPI_EXPORT_SYMBOL(acpi_acquire_global_lock) /******************************************************************************* * @@ -787,7 +780,6 @@ EXPORT_SYMBOL(acpi_acquire_global_lock); * DESCRIPTION: Release the ACPI Global Lock. The handle must be valid. * ******************************************************************************/ - acpi_status acpi_release_global_lock(u32 handle) { acpi_status status; @@ -800,4 +792,4 @@ acpi_status acpi_release_global_lock(u32 handle) return (status); } -EXPORT_SYMBOL(acpi_release_global_lock); +ACPI_EXPORT_SYMBOL(acpi_release_global_lock) diff --git a/drivers/acpi/events/evxfevnt.c b/drivers/acpi/events/evxfevnt.c index babebb501405..4a36559fa816 100644 --- a/drivers/acpi/events/evxfevnt.c +++ b/drivers/acpi/events/evxfevnt.c @@ -41,8 +41,6 @@ * POSSIBILITY OF SUCH DAMAGES. */ -#include - #include #include #include @@ -94,6 +92,8 @@ acpi_status acpi_enable(void) return_ACPI_STATUS(status); } +ACPI_EXPORT_SYMBOL(acpi_enable) + /******************************************************************************* * * FUNCTION: acpi_disable @@ -105,7 +105,6 @@ acpi_status acpi_enable(void) * DESCRIPTION: Transfers the system into LEGACY (non-ACPI) mode. * ******************************************************************************/ - acpi_status acpi_disable(void) { acpi_status status = AE_OK; @@ -137,6 +136,8 @@ acpi_status acpi_disable(void) return_ACPI_STATUS(status); } +ACPI_EXPORT_SYMBOL(acpi_disable) + /******************************************************************************* * * FUNCTION: acpi_enable_event @@ -149,7 +150,6 @@ acpi_status acpi_disable(void) * DESCRIPTION: Enable an ACPI event (fixed) * ******************************************************************************/ - acpi_status acpi_enable_event(u32 event, u32 flags) { acpi_status status = AE_OK; @@ -193,7 +193,7 @@ acpi_status acpi_enable_event(u32 event, u32 flags) return_ACPI_STATUS(status); } -EXPORT_SYMBOL(acpi_enable_event); +ACPI_EXPORT_SYMBOL(acpi_enable_event) /******************************************************************************* * @@ -208,7 +208,6 @@ EXPORT_SYMBOL(acpi_enable_event); * DESCRIPTION: Set the type of an individual GPE * ******************************************************************************/ - acpi_status acpi_set_gpe_type(acpi_handle gpe_device, u32 gpe_number, u8 type) { acpi_status status = AE_OK; @@ -236,7 +235,7 @@ acpi_status acpi_set_gpe_type(acpi_handle gpe_device, u32 gpe_number, u8 type) return_ACPI_STATUS(status); } -EXPORT_SYMBOL(acpi_set_gpe_type); +ACPI_EXPORT_SYMBOL(acpi_set_gpe_type) /******************************************************************************* * @@ -252,7 +251,6 @@ EXPORT_SYMBOL(acpi_set_gpe_type); * DESCRIPTION: Enable an ACPI event (general purpose) * ******************************************************************************/ - acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number, u32 flags) { acpi_status status = AE_OK; @@ -288,7 +286,7 @@ acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number, u32 flags) return_ACPI_STATUS(status); } -EXPORT_SYMBOL(acpi_enable_gpe); +ACPI_EXPORT_SYMBOL(acpi_enable_gpe) /******************************************************************************* * @@ -304,7 +302,6 @@ EXPORT_SYMBOL(acpi_enable_gpe); * DESCRIPTION: Disable an ACPI event (general purpose) * ******************************************************************************/ - acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number, u32 flags) { acpi_status status = AE_OK; @@ -338,6 +335,8 @@ acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number, u32 flags) return_ACPI_STATUS(status); } +ACPI_EXPORT_SYMBOL(acpi_disable_gpe) + /******************************************************************************* * * FUNCTION: acpi_disable_event @@ -350,7 +349,6 @@ acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number, u32 flags) * DESCRIPTION: Disable an ACPI event (fixed) * ******************************************************************************/ - acpi_status acpi_disable_event(u32 event, u32 flags) { acpi_status status = AE_OK; @@ -392,7 +390,7 @@ acpi_status acpi_disable_event(u32 event, u32 flags) return_ACPI_STATUS(status); } -EXPORT_SYMBOL(acpi_disable_event); +ACPI_EXPORT_SYMBOL(acpi_disable_event) /******************************************************************************* * @@ -405,7 +403,6 @@ EXPORT_SYMBOL(acpi_disable_event); * DESCRIPTION: Clear an ACPI event (fixed) * ******************************************************************************/ - acpi_status acpi_clear_event(u32 event) { acpi_status status = AE_OK; @@ -429,7 +426,7 @@ acpi_status acpi_clear_event(u32 event) return_ACPI_STATUS(status); } -EXPORT_SYMBOL(acpi_clear_event); +ACPI_EXPORT_SYMBOL(acpi_clear_event) /******************************************************************************* * @@ -444,7 +441,6 @@ EXPORT_SYMBOL(acpi_clear_event); * DESCRIPTION: Clear an ACPI event (general purpose) * ******************************************************************************/ - acpi_status acpi_clear_gpe(acpi_handle gpe_device, u32 gpe_number, u32 flags) { acpi_status status = AE_OK; @@ -478,6 +474,8 @@ acpi_status acpi_clear_gpe(acpi_handle gpe_device, u32 gpe_number, u32 flags) return_ACPI_STATUS(status); } +ACPI_EXPORT_SYMBOL(acpi_clear_gpe) + #ifdef ACPI_FUTURE_USAGE /******************************************************************************* * @@ -492,7 +490,6 @@ acpi_status acpi_clear_gpe(acpi_handle gpe_device, u32 gpe_number, u32 flags) * DESCRIPTION: Obtains and returns the current status of the event * ******************************************************************************/ - acpi_status acpi_get_event_status(u32 event, acpi_event_status * event_status) { acpi_status status = AE_OK; @@ -518,6 +515,8 @@ acpi_status acpi_get_event_status(u32 event, acpi_event_status * event_status) return_ACPI_STATUS(status); } +ACPI_EXPORT_SYMBOL(acpi_get_event_status) + /******************************************************************************* * * FUNCTION: acpi_get_gpe_status @@ -533,7 +532,6 @@ acpi_status acpi_get_event_status(u32 event, acpi_event_status * event_status) * DESCRIPTION: Get status of an event (general purpose) * ******************************************************************************/ - acpi_status acpi_get_gpe_status(acpi_handle gpe_device, u32 gpe_number, u32 flags, acpi_event_status * event_status) @@ -570,6 +568,8 @@ acpi_get_gpe_status(acpi_handle gpe_device, } return_ACPI_STATUS(status); } + +ACPI_EXPORT_SYMBOL(acpi_get_gpe_status) #endif /* ACPI_FUTURE_USAGE */ /******************************************************************************* @@ -586,7 +586,6 @@ acpi_get_gpe_status(acpi_handle gpe_device, * DESCRIPTION: Create and Install a block of GPE registers * ******************************************************************************/ - acpi_status acpi_install_gpe_block(acpi_handle gpe_device, struct acpi_generic_address *gpe_block_address, @@ -666,7 +665,7 @@ acpi_install_gpe_block(acpi_handle gpe_device, return_ACPI_STATUS(status); } -EXPORT_SYMBOL(acpi_install_gpe_block); +ACPI_EXPORT_SYMBOL(acpi_install_gpe_block) /******************************************************************************* * @@ -679,7 +678,6 @@ EXPORT_SYMBOL(acpi_install_gpe_block); * DESCRIPTION: Remove a previously installed block of GPE registers * ******************************************************************************/ - acpi_status acpi_remove_gpe_block(acpi_handle gpe_device) { union acpi_operand_object *obj_desc; @@ -722,4 +720,4 @@ acpi_status acpi_remove_gpe_block(acpi_handle gpe_device) return_ACPI_STATUS(status); } -EXPORT_SYMBOL(acpi_remove_gpe_block); +ACPI_EXPORT_SYMBOL(acpi_remove_gpe_block) diff --git a/drivers/acpi/events/evxfregn.c b/drivers/acpi/events/evxfregn.c index 368c8aa0094b..63a070bb9d17 100644 --- a/drivers/acpi/events/evxfregn.c +++ b/drivers/acpi/events/evxfregn.c @@ -42,8 +42,6 @@ * POSSIBILITY OF SUCH DAMAGES. */ -#include - #include #include #include @@ -114,7 +112,7 @@ acpi_install_address_space_handler(acpi_handle device, return_ACPI_STATUS(status); } -EXPORT_SYMBOL(acpi_install_address_space_handler); +ACPI_EXPORT_SYMBOL(acpi_install_address_space_handler) /******************************************************************************* * @@ -129,7 +127,6 @@ EXPORT_SYMBOL(acpi_install_address_space_handler); * DESCRIPTION: Remove a previously installed handler. * ******************************************************************************/ - acpi_status acpi_remove_address_space_handler(acpi_handle device, acpi_adr_space_type space_id, @@ -242,4 +239,4 @@ acpi_remove_address_space_handler(acpi_handle device, return_ACPI_STATUS(status); } -EXPORT_SYMBOL(acpi_remove_address_space_handler); +ACPI_EXPORT_SYMBOL(acpi_remove_address_space_handler) diff --git a/drivers/acpi/executer/exconfig.c b/drivers/acpi/executer/exconfig.c index 864530f754c3..e0deffb56790 100644 --- a/drivers/acpi/executer/exconfig.c +++ b/drivers/acpi/executer/exconfig.c @@ -349,7 +349,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, /* Allocate a buffer for the entire table */ - table_ptr = ACPI_MEM_ALLOCATE(table_header.length); + table_ptr = ACPI_ALLOCATE(table_header.length); if (!table_ptr) { return_ACPI_STATUS(AE_NO_MEMORY); } @@ -447,7 +447,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, cleanup: if (ACPI_FAILURE(status)) { - ACPI_MEM_FREE(table_ptr); + ACPI_FREE(table_ptr); } return_ACPI_STATUS(status); } diff --git a/drivers/acpi/executer/exdump.c b/drivers/acpi/executer/exdump.c index 0a53d31e09de..502293c35afa 100644 --- a/drivers/acpi/executer/exdump.c +++ b/drivers/acpi/executer/exdump.c @@ -903,7 +903,7 @@ static void acpi_ex_dump_reference_obj(union acpi_operand_object *obj_desc) acpi_os_printf("Could not convert name to pathname\n"); } else { acpi_os_printf("%s\n", (char *)ret_buf.pointer); - ACPI_MEM_FREE(ret_buf.pointer); + ACPI_FREE(ret_buf.pointer); } } else if (obj_desc->reference.object) { acpi_os_printf("\nReferenced Object: %p\n", diff --git a/drivers/acpi/executer/exfield.c b/drivers/acpi/executer/exfield.c index 215783a33c2c..36c265a00c26 100644 --- a/drivers/acpi/executer/exfield.c +++ b/drivers/acpi/executer/exfield.c @@ -333,7 +333,7 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, /* We need to create a new buffer */ - new_buffer = ACPI_MEM_CALLOCATE(required_length); + new_buffer = ACPI_ALLOCATE_ZEROED(required_length); if (!new_buffer) { return_ACPI_STATUS(AE_NO_MEMORY); } @@ -377,7 +377,7 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, /* Free temporary buffer if we used one */ if (new_buffer) { - ACPI_MEM_FREE(new_buffer); + ACPI_FREE(new_buffer); } return_ACPI_STATUS(status); diff --git a/drivers/acpi/executer/exnames.c b/drivers/acpi/executer/exnames.c index f9bc81c1b78d..80bbc20756a1 100644 --- a/drivers/acpi/executer/exnames.c +++ b/drivers/acpi/executer/exnames.c @@ -98,7 +98,7 @@ static char *acpi_ex_allocate_name_string(u32 prefix_count, u32 num_name_segs) * Allocate a buffer for the name. * This buffer must be deleted by the caller! */ - name_string = ACPI_MEM_ALLOCATE(size_needed); + name_string = ACPI_ALLOCATE(size_needed); if (!name_string) { ACPI_ERROR((AE_INFO, "Could not allocate size %d", size_needed)); @@ -424,7 +424,7 @@ acpi_ex_get_name_string(acpi_object_type data_type, if (ACPI_FAILURE(status)) { if (name_string) { - ACPI_MEM_FREE(name_string); + ACPI_FREE(name_string); } return_ACPI_STATUS(status); } diff --git a/drivers/acpi/executer/exoparg1.c b/drivers/acpi/executer/exoparg1.c index 4f3627ee2b2b..d00f766246f3 100644 --- a/drivers/acpi/executer/exoparg1.c +++ b/drivers/acpi/executer/exoparg1.c @@ -554,16 +554,18 @@ acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state) cleanup: - if (!walk_state->result_obj) { - walk_state->result_obj = return_desc; - } - /* Delete return object on error */ if (ACPI_FAILURE(status)) { acpi_ut_remove_reference(return_desc); } + /* Save return object on success */ + + else if (!walk_state->result_obj) { + walk_state->result_obj = return_desc; + } + return_ACPI_STATUS(status); } @@ -1028,6 +1030,11 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state) acpi_ut_remove_reference(return_desc); } - walk_state->result_obj = return_desc; + /* Save return object on success */ + + else { + walk_state->result_obj = return_desc; + } + return_ACPI_STATUS(status); } diff --git a/drivers/acpi/executer/exoparg2.c b/drivers/acpi/executer/exoparg2.c index 5e1abb12c748..690e43db0abe 100644 --- a/drivers/acpi/executer/exoparg2.c +++ b/drivers/acpi/executer/exoparg2.c @@ -391,7 +391,6 @@ acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state) index = operand[1]->integer.value; return_desc->reference.offset = (u32) index; return_desc->reference.opcode = AML_INDEX_OP; - return_desc->reference.object = operand[0]; /* * At this point, the Source operand is a String, Buffer, or Package. @@ -445,9 +444,10 @@ acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state) } /* - * Add a reference to the target package/buffer/string for the life + * Save the target object and add a reference to it for the life * of the index */ + return_desc->reference.object = operand[0]; acpi_ut_add_reference(operand[0]); /* Store the reference to the Target */ diff --git a/drivers/acpi/executer/exoparg3.c b/drivers/acpi/executer/exoparg3.c index 8da794ec35b0..4897e6c3431f 100644 --- a/drivers/acpi/executer/exoparg3.c +++ b/drivers/acpi/executer/exoparg3.c @@ -100,8 +100,7 @@ acpi_status acpi_ex_opcode_3A_0T_0R(struct acpi_walk_state *walk_state) (u32) operand[1]->integer.value, (u32) operand[2]->integer.value)); - fatal = - ACPI_MEM_ALLOCATE(sizeof(struct acpi_signal_fatal_info)); + fatal = ACPI_ALLOCATE(sizeof(struct acpi_signal_fatal_info)); if (fatal) { fatal->type = (u32) operand[0]->integer.value; fatal->code = (u32) operand[1]->integer.value; @@ -114,7 +113,7 @@ acpi_status acpi_ex_opcode_3A_0T_0R(struct acpi_walk_state *walk_state) /* Might return while OS is shutting down, just continue */ - ACPI_MEM_FREE(fatal); + ACPI_FREE(fatal); break; default: @@ -196,7 +195,7 @@ acpi_status acpi_ex_opcode_3A_1T_1R(struct acpi_walk_state *walk_state) /* Always allocate a new buffer for the String */ - buffer = ACPI_MEM_CALLOCATE((acpi_size) length + 1); + buffer = ACPI_ALLOCATE_ZEROED((acpi_size) length + 1); if (!buffer) { status = AE_NO_MEMORY; goto cleanup; @@ -211,7 +210,7 @@ acpi_status acpi_ex_opcode_3A_1T_1R(struct acpi_walk_state *walk_state) /* Allocate a new buffer for the Buffer */ - buffer = ACPI_MEM_CALLOCATE(length); + buffer = ACPI_ALLOCATE_ZEROED(length); if (!buffer) { status = AE_NO_MEMORY; goto cleanup; diff --git a/drivers/acpi/executer/exregion.c b/drivers/acpi/executer/exregion.c index 9db68d19253e..fdeda7beae43 100644 --- a/drivers/acpi/executer/exregion.c +++ b/drivers/acpi/executer/exregion.c @@ -182,8 +182,8 @@ acpi_ex_system_memory_space_handler(u32 function, (acpi_integer) mem_info->mapped_physical_address); ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "system_memory %d (%d width) Address=%8.8X%8.8X\n", - function, bit_width, ACPI_FORMAT_UINT64(address))); + "System-Memory (width %d) R/W %d Address=%8.8X%8.8X\n", + bit_width, function, ACPI_FORMAT_UINT64(address))); /* * Perform the memory read or write @@ -287,8 +287,8 @@ acpi_ex_system_io_space_handler(u32 function, ACPI_FUNCTION_TRACE("ex_system_io_space_handler"); ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "system_iO %d (%d width) Address=%8.8X%8.8X\n", - function, bit_width, ACPI_FORMAT_UINT64(address))); + "System-IO (width %d) R/W %d Address=%8.8X%8.8X\n", + bit_width, function, ACPI_FORMAT_UINT64(address))); /* Decode the function parameter */ @@ -361,7 +361,7 @@ acpi_ex_pci_config_space_handler(u32 function, pci_register = (u16) (u32) address; ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "pci_config %d (%d) Seg(%04x) Bus(%04x) Dev(%04x) Func(%04x) Reg(%04x)\n", + "Pci-Config %d (%d) Seg(%04x) Bus(%04x) Dev(%04x) Func(%04x) Reg(%04x)\n", function, bit_width, pci_id->segment, pci_id->bus, pci_id->device, pci_id->function, pci_register)); diff --git a/drivers/acpi/executer/exstorob.c b/drivers/acpi/executer/exstorob.c index 41732d382bce..db42461101e0 100644 --- a/drivers/acpi/executer/exstorob.c +++ b/drivers/acpi/executer/exstorob.c @@ -80,7 +80,7 @@ acpi_ex_store_buffer_to_buffer(union acpi_operand_object *source_desc, */ if ((target_desc->buffer.length == 0) || (target_desc->common.flags & AOPOBJ_STATIC_POINTER)) { - target_desc->buffer.pointer = ACPI_MEM_ALLOCATE(length); + target_desc->buffer.pointer = ACPI_ALLOCATE(length); if (!target_desc->buffer.pointer) { return_ACPI_STATUS(AE_NO_MEMORY); } @@ -188,11 +188,11 @@ acpi_ex_store_string_to_string(union acpi_operand_object *source_desc, /* Only free if not a pointer into the DSDT */ - ACPI_MEM_FREE(target_desc->string.pointer); + ACPI_FREE(target_desc->string.pointer); } - target_desc->string.pointer = ACPI_MEM_CALLOCATE((acpi_size) - length + 1); + target_desc->string.pointer = ACPI_ALLOCATE_ZEROED((acpi_size) + length + 1); if (!target_desc->string.pointer) { return_ACPI_STATUS(AE_NO_MEMORY); } diff --git a/drivers/acpi/hardware/hwregs.c b/drivers/acpi/hardware/hwregs.c index 95c4ccb3a378..3d1f41c6bfe9 100644 --- a/drivers/acpi/hardware/hwregs.c +++ b/drivers/acpi/hardware/hwregs.c @@ -43,8 +43,6 @@ * POSSIBILITY OF SUCH DAMAGES. */ -#include - #include #include #include @@ -220,7 +218,7 @@ acpi_get_sleep_type_data(u8 sleep_state, u8 * sleep_type_a, u8 * sleep_type_b) return_ACPI_STATUS(status); } -EXPORT_SYMBOL(acpi_get_sleep_type_data); +ACPI_EXPORT_SYMBOL(acpi_get_sleep_type_data) /******************************************************************************* * @@ -233,7 +231,6 @@ EXPORT_SYMBOL(acpi_get_sleep_type_data); * DESCRIPTION: Map register_id into a register bitmask. * ******************************************************************************/ - struct acpi_bit_register_info *acpi_hw_get_bit_register_info(u32 register_id) { ACPI_FUNCTION_ENTRY(); @@ -312,7 +309,7 @@ acpi_status acpi_get_register(u32 register_id, u32 * return_value, u32 flags) return_ACPI_STATUS(status); } -EXPORT_SYMBOL(acpi_get_register); +ACPI_EXPORT_SYMBOL(acpi_get_register) /******************************************************************************* * @@ -328,7 +325,6 @@ EXPORT_SYMBOL(acpi_get_register); * DESCRIPTION: ACPI Bit Register write function. * ******************************************************************************/ - acpi_status acpi_set_register(u32 register_id, u32 value, u32 flags) { u32 register_value = 0; @@ -475,7 +471,7 @@ acpi_status acpi_set_register(u32 register_id, u32 value, u32 flags) return_ACPI_STATUS(status); } -EXPORT_SYMBOL(acpi_set_register); +ACPI_EXPORT_SYMBOL(acpi_set_register) /****************************************************************************** * @@ -491,7 +487,6 @@ EXPORT_SYMBOL(acpi_set_register); * given offset. * ******************************************************************************/ - acpi_status acpi_hw_register_read(u8 use_lock, u32 register_id, u32 * return_value) { diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c index 284a59ebcc2c..685debafbb72 100644 --- a/drivers/acpi/hardware/hwsleep.c +++ b/drivers/acpi/hardware/hwsleep.c @@ -42,7 +42,6 @@ * POSSIBILITY OF SUCH DAMAGES. */ -#include #include #define _COMPONENT ACPI_HARDWARE @@ -79,6 +78,8 @@ acpi_set_firmware_waking_vector(acpi_physical_address physical_address) return_ACPI_STATUS(AE_OK); } +ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector) + /******************************************************************************* * * FUNCTION: acpi_get_firmware_waking_vector @@ -92,7 +93,6 @@ acpi_set_firmware_waking_vector(acpi_physical_address physical_address) * DESCRIPTION: Access function for the firmware_waking_vector field in FACS * ******************************************************************************/ - #ifdef ACPI_FUTURE_USAGE acpi_status acpi_get_firmware_waking_vector(acpi_physical_address * physical_address) @@ -118,6 +118,8 @@ acpi_get_firmware_waking_vector(acpi_physical_address * physical_address) return_ACPI_STATUS(AE_OK); } + +ACPI_EXPORT_SYMBOL(acpi_get_firmware_waking_vector) #endif /******************************************************************************* @@ -134,7 +136,6 @@ acpi_get_firmware_waking_vector(acpi_physical_address * physical_address) * various OS-specific tasks between the two steps. * ******************************************************************************/ - acpi_status acpi_enter_sleep_state_prep(u8 sleep_state) { acpi_status status; @@ -206,6 +207,8 @@ acpi_status acpi_enter_sleep_state_prep(u8 sleep_state) return_ACPI_STATUS(AE_OK); } +ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_prep) + /******************************************************************************* * * FUNCTION: acpi_enter_sleep_state @@ -218,7 +221,6 @@ acpi_status acpi_enter_sleep_state_prep(u8 sleep_state) * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED * ******************************************************************************/ - acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state) { u32 PM1Acontrol; @@ -378,7 +380,7 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state) return_ACPI_STATUS(AE_OK); } -EXPORT_SYMBOL(acpi_enter_sleep_state); +ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state) /******************************************************************************* * @@ -392,7 +394,6 @@ EXPORT_SYMBOL(acpi_enter_sleep_state); * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED * ******************************************************************************/ - acpi_status asmlinkage acpi_enter_sleep_state_s4bios(void) { u32 in_value; @@ -443,7 +444,7 @@ acpi_status asmlinkage acpi_enter_sleep_state_s4bios(void) return_ACPI_STATUS(AE_OK); } -EXPORT_SYMBOL(acpi_enter_sleep_state_s4bios); +ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_s4bios) /******************************************************************************* * @@ -457,7 +458,6 @@ EXPORT_SYMBOL(acpi_enter_sleep_state_s4bios); * Called with interrupts ENABLED. * ******************************************************************************/ - acpi_status acpi_leave_sleep_state(u8 sleep_state) { struct acpi_object_list arg_list; @@ -584,3 +584,5 @@ acpi_status acpi_leave_sleep_state(u8 sleep_state) return_ACPI_STATUS(status); } + +ACPI_EXPORT_SYMBOL(acpi_leave_sleep_state) diff --git a/drivers/acpi/hardware/hwtimer.c b/drivers/acpi/hardware/hwtimer.c index ef7c98e293a9..9d53e46bc331 100644 --- a/drivers/acpi/hardware/hwtimer.c +++ b/drivers/acpi/hardware/hwtimer.c @@ -42,7 +42,6 @@ * POSSIBILITY OF SUCH DAMAGES. */ -#include #include #define _COMPONENT ACPI_HARDWARE @@ -76,6 +75,8 @@ acpi_status acpi_get_timer_resolution(u32 * resolution) return_ACPI_STATUS(AE_OK); } +ACPI_EXPORT_SYMBOL(acpi_get_timer_resolution) + /****************************************************************************** * * FUNCTION: acpi_get_timer @@ -87,7 +88,6 @@ acpi_status acpi_get_timer_resolution(u32 * resolution) * DESCRIPTION: Obtains current value of ACPI PM Timer (in ticks). * ******************************************************************************/ - acpi_status acpi_get_timer(u32 * ticks) { acpi_status status; @@ -103,7 +103,7 @@ acpi_status acpi_get_timer(u32 * ticks) return_ACPI_STATUS(status); } -EXPORT_SYMBOL(acpi_get_timer); +ACPI_EXPORT_SYMBOL(acpi_get_timer) /****************************************************************************** * @@ -133,7 +133,6 @@ EXPORT_SYMBOL(acpi_get_timer); * 2**32 Ticks / 3,600,000 Ticks/Sec = 1193 sec or 19.88 minutes * ******************************************************************************/ - acpi_status acpi_get_timer_duration(u32 start_ticks, u32 end_ticks, u32 * time_elapsed) { @@ -184,4 +183,4 @@ acpi_get_timer_duration(u32 start_ticks, u32 end_ticks, u32 * time_elapsed) return_ACPI_STATUS(status); } -EXPORT_SYMBOL(acpi_get_timer_duration); +ACPI_EXPORT_SYMBOL(acpi_get_timer_duration) diff --git a/drivers/acpi/namespace/nsaccess.c b/drivers/acpi/namespace/nsaccess.c index 6bdad8bfcf0b..d4914fda6a37 100644 --- a/drivers/acpi/namespace/nsaccess.c +++ b/drivers/acpi/namespace/nsaccess.c @@ -347,14 +347,17 @@ acpi_ns_lookup(union acpi_generic_state *scope_info, return_ACPI_STATUS(AE_AML_INTERNAL); } - /* - * This node might not be a actual "scope" node (such as a - * Device/Method, etc.) It could be a Package or other object node. - * Backup up the tree to find the containing scope node. - */ - while (!acpi_ns_opens_scope(prefix_node->type) && - prefix_node->type != ACPI_TYPE_ANY) { - prefix_node = acpi_ns_get_parent_node(prefix_node); + if (!(flags & ACPI_NS_PREFIX_IS_SCOPE)) { + /* + * This node might not be a actual "scope" node (such as a + * Device/Method, etc.) It could be a Package or other object node. + * Backup up the tree to find the containing scope node. + */ + while (!acpi_ns_opens_scope(prefix_node->type) && + prefix_node->type != ACPI_TYPE_ANY) { + prefix_node = + acpi_ns_get_parent_node(prefix_node); + } } } diff --git a/drivers/acpi/namespace/nsalloc.c b/drivers/acpi/namespace/nsalloc.c index cd26cb971a1c..acd4b6732ac4 100644 --- a/drivers/acpi/namespace/nsalloc.c +++ b/drivers/acpi/namespace/nsalloc.c @@ -68,7 +68,7 @@ struct acpi_namespace_node *acpi_ns_create_node(u32 name) ACPI_FUNCTION_TRACE("ns_create_node"); - node = ACPI_MEM_CALLOCATE(sizeof(struct acpi_namespace_node)); + node = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_namespace_node)); if (!node) { return_PTR(NULL); } @@ -142,7 +142,7 @@ void acpi_ns_delete_node(struct acpi_namespace_node *node) * Detach an object if there is one then delete the node */ acpi_ns_detach_object(node); - ACPI_MEM_FREE(node); + ACPI_FREE(node); return_VOID; } @@ -311,7 +311,7 @@ void acpi_ns_delete_children(struct acpi_namespace_node *parent_node) /* Now we can delete the node */ - ACPI_MEM_FREE(child_node); + ACPI_FREE(child_node); /* And move on to the next child in the list */ diff --git a/drivers/acpi/namespace/nsdumpdv.c b/drivers/acpi/namespace/nsdumpdv.c index aff899a935e3..2b311da01ef5 100644 --- a/drivers/acpi/namespace/nsdumpdv.c +++ b/drivers/acpi/namespace/nsdumpdv.c @@ -92,7 +92,7 @@ acpi_ns_dump_one_device(acpi_handle obj_handle, info->hardware_id.value, ACPI_FORMAT_UINT64(info->address), info->current_status)); - ACPI_MEM_FREE(info); + ACPI_FREE(info); } return (status); diff --git a/drivers/acpi/namespace/nseval.c b/drivers/acpi/namespace/nseval.c index 80ef95545636..f5d8e71b82cc 100644 --- a/drivers/acpi/namespace/nseval.c +++ b/drivers/acpi/namespace/nseval.c @@ -151,7 +151,7 @@ acpi_ns_evaluate_relative(char *pathname, struct acpi_parameter_info *info) acpi_ut_delete_generic_state(scope_info); cleanup1: - ACPI_MEM_FREE(internal_path); + ACPI_FREE(internal_path); return_ACPI_STATUS(status); } @@ -228,7 +228,7 @@ acpi_ns_evaluate_by_name(char *pathname, struct acpi_parameter_info *info) /* Cleanup */ if (internal_path) { - ACPI_MEM_FREE(internal_path); + ACPI_FREE(internal_path); } return_ACPI_STATUS(status); diff --git a/drivers/acpi/namespace/nsinit.c b/drivers/acpi/namespace/nsinit.c index 9aa337c33887..57b2537643c7 100644 --- a/drivers/acpi/namespace/nsinit.c +++ b/drivers/acpi/namespace/nsinit.c @@ -424,7 +424,7 @@ acpi_ns_init_one_device(acpi_handle obj_handle, ACPI_WARNING((AE_INFO, "%s._INI failed: %s", scope_name, acpi_format_exception(status))); - ACPI_MEM_FREE(scope_name); + ACPI_FREE(scope_name); #endif } else { /* Delete any return object (especially if implicit_return is enabled) */ diff --git a/drivers/acpi/namespace/nsnames.c b/drivers/acpi/namespace/nsnames.c index 639f653b4b6b..ba812f43897f 100644 --- a/drivers/acpi/namespace/nsnames.c +++ b/drivers/acpi/namespace/nsnames.c @@ -48,11 +48,6 @@ #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsnames") -/* Local prototypes */ -static void -acpi_ns_build_external_path(struct acpi_namespace_node *node, - acpi_size size, char *name_buffer); - /******************************************************************************* * * FUNCTION: acpi_ns_build_external_path @@ -67,8 +62,7 @@ acpi_ns_build_external_path(struct acpi_namespace_node *node, * DESCRIPTION: Generate a full pathaname * ******************************************************************************/ - -static void +void acpi_ns_build_external_path(struct acpi_namespace_node *node, acpi_size size, char *name_buffer) { @@ -146,7 +140,7 @@ char *acpi_ns_get_external_pathname(struct acpi_namespace_node *node) /* Allocate a buffer to be returned to caller */ - name_buffer = ACPI_MEM_CALLOCATE(size); + name_buffer = ACPI_ALLOCATE_ZEROED(size); if (!name_buffer) { ACPI_ERROR((AE_INFO, "Allocation failure")); return_PTR(NULL); diff --git a/drivers/acpi/namespace/nsparse.c b/drivers/acpi/namespace/nsparse.c index 232be4303653..64daf3028dea 100644 --- a/drivers/acpi/namespace/nsparse.c +++ b/drivers/acpi/namespace/nsparse.c @@ -62,7 +62,7 @@ ACPI_MODULE_NAME("nsparse") * ******************************************************************************/ acpi_status -acpi_ns_one_complete_parse(u8 pass_number, struct acpi_table_desc * table_desc) +acpi_ns_one_complete_parse(u8 pass_number, struct acpi_table_desc *table_desc) { union acpi_parse_object *parse_root; acpi_status status; diff --git a/drivers/acpi/namespace/nssearch.c b/drivers/acpi/namespace/nssearch.c index f73a3d566168..c929f45071c0 100644 --- a/drivers/acpi/namespace/nssearch.c +++ b/drivers/acpi/namespace/nssearch.c @@ -103,7 +103,7 @@ acpi_ns_search_node(u32 target_name, &target_name), acpi_ut_get_type_name(type))); - ACPI_MEM_FREE(scope_name); + ACPI_FREE(scope_name); } } #endif diff --git a/drivers/acpi/namespace/nsutils.c b/drivers/acpi/namespace/nsutils.c index 123f454b14ab..586014ecf24b 100644 --- a/drivers/acpi/namespace/nsutils.c +++ b/drivers/acpi/namespace/nsutils.c @@ -104,7 +104,7 @@ acpi_ns_report_error(char *module_name, } if (name) { - ACPI_MEM_FREE(name); + ACPI_FREE(name); } } @@ -187,7 +187,7 @@ acpi_ns_print_node_pathname(struct acpi_namespace_node *node, char *message) } acpi_os_printf("[%s] (Node %p)", (char *)buffer.pointer, node); - ACPI_MEM_FREE(buffer.pointer); + ACPI_FREE(buffer.pointer); } } @@ -490,7 +490,7 @@ acpi_status acpi_ns_internalize_name(char *external_name, char **converted_name) /* We need a segment to store the internal name */ - internal_name = ACPI_MEM_CALLOCATE(info.length); + internal_name = ACPI_ALLOCATE_ZEROED(info.length); if (!internal_name) { return_ACPI_STATUS(AE_NO_MEMORY); } @@ -500,7 +500,7 @@ acpi_status acpi_ns_internalize_name(char *external_name, char **converted_name) info.internal_name = internal_name; status = acpi_ns_build_internal_name(&info); if (ACPI_FAILURE(status)) { - ACPI_MEM_FREE(internal_name); + ACPI_FREE(internal_name); return_ACPI_STATUS(status); } @@ -632,7 +632,7 @@ acpi_ns_externalize_name(u32 internal_name_length, /* * Build converted_name */ - *converted_name = ACPI_MEM_CALLOCATE(required_length); + *converted_name = ACPI_ALLOCATE_ZEROED(required_length); if (!(*converted_name)) { return_ACPI_STATUS(AE_NO_MEMORY); } @@ -879,7 +879,7 @@ acpi_ns_get_node_by_path(char *pathname, cleanup: if (internal_path) { - ACPI_MEM_FREE(internal_path); + ACPI_FREE(internal_path); } return_ACPI_STATUS(status); } diff --git a/drivers/acpi/namespace/nsxfeval.c b/drivers/acpi/namespace/nsxfeval.c index 71e7769d7daf..7cdedc96a40a 100644 --- a/drivers/acpi/namespace/nsxfeval.c +++ b/drivers/acpi/namespace/nsxfeval.c @@ -42,8 +42,6 @@ * POSSIBILITY OF SUCH DAMAGES. */ -#include - #include #include #include @@ -51,6 +49,7 @@ #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsxfeval") +#ifdef ACPI_FUTURE_USAGE /******************************************************************************* * * FUNCTION: acpi_evaluate_object_typed @@ -71,12 +70,11 @@ ACPI_MODULE_NAME("nsxfeval") * be valid (non-null) * ******************************************************************************/ -#ifdef ACPI_FUTURE_USAGE acpi_status acpi_evaluate_object_typed(acpi_handle handle, acpi_string pathname, - struct acpi_object_list *external_params, - struct acpi_buffer *return_buffer, + struct acpi_object_list * external_params, + struct acpi_buffer * return_buffer, acpi_object_type return_type) { acpi_status status; @@ -142,6 +140,8 @@ acpi_evaluate_object_typed(acpi_handle handle, return_buffer->length = 0; return_ACPI_STATUS(AE_TYPE); } + +ACPI_EXPORT_SYMBOL(acpi_evaluate_object_typed) #endif /* ACPI_FUTURE_USAGE */ /******************************************************************************* @@ -163,7 +163,6 @@ acpi_evaluate_object_typed(acpi_handle handle, * be valid (non-null) * ******************************************************************************/ - acpi_status acpi_evaluate_object(acpi_handle handle, acpi_string pathname, @@ -193,9 +192,9 @@ acpi_evaluate_object(acpi_handle handle, * Allocate a new parameter block for the internal objects * Add 1 to count to allow for null terminated internal list */ - info.parameters = ACPI_MEM_CALLOCATE(((acpi_size) - external_params->count + - 1) * sizeof(void *)); + info.parameters = ACPI_ALLOCATE_ZEROED(((acpi_size) + external_params->count + + 1) * sizeof(void *)); if (!info.parameters) { return_ACPI_STATUS(AE_NO_MEMORY); } @@ -356,7 +355,7 @@ acpi_evaluate_object(acpi_handle handle, return_ACPI_STATUS(status); } -EXPORT_SYMBOL(acpi_evaluate_object); +ACPI_EXPORT_SYMBOL(acpi_evaluate_object) /******************************************************************************* * @@ -387,7 +386,6 @@ EXPORT_SYMBOL(acpi_evaluate_object); * function, etc. * ******************************************************************************/ - acpi_status acpi_walk_namespace(acpi_object_type type, acpi_handle start_object, @@ -424,7 +422,7 @@ acpi_walk_namespace(acpi_object_type type, return_ACPI_STATUS(status); } -EXPORT_SYMBOL(acpi_walk_namespace); +ACPI_EXPORT_SYMBOL(acpi_walk_namespace) /******************************************************************************* * @@ -439,7 +437,6 @@ EXPORT_SYMBOL(acpi_walk_namespace); * on that. * ******************************************************************************/ - static acpi_status acpi_ns_get_device_callback(acpi_handle obj_handle, u32 nesting_level, @@ -510,11 +507,11 @@ acpi_ns_get_device_callback(acpi_handle obj_handle, sizeof(struct acpi_compatible_id)) != 0) { - ACPI_MEM_FREE(cid); + ACPI_FREE(cid); return (AE_OK); } } - ACPI_MEM_FREE(cid); + ACPI_FREE(cid); } } @@ -592,7 +589,7 @@ acpi_get_devices(char *HID, return_ACPI_STATUS(status); } -EXPORT_SYMBOL(acpi_get_devices); +ACPI_EXPORT_SYMBOL(acpi_get_devices) /******************************************************************************* * @@ -607,7 +604,6 @@ EXPORT_SYMBOL(acpi_get_devices); * DESCRIPTION: Attach arbitrary data and handler to a namespace node. * ******************************************************************************/ - acpi_status acpi_attach_data(acpi_handle obj_handle, acpi_object_handler handler, void *data) @@ -641,6 +637,8 @@ acpi_attach_data(acpi_handle obj_handle, return (status); } +ACPI_EXPORT_SYMBOL(acpi_attach_data) + /******************************************************************************* * * FUNCTION: acpi_detach_data @@ -653,7 +651,6 @@ acpi_attach_data(acpi_handle obj_handle, * DESCRIPTION: Remove data that was previously attached to a node. * ******************************************************************************/ - acpi_status acpi_detach_data(acpi_handle obj_handle, acpi_object_handler handler) { @@ -686,6 +683,8 @@ acpi_detach_data(acpi_handle obj_handle, acpi_object_handler handler) return (status); } +ACPI_EXPORT_SYMBOL(acpi_detach_data) + /******************************************************************************* * * FUNCTION: acpi_get_data @@ -699,7 +698,6 @@ acpi_detach_data(acpi_handle obj_handle, acpi_object_handler handler) * DESCRIPTION: Retrieve data that was previously attached to a namespace node. * ******************************************************************************/ - acpi_status acpi_get_data(acpi_handle obj_handle, acpi_object_handler handler, void **data) { @@ -731,3 +729,5 @@ acpi_get_data(acpi_handle obj_handle, acpi_object_handler handler, void **data) (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return (status); } + +ACPI_EXPORT_SYMBOL(acpi_get_data) diff --git a/drivers/acpi/namespace/nsxfname.c b/drivers/acpi/namespace/nsxfname.c index 55d26624ab9f..1303e2b062bb 100644 --- a/drivers/acpi/namespace/nsxfname.c +++ b/drivers/acpi/namespace/nsxfname.c @@ -42,8 +42,6 @@ * POSSIBILITY OF SUCH DAMAGES. */ -#include - #include #include @@ -126,7 +124,7 @@ acpi_get_handle(acpi_handle parent, return (status); } -EXPORT_SYMBOL(acpi_get_handle); +ACPI_EXPORT_SYMBOL(acpi_get_handle) /****************************************************************************** * @@ -143,7 +141,6 @@ EXPORT_SYMBOL(acpi_get_handle); * complementary functions. * ******************************************************************************/ - acpi_status acpi_get_name(acpi_handle handle, u32 name_type, struct acpi_buffer * buffer) { @@ -204,7 +201,7 @@ acpi_get_name(acpi_handle handle, u32 name_type, struct acpi_buffer * buffer) return (status); } -EXPORT_SYMBOL(acpi_get_name); +ACPI_EXPORT_SYMBOL(acpi_get_name) /****************************************************************************** * @@ -220,7 +217,6 @@ EXPORT_SYMBOL(acpi_get_name); * control methods (Such as in the case of a device.) * ******************************************************************************/ - acpi_status acpi_get_object_info(acpi_handle handle, struct acpi_buffer * buffer) { @@ -242,7 +238,7 @@ acpi_get_object_info(acpi_handle handle, struct acpi_buffer * buffer) return (status); } - info = ACPI_MEM_CALLOCATE(sizeof(struct acpi_device_info)); + info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_device_info)); if (!info) { return (AE_NO_MEMORY); } @@ -346,11 +342,11 @@ acpi_get_object_info(acpi_handle handle, struct acpi_buffer * buffer) } cleanup: - ACPI_MEM_FREE(info); + ACPI_FREE(info); if (cid_list) { - ACPI_MEM_FREE(cid_list); + ACPI_FREE(cid_list); } return (status); } -EXPORT_SYMBOL(acpi_get_object_info); +ACPI_EXPORT_SYMBOL(acpi_get_object_info) diff --git a/drivers/acpi/namespace/nsxfobj.c b/drivers/acpi/namespace/nsxfobj.c index 9c5f3302799c..a163e1d3708d 100644 --- a/drivers/acpi/namespace/nsxfobj.c +++ b/drivers/acpi/namespace/nsxfobj.c @@ -42,8 +42,6 @@ * POSSIBILITY OF SUCH DAMAGES. */ -#include - #include #include @@ -101,7 +99,7 @@ acpi_status acpi_get_type(acpi_handle handle, acpi_object_type * ret_type) return (status); } -EXPORT_SYMBOL(acpi_get_type); +ACPI_EXPORT_SYMBOL(acpi_get_type) /******************************************************************************* * @@ -116,7 +114,6 @@ EXPORT_SYMBOL(acpi_get_type); * Handle. * ******************************************************************************/ - acpi_status acpi_get_parent(acpi_handle handle, acpi_handle * ret_handle) { struct acpi_namespace_node *node; @@ -162,7 +159,7 @@ acpi_status acpi_get_parent(acpi_handle handle, acpi_handle * ret_handle) return (status); } -EXPORT_SYMBOL(acpi_get_parent); +ACPI_EXPORT_SYMBOL(acpi_get_parent) /******************************************************************************* * @@ -181,7 +178,6 @@ EXPORT_SYMBOL(acpi_get_parent); * Scope is returned. * ******************************************************************************/ - acpi_status acpi_get_next_object(acpi_object_type type, acpi_handle parent, @@ -243,4 +239,4 @@ acpi_get_next_object(acpi_object_type type, return (status); } -EXPORT_SYMBOL(acpi_get_next_object); +ACPI_EXPORT_SYMBOL(acpi_get_next_object) diff --git a/drivers/acpi/parser/pstree.c b/drivers/acpi/parser/pstree.c index 6aa0012643ce..0015717ef096 100644 --- a/drivers/acpi/parser/pstree.c +++ b/drivers/acpi/parser/pstree.c @@ -306,5 +306,4 @@ union acpi_parse_object *acpi_ps_get_child(union acpi_parse_object *op) return (child); } #endif - #endif /* ACPI_FUTURE_USAGE */ diff --git a/drivers/acpi/resources/rsinfo.c b/drivers/acpi/resources/rsinfo.c index d9ae64b77bd9..9e7ae2f8a1d3 100644 --- a/drivers/acpi/resources/rsinfo.c +++ b/drivers/acpi/resources/rsinfo.c @@ -141,6 +141,7 @@ struct acpi_rsdump_info *acpi_gbl_dump_resource_dispatch[] = { acpi_rs_dump_generic_reg, /* ACPI_RESOURCE_TYPE_GENERIC_REGISTER */ }; #endif + #endif /* ACPI_FUTURE_USAGE */ /* * Base sizes for external AML resource descriptors, indexed by internal type. diff --git a/drivers/acpi/resources/rsxface.c b/drivers/acpi/resources/rsxface.c index 2e1bc71acd94..b3feebbd8ca2 100644 --- a/drivers/acpi/resources/rsxface.c +++ b/drivers/acpi/resources/rsxface.c @@ -41,8 +41,6 @@ * POSSIBILITY OF SUCH DAMAGES. */ -#include - #include #include @@ -118,6 +116,8 @@ acpi_get_irq_routing_table(acpi_handle device_handle, return_ACPI_STATUS(status); } +ACPI_EXPORT_SYMBOL(acpi_get_irq_routing_table) + /******************************************************************************* * * FUNCTION: acpi_get_current_resources @@ -141,7 +141,6 @@ acpi_get_irq_routing_table(acpi_handle device_handle, * the object indicated by the passed device_handle. * ******************************************************************************/ - acpi_status acpi_get_current_resources(acpi_handle device_handle, struct acpi_buffer *ret_buffer) @@ -169,8 +168,9 @@ acpi_get_current_resources(acpi_handle device_handle, return_ACPI_STATUS(status); } -EXPORT_SYMBOL(acpi_get_current_resources); +ACPI_EXPORT_SYMBOL(acpi_get_current_resources) +#ifdef ACPI_FUTURE_USAGE /******************************************************************************* * * FUNCTION: acpi_get_possible_resources @@ -191,8 +191,6 @@ EXPORT_SYMBOL(acpi_get_current_resources); * and the value of ret_buffer is undefined. * ******************************************************************************/ - -#ifdef ACPI_FUTURE_USAGE acpi_status acpi_get_possible_resources(acpi_handle device_handle, struct acpi_buffer *ret_buffer) @@ -220,7 +218,7 @@ acpi_get_possible_resources(acpi_handle device_handle, return_ACPI_STATUS(status); } -EXPORT_SYMBOL(acpi_get_possible_resources); +ACPI_EXPORT_SYMBOL(acpi_get_possible_resources) #endif /* ACPI_FUTURE_USAGE */ /******************************************************************************* @@ -241,7 +239,6 @@ EXPORT_SYMBOL(acpi_get_possible_resources); * each resource in the list. * ******************************************************************************/ - acpi_status acpi_walk_resources(acpi_handle device_handle, char *name, @@ -313,11 +310,11 @@ acpi_walk_resources(acpi_handle device_handle, resource->length); } - ACPI_MEM_FREE(buffer.pointer); + ACPI_FREE(buffer.pointer); return_ACPI_STATUS(status); } -EXPORT_SYMBOL(acpi_walk_resources); +ACPI_EXPORT_SYMBOL(acpi_walk_resources) /******************************************************************************* * @@ -336,7 +333,6 @@ EXPORT_SYMBOL(acpi_walk_resources); * the buffer pointed to by the in_buffer variable. * ******************************************************************************/ - acpi_status acpi_set_current_resources(acpi_handle device_handle, struct acpi_buffer *in_buffer) @@ -356,7 +352,7 @@ acpi_set_current_resources(acpi_handle device_handle, return_ACPI_STATUS(status); } -EXPORT_SYMBOL(acpi_set_current_resources); +ACPI_EXPORT_SYMBOL(acpi_set_current_resources) /****************************************************************************** * @@ -375,7 +371,6 @@ EXPORT_SYMBOL(acpi_set_current_resources); * addresses. * ******************************************************************************/ - acpi_status acpi_resource_to_address64(struct acpi_resource *resource, struct acpi_resource_address64 *out) @@ -417,7 +412,7 @@ acpi_resource_to_address64(struct acpi_resource *resource, return (AE_OK); } -EXPORT_SYMBOL(acpi_resource_to_address64); +ACPI_EXPORT_SYMBOL(acpi_resource_to_address64) /******************************************************************************* * @@ -437,7 +432,6 @@ EXPORT_SYMBOL(acpi_resource_to_address64); * UUID subtype. Returns a struct acpi_resource of type Vendor. * ******************************************************************************/ - acpi_status acpi_get_vendor_resource(acpi_handle device_handle, char *name, @@ -469,6 +463,8 @@ acpi_get_vendor_resource(acpi_handle device_handle, return (info.status); } +ACPI_EXPORT_SYMBOL(acpi_get_vendor_resource) + /******************************************************************************* * * FUNCTION: acpi_rs_match_vendor_resource @@ -480,7 +476,6 @@ acpi_get_vendor_resource(acpi_handle device_handle, * DESCRIPTION: Match a vendor resource via the ACPI 3.0 UUID * ******************************************************************************/ - static acpi_status acpi_rs_match_vendor_resource(struct acpi_resource *resource, void *context) { @@ -528,3 +523,5 @@ acpi_rs_match_vendor_resource(struct acpi_resource *resource, void *context) info->status = AE_OK; return (AE_CTRL_TERMINATE); } + +ACPI_EXPORT_SYMBOL(acpi_rs_match_vendor_resource) diff --git a/drivers/acpi/tables/tbconvrt.c b/drivers/acpi/tables/tbconvrt.c index 254ebdbb7bef..5155b27cf032 100644 --- a/drivers/acpi/tables/tbconvrt.c +++ b/drivers/acpi/tables/tbconvrt.c @@ -41,8 +41,6 @@ * POSSIBILITY OF SUCH DAMAGES. */ -#include - #include #include @@ -64,7 +62,7 @@ acpi_tb_convert_fadt2(struct fadt_descriptor_rev2 *local_fadt, struct fadt_descriptor_rev2 *original_fadt); u8 acpi_fadt_is_v1; -EXPORT_SYMBOL(acpi_fadt_is_v1); +ACPI_EXPORT_SYMBOL(acpi_fadt_is_v1) /******************************************************************************* * @@ -133,7 +131,7 @@ acpi_status acpi_tb_convert_to_xsdt(struct acpi_table_desc *table_info) /* Allocate an XSDT */ - new_table = ACPI_MEM_CALLOCATE(table_size); + new_table = ACPI_ALLOCATE_ZEROED(table_size); if (!new_table) { return (AE_NO_MEMORY); } @@ -509,7 +507,7 @@ acpi_status acpi_tb_convert_table_fadt(void) /* Allocate buffer for the ACPI 2.0(+) FADT */ - local_fadt = ACPI_MEM_CALLOCATE(sizeof(struct fadt_descriptor_rev2)); + local_fadt = ACPI_ALLOCATE_ZEROED(sizeof(struct fadt_descriptor_rev2)); if (!local_fadt) { return_ACPI_STATUS(AE_NO_MEMORY); } diff --git a/drivers/acpi/tables/tbget.c b/drivers/acpi/tables/tbget.c index 4615e1afe8de..b7bd20b9a75e 100644 --- a/drivers/acpi/tables/tbget.c +++ b/drivers/acpi/tables/tbget.c @@ -330,7 +330,7 @@ acpi_tb_get_this_table(struct acpi_pointer *address, /* Pointer matches processor mode, copy the table to a new buffer */ - full_table = ACPI_MEM_ALLOCATE(header->length); + full_table = ACPI_ALLOCATE(header->length); if (!full_table) { ACPI_ERROR((AE_INFO, "Could not allocate table memory for [%4.4s] length %X", diff --git a/drivers/acpi/tables/tbinstal.c b/drivers/acpi/tables/tbinstal.c index ec2cb978b7c4..ce57a195577a 100644 --- a/drivers/acpi/tables/tbinstal.c +++ b/drivers/acpi/tables/tbinstal.c @@ -248,7 +248,7 @@ acpi_tb_init_table_descriptor(acpi_table_type table_type, /* Allocate a descriptor for this table */ - table_desc = ACPI_MEM_CALLOCATE(sizeof(struct acpi_table_desc)); + table_desc = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_table_desc)); if (!table_desc) { return_ACPI_STATUS(AE_NO_MEMORY); } @@ -275,7 +275,7 @@ acpi_tb_init_table_descriptor(acpi_table_type table_type, * at this location, so return an error. */ if (list_head->next) { - ACPI_MEM_FREE(table_desc); + ACPI_FREE(table_desc); return_ACPI_STATUS(AE_ALREADY_EXISTS); } @@ -472,7 +472,7 @@ void acpi_tb_delete_single_table(struct acpi_table_desc *table_desc) case ACPI_MEM_ALLOCATED: - ACPI_MEM_FREE(table_desc->pointer); + ACPI_FREE(table_desc->pointer); break; case ACPI_MEM_MAPPED: @@ -531,7 +531,7 @@ struct acpi_table_desc *acpi_tb_uninstall_table(struct acpi_table_desc /* Free the table descriptor */ next_desc = table_desc->next; - ACPI_MEM_FREE(table_desc); + ACPI_FREE(table_desc); /* Return pointer to the next descriptor */ diff --git a/drivers/acpi/tables/tbxface.c b/drivers/acpi/tables/tbxface.c index 3e902cdb83e1..53c627e401bf 100644 --- a/drivers/acpi/tables/tbxface.c +++ b/drivers/acpi/tables/tbxface.c @@ -42,8 +42,6 @@ * POSSIBILITY OF SUCH DAMAGES. */ -#include - #include #include #include @@ -123,6 +121,8 @@ acpi_status acpi_load_tables(void) return_ACPI_STATUS(status); } +ACPI_EXPORT_SYMBOL(acpi_load_tables) + #ifdef ACPI_FUTURE_USAGE /******************************************************************************* * @@ -139,7 +139,6 @@ acpi_status acpi_load_tables(void) * is determined that the table is invalid, the call will fail. * ******************************************************************************/ - acpi_status acpi_load_table(struct acpi_table_header *table_ptr) { acpi_status status; @@ -218,6 +217,8 @@ acpi_status acpi_load_table(struct acpi_table_header *table_ptr) return_ACPI_STATUS(status); } +ACPI_EXPORT_SYMBOL(acpi_load_table) + /******************************************************************************* * * FUNCTION: acpi_unload_table @@ -229,7 +230,6 @@ acpi_status acpi_load_table(struct acpi_table_header *table_ptr) * DESCRIPTION: This routine is used to force the unload of a table * ******************************************************************************/ - acpi_status acpi_unload_table(acpi_table_type table_type) { struct acpi_table_desc *table_desc; @@ -263,6 +263,8 @@ acpi_status acpi_unload_table(acpi_table_type table_type) return_ACPI_STATUS(AE_OK); } +ACPI_EXPORT_SYMBOL(acpi_unload_table) + /******************************************************************************* * * FUNCTION: acpi_get_table_header @@ -283,7 +285,6 @@ acpi_status acpi_unload_table(acpi_table_type table_type) * have a standard header and is fixed length. * ******************************************************************************/ - acpi_status acpi_get_table_header(acpi_table_type table_type, u32 instance, struct acpi_table_header *out_table_header) @@ -327,6 +328,7 @@ acpi_get_table_header(acpi_table_type table_type, return_ACPI_STATUS(status); } +ACPI_EXPORT_SYMBOL(acpi_get_table_header) #endif /* ACPI_FUTURE_USAGE */ /******************************************************************************* @@ -351,7 +353,6 @@ acpi_get_table_header(acpi_table_type table_type, * a complete table including the header. * ******************************************************************************/ - acpi_status acpi_get_table(acpi_table_type table_type, u32 instance, struct acpi_buffer *ret_buffer) @@ -420,4 +421,4 @@ acpi_get_table(acpi_table_type table_type, return_ACPI_STATUS(AE_OK); } -EXPORT_SYMBOL(acpi_get_table); +ACPI_EXPORT_SYMBOL(acpi_get_table) diff --git a/drivers/acpi/tables/tbxfroot.c b/drivers/acpi/tables/tbxfroot.c index 7f68b759f15a..1b6d8c510e95 100644 --- a/drivers/acpi/tables/tbxfroot.c +++ b/drivers/acpi/tables/tbxfroot.c @@ -41,8 +41,6 @@ * POSSIBILITY OF SUCH DAMAGES. */ -#include - #include #include @@ -263,7 +261,7 @@ acpi_get_firmware_table(acpi_string signature, /* Get and validate the RSDT */ - rsdt_info = ACPI_MEM_CALLOCATE(sizeof(struct acpi_table_desc)); + rsdt_info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_table_desc)); if (!rsdt_info) { return_ACPI_STATUS(AE_NO_MEMORY); } @@ -280,13 +278,13 @@ acpi_get_firmware_table(acpi_string signature, /* Allocate a scratch table header and table descriptor */ - header = ACPI_MEM_ALLOCATE(sizeof(struct acpi_table_header)); + header = ACPI_ALLOCATE(sizeof(struct acpi_table_header)); if (!header) { status = AE_NO_MEMORY; goto cleanup; } - table_info = ACPI_MEM_ALLOCATE(sizeof(struct acpi_table_desc)); + table_info = ACPI_ALLOCATE(sizeof(struct acpi_table_desc)); if (!table_info) { status = AE_NO_MEMORY; goto cleanup; @@ -359,23 +357,21 @@ acpi_get_firmware_table(acpi_string signature, acpi_os_unmap_memory(rsdt_info->pointer, (acpi_size) rsdt_info->pointer->length); } - ACPI_MEM_FREE(rsdt_info); + ACPI_FREE(rsdt_info); if (header) { - ACPI_MEM_FREE(header); + ACPI_FREE(header); } if (table_info) { - ACPI_MEM_FREE(table_info); + ACPI_FREE(table_info); } return_ACPI_STATUS(status); } -EXPORT_SYMBOL(acpi_get_firmware_table); +ACPI_EXPORT_SYMBOL(acpi_get_firmware_table) /* TBD: Move to a new file */ - #if ACPI_MACHINE_WIDTH != 16 - /******************************************************************************* * * FUNCTION: acpi_find_root_pointer @@ -388,7 +384,6 @@ EXPORT_SYMBOL(acpi_get_firmware_table); * DESCRIPTION: Find the RSDP * ******************************************************************************/ - acpi_status acpi_find_root_pointer(u32 flags, struct acpi_pointer *rsdp_address) { struct acpi_table_desc table_info; @@ -411,6 +406,8 @@ acpi_status acpi_find_root_pointer(u32 flags, struct acpi_pointer *rsdp_address) return_ACPI_STATUS(AE_OK); } +ACPI_EXPORT_SYMBOL(acpi_find_root_pointer) + /******************************************************************************* * * FUNCTION: acpi_tb_scan_memory_for_rsdp @@ -423,7 +420,6 @@ acpi_status acpi_find_root_pointer(u32 flags, struct acpi_pointer *rsdp_address) * DESCRIPTION: Search a block of memory for the RSDP signature * ******************************************************************************/ - static u8 *acpi_tb_scan_memory_for_rsdp(u8 * start_address, u32 length) { acpi_status status; diff --git a/drivers/acpi/utilities/utalloc.c b/drivers/acpi/utilities/utalloc.c index 34de3791d4c2..7b35eb84d058 100644 --- a/drivers/acpi/utilities/utalloc.c +++ b/drivers/acpi/utilities/utalloc.c @@ -252,7 +252,7 @@ acpi_ut_initialize_buffer(struct acpi_buffer * buffer, /* Allocate a new buffer with local interface to allow tracking */ - buffer->pointer = ACPI_MEM_CALLOCATE(required_length); + buffer->pointer = ACPI_ALLOCATE_ZEROED(required_length); if (!buffer->pointer) { return (AE_NO_MEMORY); } diff --git a/drivers/acpi/utilities/utcache.c b/drivers/acpi/utilities/utcache.c index 044c890e5b3c..5d2f4b2802a5 100644 --- a/drivers/acpi/utilities/utcache.c +++ b/drivers/acpi/utilities/utcache.c @@ -125,7 +125,7 @@ acpi_status acpi_os_purge_cache(struct acpi_memory_list * cache) &(((char *)cache-> list_head)[cache-> link_offset]))); - ACPI_MEM_FREE(cache->list_head); + ACPI_FREE(cache->list_head); cache->list_head = next; cache->current_depth--; @@ -194,7 +194,7 @@ acpi_os_release_object(struct acpi_memory_list * cache, void *object) /* If cache is full, just free this object */ if (cache->current_depth >= cache->max_depth) { - ACPI_MEM_FREE(object); + ACPI_FREE(object); ACPI_MEM_TRACKING(cache->total_freed++); } @@ -289,14 +289,14 @@ void *acpi_os_acquire_object(struct acpi_memory_list *cache) ACPI_MEM_TRACKING(cache->total_allocated++); - /* Avoid deadlock with ACPI_MEM_CALLOCATE */ + /* Avoid deadlock with ACPI_ALLOCATE_ZEROED */ status = acpi_ut_release_mutex(ACPI_MTX_CACHES); if (ACPI_FAILURE(status)) { return (NULL); } - object = ACPI_MEM_CALLOCATE(cache->object_size); + object = ACPI_ALLOCATE_ZEROED(cache->object_size); if (!object) { return (NULL); } diff --git a/drivers/acpi/utilities/utcopy.c b/drivers/acpi/utilities/utcopy.c index 47875935c3f4..371cddc0d574 100644 --- a/drivers/acpi/utilities/utcopy.c +++ b/drivers/acpi/utilities/utcopy.c @@ -472,8 +472,8 @@ acpi_ut_copy_esimple_to_isimple(union acpi_object *external_object, case ACPI_TYPE_STRING: internal_object->string.pointer = - ACPI_MEM_CALLOCATE((acpi_size) external_object->string. - length + 1); + ACPI_ALLOCATE_ZEROED((acpi_size) external_object->string. + length + 1); if (!internal_object->string.pointer) { goto error_exit; } @@ -488,7 +488,7 @@ acpi_ut_copy_esimple_to_isimple(union acpi_object *external_object, case ACPI_TYPE_BUFFER: internal_object->buffer.pointer = - ACPI_MEM_CALLOCATE(external_object->buffer.length); + ACPI_ALLOCATE_ZEROED(external_object->buffer.length); if (!internal_object->buffer.pointer) { goto error_exit; } @@ -676,7 +676,7 @@ acpi_ut_copy_simple_object(union acpi_operand_object *source_desc, if ((source_desc->buffer.pointer) && (source_desc->buffer.length)) { dest_desc->buffer.pointer = - ACPI_MEM_ALLOCATE(source_desc->buffer.length); + ACPI_ALLOCATE(source_desc->buffer.length); if (!dest_desc->buffer.pointer) { return (AE_NO_MEMORY); } @@ -697,8 +697,8 @@ acpi_ut_copy_simple_object(union acpi_operand_object *source_desc, */ if (source_desc->string.pointer) { dest_desc->string.pointer = - ACPI_MEM_ALLOCATE((acpi_size) source_desc->string. - length + 1); + ACPI_ALLOCATE((acpi_size) source_desc->string. + length + 1); if (!dest_desc->string.pointer) { return (AE_NO_MEMORY); } @@ -805,9 +805,7 @@ acpi_ut_copy_ielement_to_ielement(u8 object_type, /* * Create the object array */ - target_object->package.elements = - ACPI_MEM_CALLOCATE(((acpi_size) source_object->package. - count + 1) * sizeof(void *)); + target_object->package.elements = ACPI_ALLOCATE_ZEROED(((acpi_size) source_object->package.count + 1) * sizeof(void *)); if (!target_object->package.elements) { status = AE_NO_MEMORY; goto error_exit; @@ -865,10 +863,10 @@ acpi_ut_copy_ipackage_to_ipackage(union acpi_operand_object *source_obj, /* * Create the object array and walk the source package tree */ - dest_obj->package.elements = ACPI_MEM_CALLOCATE(((acpi_size) - source_obj->package. - count + - 1) * sizeof(void *)); + dest_obj->package.elements = ACPI_ALLOCATE_ZEROED(((acpi_size) + source_obj->package. + count + + 1) * sizeof(void *)); if (!dest_obj->package.elements) { ACPI_ERROR((AE_INFO, "Package allocation failure")); return_ACPI_STATUS(AE_NO_MEMORY); diff --git a/drivers/acpi/utilities/utdebug.c b/drivers/acpi/utilities/utdebug.c index 6e92b2a3c0fd..a8c350643d57 100644 --- a/drivers/acpi/utilities/utdebug.c +++ b/drivers/acpi/utilities/utdebug.c @@ -41,8 +41,6 @@ * POSSIBILITY OF SUCH DAMAGES. */ -#include - #include #define _COMPONENT ACPI_UTILITIES @@ -164,7 +162,7 @@ acpi_ut_debug_print(u32 requested_debug_level, const char *function_name, char *module_name, u32 component_id, char *format, ...) { - u32 thread_id; + acpi_thread_id thread_id; va_list args; /* @@ -179,7 +177,6 @@ acpi_ut_debug_print(u32 requested_debug_level, * Thread tracking and context switch notification */ thread_id = acpi_os_get_thread_id(); - if (thread_id != acpi_gbl_prev_thread_id) { if (ACPI_LV_THREADS & acpi_dbg_level) { acpi_os_printf @@ -208,7 +205,7 @@ acpi_ut_debug_print(u32 requested_debug_level, acpi_os_vprintf(format, args); } -EXPORT_SYMBOL(acpi_ut_debug_print); +ACPI_EXPORT_SYMBOL(acpi_ut_debug_print) /******************************************************************************* * @@ -228,7 +225,6 @@ EXPORT_SYMBOL(acpi_ut_debug_print); * debug_print so that the same macros can be used. * ******************************************************************************/ - void ACPI_INTERNAL_VAR_XFACE acpi_ut_debug_print_raw(u32 requested_debug_level, u32 line_number, @@ -246,7 +242,7 @@ acpi_ut_debug_print_raw(u32 requested_debug_level, acpi_os_vprintf(format, args); } -EXPORT_SYMBOL(acpi_ut_debug_print_raw); +ACPI_EXPORT_SYMBOL(acpi_ut_debug_print_raw) /******************************************************************************* * @@ -263,7 +259,6 @@ EXPORT_SYMBOL(acpi_ut_debug_print_raw); * set in debug_level * ******************************************************************************/ - void acpi_ut_trace(u32 line_number, const char *function_name, char *module_name, u32 component_id) @@ -277,7 +272,7 @@ acpi_ut_trace(u32 line_number, component_id, "%s\n", acpi_gbl_fn_entry_str); } -EXPORT_SYMBOL(acpi_ut_trace); +ACPI_EXPORT_SYMBOL(acpi_ut_trace) /******************************************************************************* * @@ -295,7 +290,6 @@ EXPORT_SYMBOL(acpi_ut_trace); * set in debug_level * ******************************************************************************/ - void acpi_ut_trace_ptr(u32 line_number, const char *function_name, @@ -402,7 +396,7 @@ acpi_ut_exit(u32 line_number, acpi_gbl_nesting_level--; } -EXPORT_SYMBOL(acpi_ut_exit); +ACPI_EXPORT_SYMBOL(acpi_ut_exit) /******************************************************************************* * @@ -420,7 +414,6 @@ EXPORT_SYMBOL(acpi_ut_exit); * set in debug_level. Prints exit status also. * ******************************************************************************/ - void acpi_ut_status_exit(u32 line_number, const char *function_name, @@ -444,7 +437,7 @@ acpi_ut_status_exit(u32 line_number, acpi_gbl_nesting_level--; } -EXPORT_SYMBOL(acpi_ut_status_exit); +ACPI_EXPORT_SYMBOL(acpi_ut_status_exit) /******************************************************************************* * @@ -462,7 +455,6 @@ EXPORT_SYMBOL(acpi_ut_status_exit); * set in debug_level. Prints exit value also. * ******************************************************************************/ - void acpi_ut_value_exit(u32 line_number, const char *function_name, @@ -477,7 +469,7 @@ acpi_ut_value_exit(u32 line_number, acpi_gbl_nesting_level--; } -EXPORT_SYMBOL(acpi_ut_value_exit); +ACPI_EXPORT_SYMBOL(acpi_ut_value_exit) /******************************************************************************* * @@ -495,7 +487,6 @@ EXPORT_SYMBOL(acpi_ut_value_exit); * set in debug_level. Prints exit value also. * ******************************************************************************/ - void acpi_ut_ptr_exit(u32 line_number, const char *function_name, diff --git a/drivers/acpi/utilities/utdelete.c b/drivers/acpi/utilities/utdelete.c index dbae72121cea..9c6867fcf009 100644 --- a/drivers/acpi/utilities/utdelete.c +++ b/drivers/acpi/utilities/utdelete.c @@ -236,7 +236,7 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object) if (obj_pointer) { ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "Deleting Object Subptr %p\n", obj_pointer)); - ACPI_MEM_FREE(obj_pointer); + ACPI_FREE(obj_pointer); } /* Now the object can be safely deleted */ @@ -275,7 +275,7 @@ void acpi_ut_delete_internal_object_list(union acpi_operand_object **obj_list) /* Free the combined parameter pointer list and object array */ - ACPI_MEM_FREE(obj_list); + ACPI_FREE(obj_list); return_VOID; } diff --git a/drivers/acpi/utilities/uteval.c b/drivers/acpi/utilities/uteval.c index 952ffdea93aa..68b9eff4b326 100644 --- a/drivers/acpi/utilities/uteval.c +++ b/drivers/acpi/utilities/uteval.c @@ -461,7 +461,7 @@ acpi_ut_execute_CID(struct acpi_namespace_node * device_node, size = (((count - 1) * sizeof(struct acpi_compatible_id)) + sizeof(struct acpi_compatible_id_list)); - cid_list = ACPI_MEM_CALLOCATE((acpi_size) size); + cid_list = ACPI_ALLOCATE_ZEROED((acpi_size) size); if (!cid_list) { return_ACPI_STATUS(AE_NO_MEMORY); } @@ -502,7 +502,7 @@ acpi_ut_execute_CID(struct acpi_namespace_node * device_node, /* Cleanup on error */ if (ACPI_FAILURE(status)) { - ACPI_MEM_FREE(cid_list); + ACPI_FREE(cid_list); } else { *return_cid_list = cid_list; } diff --git a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c index 767c5e44a04b..5bc8da7acc6c 100644 --- a/drivers/acpi/utilities/utglobal.c +++ b/drivers/acpi/utilities/utglobal.c @@ -43,7 +43,6 @@ #define DEFINE_ACPI_GLOBALS -#include #include #include @@ -144,12 +143,10 @@ const char *acpi_format_exception(acpi_status status) /* Debug switch - level and trace mask */ u32 acpi_dbg_level = ACPI_DEBUG_DEFAULT; -EXPORT_SYMBOL(acpi_dbg_level); /* Debug switch - layer (component) mask */ u32 acpi_dbg_layer = ACPI_COMPONENT_DEFAULT | ACPI_ALL_DRIVERS; -EXPORT_SYMBOL(acpi_dbg_layer); u32 acpi_gbl_nesting_level = 0; /* Debugger globals */ @@ -871,3 +868,6 @@ void acpi_ut_init_globals(void) return_VOID; } + +ACPI_EXPORT_SYMBOL(acpi_dbg_level) +ACPI_EXPORT_SYMBOL(acpi_dbg_layer) diff --git a/drivers/acpi/utilities/utinit.c b/drivers/acpi/utilities/utinit.c index ba771b4f39bc..40313de6977d 100644 --- a/drivers/acpi/utilities/utinit.c +++ b/drivers/acpi/utilities/utinit.c @@ -186,14 +186,14 @@ static void acpi_ut_terminate(void) gpe_block = gpe_xrupt_info->gpe_block_list_head; while (gpe_block) { next_gpe_block = gpe_block->next; - ACPI_MEM_FREE(gpe_block->event_info); - ACPI_MEM_FREE(gpe_block->register_info); - ACPI_MEM_FREE(gpe_block); + ACPI_FREE(gpe_block->event_info); + ACPI_FREE(gpe_block->register_info); + ACPI_FREE(gpe_block); gpe_block = next_gpe_block; } next_gpe_xrupt_info = gpe_xrupt_info->next; - ACPI_MEM_FREE(gpe_xrupt_info); + ACPI_FREE(gpe_xrupt_info); gpe_xrupt_info = next_gpe_xrupt_info; } diff --git a/drivers/acpi/utilities/utmisc.c b/drivers/acpi/utilities/utmisc.c index 60f36130663c..77268ba86291 100644 --- a/drivers/acpi/utilities/utmisc.c +++ b/drivers/acpi/utilities/utmisc.c @@ -463,7 +463,7 @@ acpi_ut_display_init_pathname(u8 type, } acpi_os_printf("\n"); - ACPI_MEM_FREE(buffer.pointer); + ACPI_FREE(buffer.pointer); } #endif diff --git a/drivers/acpi/utilities/utmutex.c b/drivers/acpi/utilities/utmutex.c index 45a7244df924..0ac6700a45f8 100644 --- a/drivers/acpi/utilities/utmutex.c +++ b/drivers/acpi/utilities/utmutex.c @@ -192,7 +192,7 @@ static acpi_status acpi_ut_delete_mutex(acpi_mutex_handle mutex_id) acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id) { acpi_status status; - u32 this_thread_id; + acpi_thread_id this_thread_id; ACPI_FUNCTION_NAME("ut_acquire_mutex"); @@ -275,7 +275,7 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id) acpi_status acpi_ut_release_mutex(acpi_mutex_handle mutex_id) { acpi_status status; - u32 this_thread_id; + acpi_thread_id this_thread_id; ACPI_FUNCTION_NAME("ut_release_mutex"); diff --git a/drivers/acpi/utilities/utobject.c b/drivers/acpi/utilities/utobject.c index b1205a58028c..8e3dcbd23f5d 100644 --- a/drivers/acpi/utilities/utobject.c +++ b/drivers/acpi/utilities/utobject.c @@ -176,7 +176,7 @@ union acpi_operand_object *acpi_ut_create_buffer_object(acpi_size buffer_size) /* Allocate the actual buffer */ - buffer = ACPI_MEM_CALLOCATE(buffer_size); + buffer = ACPI_ALLOCATE_ZEROED(buffer_size); if (!buffer) { ACPI_ERROR((AE_INFO, "Could not allocate size %X", (u32) buffer_size)); @@ -228,7 +228,7 @@ union acpi_operand_object *acpi_ut_create_string_object(acpi_size string_size) * Allocate the actual string buffer -- (Size + 1) for NULL terminator. * NOTE: Zero-length strings are NULL terminated */ - string = ACPI_MEM_CALLOCATE(string_size + 1); + string = ACPI_ALLOCATE_ZEROED(string_size + 1); if (!string) { ACPI_ERROR((AE_INFO, "Could not allocate size %X", (u32) string_size)); @@ -320,6 +320,7 @@ void *acpi_ut_allocate_object_desc_dbg(char *module_name, } /* Mark the descriptor type */ + memset(object, 0, sizeof(union acpi_operand_object)); ACPI_SET_DESCRIPTOR_TYPE(object, ACPI_DESC_TYPE_OPERAND); diff --git a/drivers/acpi/utilities/utxface.c b/drivers/acpi/utilities/utxface.c index 308a960871be..ac90048a8a5b 100644 --- a/drivers/acpi/utilities/utxface.c +++ b/drivers/acpi/utilities/utxface.c @@ -41,8 +41,6 @@ * POSSIBILITY OF SUCH DAMAGES. */ -#include - #include #include #include @@ -109,6 +107,8 @@ acpi_status acpi_initialize_subsystem(void) return_ACPI_STATUS(status); } +ACPI_EXPORT_SYMBOL(acpi_initialize_subsystem) + /******************************************************************************* * * FUNCTION: acpi_enable_subsystem @@ -121,7 +121,6 @@ acpi_status acpi_initialize_subsystem(void) * Puts system into ACPI mode if it isn't already. * ******************************************************************************/ - acpi_status acpi_enable_subsystem(u32 flags) { acpi_status status = AE_OK; @@ -229,6 +228,8 @@ acpi_status acpi_enable_subsystem(u32 flags) return_ACPI_STATUS(status); } +ACPI_EXPORT_SYMBOL(acpi_enable_subsystem) + /******************************************************************************* * * FUNCTION: acpi_initialize_objects @@ -241,7 +242,6 @@ acpi_status acpi_enable_subsystem(u32 flags) * objects and executing AML code for Regions, buffers, etc. * ******************************************************************************/ - acpi_status acpi_initialize_objects(u32 flags) { acpi_status status = AE_OK; @@ -305,6 +305,8 @@ acpi_status acpi_initialize_objects(u32 flags) return_ACPI_STATUS(status); } +ACPI_EXPORT_SYMBOL(acpi_initialize_objects) + /******************************************************************************* * * FUNCTION: acpi_terminate @@ -316,7 +318,6 @@ acpi_status acpi_initialize_objects(u32 flags) * DESCRIPTION: Shutdown the ACPI subsystem. Release all resources. * ******************************************************************************/ - acpi_status acpi_terminate(void) { acpi_status status; @@ -348,6 +349,8 @@ acpi_status acpi_terminate(void) return_ACPI_STATUS(status); } +ACPI_EXPORT_SYMBOL(acpi_terminate) + #ifdef ACPI_FUTURE_USAGE /******************************************************************************* * @@ -362,7 +365,6 @@ acpi_status acpi_terminate(void) * initialized successfully. * ******************************************************************************/ - acpi_status acpi_subsystem_status(void) { @@ -373,6 +375,8 @@ acpi_status acpi_subsystem_status(void) } } +ACPI_EXPORT_SYMBOL(acpi_subsystem_status) + /******************************************************************************* * * FUNCTION: acpi_get_system_info @@ -390,7 +394,6 @@ acpi_status acpi_subsystem_status(void) * and the value of out_buffer is undefined. * ******************************************************************************/ - acpi_status acpi_get_system_info(struct acpi_buffer * out_buffer) { struct acpi_system_info *info_ptr; @@ -456,7 +459,7 @@ acpi_status acpi_get_system_info(struct acpi_buffer * out_buffer) return_ACPI_STATUS(AE_OK); } -EXPORT_SYMBOL(acpi_get_system_info); +ACPI_EXPORT_SYMBOL(acpi_get_system_info) /***************************************************************************** * @@ -472,7 +475,6 @@ EXPORT_SYMBOL(acpi_get_system_info); * TBD: When a second function is added, must save the Function also. * ****************************************************************************/ - acpi_status acpi_install_initialization_handler(acpi_init_handler handler, u32 function) { @@ -489,6 +491,7 @@ acpi_install_initialization_handler(acpi_init_handler handler, u32 function) return AE_OK; } +ACPI_EXPORT_SYMBOL(acpi_install_initialization_handler) #endif /* ACPI_FUTURE_USAGE */ /***************************************************************************** @@ -502,7 +505,6 @@ acpi_install_initialization_handler(acpi_init_handler handler, u32 function) * DESCRIPTION: Empty all caches (delete the cached objects) * ****************************************************************************/ - acpi_status acpi_purge_cached_objects(void) { ACPI_FUNCTION_TRACE("acpi_purge_cached_objects"); @@ -513,3 +515,5 @@ acpi_status acpi_purge_cached_objects(void) (void)acpi_os_purge_cache(acpi_gbl_ps_node_ext_cache); return_ACPI_STATUS(AE_OK); } + +ACPI_EXPORT_SYMBOL(acpi_purge_cached_objects) diff --git a/include/acpi/acconfig.h b/include/acpi/acconfig.h index 788502256222..ebe793fc137f 100644 --- a/include/acpi/acconfig.h +++ b/include/acpi/acconfig.h @@ -63,7 +63,7 @@ /* Current ACPICA subsystem version in YYYYMMDD format */ -#define ACPI_CA_VERSION 0x20060217 +#define ACPI_CA_VERSION 0x20060310 /* * OS name, used for the _OS object. The _OS object is essentially obsolete, @@ -102,9 +102,9 @@ #define ACPI_MAX_SEMAPHORE_COUNT 256 -/* Max reference count (for debug only) */ +/* Maximum object reference count (detects object deletion issues) */ -#define ACPI_MAX_REFERENCE_COUNT 0x400 +#define ACPI_MAX_REFERENCE_COUNT 0x800 /* Size of cached memory mapping for system memory operation region */ diff --git a/include/acpi/acdisasm.h b/include/acpi/acdisasm.h index 0727c132bd3c..f004461a7753 100644 --- a/include/acpi/acdisasm.h +++ b/include/acpi/acdisasm.h @@ -50,6 +50,7 @@ #define BLOCK_PAREN 1 #define BLOCK_BRACE 2 #define BLOCK_COMMA_LIST 4 +#define ACPI_DEFAULT_RESNAME *(u32 *) "__RD" struct acpi_external_list { char *path; @@ -78,6 +79,11 @@ typedef acpi_status(*asl_walk_callback) (union acpi_parse_object * op, u32 level, void *context); +struct acpi_resource_tag { + u32 bit_index; + char *tag; +}; + /* * dmwalk */ @@ -85,6 +91,11 @@ void acpi_dm_disassemble(struct acpi_walk_state *walk_state, union acpi_parse_object *origin, u32 num_opcodes); +void +acpi_dm_walk_parse_tree(union acpi_parse_object *op, + asl_walk_callback descending_callback, + asl_walk_callback ascending_callback, void *context); + /* * dmopcode */ @@ -167,6 +178,7 @@ void acpi_dm_dump_integer64(u64 value, char *name); void acpi_dm_resource_template(struct acpi_op_walk_info *info, + union acpi_parse_object *op, u8 * byte_data, u32 byte_count); u8 acpi_dm_is_resource_template(union acpi_parse_object *op); @@ -177,6 +189,8 @@ void acpi_dm_bit_list(u16 mask); void acpi_dm_decode_attribute(u8 attribute); +void acpi_dm_descriptor_name(void); + /* * dmresrcl */ @@ -251,4 +265,13 @@ acpi_dm_vendor_small_descriptor(union aml_resource *resource, */ void acpi_dm_add_to_external_list(char *path); +/* + * dmrestag + */ +void acpi_dm_find_resources(union acpi_parse_object *root); + +void +acpi_dm_check_resource_reference(union acpi_parse_object *op, + struct acpi_walk_state *walk_state); + #endif /* __ACDISASM_H__ */ diff --git a/include/acpi/aclocal.h b/include/acpi/aclocal.h index 8361820d2970..94fbf96ed3df 100644 --- a/include/acpi/aclocal.h +++ b/include/acpi/aclocal.h @@ -129,7 +129,7 @@ typedef u8 acpi_owner_id; struct acpi_mutex_info { acpi_mutex mutex; u32 use_count; - u32 thread_id; + acpi_thread_id thread_id; }; /* Lock flag parameter for various interfaces */ @@ -181,9 +181,9 @@ struct acpi_namespace_node { u8 owner_id; /* Who created this node */ u8 flags; - /* Fields used by the ASL compiler only */ + /* Fields used by the ASL compiler and disassembler only */ -#ifdef ACPI_ASL_COMPILER +#ifdef ACPI_LARGE_NAMESPACE_NODE u32 value; union acpi_parse_object *op; #endif @@ -479,7 +479,7 @@ struct acpi_pscope_state { struct acpi_thread_state { ACPI_STATE_COMMON struct acpi_walk_state *walk_state_list; /* Head of list of walk_states for this thread */ union acpi_operand_object *acquired_mutex_list; /* List of all currently acquired mutexes */ - u32 thread_id; /* Running thread ID */ + acpi_thread_id thread_id; /* Running thread ID */ u8 current_sync_level; /* Mutex Sync (nested acquire) level */ }; diff --git a/include/acpi/acmacros.h b/include/acpi/acmacros.h index dd5644dbe946..c8aa73fc6dd3 100644 --- a/include/acpi/acmacros.h +++ b/include/acpi/acmacros.h @@ -713,18 +713,18 @@ /* Memory allocation */ -#define ACPI_MEM_ALLOCATE(a) acpi_ut_allocate((acpi_size)(a),_COMPONENT,_acpi_module_name,__LINE__) -#define ACPI_MEM_CALLOCATE(a) acpi_ut_callocate((acpi_size)(a), _COMPONENT,_acpi_module_name,__LINE__) -#define ACPI_MEM_FREE(a) acpi_os_free(a) +#define ACPI_ALLOCATE(a) acpi_ut_allocate((acpi_size)(a),_COMPONENT,_acpi_module_name,__LINE__) +#define ACPI_ALLOCATE_ZEROED(a) acpi_ut_callocate((acpi_size)(a), _COMPONENT,_acpi_module_name,__LINE__) +#define ACPI_FREE(a) acpi_os_free(a) #define ACPI_MEM_TRACKING(a) #else /* Memory allocation */ -#define ACPI_MEM_ALLOCATE(a) acpi_ut_allocate_and_track((acpi_size)(a),_COMPONENT,_acpi_module_name,__LINE__) -#define ACPI_MEM_CALLOCATE(a) acpi_ut_callocate_and_track((acpi_size)(a), _COMPONENT,_acpi_module_name,__LINE__) -#define ACPI_MEM_FREE(a) acpi_ut_free_and_track(a,_COMPONENT,_acpi_module_name,__LINE__) +#define ACPI_ALLOCATE(a) acpi_ut_allocate_and_track((acpi_size)(a),_COMPONENT,_acpi_module_name,__LINE__) +#define ACPI_ALLOCATE_ZEROED(a) acpi_ut_callocate_and_track((acpi_size)(a), _COMPONENT,_acpi_module_name,__LINE__) +#define ACPI_FREE(a) acpi_ut_free_and_track(a,_COMPONENT,_acpi_module_name,__LINE__) #define ACPI_MEM_TRACKING(a) a #endif /* ACPI_DBG_TRACK_ALLOCATIONS */ diff --git a/include/acpi/acnamesp.h b/include/acpi/acnamesp.h index b667a804fc8a..132d64af24fe 100644 --- a/include/acpi/acnamesp.h +++ b/include/acpi/acnamesp.h @@ -63,6 +63,7 @@ #define ACPI_NS_DONT_OPEN_SCOPE 0x02 #define ACPI_NS_NO_PEER_SEARCH 0x04 #define ACPI_NS_ERROR_IF_FOUND 0x08 +#define ACPI_NS_PREFIX_IS_SCOPE 0x10 #define ACPI_NS_WALK_UNLOCK TRUE #define ACPI_NS_WALK_NO_UNLOCK FALSE @@ -184,6 +185,10 @@ acpi_ns_evaluate_relative(char *pathname, struct acpi_parameter_info *info); */ u32 acpi_ns_opens_scope(acpi_object_type type); +void +acpi_ns_build_external_path(struct acpi_namespace_node *node, + acpi_size size, char *name_buffer); + char *acpi_ns_get_external_pathname(struct acpi_namespace_node *node); char *acpi_ns_name_of_current_scope(struct acpi_walk_state *walk_state); diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h index 970e9a6372c3..91c3cdff28bb 100644 --- a/include/acpi/acpiosxf.h +++ b/include/acpi/acpiosxf.h @@ -161,7 +161,7 @@ acpi_os_remove_interrupt_handler(u32 gsi, acpi_osd_handler service_routine); /* * Threads and Scheduling */ -u32 acpi_os_get_thread_id(void); +acpi_thread_id acpi_os_get_thread_id(void); acpi_status acpi_os_queue_for_execution(u32 priority, diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index 95c3c8b6d618..520f315dd53a 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -288,6 +288,21 @@ typedef acpi_native_uint acpi_size; #define ACPI_UNUSED_VAR #endif +/* + * All ACPICA functions that are available to the rest of the kernel are + * tagged with this macro which can be defined as appropriate for the host. + */ +#ifndef ACPI_EXPORT_SYMBOL +#define ACPI_EXPORT_SYMBOL(symbol) +#endif + +/* + * thread_id is returned by acpi_os_get_thread_id. + */ +#ifndef acpi_thread_id +#define acpi_thread_id acpi_native_uint +#endif + /******************************************************************************* * * Independent types diff --git a/include/acpi/amlresrc.h b/include/acpi/amlresrc.h index fb4735315ad3..e5b42eb38190 100644 --- a/include/acpi/amlresrc.h +++ b/include/acpi/amlresrc.h @@ -45,36 +45,36 @@ #ifndef __AMLRESRC_H #define __AMLRESRC_H -#define ASL_RESNAME_ADDRESS "_ADR" -#define ASL_RESNAME_ALIGNMENT "_ALN" -#define ASL_RESNAME_ADDRESSSPACE "_ASI" -#define ASL_RESNAME_ACCESSSIZE "_ASZ" -#define ASL_RESNAME_TYPESPECIFICATTRIBUTES "_ATT" -#define ASL_RESNAME_BASEADDRESS "_BAS" -#define ASL_RESNAME_BUSMASTER "_BM_" /* Master(1), Slave(0) */ -#define ASL_RESNAME_DECODE "_DEC" -#define ASL_RESNAME_DMA "_DMA" -#define ASL_RESNAME_DMATYPE "_TYP" /* Compatible(0), A(1), B(2), F(3) */ -#define ASL_RESNAME_GRANULARITY "_GRA" -#define ASL_RESNAME_INTERRUPT "_INT" -#define ASL_RESNAME_INTERRUPTLEVEL "_LL_" /* active_lo(1), active_hi(0) */ -#define ASL_RESNAME_INTERRUPTSHARE "_SHR" /* Shareable(1), no_share(0) */ -#define ASL_RESNAME_INTERRUPTTYPE "_HE_" /* Edge(1), Level(0) */ -#define ASL_RESNAME_LENGTH "_LEN" -#define ASL_RESNAME_MEMATTRIBUTES "_MTP" /* Memory(0), Reserved(1), ACPI(2), NVS(3) */ -#define ASL_RESNAME_MEMTYPE "_MEM" /* non_cache(0), Cacheable(1) Cache+combine(2), Cache+prefetch(3) */ -#define ASL_RESNAME_MAXADDR "_MAX" -#define ASL_RESNAME_MINADDR "_MIN" -#define ASL_RESNAME_MAXTYPE "_MAF" -#define ASL_RESNAME_MINTYPE "_MIF" -#define ASL_RESNAME_REGISTERBITOFFSET "_RBO" -#define ASL_RESNAME_REGISTERBITWIDTH "_RBW" -#define ASL_RESNAME_RANGETYPE "_RNG" -#define ASL_RESNAME_READWRITETYPE "_RW_" /* read_only(0), Writeable (1) */ -#define ASL_RESNAME_TRANSLATION "_TRA" -#define ASL_RESNAME_TRANSTYPE "_TRS" /* Sparse(1), Dense(0) */ -#define ASL_RESNAME_TYPE "_TTP" /* Translation(1), Static (0) */ -#define ASL_RESNAME_XFERTYPE "_SIz" /* 8(0), 8_and16(1), 16(2) */ +#define ACPI_RESTAG_ADDRESS "_ADR" +#define ACPI_RESTAG_ALIGNMENT "_ALN" +#define ACPI_RESTAG_ADDRESSSPACE "_ASI" +#define ACPI_RESTAG_ACCESSSIZE "_ASZ" +#define ACPI_RESTAG_TYPESPECIFICATTRIBUTES "_ATT" +#define ACPI_RESTAG_BASEADDRESS "_BAS" +#define ACPI_RESTAG_BUSMASTER "_BM_" /* Master(1), Slave(0) */ +#define ACPI_RESTAG_DECODE "_DEC" +#define ACPI_RESTAG_DMA "_DMA" +#define ACPI_RESTAG_DMATYPE "_TYP" /* Compatible(0), A(1), B(2), F(3) */ +#define ACPI_RESTAG_GRANULARITY "_GRA" +#define ACPI_RESTAG_INTERRUPT "_INT" +#define ACPI_RESTAG_INTERRUPTLEVEL "_LL_" /* active_lo(1), active_hi(0) */ +#define ACPI_RESTAG_INTERRUPTSHARE "_SHR" /* Shareable(1), no_share(0) */ +#define ACPI_RESTAG_INTERRUPTTYPE "_HE_" /* Edge(1), Level(0) */ +#define ACPI_RESTAG_LENGTH "_LEN" +#define ACPI_RESTAG_MEMATTRIBUTES "_MTP" /* Memory(0), Reserved(1), ACPI(2), NVS(3) */ +#define ACPI_RESTAG_MEMTYPE "_MEM" /* non_cache(0), Cacheable(1) Cache+combine(2), Cache+prefetch(3) */ +#define ACPI_RESTAG_MAXADDR "_MAX" +#define ACPI_RESTAG_MINADDR "_MIN" +#define ACPI_RESTAG_MAXTYPE "_MAF" +#define ACPI_RESTAG_MINTYPE "_MIF" +#define ACPI_RESTAG_REGISTERBITOFFSET "_RBO" +#define ACPI_RESTAG_REGISTERBITWIDTH "_RBW" +#define ACPI_RESTAG_RANGETYPE "_RNG" +#define ACPI_RESTAG_READWRITETYPE "_RW_" /* read_only(0), Writeable (1) */ +#define ACPI_RESTAG_TRANSLATION "_TRA" +#define ACPI_RESTAG_TRANSTYPE "_TRS" /* Sparse(1), Dense(0) */ +#define ACPI_RESTAG_TYPE "_TTP" /* Translation(1), Static (0) */ +#define ACPI_RESTAG_XFERTYPE "_SIz" /* 8(0), 8_and16(1), 16(2) */ /* Default sizes for "small" resource descriptors */ @@ -266,6 +266,7 @@ struct aml_resource_generic_register { union aml_resource { /* Descriptor headers */ + u8 descriptor_type; struct aml_resource_small_header small_header; struct aml_resource_large_header large_header; diff --git a/include/acpi/platform/acenv.h b/include/acpi/platform/acenv.h index 223ec6467108..d5a7f566c018 100644 --- a/include/acpi/platform/acenv.h +++ b/include/acpi/platform/acenv.h @@ -59,6 +59,7 @@ #define ACPI_APPLICATION #define ACPI_DISASSEMBLER #define ACPI_NO_METHOD_EXECUTION +#define ACPI_LARGE_NAMESPACE_NODE #endif #ifdef ACPI_EXEC_APP @@ -76,6 +77,7 @@ #define ACPI_APPLICATION #define ACPI_DISASSEMBLER #define ACPI_CONSTANT_EVAL_ONLY +#define ACPI_LARGE_NAMESPACE_NODE #endif #ifdef ACPI_APPLICATION @@ -271,8 +273,8 @@ typedef char *va_list; /* * Storage alignment properties */ -#define _AUPBND (sizeof (acpi_native_uint) - 1) -#define _ADNBND (sizeof (acpi_native_uint) - 1) +#define _AUPBND (sizeof (acpi_native_int) - 1) +#define _ADNBND (sizeof (acpi_native_int) - 1) /* * Variable argument list macro definitions diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h index 2e6d54569ee8..2f5bb5bd76b7 100644 --- a/include/acpi/platform/aclinux.h +++ b/include/acpi/platform/aclinux.h @@ -52,27 +52,22 @@ #include #include #include +#include #include #include #include #include #include +#include -#define strtoul simple_strtoul - -#define ACPI_MACHINE_WIDTH BITS_PER_LONG +/* Host-dependent types and defines */ -/* Type(s) for the OSL */ - -#ifdef ACPI_USE_LOCAL_CACHE -#define acpi_cache_t struct acpi_memory_list -#else -#include -#define acpi_cache_t kmem_cache_t -#endif +#define ACPI_MACHINE_WIDTH BITS_PER_LONG +#define acpi_cache_t kmem_cache_t +#define ACPI_EXPORT_SYMBOL(symbol) EXPORT_SYMBOL(symbol); +#define strtoul simple_strtoul /* Full namespace pathname length limit - arbitrary */ - #define ACPI_PATHNAME_MAX 256 #else /* !__KERNEL__ */ -- cgit v1.2.3 From ec7381d6bfd3e7b8d2880dd5e9d03b131b0603f6 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Sat, 1 Apr 2006 05:12:23 -0500 Subject: ACPI: inline trivial acpi_os_get_thread_id() acpi_os_get_thread_id() is used only for debugging code that is not enabled on Linux, so stub it out. Signed-off-by: Len Brown --- drivers/acpi/osl.c | 8 -------- include/acpi/platform/aclinux.h | 4 ++++ 2 files changed, 4 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 13b5fd5854a8..56d97f1d108f 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -896,14 +896,6 @@ u8 acpi_os_writable(void *ptr, acpi_size len) } #endif -u32 acpi_os_get_thread_id(void) -{ - if (!in_atomic()) - return current->pid; - - return 0; -} - acpi_status acpi_os_signal(u32 function, void *info) { switch (function) { diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h index 2f5bb5bd76b7..b5655a665ba8 100644 --- a/include/acpi/platform/aclinux.h +++ b/include/acpi/platform/aclinux.h @@ -99,4 +99,8 @@ #define acpi_cpu_flags unsigned long +#define acpi_thread_id u32 + +static inline acpi_thread_id acpi_os_get_thread_id(void) { return 0; } + #endif /* __ACLINUX_H__ */ -- cgit v1.2.3 From e1211e3fa7fd05ff0d4f597fd37e40de8acc6784 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 1 Apr 2006 01:38:18 +0900 Subject: [PATCH] libata: implement ata_dev_enabled and disabled() This patch renames ata_dev_present() to ata_dev_enabled() and adds ata_dev_disabled(). This is to discern the state where a device is present but disabled from not-present state. This disctinction is necessary when configuring transfer mode because device selection timing must not be violated even if a device fails to configure. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/scsi/libata-core.c | 24 ++++++++++++------------ drivers/scsi/libata-scsi.c | 4 ++-- drivers/scsi/sata_mv.c | 2 +- drivers/scsi/sata_sil.c | 2 +- include/linux/libata.h | 16 +++++++++++++--- 5 files changed, 29 insertions(+), 19 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 559abe4ea4e9..c10c550da38b 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -411,7 +411,7 @@ static const char *sata_spd_string(unsigned int spd) static void ata_dev_disable(struct ata_port *ap, struct ata_device *dev) { - if (ata_dev_present(dev)) { + if (ata_dev_enabled(dev)) { printk(KERN_WARNING "ata%u: dev %u disabled\n", ap->id, dev->devno); dev->class++; @@ -1222,7 +1222,7 @@ static int ata_dev_configure(struct ata_port *ap, struct ata_device *dev, unsigned int xfer_mask; int i, rc; - if (!ata_dev_present(dev)) { + if (!ata_dev_enabled(dev)) { DPRINTK("ENTER/EXIT (host %u, dev %u) -- nodev\n", ap->id, dev->devno); return 0; @@ -1401,7 +1401,7 @@ static int ata_bus_probe(struct ata_port *ap) dev->class = classes[i]; - if (!ata_dev_present(dev)) + if (!ata_dev_enabled(dev)) continue; WARN_ON(dev->id != NULL); @@ -1565,7 +1565,7 @@ void sata_phy_reset(struct ata_port *ap) struct ata_device *ata_dev_pair(struct ata_port *ap, struct ata_device *adev) { struct ata_device *pair = &ap->device[1 - adev->devno]; - if (!ata_dev_present(pair)) + if (!ata_dev_enabled(pair)) return NULL; return pair; } @@ -1778,7 +1778,7 @@ static int ata_host_set_pio(struct ata_port *ap) for (i = 0; i < ATA_MAX_DEVICES; i++) { struct ata_device *dev = &ap->device[i]; - if (!ata_dev_present(dev)) + if (!ata_dev_enabled(dev)) continue; if (!dev->pio_mode) { @@ -1802,7 +1802,7 @@ static void ata_host_set_dma(struct ata_port *ap) for (i = 0; i < ATA_MAX_DEVICES; i++) { struct ata_device *dev = &ap->device[i]; - if (!ata_dev_present(dev) || !dev->dma_mode) + if (!ata_dev_enabled(dev) || !dev->dma_mode) continue; dev->xfer_mode = dev->dma_mode; @@ -1830,7 +1830,7 @@ static void ata_set_mode(struct ata_port *ap) struct ata_device *dev = &ap->device[i]; unsigned int pio_mask, dma_mask; - if (!ata_dev_present(dev)) + if (!ata_dev_enabled(dev)) continue; ata_dev_xfermask(ap, dev); @@ -1858,7 +1858,7 @@ static void ata_set_mode(struct ata_port *ap) for (i = 0; i < ATA_MAX_DEVICES; i++) { struct ata_device *dev = &ap->device[i]; - if (!ata_dev_present(dev)) + if (!ata_dev_enabled(dev)) continue; rc = ata_dev_set_mode(ap, dev); @@ -2550,7 +2550,7 @@ int ata_dev_revalidate(struct ata_port *ap, struct ata_device *dev, u16 *id; int rc; - if (!ata_dev_present(dev)) + if (!ata_dev_enabled(dev)) return -ENODEV; class = dev->class; @@ -2679,7 +2679,7 @@ static void ata_dev_xfermask(struct ata_port *ap, struct ata_device *dev) /* FIXME: Use port-wide xfermask for now */ for (i = 0; i < ATA_MAX_DEVICES; i++) { struct ata_device *d = &ap->device[i]; - if (!ata_dev_present(d)) + if (!ata_dev_enabled(d)) continue; xfer_mask &= ata_pack_xfermask(d->pio_mask, d->mwdma_mask, d->udma_mask); @@ -4299,7 +4299,7 @@ int ata_device_resume(struct ata_port *ap, struct ata_device *dev) ap->flags &= ~ATA_FLAG_SUSPENDED; ata_set_mode(ap); } - if (!ata_dev_present(dev)) + if (!ata_dev_enabled(dev)) return 0; if (dev->class == ATA_DEV_ATA) ata_start_drive(ap, dev); @@ -4317,7 +4317,7 @@ int ata_device_resume(struct ata_port *ap, struct ata_device *dev) */ int ata_device_suspend(struct ata_port *ap, struct ata_device *dev, pm_message_t state) { - if (!ata_dev_present(dev)) + if (!ata_dev_enabled(dev)) return 0; if (dev->class == ATA_DEV_ATA) ata_flush_cache(ap, dev); diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 53f5b0d9161c..c1a4b29a9ae1 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -2349,7 +2349,7 @@ ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev) (scsidev->lun != 0))) return NULL; - if (unlikely(!ata_dev_present(dev))) + if (unlikely(!ata_dev_enabled(dev))) return NULL; if (!atapi_enabled || (ap->flags & ATA_FLAG_NO_ATAPI)) { @@ -2743,7 +2743,7 @@ void ata_scsi_scan_host(struct ata_port *ap) for (i = 0; i < ATA_MAX_DEVICES; i++) { dev = &ap->device[i]; - if (ata_dev_present(dev)) + if (ata_dev_enabled(dev)) scsi_scan_target(&ap->host->shost_gendev, 0, i, 0, 0); } } diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c index fa901fd65085..0f7d334aadcc 100644 --- a/drivers/scsi/sata_mv.c +++ b/drivers/scsi/sata_mv.c @@ -1991,7 +1991,7 @@ comreset_retry: tf.nsect = readb((void __iomem *) ap->ioaddr.nsect_addr); dev->class = ata_dev_classify(&tf); - if (!ata_dev_present(dev)) { + if (!ata_dev_enabled(dev)) { VPRINTK("Port disabled post-sig: No device present.\n"); ata_port_disable(ap); } diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c index 18c296c56899..d6c7086a5379 100644 --- a/drivers/scsi/sata_sil.c +++ b/drivers/scsi/sata_sil.c @@ -264,7 +264,7 @@ static void sil_post_set_mode (struct ata_port *ap) for (i = 0; i < 2; i++) { dev = &ap->device[i]; - if (!ata_dev_present(dev)) + if (!ata_dev_enabled(dev)) dev_mode[i] = 0; /* PIO0/1/2 */ else if (dev->flags & ATA_DFLAG_PIO) dev_mode[i] = 1; /* PIO3/4 */ diff --git a/include/linux/libata.h b/include/linux/libata.h index 0d61357604d5..c6883ba8cba9 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -672,14 +672,24 @@ static inline unsigned int ata_tag_valid(unsigned int tag) return (tag < ATA_MAX_QUEUE) ? 1 : 0; } -static inline unsigned int ata_class_present(unsigned int class) +static inline unsigned int ata_class_enabled(unsigned int class) { return class == ATA_DEV_ATA || class == ATA_DEV_ATAPI; } -static inline unsigned int ata_dev_present(const struct ata_device *dev) +static inline unsigned int ata_class_disabled(unsigned int class) { - return ata_class_present(dev->class); + return class == ATA_DEV_ATA_UNSUP || class == ATA_DEV_ATAPI_UNSUP; +} + +static inline unsigned int ata_dev_enabled(const struct ata_device *dev) +{ + return ata_class_enabled(dev->class); +} + +static inline unsigned int ata_dev_disabled(const struct ata_device *dev) +{ + return ata_class_disabled(dev->class); } static inline u8 ata_chk_status(struct ata_port *ap) -- cgit v1.2.3 From c12ea918ee175ceb3a258cd81f1c43e897d0c0bc Mon Sep 17 00:00:00 2001 From: Ashok Raj Date: Tue, 28 Mar 2006 17:04:00 -0500 Subject: x86_64: Remove stale lapic definition from apicdef.h Signed-off-by: Ashok Raj Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- include/asm-i386/apicdef.h | 1 - include/asm-x86_64/apicdef.h | 2 -- 2 files changed, 3 deletions(-) (limited to 'include') diff --git a/include/asm-i386/apicdef.h b/include/asm-i386/apicdef.h index 5e4a35af2921..9f6995341fdc 100644 --- a/include/asm-i386/apicdef.h +++ b/include/asm-i386/apicdef.h @@ -121,7 +121,6 @@ */ #define u32 unsigned int -#define lapic ((volatile struct local_apic *)APIC_BASE) struct local_apic { diff --git a/include/asm-x86_64/apicdef.h b/include/asm-x86_64/apicdef.h index 5a48e9bcf218..1dd40067c67c 100644 --- a/include/asm-x86_64/apicdef.h +++ b/include/asm-x86_64/apicdef.h @@ -137,8 +137,6 @@ */ #define u32 unsigned int -#define lapic ((volatile struct local_apic *)APIC_BASE) - struct local_apic { /*000*/ struct { u32 __reserved[4]; } __reserved_01; -- cgit v1.2.3 From 002c8054fa8d0f1afce2b0c728be32d338b9293a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 2 Apr 2006 17:54:46 +0900 Subject: [PATCH] libata: implement ata_dev_absent() For the time being we cannot use ata_dev_present() as it was renamed to ata_dev_enabled() but we still need presence test. Implement negation of the test. Conveniently, the negated result is needed in more places. This is suggested by Jeff Garzik. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- include/linux/libata.h | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'include') diff --git a/include/linux/libata.h b/include/linux/libata.h index c6883ba8cba9..0f8e3720edd9 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -682,6 +682,11 @@ static inline unsigned int ata_class_disabled(unsigned int class) return class == ATA_DEV_ATA_UNSUP || class == ATA_DEV_ATAPI_UNSUP; } +static inline unsigned int ata_class_absent(unsigned int class) +{ + return !ata_class_enabled(class) && !ata_class_disabled(class); +} + static inline unsigned int ata_dev_enabled(const struct ata_device *dev) { return ata_class_enabled(dev->class); @@ -692,6 +697,11 @@ static inline unsigned int ata_dev_disabled(const struct ata_device *dev) return ata_class_disabled(dev->class); } +static inline unsigned int ata_dev_absent(const struct ata_device *dev) +{ + return ata_class_absent(dev->class); +} + static inline u8 ata_chk_status(struct ata_port *ap) { return ap->ops->check_status(ap); -- cgit v1.2.3 From 1c3fae4d7eb121933341443c37d3bbee43c0fb68 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 2 Apr 2006 20:53:28 +0900 Subject: [PATCH] libata: implement ap->sata_spd_limit and helpers ap->sata_spd_limit contrains SATA PHY speed of the port. It is initialized to the configured value prior to probing thus preserving BIOS configured value. hardreset is responsible for applying SPD limit and sata_std_hardreset() is updated to do that. SATA SPD limit will be used to enhance failure handling during probing and later by EH. This patch also normalizes some comments around affected code. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/scsi/libata-core.c | 143 +++++++++++++++++++++++++++++++++++++++++++-- include/linux/libata.h | 1 + 2 files changed, 140 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 3acf56200d87..63488673765f 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -65,6 +65,7 @@ static unsigned int ata_dev_init_params(struct ata_port *ap, struct ata_device *dev, u16 heads, u16 sectors); +static int ata_down_sata_spd_limit(struct ata_port *ap); static int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev); static unsigned int ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev); @@ -1596,6 +1597,120 @@ void ata_port_disable(struct ata_port *ap) ap->flags |= ATA_FLAG_PORT_DISABLED; } +/** + * ata_down_sata_spd_limit - adjust SATA spd limit downward + * @ap: Port to adjust SATA spd limit for + * + * Adjust SATA spd limit of @ap downward. Note that this + * function only adjusts the limit. The change must be applied + * using ata_set_sata_spd(). + * + * LOCKING: + * Inherited from caller. + * + * RETURNS: + * 0 on success, negative errno on failure + */ +static int ata_down_sata_spd_limit(struct ata_port *ap) +{ + u32 spd, mask; + int highbit; + + if (ap->cbl != ATA_CBL_SATA || !ap->ops->scr_read) + return -EOPNOTSUPP; + + mask = ap->sata_spd_limit; + if (mask <= 1) + return -EINVAL; + highbit = fls(mask) - 1; + mask &= ~(1 << highbit); + + spd = (scr_read(ap, SCR_STATUS) >> 4) & 0xf; + if (spd <= 1) + return -EINVAL; + spd--; + mask &= (1 << spd) - 1; + if (!mask) + return -EINVAL; + + ap->sata_spd_limit = mask; + + printk(KERN_WARNING "ata%u: limiting SATA link speed to %s\n", + ap->id, sata_spd_string(fls(mask))); + + return 0; +} + +static int __ata_set_sata_spd_needed(struct ata_port *ap, u32 *scontrol) +{ + u32 spd, limit; + + if (ap->sata_spd_limit == UINT_MAX) + limit = 0; + else + limit = fls(ap->sata_spd_limit); + + spd = (*scontrol >> 4) & 0xf; + *scontrol = (*scontrol & ~0xf0) | ((limit & 0xf) << 4); + + return spd != limit; +} + +/** + * ata_set_sata_spd_needed - is SATA spd configuration needed + * @ap: Port in question + * + * Test whether the spd limit in SControl matches + * @ap->sata_spd_limit. This function is used to determine + * whether hardreset is necessary to apply SATA spd + * configuration. + * + * LOCKING: + * Inherited from caller. + * + * RETURNS: + * 1 if SATA spd configuration is needed, 0 otherwise. + */ +static int ata_set_sata_spd_needed(struct ata_port *ap) +{ + u32 scontrol; + + if (ap->cbl != ATA_CBL_SATA || !ap->ops->scr_read) + return 0; + + scontrol = scr_read(ap, SCR_CONTROL); + + return __ata_set_sata_spd_needed(ap, &scontrol); +} + +/** + * ata_set_sata_spd - set SATA spd according to spd limit + * @ap: Port to set SATA spd for + * + * Set SATA spd of @ap according to sata_spd_limit. + * + * LOCKING: + * Inherited from caller. + * + * RETURNS: + * 0 if spd doesn't need to be changed, 1 if spd has been + * changed. -EOPNOTSUPP if SCR registers are inaccessible. + */ +static int ata_set_sata_spd(struct ata_port *ap) +{ + u32 scontrol; + + if (ap->cbl != ATA_CBL_SATA || !ap->ops->scr_read) + return -EOPNOTSUPP; + + scontrol = scr_read(ap, SCR_CONTROL); + if (!__ata_set_sata_spd_needed(ap, &scontrol)) + return 0; + + scr_write(ap, SCR_CONTROL, scontrol); + return 1; +} + /* * This mode timing computation functionality is ported over from * drivers/ide/ide-timing.h and was originally written by Vojtech Pavlik @@ -2165,7 +2280,14 @@ static int sata_phy_resume(struct ata_port *ap) void ata_std_probeinit(struct ata_port *ap) { if ((ap->flags & ATA_FLAG_SATA) && ap->ops->scr_read) { + u32 spd; + sata_phy_resume(ap); + + spd = (scr_read(ap, SCR_CONTROL) & 0xf0) >> 4; + if (spd) + ap->sata_spd_limit &= (1 << spd) - 1; + if (sata_dev_present(ap)) ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT); } @@ -2253,18 +2375,30 @@ int sata_std_hardreset(struct ata_port *ap, int verbose, unsigned int *class) DPRINTK("ENTER\n"); - /* Issue phy wake/reset */ + if (ata_set_sata_spd_needed(ap)) { + /* SATA spec says nothing about how to reconfigure + * spd. To be on the safe side, turn off phy during + * reconfiguration. This works for at least ICH7 AHCI + * and Sil3124. + */ + scontrol = scr_read(ap, SCR_CONTROL); + scontrol = (scontrol & 0x0f0) | 0x302; + scr_write_flush(ap, SCR_CONTROL, scontrol); + + ata_set_sata_spd(ap); + } + + /* issue phy wake/reset */ scontrol = scr_read(ap, SCR_CONTROL); scontrol = (scontrol & 0x0f0) | 0x301; scr_write_flush(ap, SCR_CONTROL, scontrol); - /* - * Couldn't find anything in SATA I/II specs, but AHCI-1.1 + /* Couldn't find anything in SATA I/II specs, but AHCI-1.1 * 10.4.2 says at least 1 ms. */ msleep(1); - /* Bring phy back */ + /* bring phy back */ sata_phy_resume(ap); /* TODO: phy layer with polling, timeouts, etc. */ @@ -4454,6 +4588,7 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host, ap->flags |= ent->host_flags; ap->ops = ent->port_ops; ap->cbl = ATA_CBL_NONE; + ap->sata_spd_limit = UINT_MAX; ap->active_tag = ATA_TAG_POISON; ap->last_ctl = 0xFF; diff --git a/include/linux/libata.h b/include/linux/libata.h index 0f8e3720edd9..a5207e66ca52 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -397,6 +397,7 @@ struct ata_port { unsigned int mwdma_mask; unsigned int udma_mask; unsigned int cbl; /* cable type; ATA_CBL_xxx */ + unsigned int sata_spd_limit; /* SATA PHY speed limit */ struct ata_device device[ATA_MAX_DEVICES]; -- cgit v1.2.3 From 14d2bac1877ed4e2cc940d1680db1a4f29225811 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 2 Apr 2006 17:54:46 +0900 Subject: [PATCH] libata: improve ata_bus_probe() Improve ata_bus_probe() such that configuration failures are handled better. Each device is given ATA_PROBE_MAX_TRIES chances, but any non-transient error (revalidation failure with -ENODEV, configuration failure with -EINVAL...) disables the device directly. Any IO error results in SATA PHY speed down and ata_set_mode() failure lowers transfer mode. The last try always puts a device into PIO-0. After each failure, the whole port is reset to make sure that the controller and all the devices are in a known and stable state. The reset also applies SATA SPD configuration if necessary. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/scsi/libata-core.c | 65 ++++++++++++++++++++++++++++++++++------------ include/linux/libata.h | 3 +++ 2 files changed, 52 insertions(+), 16 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 68fa64d24721..33b5bff58cc3 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -1370,11 +1370,18 @@ err_out_nosup: static int ata_bus_probe(struct ata_port *ap) { unsigned int classes[ATA_MAX_DEVICES]; - int i, rc, found = 0; + int tries[ATA_MAX_DEVICES]; + int i, rc, down_xfermask; struct ata_device *dev; ata_port_probe(ap); + for (i = 0; i < ATA_MAX_DEVICES; i++) + tries[i] = ATA_PROBE_MAX_TRIES; + + retry: + down_xfermask = 0; + /* reset and determine device classes */ for (i = 0; i < ATA_MAX_DEVICES; i++) classes[i] = ATA_DEV_UNKNOWN; @@ -1404,21 +1411,23 @@ static int ata_bus_probe(struct ata_port *ap) dev = &ap->device[i]; dev->class = classes[i]; - if (!ata_dev_enabled(dev)) - continue; - - WARN_ON(dev->id != NULL); - if (ata_dev_read_id(ap, dev, &dev->class, 1, &dev->id)) { - dev->class = ATA_DEV_NONE; - continue; + if (!tries[i]) { + ata_down_xfermask_limit(ap, dev, 1); + ata_dev_disable(ap, dev); } - if (ata_dev_configure(ap, dev, 1)) { - ata_dev_disable(ap, dev); + if (!ata_dev_enabled(dev)) continue; - } - found = 1; + kfree(dev->id); + dev->id = NULL; + rc = ata_dev_read_id(ap, dev, &dev->class, 1, &dev->id); + if (rc) + goto fail; + + rc = ata_dev_configure(ap, dev, 1); + if (rc) + goto fail; } /* configure transfer mode */ @@ -1427,12 +1436,18 @@ static int ata_bus_probe(struct ata_port *ap) * return error code and failing device on failure as * ata_set_mode() does. */ - if (found) - ap->ops->set_mode(ap); + for (i = 0; i < ATA_MAX_DEVICES; i++) + if (ata_dev_enabled(&ap->device[i])) { + ap->ops->set_mode(ap); + break; + } rc = 0; } else { - while (ata_set_mode(ap, &dev)) - ata_dev_disable(ap, dev); + rc = ata_set_mode(ap, &dev); + if (rc) { + down_xfermask = 1; + goto fail; + } } for (i = 0; i < ATA_MAX_DEVICES; i++) @@ -1443,6 +1458,24 @@ static int ata_bus_probe(struct ata_port *ap) ata_port_disable(ap); ap->ops->port_disable(ap); return -ENODEV; + + fail: + switch (rc) { + case -EINVAL: + case -ENODEV: + tries[dev->devno] = 0; + break; + case -EIO: + ata_down_sata_spd_limit(ap); + /* fall through */ + default: + tries[dev->devno]--; + if (down_xfermask && + ata_down_xfermask_limit(ap, dev, tries[dev->devno] == 1)) + tries[dev->devno] = 0; + } + + goto retry; } /** diff --git a/include/linux/libata.h b/include/linux/libata.h index a5207e66ca52..a4a1e6304e78 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -211,6 +211,9 @@ enum { /* Masks for port functions */ ATA_PORT_PRIMARY = (1 << 0), ATA_PORT_SECONDARY = (1 << 1), + + /* how hard are we gonna try to probe/recover devices */ + ATA_PROBE_MAX_TRIES = 3, }; enum hsm_task_states { -- cgit v1.2.3 From c43c555c3a6db7f0b55fd9b66d7ecff16e827d4e Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 2 Apr 2006 18:51:52 +0900 Subject: [PATCH] libata: ATA_FLAG_IN_EH is not used, kill it Kill unused flag ATA_FLAG_IN_EH. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/scsi/libata-scsi.c | 17 ++++------------- include/linux/libata.h | 1 - 2 files changed, 4 insertions(+), 14 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index c1a4b29a9ae1..bcbf71e9895b 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -779,20 +779,15 @@ enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd) int ata_scsi_error(struct Scsi_Host *host) { - struct ata_port *ap; - unsigned long flags; + struct ata_port *ap = (struct ata_port *)&host->hostdata[0]; DPRINTK("ENTER\n"); - ap = (struct ata_port *) &host->hostdata[0]; + /* synchronize with IRQ handler and port task */ + spin_unlock_wait(&ap->host_set->lock); + ata_port_flush_task(ap); - spin_lock_irqsave(&ap->host_set->lock, flags); - WARN_ON(ap->flags & ATA_FLAG_IN_EH); - ap->flags |= ATA_FLAG_IN_EH; WARN_ON(ata_qc_from_tag(ap, ap->active_tag) == NULL); - spin_unlock_irqrestore(&ap->host_set->lock, flags); - - ata_port_flush_task(ap); ap->ops->eng_timeout(ap); @@ -800,10 +795,6 @@ int ata_scsi_error(struct Scsi_Host *host) scsi_eh_flush_done_q(&ap->eh_done_q); - spin_lock_irqsave(&ap->host_set->lock, flags); - ap->flags &= ~ATA_FLAG_IN_EH; - spin_unlock_irqrestore(&ap->host_set->lock, flags); - DPRINTK("EXIT\n"); return 0; } diff --git a/include/linux/libata.h b/include/linux/libata.h index a4a1e6304e78..e20b0bfbd5f2 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -152,7 +152,6 @@ enum { ATA_FLAG_IRQ_MASK = (1 << 14), /* Mask IRQ in PIO xfers */ ATA_FLAG_FLUSH_PORT_TASK = (1 << 15), /* Flush port task */ - ATA_FLAG_IN_EH = (1 << 16), /* EH in progress */ ATA_QCFLAG_ACTIVE = (1 << 1), /* cmd not yet ack'd to scsi lyer */ ATA_QCFLAG_SG = (1 << 3), /* have s/g table? */ -- cgit v1.2.3 From 949b38af40a0b88b7267908b1554a45b97b5b737 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 2 Apr 2006 18:51:52 +0900 Subject: [PATCH] libata: clean up constants * Reorder ATA_DFLAG_* such that feature flags determined by ata_dev_configure() are on lower bits. Reserve lower eight bits for this purpose and allocate dynamic flags from bit 8. * Reorder ATA_FLAG_* such that feature flags determined during driver initiailization are on bits 0:15, dynamic flags on 16:23 and LLDD specific flags on 24:31. * Kill trailing white space and lower-case an one line comment for consistency. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- include/linux/libata.h | 61 ++++++++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 29 deletions(-) (limited to 'include') diff --git a/include/linux/libata.h b/include/linux/libata.h index e20b0bfbd5f2..b7488a31e320 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -120,9 +120,10 @@ enum { ATA_SHT_USE_CLUSTERING = 1, /* struct ata_device stuff */ - ATA_DFLAG_LBA48 = (1 << 0), /* device supports LBA48 */ - ATA_DFLAG_PIO = (1 << 1), /* device currently in PIO mode */ - ATA_DFLAG_LBA = (1 << 2), /* device supports LBA */ + ATA_DFLAG_LBA = (1 << 0), /* device supports LBA */ + ATA_DFLAG_LBA48 = (1 << 1), /* device supports LBA48 */ + + ATA_DFLAG_PIO = (1 << 8), /* device currently in PIO mode */ ATA_DEV_UNKNOWN = 0, /* unknown device */ ATA_DEV_ATA = 1, /* ATA device */ @@ -132,32 +133,34 @@ enum { ATA_DEV_NONE = 5, /* no device */ /* struct ata_port flags */ - ATA_FLAG_SLAVE_POSS = (1 << 1), /* host supports slave dev */ + ATA_FLAG_SLAVE_POSS = (1 << 0), /* host supports slave dev */ /* (doesn't imply presence) */ - ATA_FLAG_PORT_DISABLED = (1 << 2), /* port is disabled, ignore it */ - ATA_FLAG_SATA = (1 << 3), - ATA_FLAG_NO_LEGACY = (1 << 4), /* no legacy mode check */ - ATA_FLAG_SRST = (1 << 5), /* (obsolete) use ATA SRST, not E.D.D. */ - ATA_FLAG_MMIO = (1 << 6), /* use MMIO, not PIO */ - ATA_FLAG_SATA_RESET = (1 << 7), /* (obsolete) use COMRESET */ - ATA_FLAG_PIO_DMA = (1 << 8), /* PIO cmds via DMA */ - ATA_FLAG_NOINTR = (1 << 9), /* FIXME: Remove this once - * proper HSM is in place. */ - ATA_FLAG_DEBUGMSG = (1 << 10), - ATA_FLAG_NO_ATAPI = (1 << 11), /* No ATAPI support */ - - ATA_FLAG_SUSPENDED = (1 << 12), /* port is suspended */ - - ATA_FLAG_PIO_LBA48 = (1 << 13), /* Host DMA engine is LBA28 only */ - ATA_FLAG_IRQ_MASK = (1 << 14), /* Mask IRQ in PIO xfers */ - - ATA_FLAG_FLUSH_PORT_TASK = (1 << 15), /* Flush port task */ - - ATA_QCFLAG_ACTIVE = (1 << 1), /* cmd not yet ack'd to scsi lyer */ - ATA_QCFLAG_SG = (1 << 3), /* have s/g table? */ - ATA_QCFLAG_SINGLE = (1 << 4), /* no s/g, just a single buffer */ + ATA_FLAG_SATA = (1 << 1), + ATA_FLAG_NO_LEGACY = (1 << 2), /* no legacy mode check */ + ATA_FLAG_MMIO = (1 << 3), /* use MMIO, not PIO */ + ATA_FLAG_SRST = (1 << 4), /* (obsolete) use ATA SRST, not E.D.D. */ + ATA_FLAG_SATA_RESET = (1 << 5), /* (obsolete) use COMRESET */ + ATA_FLAG_NO_ATAPI = (1 << 6), /* No ATAPI support */ + ATA_FLAG_PIO_DMA = (1 << 7), /* PIO cmds via DMA */ + ATA_FLAG_PIO_LBA48 = (1 << 8), /* Host DMA engine is LBA28 only */ + ATA_FLAG_IRQ_MASK = (1 << 9), /* Mask IRQ in PIO xfers */ + + ATA_FLAG_NOINTR = (1 << 16), /* FIXME: Remove this once + * proper HSM is in place. */ + ATA_FLAG_DEBUGMSG = (1 << 17), + ATA_FLAG_FLUSH_PORT_TASK = (1 << 18), /* flush port task */ + + ATA_FLAG_PORT_DISABLED = (1 << 19), /* port is disabled, ignore it */ + ATA_FLAG_SUSPENDED = (1 << 20), /* port is suspended */ + + /* bits 24:31 of ap->flags are reserved for LLDD specific flags */ + + /* struct ata_queued_cmd flags */ + ATA_QCFLAG_ACTIVE = (1 << 0), /* cmd not yet ack'd to scsi lyer */ + ATA_QCFLAG_SG = (1 << 1), /* have s/g table? */ + ATA_QCFLAG_SINGLE = (1 << 2), /* no s/g, just a single buffer */ ATA_QCFLAG_DMAMAP = ATA_QCFLAG_SG | ATA_QCFLAG_SINGLE, - ATA_QCFLAG_EH_SCHEDULED = (1 << 5), /* EH scheduled */ + ATA_QCFLAG_EH_SCHEDULED = (1 << 3), /* EH scheduled */ /* host set flags */ ATA_HOST_SIMPLEX = (1 << 0), /* Host is simplex, one DMA channel per host_set only */ @@ -206,8 +209,8 @@ enum { /* size of buffer to pad xfers ending on unaligned boundaries */ ATA_DMA_PAD_SZ = 4, ATA_DMA_PAD_BUF_SZ = ATA_DMA_PAD_SZ * ATA_MAX_QUEUE, - - /* Masks for port functions */ + + /* masks for port functions */ ATA_PORT_PRIMARY = (1 << 0), ATA_PORT_SECONDARY = (1 << 1), -- cgit v1.2.3 From 198e0fed9e59461fc1890dd8b75ec72d14638873 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 2 Apr 2006 18:51:52 +0900 Subject: [PATCH] libata: rename ATA_FLAG_PORT_DISABLED to ATA_FLAG_DISABLED Rename ATA_FLAG_PORT_DISABLED to ATA_FLAG_DISABLED for consistency. (ATA_FLAG_* are always about ports). Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/scsi/libata-core.c | 18 +++++++++--------- drivers/scsi/libata-scsi.c | 2 +- drivers/scsi/pdc_adma.c | 4 ++-- drivers/scsi/sata_mv.c | 2 +- drivers/scsi/sata_nv.c | 2 +- drivers/scsi/sata_promise.c | 2 +- drivers/scsi/sata_qstor.c | 4 ++-- drivers/scsi/sata_sil24.c | 2 +- drivers/scsi/sata_sx4.c | 2 +- drivers/scsi/sata_vsc.c | 2 +- include/linux/libata.h | 2 +- 11 files changed, 21 insertions(+), 21 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index f39352a3ac11..53226b16355c 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -1045,7 +1045,7 @@ ata_exec_internal(struct ata_port *ap, struct ata_device *dev, * * Kill the following code as soon as those drivers are fixed. */ - if (ap->flags & ATA_FLAG_PORT_DISABLED) { + if (ap->flags & ATA_FLAG_DISABLED) { err_mask |= AC_ERR_SYSTEM; ata_port_probe(ap); } @@ -1395,7 +1395,7 @@ static int ata_bus_probe(struct ata_port *ap) } else { ap->ops->phy_reset(ap); - if (!(ap->flags & ATA_FLAG_PORT_DISABLED)) + if (!(ap->flags & ATA_FLAG_DISABLED)) for (i = 0; i < ATA_MAX_DEVICES; i++) classes[i] = ap->device[i].class; @@ -1491,7 +1491,7 @@ static int ata_bus_probe(struct ata_port *ap) void ata_port_probe(struct ata_port *ap) { - ap->flags &= ~ATA_FLAG_PORT_DISABLED; + ap->flags &= ~ATA_FLAG_DISABLED; } /** @@ -1565,7 +1565,7 @@ void __sata_phy_reset(struct ata_port *ap) else ata_port_disable(ap); - if (ap->flags & ATA_FLAG_PORT_DISABLED) + if (ap->flags & ATA_FLAG_DISABLED) return; if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) { @@ -1590,7 +1590,7 @@ void __sata_phy_reset(struct ata_port *ap) void sata_phy_reset(struct ata_port *ap) { __sata_phy_reset(ap); - if (ap->flags & ATA_FLAG_PORT_DISABLED) + if (ap->flags & ATA_FLAG_DISABLED) return; ata_bus_reset(ap); } @@ -1629,7 +1629,7 @@ void ata_port_disable(struct ata_port *ap) { ap->device[0].class = ATA_DEV_NONE; ap->device[1].class = ATA_DEV_NONE; - ap->flags |= ATA_FLAG_PORT_DISABLED; + ap->flags |= ATA_FLAG_DISABLED; } /** @@ -2251,7 +2251,7 @@ static unsigned int ata_bus_softreset(struct ata_port *ap, * Obtains host_set lock. * * SIDE EFFECTS: - * Sets ATA_FLAG_PORT_DISABLED if bus reset fails. + * Sets ATA_FLAG_DISABLED if bus reset fails. */ void ata_bus_reset(struct ata_port *ap) @@ -4468,7 +4468,7 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs) ap = host_set->ports[i]; if (ap && - !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) { + !(ap->flags & (ATA_FLAG_DISABLED | ATA_FLAG_NOINTR))) { struct ata_queued_cmd *qc; qc = ata_qc_from_tag(ap, ap->active_tag); @@ -4689,7 +4689,7 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host, host->unique_id = ata_unique_id++; host->max_cmd_len = 12; - ap->flags = ATA_FLAG_PORT_DISABLED; + ap->flags = ATA_FLAG_DISABLED; ap->id = host->unique_id; ap->host = host; ap->ctl = ATA_DEVCTL_OBS; diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index bcbf71e9895b..096bdffbde11 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -2728,7 +2728,7 @@ void ata_scsi_scan_host(struct ata_port *ap) struct ata_device *dev; unsigned int i; - if (ap->flags & ATA_FLAG_PORT_DISABLED) + if (ap->flags & ATA_FLAG_DISABLED) return; for (i = 0; i < ATA_MAX_DEVICES; i++) { diff --git a/drivers/scsi/pdc_adma.c b/drivers/scsi/pdc_adma.c index 3c85c4b66e19..d64073dd028f 100644 --- a/drivers/scsi/pdc_adma.c +++ b/drivers/scsi/pdc_adma.c @@ -456,7 +456,7 @@ static inline unsigned int adma_intr_pkt(struct ata_host_set *host_set) continue; handled = 1; adma_enter_reg_mode(ap); - if (ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR)) + if (ap->flags & (ATA_FLAG_DISABLED | ATA_FLAG_NOINTR)) continue; pp = ap->private_data; if (!pp || pp->state != adma_state_pkt) @@ -481,7 +481,7 @@ static inline unsigned int adma_intr_mmio(struct ata_host_set *host_set) for (port_no = 0; port_no < host_set->n_ports; ++port_no) { struct ata_port *ap; ap = host_set->ports[port_no]; - if (ap && (!(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR)))) { + if (ap && (!(ap->flags & (ATA_FLAG_DISABLED | ATA_FLAG_NOINTR)))) { struct ata_queued_cmd *qc; struct adma_port_priv *pp = ap->private_data; if (!pp || pp->state != adma_state_mmio) diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c index 0f7d334aadcc..e9152f850003 100644 --- a/drivers/scsi/sata_mv.c +++ b/drivers/scsi/sata_mv.c @@ -1397,7 +1397,7 @@ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant, } } - if (ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR)) + if (ap->flags & (ATA_FLAG_DISABLED | ATA_FLAG_NOINTR)) continue; err_mask = ac_err_mask(ata_status); diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c index f77bf183dfab..72721ac482d8 100644 --- a/drivers/scsi/sata_nv.c +++ b/drivers/scsi/sata_nv.c @@ -280,7 +280,7 @@ static irqreturn_t nv_interrupt (int irq, void *dev_instance, ap = host_set->ports[i]; if (ap && - !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) { + !(ap->flags & (ATA_FLAG_DISABLED | ATA_FLAG_NOINTR))) { struct ata_queued_cmd *qc; qc = ata_qc_from_tag(ap, ap->active_tag); diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c index cc928c68a479..9557c7aa45e0 100644 --- a/drivers/scsi/sata_promise.c +++ b/drivers/scsi/sata_promise.c @@ -534,7 +534,7 @@ static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *r ap = host_set->ports[i]; tmp = mask & (1 << (i + 1)); if (tmp && ap && - !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) { + !(ap->flags & (ATA_FLAG_DISABLED | ATA_FLAG_NOINTR))) { struct ata_queued_cmd *qc; qc = ata_qc_from_tag(ap, ap->active_tag); diff --git a/drivers/scsi/sata_qstor.c b/drivers/scsi/sata_qstor.c index 9ffe1ef0d205..8ef042a09448 100644 --- a/drivers/scsi/sata_qstor.c +++ b/drivers/scsi/sata_qstor.c @@ -396,7 +396,7 @@ static inline unsigned int qs_intr_pkt(struct ata_host_set *host_set) sff1, sff0, port_no, sHST, sDST); handled = 1; if (ap && !(ap->flags & - (ATA_FLAG_PORT_DISABLED|ATA_FLAG_NOINTR))) { + (ATA_FLAG_DISABLED|ATA_FLAG_NOINTR))) { struct ata_queued_cmd *qc; struct qs_port_priv *pp = ap->private_data; if (!pp || pp->state != qs_state_pkt) @@ -429,7 +429,7 @@ static inline unsigned int qs_intr_mmio(struct ata_host_set *host_set) struct ata_port *ap; ap = host_set->ports[port_no]; if (ap && - !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) { + !(ap->flags & (ATA_FLAG_DISABLED | ATA_FLAG_NOINTR))) { struct ata_queued_cmd *qc; struct qs_port_priv *pp = ap->private_data; if (!pp || pp->state != qs_state_mmio) diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c index 068c98a4111b..c34f6dabf418 100644 --- a/drivers/scsi/sata_sil24.c +++ b/drivers/scsi/sata_sil24.c @@ -770,7 +770,7 @@ static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs * for (i = 0; i < host_set->n_ports; i++) if (status & (1 << i)) { struct ata_port *ap = host_set->ports[i]; - if (ap && !(ap->flags & ATA_FLAG_PORT_DISABLED)) { + if (ap && !(ap->flags & ATA_FLAG_DISABLED)) { sil24_host_intr(host_set->ports[i]); handled++; } else diff --git a/drivers/scsi/sata_sx4.c b/drivers/scsi/sata_sx4.c index ae70f60c7c0d..3af28ef76fd9 100644 --- a/drivers/scsi/sata_sx4.c +++ b/drivers/scsi/sata_sx4.c @@ -834,7 +834,7 @@ static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_re tmp = mask & (1 << i); VPRINTK("seq %u, port_no %u, ap %p, tmp %x\n", i, port_no, ap, tmp); if (tmp && ap && - !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) { + !(ap->flags & (ATA_FLAG_DISABLED | ATA_FLAG_NOINTR))) { struct ata_queued_cmd *qc; qc = ata_qc_from_tag(ap, ap->active_tag); diff --git a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c index 836bbbb26ff2..cecc1f76256b 100644 --- a/drivers/scsi/sata_vsc.c +++ b/drivers/scsi/sata_vsc.c @@ -222,7 +222,7 @@ static irqreturn_t vsc_sata_interrupt (int irq, void *dev_instance, ap = host_set->ports[i]; if (ap && !(ap->flags & - (ATA_FLAG_PORT_DISABLED|ATA_FLAG_NOINTR))) { + (ATA_FLAG_DISABLED|ATA_FLAG_NOINTR))) { struct ata_queued_cmd *qc; qc = ata_qc_from_tag(ap, ap->active_tag); diff --git a/include/linux/libata.h b/include/linux/libata.h index b7488a31e320..890262f44d0a 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -150,7 +150,7 @@ enum { ATA_FLAG_DEBUGMSG = (1 << 17), ATA_FLAG_FLUSH_PORT_TASK = (1 << 18), /* flush port task */ - ATA_FLAG_PORT_DISABLED = (1 << 19), /* port is disabled, ignore it */ + ATA_FLAG_DISABLED = (1 << 19), /* port is disabled, ignore it */ ATA_FLAG_SUSPENDED = (1 << 20), /* port is suspended */ /* bits 24:31 of ap->flags are reserved for LLDD specific flags */ -- cgit v1.2.3 From ea1dd4e13010eb9dd5ffb4bfabbb472bc238bebb Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 2 Apr 2006 18:51:53 +0900 Subject: [PATCH] libata: clear only affected flags during ata_dev_configure() ata_dev_configure() should not clear dynamic device flags determined elsewhere. Lower eight bits are reserved for feature flags, define ATA_DFLAG_CFG_MASK and clear only those bits before configuring device. Without this patch, ATA_DFLAG_PIO gets turned off during revalidation making PIO mode unuseable. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/scsi/libata-core.c | 2 +- include/linux/libata.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 53226b16355c..985283cbcbdf 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -1241,7 +1241,7 @@ static int ata_dev_configure(struct ata_port *ap, struct ata_device *dev, id[84], id[85], id[86], id[87], id[88]); /* initialize to-be-configured parameters */ - dev->flags = 0; + dev->flags &= ~ATA_DFLAG_CFG_MASK; dev->max_sectors = 0; dev->cdb_len = 0; dev->n_sectors = 0; diff --git a/include/linux/libata.h b/include/linux/libata.h index 890262f44d0a..cbbc821fe22c 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -122,6 +122,7 @@ enum { /* struct ata_device stuff */ ATA_DFLAG_LBA = (1 << 0), /* device supports LBA */ ATA_DFLAG_LBA48 = (1 << 1), /* device supports LBA48 */ + ATA_DFLAG_CFG_MASK = (1 << 8) - 1, ATA_DFLAG_PIO = (1 << 8), /* device currently in PIO mode */ -- cgit v1.2.3 From 2719736779da2c7fbb17d3de16c817b429bfeb9c Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 2 Apr 2006 18:51:53 +0900 Subject: [PATCH] libata: add ATA_QCFLAG_IO Add a new qc flag ATA_QCFLAG_IO. This flag gets set for normal IO commands originating from SCSI midlayer. This information will be used by EH to determine transfer speed reconfiguration. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/scsi/libata-scsi.c | 1 + include/linux/libata.h | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 096bdffbde11..234e1cadb070 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -1188,6 +1188,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicm u64 block; u32 n_block; + qc->flags |= ATA_QCFLAG_IO; tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; if (scsicmd[0] == WRITE_10 || scsicmd[0] == WRITE_6 || diff --git a/include/linux/libata.h b/include/linux/libata.h index cbbc821fe22c..a6d829cb0567 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -161,7 +161,8 @@ enum { ATA_QCFLAG_SG = (1 << 1), /* have s/g table? */ ATA_QCFLAG_SINGLE = (1 << 2), /* no s/g, just a single buffer */ ATA_QCFLAG_DMAMAP = ATA_QCFLAG_SG | ATA_QCFLAG_SINGLE, - ATA_QCFLAG_EH_SCHEDULED = (1 << 3), /* EH scheduled */ + ATA_QCFLAG_IO = (1 << 3), /* standard IO command */ + ATA_QCFLAG_EH_SCHEDULED = (1 << 4), /* EH scheduled */ /* host set flags */ ATA_HOST_SIMPLEX = (1 << 0), /* Host is simplex, one DMA channel per host_set only */ -- cgit v1.2.3 From ece1d63619df010b8c4f08e43755e2a03f3b6eed Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 2 Apr 2006 18:51:53 +0900 Subject: [PATCH] libata: separate out libata-eh.c A lot of EH codes are about to be added to libata. Separate out libata-eh.c. ata_scsi_timed_out(), ata_scsi_error(), ata_qc_timeout(), ata_eng_timeout(), ata_eh_qc_complete() and ata_eh_qc_retry() are moved. No code is changed by this patch. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/scsi/Makefile | 2 +- drivers/scsi/libata-core.c | 102 +----------------- drivers/scsi/libata-eh.c | 264 +++++++++++++++++++++++++++++++++++++++++++++ drivers/scsi/libata-scsi.c | 130 ---------------------- drivers/scsi/libata.h | 4 +- include/linux/libata.h | 12 ++- 6 files changed, 281 insertions(+), 233 deletions(-) create mode 100644 drivers/scsi/libata-eh.c (limited to 'include') diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index e513c3158ad9..503f189dab3b 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -165,7 +165,7 @@ ncr53c8xx-flags-$(CONFIG_SCSI_ZALON) \ CFLAGS_ncr53c8xx.o := $(ncr53c8xx-flags-y) $(ncr53c8xx-flags-m) zalon7xx-objs := zalon.o ncr53c8xx.o NCR_Q720_mod-objs := NCR_Q720.o ncr53c8xx.o -libata-objs := libata-core.o libata-scsi.o libata-bmdma.o +libata-objs := libata-core.o libata-scsi.o libata-bmdma.o libata-eh.o oktagon_esp_mod-objs := oktagon_esp.o oktagon_io.o # Files generated that shall be removed upon make clean diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 66b48b11fa0e..186a9ce4f072 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -4015,99 +4015,6 @@ err_out: ata_poll_qc_complete(qc); } -/** - * ata_qc_timeout - Handle timeout of queued command - * @qc: Command that timed out - * - * Some part of the kernel (currently, only the SCSI layer) - * has noticed that the active command on port @ap has not - * completed after a specified length of time. Handle this - * condition by disabling DMA (if necessary) and completing - * transactions, with error if necessary. - * - * This also handles the case of the "lost interrupt", where - * for some reason (possibly hardware bug, possibly driver bug) - * an interrupt was not delivered to the driver, even though the - * transaction completed successfully. - * - * LOCKING: - * Inherited from SCSI layer (none, can sleep) - */ - -static void ata_qc_timeout(struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - struct ata_host_set *host_set = ap->host_set; - u8 host_stat = 0, drv_stat; - unsigned long flags; - - DPRINTK("ENTER\n"); - - ap->hsm_task_state = HSM_ST_IDLE; - - spin_lock_irqsave(&host_set->lock, flags); - - switch (qc->tf.protocol) { - - case ATA_PROT_DMA: - case ATA_PROT_ATAPI_DMA: - host_stat = ap->ops->bmdma_status(ap); - - /* before we do anything else, clear DMA-Start bit */ - ap->ops->bmdma_stop(qc); - - /* fall through */ - - default: - ata_altstatus(ap); - drv_stat = ata_chk_status(ap); - - /* ack bmdma irq events */ - ap->ops->irq_clear(ap); - - printk(KERN_ERR "ata%u: command 0x%x timeout, stat 0x%x host_stat 0x%x\n", - ap->id, qc->tf.command, drv_stat, host_stat); - - /* complete taskfile transaction */ - qc->err_mask |= ac_err_mask(drv_stat); - break; - } - - spin_unlock_irqrestore(&host_set->lock, flags); - - ata_eh_qc_complete(qc); - - DPRINTK("EXIT\n"); -} - -/** - * ata_eng_timeout - Handle timeout of queued command - * @ap: Port on which timed-out command is active - * - * Some part of the kernel (currently, only the SCSI layer) - * has noticed that the active command on port @ap has not - * completed after a specified length of time. Handle this - * condition by disabling DMA (if necessary) and completing - * transactions, with error if necessary. - * - * This also handles the case of the "lost interrupt", where - * for some reason (possibly hardware bug, possibly driver bug) - * an interrupt was not delivered to the driver, even though the - * transaction completed successfully. - * - * LOCKING: - * Inherited from SCSI layer (none, can sleep) - */ - -void ata_eng_timeout(struct ata_port *ap) -{ - DPRINTK("ENTER\n"); - - ata_qc_timeout(ata_qc_from_tag(ap, ap->active_tag)); - - DPRINTK("EXIT\n"); -} - /** * ata_qc_new - Request an available ATA command, for queueing * @ap: Port associated with device @dev @@ -5145,7 +5052,6 @@ EXPORT_SYMBOL_GPL(ata_sg_init); EXPORT_SYMBOL_GPL(ata_sg_init_one); EXPORT_SYMBOL_GPL(__ata_qc_complete); EXPORT_SYMBOL_GPL(ata_qc_issue_prot); -EXPORT_SYMBOL_GPL(ata_eng_timeout); EXPORT_SYMBOL_GPL(ata_tf_load); EXPORT_SYMBOL_GPL(ata_tf_read); EXPORT_SYMBOL_GPL(ata_noop_dev_select); @@ -5185,15 +5091,12 @@ EXPORT_SYMBOL_GPL(ata_busy_sleep); EXPORT_SYMBOL_GPL(ata_port_queue_task); EXPORT_SYMBOL_GPL(ata_scsi_ioctl); EXPORT_SYMBOL_GPL(ata_scsi_queuecmd); -EXPORT_SYMBOL_GPL(ata_scsi_error); EXPORT_SYMBOL_GPL(ata_scsi_slave_config); EXPORT_SYMBOL_GPL(ata_scsi_release); EXPORT_SYMBOL_GPL(ata_host_intr); EXPORT_SYMBOL_GPL(ata_id_string); EXPORT_SYMBOL_GPL(ata_id_c_string); EXPORT_SYMBOL_GPL(ata_scsi_simulate); -EXPORT_SYMBOL_GPL(ata_eh_qc_complete); -EXPORT_SYMBOL_GPL(ata_eh_qc_retry); EXPORT_SYMBOL_GPL(ata_pio_need_iordy); EXPORT_SYMBOL_GPL(ata_timing_compute); @@ -5215,3 +5118,8 @@ EXPORT_SYMBOL_GPL(ata_device_suspend); EXPORT_SYMBOL_GPL(ata_device_resume); EXPORT_SYMBOL_GPL(ata_scsi_device_suspend); EXPORT_SYMBOL_GPL(ata_scsi_device_resume); + +EXPORT_SYMBOL_GPL(ata_scsi_error); +EXPORT_SYMBOL_GPL(ata_eng_timeout); +EXPORT_SYMBOL_GPL(ata_eh_qc_complete); +EXPORT_SYMBOL_GPL(ata_eh_qc_retry); diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c new file mode 100644 index 000000000000..e73f5612aea8 --- /dev/null +++ b/drivers/scsi/libata-eh.c @@ -0,0 +1,264 @@ +/* + * libata-eh.c - libata error handling + * + * Maintained by: Jeff Garzik + * Please ALWAYS copy linux-ide@vger.kernel.org + * on emails. + * + * Copyright 2006 Tejun Heo + * + * + * 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, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, + * USA. + * + * + * libata documentation is available via 'make {ps|pdf}docs', + * as Documentation/DocBook/libata.* + * + * Hardware documentation available from http://www.t13.org/ and + * http://www.sata-io.org/ + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "libata.h" + +/** + * ata_scsi_timed_out - SCSI layer time out callback + * @cmd: timed out SCSI command + * + * Handles SCSI layer timeout. We race with normal completion of + * the qc for @cmd. If the qc is already gone, we lose and let + * the scsi command finish (EH_HANDLED). Otherwise, the qc has + * timed out and EH should be invoked. Prevent ata_qc_complete() + * from finishing it by setting EH_SCHEDULED and return + * EH_NOT_HANDLED. + * + * LOCKING: + * Called from timer context + * + * RETURNS: + * EH_HANDLED or EH_NOT_HANDLED + */ +enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd) +{ + struct Scsi_Host *host = cmd->device->host; + struct ata_port *ap = (struct ata_port *) &host->hostdata[0]; + unsigned long flags; + struct ata_queued_cmd *qc; + enum scsi_eh_timer_return ret = EH_HANDLED; + + DPRINTK("ENTER\n"); + + spin_lock_irqsave(&ap->host_set->lock, flags); + qc = ata_qc_from_tag(ap, ap->active_tag); + if (qc) { + WARN_ON(qc->scsicmd != cmd); + qc->flags |= ATA_QCFLAG_EH_SCHEDULED; + qc->err_mask |= AC_ERR_TIMEOUT; + ret = EH_NOT_HANDLED; + } + spin_unlock_irqrestore(&ap->host_set->lock, flags); + + DPRINTK("EXIT, ret=%d\n", ret); + return ret; +} + +/** + * ata_scsi_error - SCSI layer error handler callback + * @host: SCSI host on which error occurred + * + * Handles SCSI-layer-thrown error events. + * + * LOCKING: + * Inherited from SCSI layer (none, can sleep) + * + * RETURNS: + * Zero. + */ +int ata_scsi_error(struct Scsi_Host *host) +{ + struct ata_port *ap = (struct ata_port *)&host->hostdata[0]; + + DPRINTK("ENTER\n"); + + /* synchronize with IRQ handler and port task */ + spin_unlock_wait(&ap->host_set->lock); + ata_port_flush_task(ap); + + WARN_ON(ata_qc_from_tag(ap, ap->active_tag) == NULL); + + ap->ops->eng_timeout(ap); + + WARN_ON(host->host_failed || !list_empty(&host->eh_cmd_q)); + + scsi_eh_flush_done_q(&ap->eh_done_q); + + DPRINTK("EXIT\n"); + return 0; +} + +/** + * ata_qc_timeout - Handle timeout of queued command + * @qc: Command that timed out + * + * Some part of the kernel (currently, only the SCSI layer) + * has noticed that the active command on port @ap has not + * completed after a specified length of time. Handle this + * condition by disabling DMA (if necessary) and completing + * transactions, with error if necessary. + * + * This also handles the case of the "lost interrupt", where + * for some reason (possibly hardware bug, possibly driver bug) + * an interrupt was not delivered to the driver, even though the + * transaction completed successfully. + * + * LOCKING: + * Inherited from SCSI layer (none, can sleep) + */ +static void ata_qc_timeout(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct ata_host_set *host_set = ap->host_set; + u8 host_stat = 0, drv_stat; + unsigned long flags; + + DPRINTK("ENTER\n"); + + ap->hsm_task_state = HSM_ST_IDLE; + + spin_lock_irqsave(&host_set->lock, flags); + + switch (qc->tf.protocol) { + + case ATA_PROT_DMA: + case ATA_PROT_ATAPI_DMA: + host_stat = ap->ops->bmdma_status(ap); + + /* before we do anything else, clear DMA-Start bit */ + ap->ops->bmdma_stop(qc); + + /* fall through */ + + default: + ata_altstatus(ap); + drv_stat = ata_chk_status(ap); + + /* ack bmdma irq events */ + ap->ops->irq_clear(ap); + + printk(KERN_ERR "ata%u: command 0x%x timeout, stat 0x%x host_stat 0x%x\n", + ap->id, qc->tf.command, drv_stat, host_stat); + + /* complete taskfile transaction */ + qc->err_mask |= ac_err_mask(drv_stat); + break; + } + + spin_unlock_irqrestore(&host_set->lock, flags); + + ata_eh_qc_complete(qc); + + DPRINTK("EXIT\n"); +} + +/** + * ata_eng_timeout - Handle timeout of queued command + * @ap: Port on which timed-out command is active + * + * Some part of the kernel (currently, only the SCSI layer) + * has noticed that the active command on port @ap has not + * completed after a specified length of time. Handle this + * condition by disabling DMA (if necessary) and completing + * transactions, with error if necessary. + * + * This also handles the case of the "lost interrupt", where + * for some reason (possibly hardware bug, possibly driver bug) + * an interrupt was not delivered to the driver, even though the + * transaction completed successfully. + * + * LOCKING: + * Inherited from SCSI layer (none, can sleep) + */ +void ata_eng_timeout(struct ata_port *ap) +{ + DPRINTK("ENTER\n"); + + ata_qc_timeout(ata_qc_from_tag(ap, ap->active_tag)); + + DPRINTK("EXIT\n"); +} + +static void ata_eh_scsidone(struct scsi_cmnd *scmd) +{ + /* nada */ +} + +static void __ata_eh_qc_complete(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct scsi_cmnd *scmd = qc->scsicmd; + unsigned long flags; + + spin_lock_irqsave(&ap->host_set->lock, flags); + qc->scsidone = ata_eh_scsidone; + __ata_qc_complete(qc); + WARN_ON(ata_tag_valid(qc->tag)); + spin_unlock_irqrestore(&ap->host_set->lock, flags); + + scsi_eh_finish_cmd(scmd, &ap->eh_done_q); +} + +/** + * ata_eh_qc_complete - Complete an active ATA command from EH + * @qc: Command to complete + * + * Indicate to the mid and upper layers that an ATA command has + * completed. To be used from EH. + */ +void ata_eh_qc_complete(struct ata_queued_cmd *qc) +{ + struct scsi_cmnd *scmd = qc->scsicmd; + scmd->retries = scmd->allowed; + __ata_eh_qc_complete(qc); +} + +/** + * ata_eh_qc_retry - Tell midlayer to retry an ATA command after EH + * @qc: Command to retry + * + * Indicate to the mid and upper layers that an ATA command + * should be retried. To be used from EH. + * + * SCSI midlayer limits the number of retries to scmd->allowed. + * scmd->retries is decremented for commands which get retried + * due to unrelated failures (qc->err_mask is zero). + */ +void ata_eh_qc_retry(struct ata_queued_cmd *qc) +{ + struct scsi_cmnd *scmd = qc->scsicmd; + if (!qc->err_mask && scmd->retries) + scmd->retries--; + __ata_eh_qc_complete(qc); +} diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 44008150d310..745fc263feeb 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -53,7 +53,6 @@ typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc, const u8 *scsicmd); static struct ata_device * ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev); -enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd); #define RW_RECOVERY_MPAGE 0x1 #define RW_RECOVERY_MPAGE_LEN 12 @@ -713,135 +712,6 @@ int ata_scsi_slave_config(struct scsi_device *sdev) return 0; /* scsi layer doesn't check return value, sigh */ } -/** - * ata_scsi_timed_out - SCSI layer time out callback - * @cmd: timed out SCSI command - * - * Handles SCSI layer timeout. We race with normal completion of - * the qc for @cmd. If the qc is already gone, we lose and let - * the scsi command finish (EH_HANDLED). Otherwise, the qc has - * timed out and EH should be invoked. Prevent ata_qc_complete() - * from finishing it by setting EH_SCHEDULED and return - * EH_NOT_HANDLED. - * - * LOCKING: - * Called from timer context - * - * RETURNS: - * EH_HANDLED or EH_NOT_HANDLED - */ -enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd) -{ - struct Scsi_Host *host = cmd->device->host; - struct ata_port *ap = (struct ata_port *) &host->hostdata[0]; - unsigned long flags; - struct ata_queued_cmd *qc; - enum scsi_eh_timer_return ret = EH_HANDLED; - - DPRINTK("ENTER\n"); - - spin_lock_irqsave(&ap->host_set->lock, flags); - qc = ata_qc_from_tag(ap, ap->active_tag); - if (qc) { - WARN_ON(qc->scsicmd != cmd); - qc->flags |= ATA_QCFLAG_EH_SCHEDULED; - qc->err_mask |= AC_ERR_TIMEOUT; - ret = EH_NOT_HANDLED; - } - spin_unlock_irqrestore(&ap->host_set->lock, flags); - - DPRINTK("EXIT, ret=%d\n", ret); - return ret; -} - -/** - * ata_scsi_error - SCSI layer error handler callback - * @host: SCSI host on which error occurred - * - * Handles SCSI-layer-thrown error events. - * - * LOCKING: - * Inherited from SCSI layer (none, can sleep) - * - * RETURNS: - * Zero. - */ - -int ata_scsi_error(struct Scsi_Host *host) -{ - struct ata_port *ap = (struct ata_port *)&host->hostdata[0]; - - DPRINTK("ENTER\n"); - - /* synchronize with IRQ handler and port task */ - spin_unlock_wait(&ap->host_set->lock); - ata_port_flush_task(ap); - - WARN_ON(ata_qc_from_tag(ap, ap->active_tag) == NULL); - - ap->ops->eng_timeout(ap); - - WARN_ON(host->host_failed || !list_empty(&host->eh_cmd_q)); - - scsi_eh_flush_done_q(&ap->eh_done_q); - - DPRINTK("EXIT\n"); - return 0; -} - -static void ata_eh_scsidone(struct scsi_cmnd *scmd) -{ - /* nada */ -} - -static void __ata_eh_qc_complete(struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - struct scsi_cmnd *scmd = qc->scsicmd; - unsigned long flags; - - spin_lock_irqsave(&ap->host_set->lock, flags); - qc->scsidone = ata_eh_scsidone; - __ata_qc_complete(qc); - WARN_ON(ata_tag_valid(qc->tag)); - spin_unlock_irqrestore(&ap->host_set->lock, flags); - - scsi_eh_finish_cmd(scmd, &ap->eh_done_q); -} - -/** - * ata_eh_qc_complete - Complete an active ATA command from EH - * @qc: Command to complete - * - * Indicate to the mid and upper layers that an ATA command has - * completed. To be used from EH. - */ -void ata_eh_qc_complete(struct ata_queued_cmd *qc) -{ - struct scsi_cmnd *scmd = qc->scsicmd; - scmd->retries = scmd->allowed; - __ata_eh_qc_complete(qc); -} - -/** - * ata_eh_qc_retry - Tell midlayer to retry an ATA command after EH - * @qc: Command to retry - * - * Indicate to the mid and upper layers that an ATA command - * should be retried. To be used from EH. - * - * SCSI midlayer limits the number of retries to scmd->allowed. - * scmd->retries is decremented for commands which get retried - * due to unrelated failures (qc->err_mask is zero). - */ -void ata_eh_qc_retry(struct ata_queued_cmd *qc) -{ - struct scsi_cmnd *scmd = qc->scsicmd; - if (!qc->err_mask && scmd->retries) - scmd->retries--; - __ata_eh_qc_complete(qc); -} - /** * ata_scsi_start_stop_xlat - Translate SCSI START STOP UNIT command * @qc: Storage for translated ATA taskfile diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h index 1c755b14521a..75e9bd5833da 100644 --- a/drivers/scsi/libata.h +++ b/drivers/scsi/libata.h @@ -60,7 +60,6 @@ extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg); extern struct scsi_transport_template ata_scsi_transport_template; extern void ata_scsi_scan_host(struct ata_port *ap); -extern int ata_scsi_error(struct Scsi_Host *host); extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen); @@ -90,4 +89,7 @@ extern void ata_scsi_rbuf_fill(struct ata_scsi_args *args, unsigned int (*actor) (struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen)); +/* libata-eh.c */ +extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd); + #endif /* __LIBATA_H__ */ diff --git a/include/linux/libata.h b/include/linux/libata.h index a6d829cb0567..75bdee09c307 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -531,9 +531,6 @@ extern void ata_host_set_remove(struct ata_host_set *host_set); extern int ata_scsi_detect(struct scsi_host_template *sht); extern int ata_scsi_ioctl(struct scsi_device *dev, int cmd, void __user *arg); extern int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)); -extern int ata_scsi_error(struct Scsi_Host *host); -extern void ata_eh_qc_complete(struct ata_queued_cmd *qc); -extern void ata_eh_qc_retry(struct ata_queued_cmd *qc); extern int ata_scsi_release(struct Scsi_Host *host); extern unsigned int ata_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc); extern int ata_scsi_device_resume(struct scsi_device *); @@ -582,7 +579,6 @@ extern void ata_bmdma_stop(struct ata_queued_cmd *qc); extern u8 ata_bmdma_status(struct ata_port *ap); extern void ata_bmdma_irq_clear(struct ata_port *ap); extern void __ata_qc_complete(struct ata_queued_cmd *qc); -extern void ata_eng_timeout(struct ata_port *ap); extern void ata_scsi_simulate(struct ata_port *ap, struct ata_device *dev, struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)); @@ -637,6 +633,14 @@ extern int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bit extern unsigned long ata_pci_default_filter(const struct ata_port *, struct ata_device *, unsigned long); #endif /* CONFIG_PCI */ +/* + * EH + */ +extern int ata_scsi_error(struct Scsi_Host *host); +extern void ata_eng_timeout(struct ata_port *ap); +extern void ata_eh_qc_complete(struct ata_queued_cmd *qc); +extern void ata_eh_qc_retry(struct ata_queued_cmd *qc); + static inline int ata_sg_is_last(struct scatterlist *sg, struct ata_queued_cmd *qc) -- cgit v1.2.3 From 95de719adc94392a95c3c4d0a2d6b8b1ea39d236 Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Tue, 4 Apr 2006 10:57:18 +0800 Subject: [PATCH] libata: convert ATAPI_ENABLE_DMADIR to module parameter Convert the ATAPI_ENABLE_DMADIR compile time option needed by some SATA-PATA bridge to runtime module parameter. Signed-off-by: Albert Lee Signed-off-by: Jeff Garzik --- drivers/scsi/libata-core.c | 4 ++++ drivers/scsi/libata-scsi.c | 6 ++---- drivers/scsi/libata.h | 1 + include/linux/libata.h | 1 - 4 files changed, 7 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 966be3034bf0..3387fe35c54f 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -76,6 +76,10 @@ int atapi_enabled = 1; module_param(atapi_enabled, int, 0444); MODULE_PARM_DESC(atapi_enabled, "Enable discovery of ATAPI devices (0=off, 1=on)"); +int atapi_dmadir = 0; +module_param(atapi_dmadir, int, 0444); +MODULE_PARM_DESC(atapi_dmadir, "Enable ATAPI DMADIR bridge support (0=off, 1=on)"); + int libata_fua = 0; module_param_named(fua, libata_fua, int, 0444); MODULE_PARM_DESC(fua, "FUA support (0=off, 1=on)"); diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 745fc263feeb..c9c001490293 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -2163,11 +2163,9 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd) qc->tf.protocol = ATA_PROT_ATAPI_DMA; qc->tf.feature |= ATAPI_PKT_DMA; -#ifdef ATAPI_ENABLE_DMADIR - /* some SATA bridges need us to indicate data xfer direction */ - if (cmd->sc_data_direction != DMA_TO_DEVICE) + if (atapi_dmadir && (cmd->sc_data_direction != DMA_TO_DEVICE)) + /* some SATA bridges need us to indicate data xfer direction */ qc->tf.feature |= ATAPI_DMADIR; -#endif } qc->nbytes = cmd->bufflen; diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h index e3bd1ddb5387..652c08e3808e 100644 --- a/drivers/scsi/libata.h +++ b/drivers/scsi/libata.h @@ -41,6 +41,7 @@ struct ata_scsi_args { /* libata-core.c */ extern int atapi_enabled; +extern int atapi_dmadir; extern int libata_fua; extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap, struct ata_device *dev); diff --git a/include/linux/libata.h b/include/linux/libata.h index 75bdee09c307..03231cb6b406 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -44,7 +44,6 @@ #undef ATA_NDEBUG /* define to disable quick runtime checks */ #undef ATA_ENABLE_PATA /* define to enable PATA support in some * low-level drivers */ -#undef ATAPI_ENABLE_DMADIR /* enables ATAPI DMADIR bridge support */ /* note: prints function name for you */ -- cgit v1.2.3 From 591f0a4287d0de243493fd0c133c862e1d1f1c97 Mon Sep 17 00:00:00 2001 From: Andy Fleming Date: Sun, 2 Apr 2006 17:42:40 -0500 Subject: Add 85xx CDS to arch/powerpc This patch adds support for 85xx CDS support to arch/powerpc Signed-off-by: Andy Fleming Signed-off-by: Kumar Gala --- arch/powerpc/configs/mpc85xx_cds_defconfig | 846 +++++++++++++++++++++++++++++ arch/powerpc/platforms/85xx/Kconfig | 9 +- arch/powerpc/platforms/85xx/Makefile | 1 + arch/powerpc/platforms/85xx/mpc85xx_cds.c | 359 ++++++++++++ arch/powerpc/platforms/85xx/mpc85xx_cds.h | 43 ++ include/asm-ppc/mpc85xx.h | 3 + 6 files changed, 1260 insertions(+), 1 deletion(-) create mode 100644 arch/powerpc/configs/mpc85xx_cds_defconfig create mode 100644 arch/powerpc/platforms/85xx/mpc85xx_cds.c create mode 100644 arch/powerpc/platforms/85xx/mpc85xx_cds.h (limited to 'include') diff --git a/arch/powerpc/configs/mpc85xx_cds_defconfig b/arch/powerpc/configs/mpc85xx_cds_defconfig new file mode 100644 index 000000000000..9bb022a523fe --- /dev/null +++ b/arch/powerpc/configs/mpc85xx_cds_defconfig @@ -0,0 +1,846 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.16 +# Sun Apr 2 11:23:42 2006 +# +# CONFIG_PPC64 is not set +CONFIG_PPC32=y +CONFIG_PPC_MERGE=y +CONFIG_MMU=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_PPC=y +CONFIG_EARLY_PRINTK=y +CONFIG_GENERIC_NVRAM=y +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_PPC_OF=y +CONFIG_PPC_UDBG_16550=y +# CONFIG_GENERIC_TBSYNC is not set +# CONFIG_DEFAULT_UIMAGE is not set + +# +# Processor support +# +# CONFIG_CLASSIC32 is not set +# CONFIG_PPC_52xx is not set +# CONFIG_PPC_82xx is not set +# CONFIG_PPC_83xx is not set +CONFIG_PPC_85xx=y +# CONFIG_40x is not set +# CONFIG_44x is not set +# CONFIG_8xx is not set +# CONFIG_E200 is not set +CONFIG_85xx=y +CONFIG_E500=y +CONFIG_BOOKE=y +CONFIG_FSL_BOOKE=y +# CONFIG_PHYS_64BIT is not set +CONFIG_SPE=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +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_IKCONFIG is not set +# CONFIG_RELAY is not set +CONFIG_INITRAMFS_SOURCE="" +# 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_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SHMEM=y +CONFIG_SLAB=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +# CONFIG_SLOB is not set + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# Block layer +# +# CONFIG_LBD is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_LSF 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" +CONFIG_MPIC=y +# CONFIG_WANT_EARLY_SERIAL is not set + +# +# Platform support +# +# CONFIG_MPC8540_ADS is not set +CONFIG_MPC85xx_CDS=y +CONFIG_MPC8540=y +CONFIG_PPC_INDIRECT_PCI_BE=y + +# +# Kernel options +# +# CONFIG_HIGHMEM is not set +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=y +CONFIG_MATH_EMULATION=y +CONFIG_ARCH_FLATMEM_ENABLE=y +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=4 +CONFIG_PROC_DEVICETREE=y +# CONFIG_CMDLINE_BOOL is not set +# CONFIG_PM is not set +# CONFIG_SOFTWARE_SUSPEND is not set +# CONFIG_SECCOMP is not set +CONFIG_ISA_DMA_API=y + +# +# Bus options +# +CONFIG_PPC_I8259=y +CONFIG_PPC_INDIRECT_PCI=y +CONFIG_FSL_SOC=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +# CONFIG_PCI_DEBUG is not set + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# PCI Hotplug Support +# +# CONFIG_HOTPLUG_PCI is not set + +# +# Advanced setup +# +# CONFIG_ADVANCED_OPTIONS is not set + +# +# Default settings for advanced configuration options are used +# +CONFIG_HIGHMEM_START=0xfe000000 +CONFIG_LOWMEM_SIZE=0x30000000 +CONFIG_KERNEL_START=0xc0000000 +CONFIG_TASK_SIZE=0x80000000 +CONFIG_BOOT_LOAD=0x00800000 + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_NETDEBUG is not set +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP 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_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +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=y +# 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 + +# +# 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 +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +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) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=32768 +CONFIG_BLK_DEV_INITRD=y +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_IDE_SATA is not set +# CONFIG_BLK_DEV_IDEDISK is not set +# CONFIG_IDEDISK_MULTI_MODE is not set +# 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_GENERIC=y +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +# CONFIG_BLK_DEV_OFFBOARD is not set +CONFIG_BLK_DEV_GENERIC=y +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_SL82C105 is not set +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +# CONFIG_IDEDMA_PCI_AUTO is not set +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_TRIFLEX is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5520 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_SC1200 is not set +# CONFIG_BLK_DEV_PIIX is not set +# CONFIG_BLK_DEV_IT821X is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_PDC202XX_OLD is not set +# CONFIG_BLK_DEV_PDC202XX_NEW is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIIMAGE is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +CONFIG_BLK_DEV_VIA82CXXX=y +# CONFIG_IDE_ARM is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_IVB is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set + +# +# Macintosh device drivers +# +# CONFIG_WINDFARM is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# +# PHY device support +# +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_CASSINI is not set +# CONFIG_NET_VENDOR_3COM is not set + +# +# Tulip family network device support +# +# CONFIG_NET_TULIP is not set +# CONFIG_HP100 is not set +# CONFIG_NET_PCI is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +CONFIG_E1000=y +CONFIG_E1000_NAPI=y +# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SIS190 is not set +# CONFIG_SKGE is not set +# CONFIG_SKY2 is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set +# CONFIG_BNX2 is not set +CONFIG_GIANFAR=y +CONFIG_GFAR_NAPI=y + +# +# Ethernet (10000 Mbit) +# +# CONFIG_CHELSIO_T1 is not set +# CONFIG_IXGB is not set +# CONFIG_S2IO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP 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 + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +CONFIG_GEN_RTC=y +# CONFIG_GEN_RTC_X is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_AGP is not set +# 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 +# +# CONFIG_I2C 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=y +# CONFIG_HWMON_VID is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Misc devices +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARCH_HAS_EHCI=y +# CONFIG_USB is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# LED devices +# +# CONFIG_NEW_LEDS is not set + +# +# InfiniBand support +# +# CONFIG_INFINIBAND is not set + +# +# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) +# + +# +# Real Time Clock +# +# 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=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# 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 is not set +CONFIG_INOTIFY=y +# 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 +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# 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 +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MSDOS_PARTITION is not set +# CONFIG_LDM_PARTITION is not set +# 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 + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set + +# +# Instrumentation Support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +# CONFIG_MAGIC_SYSRQ is not set +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=y +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_UNWIND_INFO is not set +CONFIG_FORCED_INLINING=y +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_DEBUGGER is not set +# CONFIG_BDI_SWITCH is not set +# CONFIG_BOOTX_TEXT is not set +# CONFIG_PPC_EARLY_DEBUG_LPAR is not set +# CONFIG_PPC_EARLY_DEBUG_G5 is not set +# CONFIG_PPC_EARLY_DEBUG_RTAS is not set +# CONFIG_PPC_EARLY_DEBUG_MAPLE is not set +# CONFIG_PPC_EARLY_DEBUG_ISERIES is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Hardware crypto devices +# diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig index 06e371282f57..454fc53289ab 100644 --- a/arch/powerpc/platforms/85xx/Kconfig +++ b/arch/powerpc/platforms/85xx/Kconfig @@ -11,13 +11,20 @@ config MPC8540_ADS help This option enables support for the MPC 8540 ADS board +config MPC85xx_CDS + bool "Freescale MPC85xx CDS" + select DEFAULT_UIMAGE + select PPC_I8259 if PCI + help + This option enables support for the MPC85xx CDS board + endchoice config MPC8540 bool select PPC_UDBG_16550 select PPC_INDIRECT_PCI - default y if MPC8540_ADS + default y if MPC8540_ADS || MPC85xx_CDS config PPC_INDIRECT_PCI_BE bool diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile index ffc4139cb214..7615aa59c78b 100644 --- a/arch/powerpc/platforms/85xx/Makefile +++ b/arch/powerpc/platforms/85xx/Makefile @@ -3,3 +3,4 @@ # obj-$(CONFIG_PPC_85xx) += misc.o pci.o obj-$(CONFIG_MPC8540_ADS) += mpc85xx_ads.o +obj-$(CONFIG_MPC85xx_CDS) += mpc85xx_cds.o diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c new file mode 100644 index 000000000000..18e6e11f7020 --- /dev/null +++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c @@ -0,0 +1,359 @@ +/* + * MPC85xx setup and early boot code plus other random bits. + * + * Maintained by Kumar Gala (see MAINTAINERS for contact information) + * + * Copyright 2005 Freescale Semiconductor Inc. + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "mpc85xx.h" + +#ifndef CONFIG_PCI +unsigned long isa_io_base = 0; +unsigned long isa_mem_base = 0; +#endif + +static int cds_pci_slot = 2; +static volatile u8 *cadmus; + +/* + * Internal interrupts are all Level Sensitive, and Positive Polarity + * + * Note: Likely, this table and the following function should be + * obtained and derived from the OF Device Tree. + */ +static u_char mpc85xx_cds_openpic_initsenses[] __initdata = { + MPC85XX_INTERNAL_IRQ_SENSES, +#if defined(CONFIG_PCI) + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Ext 0: PCI slot 0 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext 1: PCI slot 1 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext 2: PCI slot 2 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext 3: PCI slot 3 */ +#else + 0x0, /* External 0: */ + 0x0, /* External 1: */ + 0x0, /* External 2: */ + 0x0, /* External 3: */ +#endif + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 5: PHY */ + 0x0, /* External 6: */ + 0x0, /* External 7: */ + 0x0, /* External 8: */ + 0x0, /* External 9: */ + 0x0, /* External 10: */ +#ifdef CONFIG_PCI + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext 11: PCI2 slot 0 */ +#else + 0x0, /* External 11: */ +#endif +}; + + +#ifdef CONFIG_PCI +/* + * interrupt routing + */ +int +mpc85xx_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + struct pci_controller *hose = pci_bus_to_hose(dev->bus->number); + + if (!hose->index) + { + /* Handle PCI1 interrupts */ + char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + + /* Note IRQ assignment for slots is based on which slot the elysium is + * in -- in this setup elysium is in slot #2 (this PIRQA as first + * interrupt on slot */ + { + { 0, 1, 2, 3 }, /* 16 - PMC */ + { 0, 1, 2, 3 }, /* 17 P2P (Tsi320) */ + { 0, 1, 2, 3 }, /* 18 - Slot 1 */ + { 1, 2, 3, 0 }, /* 19 - Slot 2 */ + { 2, 3, 0, 1 }, /* 20 - Slot 3 */ + { 3, 0, 1, 2 }, /* 21 - Slot 4 */ + }; + + const long min_idsel = 16, max_idsel = 21, irqs_per_slot = 4; + int i, j; + + for (i = 0; i < 6; i++) + for (j = 0; j < 4; j++) + pci_irq_table[i][j] = + ((pci_irq_table[i][j] + 5 - + cds_pci_slot) & 0x3) + PIRQ0A; + + return PCI_IRQ_TABLE_LOOKUP; + } else { + /* Handle PCI2 interrupts (if we have one) */ + char pci_irq_table[][4] = + { + /* + * We only have one slot and one interrupt + * going to PIRQA - PIRQD */ + { PIRQ1A, PIRQ1A, PIRQ1A, PIRQ1A }, /* 21 - slot 0 */ + }; + + const long min_idsel = 21, max_idsel = 21, irqs_per_slot = 4; + + return PCI_IRQ_TABLE_LOOKUP; + } +} + +#define ARCADIA_HOST_BRIDGE_IDSEL 17 +#define ARCADIA_2ND_BRIDGE_IDSEL 3 + +extern int mpc85xx_pci2_busno; + +int +mpc85xx_exclude_device(u_char bus, u_char devfn) +{ + if (bus == 0 && PCI_SLOT(devfn) == 0) + return PCIBIOS_DEVICE_NOT_FOUND; + if (mpc85xx_pci2_busno) + if (bus == (mpc85xx_pci2_busno) && PCI_SLOT(devfn) == 0) + return PCIBIOS_DEVICE_NOT_FOUND; + /* We explicitly do not go past the Tundra 320 Bridge */ + if ((bus == 1) && (PCI_SLOT(devfn) == ARCADIA_2ND_BRIDGE_IDSEL)) + return PCIBIOS_DEVICE_NOT_FOUND; + if ((bus == 0) && (PCI_SLOT(devfn) == ARCADIA_2ND_BRIDGE_IDSEL)) + return PCIBIOS_DEVICE_NOT_FOUND; + else + return PCIBIOS_SUCCESSFUL; +} + +void __init +mpc85xx_cds_pcibios_fixup(void) +{ + struct pci_dev *dev; + u_char c; + + if ((dev = pci_get_device(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_82C586_1, NULL))) { + /* + * U-Boot does not set the enable bits + * for the IDE device. Force them on here. + */ + pci_read_config_byte(dev, 0x40, &c); + c |= 0x03; /* IDE: Chip Enable Bits */ + pci_write_config_byte(dev, 0x40, c); + + /* + * Since only primary interface works, force the + * IDE function to standard primary IDE interrupt + * w/ 8259 offset + */ + dev->irq = 14; + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); + pci_dev_put(dev); + } + + /* + * Force legacy USB interrupt routing + */ + if ((dev = pci_get_device(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_82C586_2, NULL))) { + dev->irq = 10; + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 10); + pci_dev_put(dev); + } + + if ((dev = pci_get_device(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_82C586_2, dev))) { + dev->irq = 11; + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 11); + pci_dev_put(dev); + } +} +#endif /* CONFIG_PCI */ + +void __init mpc85xx_cds_pic_init(void) +{ + struct mpic *mpic1; + phys_addr_t OpenPIC_PAddr; + + /* Determine the Physical Address of the OpenPIC regs */ + OpenPIC_PAddr = get_immrbase() + MPC85xx_OPENPIC_OFFSET; + + mpic1 = mpic_alloc(OpenPIC_PAddr, + MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, + 4, MPC85xx_OPENPIC_IRQ_OFFSET, 0, 250, + mpc85xx_cds_openpic_initsenses, + sizeof(mpc85xx_cds_openpic_initsenses), " OpenPIC "); + BUG_ON(mpic1 == NULL); + mpic_assign_isu(mpic1, 0, OpenPIC_PAddr + 0x10200); + mpic_assign_isu(mpic1, 1, OpenPIC_PAddr + 0x10280); + mpic_assign_isu(mpic1, 2, OpenPIC_PAddr + 0x10300); + mpic_assign_isu(mpic1, 3, OpenPIC_PAddr + 0x10380); + mpic_assign_isu(mpic1, 4, OpenPIC_PAddr + 0x10400); + mpic_assign_isu(mpic1, 5, OpenPIC_PAddr + 0x10480); + mpic_assign_isu(mpic1, 6, OpenPIC_PAddr + 0x10500); + mpic_assign_isu(mpic1, 7, OpenPIC_PAddr + 0x10580); + + /* dummy mappings to get to 48 */ + mpic_assign_isu(mpic1, 8, OpenPIC_PAddr + 0x10600); + mpic_assign_isu(mpic1, 9, OpenPIC_PAddr + 0x10680); + mpic_assign_isu(mpic1, 10, OpenPIC_PAddr + 0x10700); + mpic_assign_isu(mpic1, 11, OpenPIC_PAddr + 0x10780); + + /* External ints */ + mpic_assign_isu(mpic1, 12, OpenPIC_PAddr + 0x10000); + mpic_assign_isu(mpic1, 13, OpenPIC_PAddr + 0x10080); + mpic_assign_isu(mpic1, 14, OpenPIC_PAddr + 0x10100); + + mpic_init(mpic1); + +#ifdef CONFIG_PCI + mpic_setup_cascade(PIRQ0A, i8259_irq_cascade, NULL); + + i8259_init(0,0); +#endif +} + + +/* + * Setup the architecture + */ +static void __init +mpc85xx_cds_setup_arch(void) +{ + struct device_node *cpu; +#ifdef CONFIG_PCI + struct device_node *np; +#endif + + if (ppc_md.progress) + ppc_md.progress("mpc85xx_cds_setup_arch()", 0); + + cpu = of_find_node_by_type(NULL, "cpu"); + if (cpu != 0) { + unsigned int *fp; + + fp = (int *)get_property(cpu, "clock-frequency", NULL); + if (fp != 0) + loops_per_jiffy = *fp / HZ; + else + loops_per_jiffy = 500000000 / HZ; + of_node_put(cpu); + } + + cadmus = ioremap(CADMUS_BASE, CADMUS_SIZE); + cds_pci_slot = ((cadmus[CM_CSR] >> 6) & 0x3) + 1; + + if (ppc_md.progress) { + char buf[40]; + snprintf(buf, 40, "CDS Version = 0x%x in slot %d\n", + cadmus[CM_VER], cds_pci_slot); + ppc_md.progress(buf, 0); + } + +#ifdef CONFIG_PCI + for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) + add_bridge(np); + + ppc_md.pcibios_fixup = mpc85xx_cds_pcibios_fixup; + ppc_md.pci_swizzle = common_swizzle; + ppc_md.pci_map_irq = mpc85xx_map_irq; + ppc_md.pci_exclude_device = mpc85xx_exclude_device; +#endif + +#ifdef CONFIG_ROOT_NFS + ROOT_DEV = Root_NFS; +#else + ROOT_DEV = Root_HDA1; +#endif +} + + +void +mpc85xx_cds_show_cpuinfo(struct seq_file *m) +{ + uint pvid, svid, phid1; + uint memsize = total_memory; + + pvid = mfspr(SPRN_PVR); + svid = mfspr(SPRN_SVR); + + seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n"); + seq_printf(m, "Machine\t\t: MPC85xx CDS (0x%x)\n", cadmus[CM_VER]); + seq_printf(m, "PVR\t\t: 0x%x\n", pvid); + seq_printf(m, "SVR\t\t: 0x%x\n", svid); + + /* Display cpu Pll setting */ + phid1 = mfspr(SPRN_HID1); + seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f)); + + /* Display the amount of memory */ + seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024)); +} + + +/* + * Called very early, device-tree isn't unflattened + */ +static int __init mpc85xx_cds_probe(void) +{ + /* We always match for now, eventually we should look at + * the flat dev tree to ensure this is the board we are + * supposed to run on + */ + return 1; +} + +define_machine(mpc85xx_cds) { + .name = "MPC85xx CDS", + .probe = mpc85xx_cds_probe, + .setup_arch = mpc85xx_cds_setup_arch, + .init_IRQ = mpc85xx_cds_pic_init, + .show_cpuinfo = mpc85xx_cds_show_cpuinfo, + .get_irq = mpic_get_irq, + .restart = mpc85xx_restart, + .calibrate_decr = generic_calibrate_decr, + .progress = udbg_progress, +}; diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.h b/arch/powerpc/platforms/85xx/mpc85xx_cds.h new file mode 100644 index 000000000000..671f54ff185a --- /dev/null +++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.h @@ -0,0 +1,43 @@ +/* + * arch/ppc/platforms/85xx/mpc85xx_cds_common.h + * + * MPC85xx CDS board definitions + * + * Maintainer: Kumar Gala + * + * Copyright 2004 Freescale Semiconductor, Inc + * + * 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. + * + */ + +#ifndef __MACH_MPC85XX_CDS_H__ +#define __MACH_MPC85XX_CDS_H__ + +/* CADMUS info */ +#define CADMUS_BASE (0xf8004000) +#define CADMUS_SIZE (256) +#define CM_VER (0) +#define CM_CSR (1) +#define CM_RST (2) + +/* CDS NVRAM/RTC */ +#define CDS_RTC_ADDR (0xf8000000) +#define CDS_RTC_SIZE (8 * 1024) + +/* PCI interrupt controller */ +#define PIRQ0A MPC85xx_IRQ_EXT0 +#define PIRQ0B MPC85xx_IRQ_EXT1 +#define PIRQ0C MPC85xx_IRQ_EXT2 +#define PIRQ0D MPC85xx_IRQ_EXT3 +#define PIRQ1A MPC85xx_IRQ_EXT11 + +#define NR_8259_INTS 16 +#define CPM_IRQ_OFFSET NR_8259_INTS + +#define MPC85xx_OPENPIC_IRQ_OFFSET 80 + +#endif /* __MACH_MPC85XX_CDS_H__ */ diff --git a/include/asm-ppc/mpc85xx.h b/include/asm-ppc/mpc85xx.h index f47002a60edf..4f844ebe7669 100644 --- a/include/asm-ppc/mpc85xx.h +++ b/include/asm-ppc/mpc85xx.h @@ -28,6 +28,9 @@ #if defined(CONFIG_MPC8555_CDS) || defined(CONFIG_MPC8548_CDS) #include #endif +#ifdef CONFIG_MPC85xx_CDS +#include +#endif #ifdef CONFIG_MPC8560_ADS #include #endif -- cgit v1.2.3 From 381544bba3ae6f2f1004b267da34f840b469033c Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Tue, 11 Apr 2006 13:04:39 -0400 Subject: libata: Fix EH merge difference between this branch and upstream. --- drivers/scsi/libata-eh.c | 3 +-- drivers/scsi/libata.h | 1 + include/linux/libata.h | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index e73f5612aea8..b518654b9d60 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c @@ -97,7 +97,7 @@ enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd) * RETURNS: * Zero. */ -int ata_scsi_error(struct Scsi_Host *host) +void ata_scsi_error(struct Scsi_Host *host) { struct ata_port *ap = (struct ata_port *)&host->hostdata[0]; @@ -116,7 +116,6 @@ int ata_scsi_error(struct Scsi_Host *host) scsi_eh_flush_done_q(&ap->eh_done_q); DPRINTK("EXIT\n"); - return 0; } /** diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h index 652c08e3808e..b18d377588dc 100644 --- a/drivers/scsi/libata.h +++ b/drivers/scsi/libata.h @@ -105,5 +105,6 @@ extern void ata_scsi_rbuf_fill(struct ata_scsi_args *args, /* libata-eh.c */ extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd); +extern void ata_scsi_error(struct Scsi_Host *host); #endif /* __LIBATA_H__ */ diff --git a/include/linux/libata.h b/include/linux/libata.h index a7161d42d18f..2564bc514bca 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -637,7 +637,6 @@ extern unsigned long ata_pci_default_filter(const struct ata_port *, struct ata_ /* * EH */ -extern int ata_scsi_error(struct Scsi_Host *host); extern void ata_eng_timeout(struct ata_port *ap); extern void ata_eh_qc_complete(struct ata_queued_cmd *qc); extern void ata_eh_qc_retry(struct ata_queued_cmd *qc); -- cgit v1.2.3 From 35bb94b116e1fd4959ef0d3187458b5820eac8c4 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Tue, 11 Apr 2006 13:12:34 -0400 Subject: libata: Add helper ata_shost_to_port() --- drivers/scsi/libata-core.c | 4 ++-- drivers/scsi/libata-eh.c | 4 ++-- drivers/scsi/libata-scsi.c | 8 ++++---- drivers/scsi/sata_svw.c | 2 +- include/linux/libata.h | 6 ++++++ 5 files changed, 15 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 3387fe35c54f..6420062f2c1e 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -4659,7 +4659,7 @@ static struct ata_port * ata_host_add(const struct ata_probe_ent *ent, host->transportt = &ata_scsi_transport_template; - ap = (struct ata_port *) &host->hostdata[0]; + ap = ata_shost_to_port(host); ata_host_init(ap, host, host_set, ent, port_no); @@ -4872,7 +4872,7 @@ void ata_host_set_remove(struct ata_host_set *host_set) int ata_scsi_release(struct Scsi_Host *host) { - struct ata_port *ap = (struct ata_port *) &host->hostdata[0]; + struct ata_port *ap = ata_shost_to_port(host); int i; DPRINTK("ENTER\n"); diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index b518654b9d60..c31b13fd5307 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c @@ -64,7 +64,7 @@ enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd) { struct Scsi_Host *host = cmd->device->host; - struct ata_port *ap = (struct ata_port *) &host->hostdata[0]; + struct ata_port *ap = ata_shost_to_port(host); unsigned long flags; struct ata_queued_cmd *qc; enum scsi_eh_timer_return ret = EH_HANDLED; @@ -99,7 +99,7 @@ enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd) */ void ata_scsi_error(struct Scsi_Host *host) { - struct ata_port *ap = (struct ata_port *)&host->hostdata[0]; + struct ata_port *ap = ata_shost_to_port(host); DPRINTK("ENTER\n"); diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 5ae7613bc157..9871f8272df0 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -395,7 +395,7 @@ void ata_dump_status(unsigned id, struct ata_taskfile *tf) int ata_scsi_device_resume(struct scsi_device *sdev) { - struct ata_port *ap = (struct ata_port *) &sdev->host->hostdata[0]; + struct ata_port *ap = ata_shost_to_port(sdev->host); struct ata_device *dev = &ap->device[sdev->id]; return ata_device_resume(ap, dev); @@ -403,7 +403,7 @@ int ata_scsi_device_resume(struct scsi_device *sdev) int ata_scsi_device_suspend(struct scsi_device *sdev, pm_message_t state) { - struct ata_port *ap = (struct ata_port *) &sdev->host->hostdata[0]; + struct ata_port *ap = ata_shost_to_port(sdev->host); struct ata_device *dev = &ap->device[sdev->id]; return ata_device_suspend(ap, dev, state); @@ -704,7 +704,7 @@ int ata_scsi_slave_config(struct scsi_device *sdev) struct ata_port *ap; struct ata_device *dev; - ap = (struct ata_port *) &sdev->host->hostdata[0]; + ap = ata_shost_to_port(sdev->host); dev = &ap->device[sdev->id]; ata_scsi_dev_config(sdev, dev); @@ -2478,7 +2478,7 @@ int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) struct scsi_device *scsidev = cmd->device; struct Scsi_Host *shost = scsidev->host; - ap = (struct ata_port *) &shost->hostdata[0]; + ap = ata_shost_to_port(shost); spin_unlock(shost->host_lock); spin_lock(&ap->host_set->lock); diff --git a/drivers/scsi/sata_svw.c b/drivers/scsi/sata_svw.c index e15c693e0539..d5eb5375e265 100644 --- a/drivers/scsi/sata_svw.c +++ b/drivers/scsi/sata_svw.c @@ -257,7 +257,7 @@ static int k2_sata_proc_info(struct Scsi_Host *shost, char *page, char **start, int len, index; /* Find the ata_port */ - ap = (struct ata_port *) &shost->hostdata[0]; + ap = ata_shost_to_port(shost); if (ap == NULL) return 0; diff --git a/include/linux/libata.h b/include/linux/libata.h index 2564bc514bca..fe0a1dcc76c2 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -33,6 +33,7 @@ #include #include #include +#include /* * compile-time options: to be removed as soon as all the drivers are @@ -977,4 +978,9 @@ static inline void ata_pad_free(struct ata_port *ap, struct device *dev) dma_free_coherent(dev, ATA_DMA_PAD_BUF_SZ, ap->pad, ap->pad_dma); } +static inline struct ata_port *ata_shost_to_port(struct Scsi_Host *host) +{ + return (struct ata_port *) &host->hostdata[0]; +} + #endif /* __LINUX_LIBATA_H__ */ -- cgit v1.2.3 From 2bf2cb26b2512c6a609bb152982c388329bedff6 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 11 Apr 2006 22:16:45 +0900 Subject: [PATCH] libata: kill @verbose from ata_reset_fn_t @verbose was added to ata_reset_fn_t because AHCI complained during probing if no device was attached to the port. However, muting failure message isn't the correct approach. Reset methods are responsible for detecting no device condition and finishing successfully. Now that AHCI softreset is fixed, kill @verbose. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/scsi/ahci.c | 13 +++++-------- drivers/scsi/libata-core.c | 36 ++++++++++++------------------------ drivers/scsi/libata.h | 6 ++---- drivers/scsi/sata_sil24.c | 8 +++----- include/linux/libata.h | 8 +++----- 5 files changed, 25 insertions(+), 46 deletions(-) (limited to 'include') diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index 20fc0846e0be..0e7fb9bf2cd1 100644 --- a/drivers/scsi/ahci.c +++ b/drivers/scsi/ahci.c @@ -534,7 +534,7 @@ static int ahci_poll_register(void __iomem *reg, u32 mask, u32 val, return -1; } -static int ahci_softreset(struct ata_port *ap, int verbose, unsigned int *class) +static int ahci_softreset(struct ata_port *ap, unsigned int *class) { struct ahci_host_priv *hpriv = ap->host_set->private_data; struct ahci_port_priv *pp = ap->private_data; @@ -646,22 +646,19 @@ static int ahci_softreset(struct ata_port *ap, int verbose, unsigned int *class) fail_restart: ahci_start_engine(ap); fail: - if (verbose) - printk(KERN_ERR "ata%u: softreset failed (%s)\n", - ap->id, reason); - else - DPRINTK("EXIT, rc=%d reason=\"%s\"\n", rc, reason); + printk(KERN_ERR "ata%u: softreset failed (%s)\n", + ap->id, reason); return rc; } -static int ahci_hardreset(struct ata_port *ap, int verbose, unsigned int *class) +static int ahci_hardreset(struct ata_port *ap, unsigned int *class) { int rc; DPRINTK("ENTER\n"); ahci_stop_engine(ap); - rc = sata_std_hardreset(ap, verbose, class); + rc = sata_std_hardreset(ap, class); ahci_start_engine(ap); if (rc == 0) diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index f37179623efa..92b5077ac052 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -2387,7 +2387,6 @@ void ata_std_probeinit(struct ata_port *ap) /** * ata_std_softreset - reset host port via ATA SRST * @ap: port to reset - * @verbose: fail verbosely * @classes: resulting classes of attached devices * * Reset host port using ATA SRST. This function is to be used @@ -2399,7 +2398,7 @@ void ata_std_probeinit(struct ata_port *ap) * RETURNS: * 0 on success, -errno otherwise. */ -int ata_std_softreset(struct ata_port *ap, int verbose, unsigned int *classes) +int ata_std_softreset(struct ata_port *ap, unsigned int *classes) { unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS; unsigned int devmask = 0, err_mask; @@ -2425,12 +2424,8 @@ int ata_std_softreset(struct ata_port *ap, int verbose, unsigned int *classes) DPRINTK("about to softreset, devmask=%x\n", devmask); err_mask = ata_bus_softreset(ap, devmask); if (err_mask) { - if (verbose) - printk(KERN_ERR "ata%u: SRST failed (err_mask=0x%x)\n", - ap->id, err_mask); - else - DPRINTK("EXIT, softreset failed (err_mask=0x%x)\n", - err_mask); + printk(KERN_ERR "ata%u: SRST failed (err_mask=0x%x)\n", + ap->id, err_mask); return -EIO; } @@ -2447,7 +2442,6 @@ int ata_std_softreset(struct ata_port *ap, int verbose, unsigned int *classes) /** * sata_std_hardreset - reset host port via SATA phy reset * @ap: port to reset - * @verbose: fail verbosely * @class: resulting class of attached device * * SATA phy-reset host port using DET bits of SControl register. @@ -2460,7 +2454,7 @@ int ata_std_softreset(struct ata_port *ap, int verbose, unsigned int *classes) * RETURNS: * 0 on success, -errno otherwise. */ -int sata_std_hardreset(struct ata_port *ap, int verbose, unsigned int *class) +int sata_std_hardreset(struct ata_port *ap, unsigned int *class) { u32 scontrol; @@ -2500,11 +2494,8 @@ int sata_std_hardreset(struct ata_port *ap, int verbose, unsigned int *class) } if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) { - if (verbose) - printk(KERN_ERR "ata%u: COMRESET failed " - "(device not ready)\n", ap->id); - else - DPRINTK("EXIT, device not ready\n"); + printk(KERN_ERR "ata%u: COMRESET failed " + "(device not ready)\n", ap->id); return -EIO; } @@ -2592,16 +2583,15 @@ int ata_std_probe_reset(struct ata_port *ap, unsigned int *classes) ata_std_postreset, classes); } -int ata_do_reset(struct ata_port *ap, - ata_reset_fn_t reset, ata_postreset_fn_t postreset, - int verbose, unsigned int *classes) +int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset, + ata_postreset_fn_t postreset, unsigned int *classes) { int i, rc; for (i = 0; i < ATA_MAX_DEVICES; i++) classes[i] = ATA_DEV_UNKNOWN; - rc = reset(ap, verbose, classes); + rc = reset(ap, classes); if (rc) return rc; @@ -2645,8 +2635,6 @@ int ata_do_reset(struct ata_port *ap, * - If classification is supported, fill classes[] with * recognized class codes. * - If classification is not supported, leave classes[] alone. - * - If verbose is non-zero, print error message on failure; - * otherwise, shut up. * * LOCKING: * Kernel thread context (may sleep) @@ -2666,7 +2654,7 @@ int ata_drive_probe_reset(struct ata_port *ap, ata_probeinit_fn_t probeinit, probeinit(ap); if (softreset && !ata_set_sata_spd_needed(ap)) { - rc = ata_do_reset(ap, softreset, postreset, 0, classes); + rc = ata_do_reset(ap, softreset, postreset, classes); if (rc == 0 && classes[0] != ATA_DEV_UNKNOWN) goto done; printk(KERN_INFO "ata%u: softreset failed, will try " @@ -2678,7 +2666,7 @@ int ata_drive_probe_reset(struct ata_port *ap, ata_probeinit_fn_t probeinit, goto done; while (1) { - rc = ata_do_reset(ap, hardreset, postreset, 0, classes); + rc = ata_do_reset(ap, hardreset, postreset, classes); if (rc == 0) { if (classes[0] != ATA_DEV_UNKNOWN) goto done; @@ -2699,7 +2687,7 @@ int ata_drive_probe_reset(struct ata_port *ap, ata_probeinit_fn_t probeinit, ap->id); ssleep(5); - rc = ata_do_reset(ap, softreset, postreset, 0, classes); + rc = ata_do_reset(ap, softreset, postreset, classes); } done: diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h index b18d377588dc..3f8b0a863781 100644 --- a/drivers/scsi/libata.h +++ b/drivers/scsi/libata.h @@ -56,10 +56,8 @@ extern int ata_set_sata_spd_needed(struct ata_port *ap); extern int ata_down_xfermask_limit(struct ata_port *ap, struct ata_device *dev, int force_pio0); extern int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev); -extern int ata_do_reset(struct ata_port *ap, - ata_reset_fn_t reset, - ata_postreset_fn_t postreset, - int verbose, unsigned int *classes); +extern int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset, + ata_postreset_fn_t postreset, unsigned int *classes); extern void ata_qc_free(struct ata_queued_cmd *qc); extern void ata_qc_issue(struct ata_queued_cmd *qc); extern int ata_check_atapi_dma(struct ata_queued_cmd *qc); diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c index 9aa7493ea146..26d84e094b1d 100644 --- a/drivers/scsi/sata_sil24.c +++ b/drivers/scsi/sata_sil24.c @@ -426,8 +426,7 @@ static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf) *tf = pp->tf; } -static int sil24_softreset(struct ata_port *ap, int verbose, - unsigned int *class) +static int sil24_softreset(struct ata_port *ap, unsigned int *class) { void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr; struct sil24_port_priv *pp = ap->private_data; @@ -489,13 +488,12 @@ static int sil24_softreset(struct ata_port *ap, int verbose, return 0; } -static int sil24_hardreset(struct ata_port *ap, int verbose, - unsigned int *class) +static int sil24_hardreset(struct ata_port *ap, unsigned int *class) { unsigned int dummy_class; /* sil24 doesn't report device signature after hard reset */ - return sata_std_hardreset(ap, verbose, &dummy_class); + return sata_std_hardreset(ap, &dummy_class); } static int sil24_probe_reset(struct ata_port *ap, unsigned int *classes) diff --git a/include/linux/libata.h b/include/linux/libata.h index fe0a1dcc76c2..d5fd5c06e755 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -252,7 +252,7 @@ struct ata_queued_cmd; /* typedefs */ typedef void (*ata_qc_cb_t) (struct ata_queued_cmd *qc); typedef void (*ata_probeinit_fn_t)(struct ata_port *); -typedef int (*ata_reset_fn_t)(struct ata_port *, int, unsigned int *); +typedef int (*ata_reset_fn_t)(struct ata_port *, unsigned int *); typedef void (*ata_postreset_fn_t)(struct ata_port *ap, unsigned int *); struct ata_ioports { @@ -509,10 +509,8 @@ extern int ata_drive_probe_reset(struct ata_port *ap, ata_reset_fn_t softreset, ata_reset_fn_t hardreset, ata_postreset_fn_t postreset, unsigned int *classes); extern void ata_std_probeinit(struct ata_port *ap); -extern int ata_std_softreset(struct ata_port *ap, int verbose, - unsigned int *classes); -extern int sata_std_hardreset(struct ata_port *ap, int verbose, - unsigned int *class); +extern int ata_std_softreset(struct ata_port *ap, unsigned int *classes); +extern int sata_std_hardreset(struct ata_port *ap, unsigned int *class); extern void ata_std_postreset(struct ata_port *ap, unsigned int *classes); extern int ata_dev_revalidate(struct ata_port *ap, struct ata_device *dev, int post_reset); -- cgit v1.2.3 From c22daff41001e9ccead87179ac0547f85447139e Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 11 Apr 2006 22:22:29 +0900 Subject: [PATCH] libata: implement ata_wait_register() As waiting for some register bits to change seems to be a common operation shared by some controllers, implement helper function ata_wait_register(). This function also takes care of register write flushing. Note that the condition is inverted, the wait is over when the masked value does NOT match @val. As we're waiting for bits to change, this test is more powerful and allows the function to be used in more places. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/scsi/libata-core.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/libata.h | 3 +++ 2 files changed, 50 insertions(+) (limited to 'include') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 2d76ce23728f..0075fe7404d5 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -5029,6 +5029,52 @@ int ata_ratelimit(void) return rc; } +/** + * ata_wait_register - wait until register value changes + * @reg: IO-mapped register + * @mask: Mask to apply to read register value + * @val: Wait condition + * @interval_msec: polling interval in milliseconds + * @timeout_msec: timeout in milliseconds + * + * Waiting for some bits of register to change is a common + * operation for ATA controllers. This function reads 32bit LE + * IO-mapped register @reg and tests for the following condition. + * + * (*@reg & mask) != val + * + * If the condition is met, it returns; otherwise, the process is + * repeated after @interval_msec until timeout. + * + * LOCKING: + * Kernel thread context (may sleep) + * + * RETURNS: + * The final register value. + */ +u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val, + unsigned long interval_msec, + unsigned long timeout_msec) +{ + unsigned long timeout; + u32 tmp; + + tmp = ioread32(reg); + + /* Calculate timeout _after_ the first read to make sure + * preceding writes reach the controller before starting to + * eat away the timeout. + */ + timeout = jiffies + (timeout_msec * HZ) / 1000; + + while ((tmp & mask) == val && time_before(jiffies, timeout)) { + msleep(interval_msec); + tmp = ioread32(reg); + } + + return tmp; +} + /* * libata is essentially a library of internal helper functions for * low-level ATA host controller drivers. As such, the API/ABI is @@ -5079,6 +5125,7 @@ EXPORT_SYMBOL_GPL(ata_dev_classify); EXPORT_SYMBOL_GPL(ata_dev_pair); EXPORT_SYMBOL_GPL(ata_port_disable); EXPORT_SYMBOL_GPL(ata_ratelimit); +EXPORT_SYMBOL_GPL(ata_wait_register); EXPORT_SYMBOL_GPL(ata_busy_sleep); EXPORT_SYMBOL_GPL(ata_port_queue_task); EXPORT_SYMBOL_GPL(ata_scsi_ioctl); diff --git a/include/linux/libata.h b/include/linux/libata.h index d5fd5c06e755..dd5bcb5d29b5 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -543,6 +543,9 @@ extern unsigned int ata_busy_sleep(struct ata_port *ap, unsigned long timeout); extern void ata_port_queue_task(struct ata_port *ap, void (*fn)(void *), void *data, unsigned long delay); +extern u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val, + unsigned long interval_msec, + unsigned long timeout_msec); /* * Default driver ops implementations -- cgit v1.2.3 From 499a86af41cf5a4bf811726841bbc49c0e96fd35 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 11 Apr 2006 22:32:18 +0900 Subject: [PATCH] libata: export ata_set_sata_spd() This will be used by LLDD hardreset implementation. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/scsi/libata-core.c | 3 ++- include/linux/libata.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 588578dc6caf..509178c3700c 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -1738,7 +1738,7 @@ int ata_set_sata_spd_needed(struct ata_port *ap) * 0 if spd doesn't need to be changed, 1 if spd has been * changed. -EOPNOTSUPP if SCR registers are inaccessible. */ -static int ata_set_sata_spd(struct ata_port *ap) +int ata_set_sata_spd(struct ata_port *ap) { u32 scontrol; @@ -5113,6 +5113,7 @@ EXPORT_SYMBOL_GPL(ata_bmdma_irq_clear); EXPORT_SYMBOL_GPL(ata_bmdma_status); EXPORT_SYMBOL_GPL(ata_bmdma_stop); EXPORT_SYMBOL_GPL(ata_port_probe); +EXPORT_SYMBOL_GPL(ata_set_sata_spd); EXPORT_SYMBOL_GPL(sata_phy_reset); EXPORT_SYMBOL_GPL(__sata_phy_reset); EXPORT_SYMBOL_GPL(ata_bus_reset); diff --git a/include/linux/libata.h b/include/linux/libata.h index dd5bcb5d29b5..d35b1e3bb7e0 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -504,6 +504,7 @@ extern void ata_port_probe(struct ata_port *); extern void __sata_phy_reset(struct ata_port *ap); extern void sata_phy_reset(struct ata_port *ap); extern void ata_bus_reset(struct ata_port *ap); +extern int ata_set_sata_spd(struct ata_port *ap); extern int ata_drive_probe_reset(struct ata_port *ap, ata_probeinit_fn_t probeinit, ata_reset_fn_t softreset, ata_reset_fn_t hardreset, -- cgit v1.2.3 From 13f7e5acc8b329080672c13f05f252ace5b79825 Mon Sep 17 00:00:00 2001 From: Kurt Garloff Date: Mon, 3 Apr 2006 15:20:08 +0200 Subject: [SCSI] BLIST_ATTACH_PQ3 flags Some devices report a peripheral qualifier of 3 for LUN 0; with the original code, we would still try a REPORT_LUNS scan (if SCSI level is >= 3 or if we have the BLIST_REPORTLUNS2 passed in), but NOT any sequential scan. Also, the device at LUN 0 (which is not connected according to the PQ) is not registered with the OS. Unfortunately, SANs exist that are SCSI-2 and do NOT support REPORT_LUNS, but report a unknown device with PQ 3 on LUN 0. We still need to scan them, and most probably we even need BLIST_SPARSELUN (and BLIST_LARGELUN). See the bug reference for an infamous example. This is patch 3/3: 3. Implement the blacklist flag BLIST_ATTACH_PQ3 that makes the scsi scanning code register PQ3 devices and continues scanning; only sg will attach thanks to scsi_bus_match(). Signed-off-by: Kurt Garloff Signed-off-by: James Bottomley --- drivers/scsi/scsi_devinfo.c | 2 ++ drivers/scsi/scsi_scan.c | 2 +- include/scsi/scsi_devinfo.h | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index 84c3937ae8fb..6f46b338c991 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -155,6 +155,8 @@ static struct { {"HITACHI", "DF400", "*", BLIST_SPARSELUN}, {"HITACHI", "DF500", "*", BLIST_SPARSELUN}, {"HITACHI", "DF600", "*", BLIST_SPARSELUN}, + {"HITACHI", "DISK-SUBSYSTEM", "*", BLIST_ATTACH_PQ3 | BLIST_SPARSELUN | BLIST_LARGELUN}, + {"HITACHI", "OPEN-E", "*", BLIST_ATTACH_PQ3 | BLIST_SPARSELUN | BLIST_LARGELUN}, {"HP", "A6189A", NULL, BLIST_SPARSELUN | BLIST_LARGELUN}, /* HP VA7400 */ {"HP", "OPEN-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, /* HP XP Arrays */ {"HP", "NetRAID-4M", NULL, BLIST_FORCELUN}, diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 5603dc6eca47..7d31a4b0f802 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -900,7 +900,7 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget, /* * result contains valid SCSI INQUIRY data. */ - if ((result[0] >> 5) == 3) { + if (((result[0] >> 5) == 3) && !(bflags & BLIST_ATTACH_PQ3)) { /* * For a Peripheral qualifier 3 (011b), the SCSI * spec says: The device server is not capable of diff --git a/include/scsi/scsi_devinfo.h b/include/scsi/scsi_devinfo.h index 174101b2069b..599966898208 100644 --- a/include/scsi/scsi_devinfo.h +++ b/include/scsi/scsi_devinfo.h @@ -28,4 +28,5 @@ #define BLIST_NO_ULD_ATTACH 0x100000 /* device is actually for RAID config */ #define BLIST_SELECT_NO_ATN 0x200000 /* select without ATN */ #define BLIST_RETRY_HWERROR 0x400000 /* retry HARDWARE_ERROR */ +#define BLIST_ATTACH_PQ3 0x800000 /* Scan: Attach to PQ3 devices */ #endif -- cgit v1.2.3 From b5c7a12dc29ae0990d9e867749bdd717a3160325 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Thu, 6 Apr 2006 21:13:33 -0500 Subject: [SCSI] iscsi: rm kernel iscsi handles usage for session and connection from hare@suse.de and michaelc@cs.wisc.edu hw iscsi like qla4xxx does not allocate a host per session and for userspace it is difficult to restart iscsid using the "iscsi handles" for the session and connection, so this patch just has the class or userspace allocate the id for the session and connection. Note: this breaks userspace and requires users to upgrade to the newest open-iscsi tools. Sorry about his but open-iscsi is still too new to say we have a stable user-kernel api and we were not good nough designers to know that other hw iscsi drivers and iscsid itself would need such changes. Actually we sorta did but at the time we did not have the HW available to us so we could only guess. Luckily, the only tools hooking into the class are the open-iscsi ones or other tools like iscsitart hook into the open-iscsi engine from userspace or prgroams like anaconda call our tools so they are not affected. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/iscsi_tcp.c | 5 +- drivers/scsi/scsi_transport_iscsi.c | 106 +++++++++++++++++++++++++----------- include/scsi/iscsi_if.h | 37 ++++++++----- include/scsi/scsi_transport_iscsi.h | 7 ++- 4 files changed, 105 insertions(+), 50 deletions(-) (limited to 'include') diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 2068b66822b7..6ecb4baa37e2 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -3254,7 +3254,7 @@ static struct iscsi_transport iscsi_tcp_transport; static struct iscsi_cls_session * iscsi_session_create(struct scsi_transport_template *scsit, - uint32_t initial_cmdsn, uint32_t *sid) + uint32_t initial_cmdsn, uint32_t *hostno) { struct Scsi_Host *shost; struct iscsi_session *session; @@ -3274,7 +3274,8 @@ iscsi_session_create(struct scsi_transport_template *scsit, session->exp_cmdsn = initial_cmdsn + 1; session->max_cmdsn = initial_cmdsn + 1; session->max_r2t = 1; - *sid = shost->host_no; + + *hostno = shost->host_no; /* initialize SCSI PDU commands pool */ if (iscsi_pool_init(&session->cmdpool, session->cmds_max, diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 2730d507e585..10ff0f0210ba 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -56,6 +56,8 @@ struct iscsi_internal { struct class_device_attribute *session_attrs[ISCSI_SESSION_ATTRS + 1]; }; +static int iscsi_session_nr; /* sysfs session id for next new session */ + /* * list of registered transports and lock that must * be held while accessing list. The iscsi_transport_lock must @@ -165,14 +167,23 @@ static DEFINE_SPINLOCK(sesslock); static LIST_HEAD(connlist); static DEFINE_SPINLOCK(connlock); -static struct iscsi_cls_session *iscsi_session_lookup(uint64_t handle) +static uint32_t iscsi_conn_get_sid(struct iscsi_cls_conn *conn) +{ + struct iscsi_cls_session *sess = iscsi_dev_to_session(conn->dev.parent); + return sess->sid; +} + +/* + * Returns the matching session to a given sid + */ +static struct iscsi_cls_session *iscsi_session_lookup(uint32_t sid) { unsigned long flags; struct iscsi_cls_session *sess; spin_lock_irqsave(&sesslock, flags); list_for_each_entry(sess, &sesslist, sess_list) { - if (sess == iscsi_ptr(handle)) { + if (sess->sid == sid) { spin_unlock_irqrestore(&sesslock, flags); return sess; } @@ -181,14 +192,17 @@ static struct iscsi_cls_session *iscsi_session_lookup(uint64_t handle) return NULL; } -static struct iscsi_cls_conn *iscsi_conn_lookup(uint64_t handle) +/* + * Returns the matching connection to a given sid / cid tuple + */ +static struct iscsi_cls_conn *iscsi_conn_lookup(uint32_t sid, uint32_t cid) { unsigned long flags; struct iscsi_cls_conn *conn; spin_lock_irqsave(&connlock, flags); list_for_each_entry(conn, &connlist, conn_list) { - if (conn == iscsi_ptr(handle)) { + if ((conn->cid == cid) && (iscsi_conn_get_sid(conn) == sid)) { spin_unlock_irqrestore(&connlock, flags); return conn; } @@ -223,7 +237,7 @@ static int iscsi_is_session_dev(const struct device *dev) * @shost: scsi host * @transport: iscsi transport * - * This can be called from a LLD or iscsi_transport + * This can be called from a LLD or iscsi_transport. **/ struct iscsi_cls_session * iscsi_create_session(struct Scsi_Host *shost, struct iscsi_transport *transport) @@ -234,14 +248,20 @@ iscsi_create_session(struct Scsi_Host *shost, struct iscsi_transport *transport) if (!try_module_get(transport->owner)) return NULL; - session = kzalloc(sizeof(*session), GFP_KERNEL); + session = kzalloc(sizeof(*session) + transport->sessiondata_size, + GFP_KERNEL); if (!session) goto module_put; session->transport = transport; + if (transport->sessiondata_size) + session->dd_data = &session[1]; + /* this is released in the dev's release function */ scsi_host_get(shost); - snprintf(session->dev.bus_id, BUS_ID_SIZE, "session%u", shost->host_no); + session->sid = iscsi_session_nr++; + snprintf(session->dev.bus_id, BUS_ID_SIZE, "session%u", + session->sid); session->dev.parent = &shost->shost_gendev; session->dev.release = iscsi_session_release; err = device_register(&session->dev); @@ -301,12 +321,16 @@ static int iscsi_is_conn_dev(const struct device *dev) * This can be called from a LLD or iscsi_transport. The connection * is child of the session so cid must be unique for all connections * on the session. + * + * Since we do not support MCS, cid will normally be zero. In some cases + * for software iscsi we could be trying to preallocate a connection struct + * in which case there could be two connection structs and cid would be + * non-zero. **/ struct iscsi_cls_conn * iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid) { struct iscsi_transport *transport = session->transport; - struct Scsi_Host *shost = iscsi_session_to_shost(session); struct iscsi_cls_conn *conn; int err; @@ -319,12 +343,14 @@ iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid) INIT_LIST_HEAD(&conn->conn_list); conn->transport = transport; + conn->cid = cid; /* this is released in the dev's release function */ if (!get_device(&session->dev)) goto free_conn; + snprintf(conn->dev.bus_id, BUS_ID_SIZE, "connection%d:%u", - shost->host_no, cid); + session->sid, cid); conn->dev.parent = &session->dev; conn->dev.release = iscsi_conn_release; err = device_register(&conn->dev); @@ -607,7 +633,8 @@ int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr, ev->type = ISCSI_KEVENT_RECV_PDU; if (atomic_read(&conn->z_pdu->allocated) >= conn->z_pdu->hiwat) ev->iferror = -ENOMEM; - ev->r.recv_req.conn_handle = iscsi_handle(conn); + ev->r.recv_req.cid = conn->cid; + ev->r.recv_req.sid = iscsi_conn_get_sid(conn); pdu = (char*)ev + sizeof(*ev); memcpy(pdu, hdr, sizeof(struct iscsi_hdr)); memcpy(pdu + sizeof(struct iscsi_hdr), data, data_size); @@ -639,7 +666,8 @@ void iscsi_conn_error(struct iscsi_cls_conn *conn, enum iscsi_err error) if (atomic_read(&conn->z_error->allocated) >= conn->z_error->hiwat) ev->iferror = -ENOMEM; ev->r.connerror.error = error; - ev->r.connerror.conn_handle = iscsi_handle(conn); + ev->r.connerror.cid = conn->cid; + ev->r.connerror.sid = iscsi_conn_get_sid(conn); iscsi_unicast_skb(conn->z_error, skb); @@ -689,7 +717,7 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh) ISCSI_STATS_CUSTOM_MAX); int err = 0; - conn = iscsi_conn_lookup(ev->u.get_stats.conn_handle); + conn = iscsi_conn_lookup(ev->u.get_stats.sid, ev->u.get_stats.cid); if (!conn) return -EEXIST; @@ -713,8 +741,10 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh) evstat->type = nlh->nlmsg_type; if (atomic_read(&conn->z_pdu->allocated) >= conn->z_pdu->hiwat) evstat->iferror = -ENOMEM; - evstat->u.get_stats.conn_handle = - ev->u.get_stats.conn_handle; + evstat->u.get_stats.cid = + ev->u.get_stats.cid; + evstat->u.get_stats.sid = + ev->u.get_stats.sid; stats = (struct iscsi_stats *) ((char*)evstat + sizeof(*evstat)); memset(stats, 0, sizeof(*stats)); @@ -740,16 +770,16 @@ iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_uevent *ev) { struct iscsi_transport *transport = priv->iscsi_transport; struct iscsi_cls_session *session; - uint32_t sid; + uint32_t hostno; session = transport->create_session(&priv->t, ev->u.c_session.initial_cmdsn, - &sid); + &hostno); if (!session) return -ENOMEM; - ev->r.c_session_ret.session_handle = iscsi_handle(session); - ev->r.c_session_ret.sid = sid; + ev->r.c_session_ret.host_no = hostno; + ev->r.c_session_ret.sid = session->sid; return 0; } @@ -760,13 +790,20 @@ iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev) struct iscsi_cls_session *session; unsigned long flags; - session = iscsi_session_lookup(ev->u.c_conn.session_handle); - if (!session) + session = iscsi_session_lookup(ev->u.c_conn.sid); + if (!session) { + printk(KERN_ERR "iscsi: invalid session %d\n", + ev->u.c_conn.sid); return -EINVAL; + } conn = transport->create_conn(session, ev->u.c_conn.cid); - if (!conn) + if (!conn) { + printk(KERN_ERR "iscsi: couldn't create a new " + "connection for session %d\n", + session->sid); return -ENOMEM; + } conn->z_pdu = mempool_zone_init(Z_MAX_PDU, NLMSG_SPACE(sizeof(struct iscsi_uevent) + @@ -788,7 +825,8 @@ iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev) goto free_pdu_pool; } - ev->r.handle = iscsi_handle(conn); + ev->r.c_conn_ret.sid = session->sid; + ev->r.c_conn_ret.cid = conn->cid; spin_lock_irqsave(&connlock, flags); list_add(&conn->conn_list, &connlist); @@ -812,7 +850,7 @@ iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev struct iscsi_cls_conn *conn; struct mempool_zone *z_error, *z_pdu; - conn = iscsi_conn_lookup(ev->u.d_conn.conn_handle); + conn = iscsi_conn_lookup(ev->u.d_conn.sid, ev->u.d_conn.cid); if (!conn) return -EINVAL; spin_lock_irqsave(&connlock, flags); @@ -855,7 +893,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) err = iscsi_if_create_session(priv, ev); break; case ISCSI_UEVENT_DESTROY_SESSION: - session = iscsi_session_lookup(ev->u.d_session.session_handle); + session = iscsi_session_lookup(ev->u.d_session.sid); if (session) transport->destroy_session(session); else @@ -868,8 +906,8 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) err = iscsi_if_destroy_conn(transport, ev); break; case ISCSI_UEVENT_BIND_CONN: - session = iscsi_session_lookup(ev->u.b_conn.session_handle); - conn = iscsi_conn_lookup(ev->u.b_conn.conn_handle); + session = iscsi_session_lookup(ev->u.b_conn.sid); + conn = iscsi_conn_lookup(ev->u.b_conn.sid, ev->u.b_conn.cid); if (session && conn) ev->r.retcode = transport->bind_conn(session, conn, @@ -879,7 +917,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) err = -EINVAL; break; case ISCSI_UEVENT_SET_PARAM: - conn = iscsi_conn_lookup(ev->u.set_param.conn_handle); + conn = iscsi_conn_lookup(ev->u.set_param.sid, ev->u.set_param.cid); if (conn) ev->r.retcode = transport->set_param(conn, ev->u.set_param.param, ev->u.set_param.value); @@ -887,7 +925,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) err = -EINVAL; break; case ISCSI_UEVENT_START_CONN: - conn = iscsi_conn_lookup(ev->u.start_conn.conn_handle); + conn = iscsi_conn_lookup(ev->u.start_conn.sid, ev->u.start_conn.cid); if (conn) ev->r.retcode = transport->start_conn(conn); else @@ -895,14 +933,14 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) break; case ISCSI_UEVENT_STOP_CONN: - conn = iscsi_conn_lookup(ev->u.stop_conn.conn_handle); + conn = iscsi_conn_lookup(ev->u.stop_conn.sid, ev->u.stop_conn.cid); if (conn) transport->stop_conn(conn, ev->u.stop_conn.flag); else err = -EINVAL; break; case ISCSI_UEVENT_SEND_PDU: - conn = iscsi_conn_lookup(ev->u.send_pdu.conn_handle); + conn = iscsi_conn_lookup(ev->u.send_pdu.sid, ev->u.send_pdu.cid); if (conn) ev->r.retcode = transport->send_pdu(conn, (struct iscsi_hdr*)((char*)ev + sizeof(*ev)), @@ -923,9 +961,11 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) return err; } -/* Get message from skb (based on rtnetlink_rcv_skb). Each message is - * processed by iscsi_if_recv_msg. Malformed skbs with wrong length are - * or invalid creds discarded silently. */ +/* + * Get message from skb (based on rtnetlink_rcv_skb). Each message is + * processed by iscsi_if_recv_msg. Malformed skbs with wrong lengths or + * invalid creds are discarded silently. + */ static void iscsi_if_rx(struct sock *sk, int len) { diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h index e5618b90996e..933a91b1474e 100644 --- a/include/scsi/iscsi_if.h +++ b/include/scsi/iscsi_if.h @@ -60,59 +60,68 @@ struct iscsi_uevent { uint32_t initial_cmdsn; } c_session; struct msg_destroy_session { - uint64_t session_handle; uint32_t sid; } d_session; struct msg_create_conn { - uint64_t session_handle; - uint32_t cid; uint32_t sid; + uint32_t cid; } c_conn; struct msg_bind_conn { - uint64_t session_handle; - uint64_t conn_handle; + uint32_t sid; + uint32_t cid; uint32_t transport_fd; uint32_t is_leading; } b_conn; struct msg_destroy_conn { - uint64_t conn_handle; + uint32_t sid; uint32_t cid; } d_conn; struct msg_send_pdu { + uint32_t sid; + uint32_t cid; uint32_t hdr_size; uint32_t data_size; - uint64_t conn_handle; } send_pdu; struct msg_set_param { - uint64_t conn_handle; + uint32_t sid; + uint32_t cid; uint32_t param; /* enum iscsi_param */ uint32_t value; } set_param; struct msg_start_conn { - uint64_t conn_handle; + uint32_t sid; + uint32_t cid; } start_conn; struct msg_stop_conn { + uint32_t sid; + uint32_t cid; uint64_t conn_handle; uint32_t flag; } stop_conn; struct msg_get_stats { - uint64_t conn_handle; + uint32_t sid; + uint32_t cid; } get_stats; } u; union { /* messages k -> u */ - uint64_t handle; int retcode; struct msg_create_session_ret { - uint64_t session_handle; uint32_t sid; + uint32_t host_no; } c_session_ret; + struct msg_create_conn_ret { + uint32_t sid; + uint32_t cid; + } c_conn_ret; struct msg_recv_req { + uint32_t sid; + uint32_t cid; uint64_t recv_handle; - uint64_t conn_handle; } recv_req; struct msg_conn_error { - uint64_t conn_handle; + uint32_t sid; + uint32_t cid; uint32_t error; /* enum iscsi_err */ } connerror; } r; diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h index b41cf077e54b..631463cd4892 100644 --- a/include/scsi/scsi_transport_iscsi.h +++ b/include/scsi/scsi_transport_iscsi.h @@ -60,11 +60,13 @@ struct iscsi_transport { int ihostdata_size; /* LLD connection data size */ int conndata_size; + /* LLD session data size */ + int sessiondata_size; int max_lun; unsigned int max_conn; unsigned int max_cmd_len; struct iscsi_cls_session *(*create_session) - (struct scsi_transport_template *t, uint32_t sn, uint32_t *sid); + (struct scsi_transport_template *t, uint32_t sn, uint32_t *hn); void (*destroy_session) (struct iscsi_cls_session *session); struct iscsi_cls_conn *(*create_conn) (struct iscsi_cls_session *sess, uint32_t cid); @@ -104,6 +106,7 @@ struct iscsi_cls_conn { struct list_head conn_list; /* item in connlist */ void *dd_data; /* LLD private data */ struct iscsi_transport *transport; + uint32_t cid; /* connection id */ int active; /* must be accessed with the connlock */ struct device dev; /* sysfs transport/container device */ struct mempool_zone *z_error; @@ -117,6 +120,8 @@ struct iscsi_cls_conn { struct iscsi_cls_session { struct list_head sess_list; /* item in session_list */ struct iscsi_transport *transport; + int sid; /* session id */ + void *dd_data; /* LLD private data */ struct device dev; /* sysfs transport/container device */ }; -- cgit v1.2.3 From fd7255f51a13ea915099c7e488001dfbbeb05104 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Thu, 6 Apr 2006 21:13:36 -0500 Subject: [SCSI] iscsi: add sysfs attrs for uspace sync up For iscsi boot when going from initramfs to the real root we need to stop the userpsace iscsi daemon. To later restart it iscsid needs to be able to rebuild itself and part of that process is matching a session running the kernel with the iscsid representation. To do this the attached patch adds several required iscsi values. If the LLD does not provide them becuase, login is done in userspace, then the transport class and userspace set ths up for the LLD. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/iscsi_tcp.c | 68 +++++++++- drivers/scsi/scsi_transport_iscsi.c | 262 ++++++++++++++++++++++++++++-------- include/scsi/iscsi_if.h | 64 ++++++--- include/scsi/scsi_transport_iscsi.h | 24 +++- 4 files changed, 342 insertions(+), 76 deletions(-) (limited to 'include') diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 6ecb4baa37e2..6e510f3cfbf6 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -3536,7 +3536,7 @@ iscsi_session_get_param(struct iscsi_cls_session *cls_session, *value = session->ofmarker_en; break; default: - return ISCSI_ERR_PARAM_NOT_FOUND; + return -EINVAL; } return 0; @@ -3547,6 +3547,7 @@ iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param, uint32_t *value) { struct iscsi_conn *conn = cls_conn->dd_data; + struct inet_sock *inet; switch(param) { case ISCSI_PARAM_MAX_RECV_DLENGTH: @@ -3561,13 +3562,61 @@ iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn, case ISCSI_PARAM_DATADGST_EN: *value = conn->datadgst_en; break; + case ISCSI_PARAM_CONN_PORT: + mutex_lock(&conn->xmitmutex); + if (!conn->sock) { + mutex_unlock(&conn->xmitmutex); + return -EINVAL; + } + + inet = inet_sk(conn->sock->sk); + *value = be16_to_cpu(inet->dport); + mutex_unlock(&conn->xmitmutex); default: - return ISCSI_ERR_PARAM_NOT_FOUND; + return -EINVAL; } return 0; } +static int +iscsi_conn_get_str_param(struct iscsi_cls_conn *cls_conn, + enum iscsi_param param, char *buf) +{ + struct iscsi_conn *conn = cls_conn->dd_data; + struct sock *sk; + struct inet_sock *inet; + struct ipv6_pinfo *np; + int len = 0; + + switch (param) { + case ISCSI_PARAM_CONN_ADDRESS: + mutex_lock(&conn->xmitmutex); + if (!conn->sock) { + mutex_unlock(&conn->xmitmutex); + return -EINVAL; + } + + sk = conn->sock->sk; + if (sk->sk_family == PF_INET) { + inet = inet_sk(sk); + len = sprintf(buf, "%u.%u.%u.%u\n", + NIPQUAD(inet->daddr)); + } else { + np = inet6_sk(sk); + len = sprintf(buf, + "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", + NIP6(np->daddr)); + } + mutex_unlock(&conn->xmitmutex); + break; + default: + return -EINVAL; + } + + return len; +} + static void iscsi_conn_get_stats(struct iscsi_cls_conn *cls_conn, struct iscsi_stats *stats) { @@ -3610,6 +3659,20 @@ static struct iscsi_transport iscsi_tcp_transport = { .name = "tcp", .caps = CAP_RECOVERY_L0 | CAP_MULTI_R2T | CAP_HDRDGST | CAP_DATADGST, + .param_mask = ISCSI_MAX_RECV_DLENGTH | + ISCSI_MAX_XMIT_DLENGTH | + ISCSI_HDRDGST_EN | + ISCSI_DATADGST_EN | + ISCSI_INITIAL_R2T_EN | + ISCSI_MAX_R2T | + ISCSI_IMM_DATA_EN | + ISCSI_FIRST_BURST | + ISCSI_MAX_BURST | + ISCSI_PDU_INORDER_EN | + ISCSI_DATASEQ_INORDER_EN | + ISCSI_ERL | + ISCSI_CONN_PORT | + ISCSI_CONN_ADDRESS, .host_template = &iscsi_sht, .hostdata_size = sizeof(struct iscsi_session), .conndata_size = sizeof(struct iscsi_conn), @@ -3622,6 +3685,7 @@ static struct iscsi_transport iscsi_tcp_transport = { .destroy_conn = iscsi_conn_destroy, .set_param = iscsi_conn_set_param, .get_conn_param = iscsi_conn_get_param, + .get_conn_str_param = iscsi_conn_get_str_param, .get_session_param = iscsi_session_get_param, .start_conn = iscsi_conn_start, .stop_conn = iscsi_conn_stop, diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 10ff0f0210ba..72a71ebc9d03 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -31,21 +31,13 @@ #include #include -#define ISCSI_SESSION_ATTRS 8 -#define ISCSI_CONN_ATTRS 6 +#define ISCSI_SESSION_ATTRS 10 +#define ISCSI_CONN_ATTRS 10 struct iscsi_internal { struct scsi_transport_template t; struct iscsi_transport *iscsi_transport; struct list_head list; - /* - * based on transport capabilities, at register time we set these - * bits to tell the transport class it wants attributes displayed - * in sysfs or that it can support different iSCSI Data-Path - * capabilities - */ - uint32_t param_mask; - struct class_device cdev; /* * We do not have any private or other attrs. @@ -223,6 +215,7 @@ static void iscsi_session_release(struct device *dev) shost = iscsi_session_to_shost(session); scsi_host_put(shost); + kfree(session->targetname); kfree(session); module_put(transport->owner); } @@ -304,6 +297,7 @@ static void iscsi_conn_release(struct device *dev) struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev); struct device *parent = conn->dev.parent; + kfree(conn->persistent_address); kfree(conn); put_device(parent); } @@ -870,6 +864,67 @@ iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev return 0; } +static void +iscsi_copy_param(struct iscsi_uevent *ev, uint32_t *value, char *data) +{ + if (ev->u.set_param.len != sizeof(uint32_t)) + BUG(); + memcpy(value, data, min_t(uint32_t, sizeof(uint32_t), + ev->u.set_param.len)); +} + +static int +iscsi_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev) +{ + char *data = (char*)ev + sizeof(*ev); + struct iscsi_cls_conn *conn; + struct iscsi_cls_session *session; + int err = 0; + uint32_t value = 0; + + session = iscsi_session_lookup(ev->u.set_param.sid); + conn = iscsi_conn_lookup(ev->u.set_param.sid, ev->u.set_param.cid); + if (!conn || !session) + return -EINVAL; + + switch (ev->u.set_param.param) { + case ISCSI_PARAM_TARGET_NAME: + /* this should not change between logins */ + if (session->targetname) + return 0; + + session->targetname = kstrdup(data, GFP_KERNEL); + if (!session->targetname) + return -ENOMEM; + break; + case ISCSI_PARAM_TPGT: + iscsi_copy_param(ev, &value, data); + session->tpgt = value; + break; + case ISCSI_PARAM_PERSISTENT_PORT: + iscsi_copy_param(ev, &value, data); + conn->persistent_port = value; + break; + case ISCSI_PARAM_PERSISTENT_ADDRESS: + /* + * this is the address returned in discovery so it should + * not change between logins. + */ + if (conn->persistent_address) + return 0; + + conn->persistent_address = kstrdup(data, GFP_KERNEL); + if (!conn->persistent_address) + return -ENOMEM; + break; + default: + iscsi_copy_param(ev, &value, data); + err = transport->set_param(conn, ev->u.set_param.param, value); + } + + return err; +} + static int iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) { @@ -917,12 +972,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) err = -EINVAL; break; case ISCSI_UEVENT_SET_PARAM: - conn = iscsi_conn_lookup(ev->u.set_param.sid, ev->u.set_param.cid); - if (conn) - ev->r.retcode = transport->set_param(conn, - ev->u.set_param.param, ev->u.set_param.value); - else - err = -EINVAL; + err = iscsi_set_param(transport, ev); break; case ISCSI_UEVENT_START_CONN: conn = iscsi_conn_lookup(ev->u.start_conn.sid, ev->u.start_conn.cid); @@ -1028,6 +1078,10 @@ free_skb: #define iscsi_cdev_to_conn(_cdev) \ iscsi_dev_to_conn(_cdev->dev) +#define ISCSI_CLASS_ATTR(_prefix,_name,_mode,_show,_store) \ +struct class_device_attribute class_device_attr_##_prefix##_##_name = \ + __ATTR(_name,_mode,_show,_store) + /* * iSCSI connection attrs */ @@ -1045,7 +1099,8 @@ show_conn_int_param_##param(struct class_device *cdev, char *buf) \ #define iscsi_conn_int_attr(field, param, format) \ iscsi_conn_int_attr_show(param, format) \ -static CLASS_DEVICE_ATTR(field, S_IRUGO, show_conn_int_param_##param, NULL); +static ISCSI_CLASS_ATTR(conn, field, S_IRUGO, show_conn_int_param_##param, \ + NULL); iscsi_conn_int_attr(max_recv_dlength, ISCSI_PARAM_MAX_RECV_DLENGTH, "%u"); iscsi_conn_int_attr(max_xmit_dlength, ISCSI_PARAM_MAX_XMIT_DLENGTH, "%u"); @@ -1053,6 +1108,25 @@ iscsi_conn_int_attr(header_digest, ISCSI_PARAM_HDRDGST_EN, "%d"); iscsi_conn_int_attr(data_digest, ISCSI_PARAM_DATADGST_EN, "%d"); iscsi_conn_int_attr(ifmarker, ISCSI_PARAM_IFMARKER_EN, "%d"); iscsi_conn_int_attr(ofmarker, ISCSI_PARAM_OFMARKER_EN, "%d"); +iscsi_conn_int_attr(persistent_port, ISCSI_PARAM_PERSISTENT_PORT, "%d"); +iscsi_conn_int_attr(port, ISCSI_PARAM_CONN_PORT, "%d"); + +#define iscsi_conn_str_attr_show(param) \ +static ssize_t \ +show_conn_str_param_##param(struct class_device *cdev, char *buf) \ +{ \ + struct iscsi_cls_conn *conn = iscsi_cdev_to_conn(cdev); \ + struct iscsi_transport *t = conn->transport; \ + return t->get_conn_str_param(conn, param, buf); \ +} + +#define iscsi_conn_str_attr(field, param) \ + iscsi_conn_str_attr_show(param) \ +static ISCSI_CLASS_ATTR(conn, field, S_IRUGO, show_conn_str_param_##param, \ + NULL); + +iscsi_conn_str_attr(persistent_address, ISCSI_PARAM_PERSISTENT_ADDRESS); +iscsi_conn_str_attr(address, ISCSI_PARAM_CONN_ADDRESS); #define iscsi_cdev_to_session(_cdev) \ iscsi_dev_to_session(_cdev->dev) @@ -1074,7 +1148,8 @@ show_session_int_param_##param(struct class_device *cdev, char *buf) \ #define iscsi_session_int_attr(field, param, format) \ iscsi_session_int_attr_show(param, format) \ -static CLASS_DEVICE_ATTR(field, S_IRUGO, show_session_int_param_##param, NULL); +static ISCSI_CLASS_ATTR(sess, field, S_IRUGO, show_session_int_param_##param, \ + NULL); iscsi_session_int_attr(initial_r2t, ISCSI_PARAM_INITIAL_R2T_EN, "%d"); iscsi_session_int_attr(max_outstanding_r2t, ISCSI_PARAM_MAX_R2T, "%hu"); @@ -1084,18 +1159,88 @@ iscsi_session_int_attr(max_burst_len, ISCSI_PARAM_MAX_BURST, "%u"); iscsi_session_int_attr(data_pdu_in_order, ISCSI_PARAM_PDU_INORDER_EN, "%d"); iscsi_session_int_attr(data_seq_in_order, ISCSI_PARAM_DATASEQ_INORDER_EN, "%d"); iscsi_session_int_attr(erl, ISCSI_PARAM_ERL, "%d"); +iscsi_session_int_attr(tpgt, ISCSI_PARAM_TPGT, "%d"); -#define SETUP_SESSION_RD_ATTR(field, param) \ - if (priv->param_mask & (1 << param)) { \ - priv->session_attrs[count] = &class_device_attr_##field;\ - count++; \ - } +#define iscsi_session_str_attr_show(param) \ +static ssize_t \ +show_session_str_param_##param(struct class_device *cdev, char *buf) \ +{ \ + struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev); \ + struct iscsi_transport *t = session->transport; \ + return t->get_session_str_param(session, param, buf); \ +} + +#define iscsi_session_str_attr(field, param) \ + iscsi_session_str_attr_show(param) \ +static ISCSI_CLASS_ATTR(sess, field, S_IRUGO, show_session_str_param_##param, \ + NULL); + +iscsi_session_str_attr(targetname, ISCSI_PARAM_TARGET_NAME); -#define SETUP_CONN_RD_ATTR(field, param) \ - if (priv->param_mask & (1 << param)) { \ - priv->conn_attrs[count] = &class_device_attr_##field; \ +/* + * Private session and conn attrs. userspace uses several iscsi values + * to identify each session between reboots. Some of these values may not + * be present in the iscsi_transport/LLD driver becuase userspace handles + * login (and failback for login redirect) so for these type of drivers + * the class manages the attrs and values for the iscsi_transport/LLD + */ +#define iscsi_priv_session_attr_show(field, format) \ +static ssize_t \ +show_priv_session_##field(struct class_device *cdev, char *buf) \ +{ \ + struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev); \ + return sprintf(buf, format"\n", session->field); \ +} + +#define iscsi_priv_session_attr(field, format) \ + iscsi_priv_session_attr_show(field, format) \ +static ISCSI_CLASS_ATTR(priv_sess, field, S_IRUGO, show_priv_session_##field, \ + NULL) +iscsi_priv_session_attr(targetname, "%s"); +iscsi_priv_session_attr(tpgt, "%d"); + +#define iscsi_priv_conn_attr_show(field, format) \ +static ssize_t \ +show_priv_conn_##field(struct class_device *cdev, char *buf) \ +{ \ + struct iscsi_cls_conn *conn = iscsi_cdev_to_conn(cdev); \ + return sprintf(buf, format"\n", conn->field); \ +} + +#define iscsi_priv_conn_attr(field, format) \ + iscsi_priv_conn_attr_show(field, format) \ +static ISCSI_CLASS_ATTR(priv_conn, field, S_IRUGO, show_priv_conn_##field, \ + NULL) +iscsi_priv_conn_attr(persistent_address, "%s"); +iscsi_priv_conn_attr(persistent_port, "%d"); + +#define SETUP_PRIV_SESSION_RD_ATTR(field) \ +do { \ + priv->session_attrs[count] = &class_device_attr_priv_sess_##field; \ + count++; \ +} while (0) + +#define SETUP_SESSION_RD_ATTR(field, param_flag) \ +do { \ + if (tt->param_mask & param_flag) { \ + priv->session_attrs[count] = &class_device_attr_sess_##field; \ count++; \ - } + } \ +} while (0) + +#define SETUP_PRIV_CONN_RD_ATTR(field) \ +do { \ + priv->conn_attrs[count] = &class_device_attr_priv_conn_##field; \ + count++; \ +} while (0) + +#define SETUP_CONN_RD_ATTR(field, param_flag) \ +do { \ + if (tt->param_mask & param_flag) { \ + priv->conn_attrs[count] = &class_device_attr_conn_##field; \ + count++; \ + } \ +} while (0) static int iscsi_session_match(struct attribute_container *cont, struct device *dev) @@ -1173,31 +1318,30 @@ iscsi_register_transport(struct iscsi_transport *tt) if (err) goto unregister_cdev; - /* setup parameters mask */ - priv->param_mask = 0xFFFFFFFF; - if (!(tt->caps & CAP_MULTI_R2T)) - priv->param_mask &= ~(1 << ISCSI_PARAM_MAX_R2T); - if (!(tt->caps & CAP_HDRDGST)) - priv->param_mask &= ~(1 << ISCSI_PARAM_HDRDGST_EN); - if (!(tt->caps & CAP_DATADGST)) - priv->param_mask &= ~(1 << ISCSI_PARAM_DATADGST_EN); - if (!(tt->caps & CAP_MARKERS)) { - priv->param_mask &= ~(1 << ISCSI_PARAM_IFMARKER_EN); - priv->param_mask &= ~(1 << ISCSI_PARAM_OFMARKER_EN); - } - /* connection parameters */ priv->conn_cont.ac.attrs = &priv->conn_attrs[0]; priv->conn_cont.ac.class = &iscsi_connection_class.class; priv->conn_cont.ac.match = iscsi_conn_match; transport_container_register(&priv->conn_cont); - SETUP_CONN_RD_ATTR(max_recv_dlength, ISCSI_PARAM_MAX_RECV_DLENGTH); - SETUP_CONN_RD_ATTR(max_xmit_dlength, ISCSI_PARAM_MAX_XMIT_DLENGTH); - SETUP_CONN_RD_ATTR(header_digest, ISCSI_PARAM_HDRDGST_EN); - SETUP_CONN_RD_ATTR(data_digest, ISCSI_PARAM_DATADGST_EN); - SETUP_CONN_RD_ATTR(ifmarker, ISCSI_PARAM_IFMARKER_EN); - SETUP_CONN_RD_ATTR(ofmarker, ISCSI_PARAM_OFMARKER_EN); + SETUP_CONN_RD_ATTR(max_recv_dlength, ISCSI_MAX_RECV_DLENGTH); + SETUP_CONN_RD_ATTR(max_xmit_dlength, ISCSI_MAX_XMIT_DLENGTH); + SETUP_CONN_RD_ATTR(header_digest, ISCSI_HDRDGST_EN); + SETUP_CONN_RD_ATTR(data_digest, ISCSI_DATADGST_EN); + SETUP_CONN_RD_ATTR(ifmarker, ISCSI_IFMARKER_EN); + SETUP_CONN_RD_ATTR(ofmarker, ISCSI_OFMARKER_EN); + SETUP_CONN_RD_ATTR(address, ISCSI_CONN_ADDRESS); + SETUP_CONN_RD_ATTR(port, ISCSI_CONN_PORT); + + if (tt->param_mask & ISCSI_PERSISTENT_ADDRESS) + SETUP_CONN_RD_ATTR(persistent_address, ISCSI_PERSISTENT_ADDRESS); + else + SETUP_PRIV_CONN_RD_ATTR(persistent_address); + + if (tt->param_mask & ISCSI_PERSISTENT_PORT) + SETUP_CONN_RD_ATTR(persistent_port, ISCSI_PERSISTENT_PORT); + else + SETUP_PRIV_CONN_RD_ATTR(persistent_port); BUG_ON(count > ISCSI_CONN_ATTRS); priv->conn_attrs[count] = NULL; @@ -1209,14 +1353,24 @@ iscsi_register_transport(struct iscsi_transport *tt) priv->session_cont.ac.match = iscsi_session_match; transport_container_register(&priv->session_cont); - SETUP_SESSION_RD_ATTR(initial_r2t, ISCSI_PARAM_INITIAL_R2T_EN); - SETUP_SESSION_RD_ATTR(max_outstanding_r2t, ISCSI_PARAM_MAX_R2T); - SETUP_SESSION_RD_ATTR(immediate_data, ISCSI_PARAM_IMM_DATA_EN); - SETUP_SESSION_RD_ATTR(first_burst_len, ISCSI_PARAM_FIRST_BURST); - SETUP_SESSION_RD_ATTR(max_burst_len, ISCSI_PARAM_MAX_BURST); - SETUP_SESSION_RD_ATTR(data_pdu_in_order, ISCSI_PARAM_PDU_INORDER_EN); - SETUP_SESSION_RD_ATTR(data_seq_in_order,ISCSI_PARAM_DATASEQ_INORDER_EN) - SETUP_SESSION_RD_ATTR(erl, ISCSI_PARAM_ERL); + SETUP_SESSION_RD_ATTR(initial_r2t, ISCSI_INITIAL_R2T_EN); + SETUP_SESSION_RD_ATTR(max_outstanding_r2t, ISCSI_MAX_R2T); + SETUP_SESSION_RD_ATTR(immediate_data, ISCSI_IMM_DATA_EN); + SETUP_SESSION_RD_ATTR(first_burst_len, ISCSI_FIRST_BURST); + SETUP_SESSION_RD_ATTR(max_burst_len, ISCSI_MAX_BURST); + SETUP_SESSION_RD_ATTR(data_pdu_in_order, ISCSI_PDU_INORDER_EN); + SETUP_SESSION_RD_ATTR(data_seq_in_order, ISCSI_DATASEQ_INORDER_EN); + SETUP_SESSION_RD_ATTR(erl, ISCSI_ERL); + + if (tt->param_mask & ISCSI_TARGET_NAME) + SETUP_SESSION_RD_ATTR(targetname, ISCSI_TARGET_NAME); + else + SETUP_PRIV_SESSION_RD_ATTR(targetname); + + if (tt->param_mask & ISCSI_TPGT) + SETUP_SESSION_RD_ATTR(tpgt, ISCSI_TPGT); + else + SETUP_PRIV_SESSION_RD_ATTR(tpgt); BUG_ON(count > ISCSI_SESSION_ATTRS); priv->session_attrs[count] = NULL; diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h index 933a91b1474e..2c3a89b64e71 100644 --- a/include/scsi/iscsi_if.h +++ b/include/scsi/iscsi_if.h @@ -86,7 +86,7 @@ struct iscsi_uevent { uint32_t sid; uint32_t cid; uint32_t param; /* enum iscsi_param */ - uint32_t value; + uint32_t len; } set_param; struct msg_start_conn { uint32_t sid; @@ -155,22 +155,54 @@ enum iscsi_err { * iSCSI Parameters (RFC3720) */ enum iscsi_param { - ISCSI_PARAM_MAX_RECV_DLENGTH = 0, - ISCSI_PARAM_MAX_XMIT_DLENGTH = 1, - ISCSI_PARAM_HDRDGST_EN = 2, - ISCSI_PARAM_DATADGST_EN = 3, - ISCSI_PARAM_INITIAL_R2T_EN = 4, - ISCSI_PARAM_MAX_R2T = 5, - ISCSI_PARAM_IMM_DATA_EN = 6, - ISCSI_PARAM_FIRST_BURST = 7, - ISCSI_PARAM_MAX_BURST = 8, - ISCSI_PARAM_PDU_INORDER_EN = 9, - ISCSI_PARAM_DATASEQ_INORDER_EN = 10, - ISCSI_PARAM_ERL = 11, - ISCSI_PARAM_IFMARKER_EN = 12, - ISCSI_PARAM_OFMARKER_EN = 13, + /* passed in using netlink set param */ + ISCSI_PARAM_MAX_RECV_DLENGTH, + ISCSI_PARAM_MAX_XMIT_DLENGTH, + ISCSI_PARAM_HDRDGST_EN, + ISCSI_PARAM_DATADGST_EN, + ISCSI_PARAM_INITIAL_R2T_EN, + ISCSI_PARAM_MAX_R2T, + ISCSI_PARAM_IMM_DATA_EN, + ISCSI_PARAM_FIRST_BURST, + ISCSI_PARAM_MAX_BURST, + ISCSI_PARAM_PDU_INORDER_EN, + ISCSI_PARAM_DATASEQ_INORDER_EN, + ISCSI_PARAM_ERL, + ISCSI_PARAM_IFMARKER_EN, + ISCSI_PARAM_OFMARKER_EN, + ISCSI_PARAM_TARGET_NAME, + ISCSI_PARAM_TPGT, + ISCSI_PARAM_PERSISTENT_ADDRESS, + ISCSI_PARAM_PERSISTENT_PORT, + + /* pased in through bind conn using transport_fd */ + ISCSI_PARAM_CONN_PORT, + ISCSI_PARAM_CONN_ADDRESS, + + /* must always be last */ + ISCSI_PARAM_MAX, }; -#define ISCSI_PARAM_MAX 14 + +#define ISCSI_MAX_RECV_DLENGTH (1 << ISCSI_PARAM_MAX_RECV_DLENGTH) +#define ISCSI_MAX_XMIT_DLENGTH (1 << ISCSI_PARAM_MAX_XMIT_DLENGTH) +#define ISCSI_HDRDGST_EN (1 << ISCSI_PARAM_HDRDGST_EN) +#define ISCSI_DATADGST_EN (1 << ISCSI_PARAM_DATADGST_EN) +#define ISCSI_INITIAL_R2T_EN (1 << ISCSI_PARAM_INITIAL_R2T_EN) +#define ISCSI_MAX_R2T (1 << ISCSI_PARAM_MAX_R2T) +#define ISCSI_IMM_DATA_EN (1 << ISCSI_PARAM_IMM_DATA_EN) +#define ISCSI_FIRST_BURST (1 << ISCSI_PARAM_FIRST_BURST) +#define ISCSI_MAX_BURST (1 << ISCSI_PARAM_MAX_BURST) +#define ISCSI_PDU_INORDER_EN (1 << ISCSI_PARAM_PDU_INORDER_EN) +#define ISCSI_DATASEQ_INORDER_EN (1 << ISCSI_PARAM_DATASEQ_INORDER_EN) +#define ISCSI_ERL (1 << ISCSI_PARAM_ERL) +#define ISCSI_IFMARKER_EN (1 << ISCSI_PARAM_IFMARKER_EN) +#define ISCSI_OFMARKER_EN (1 << ISCSI_PARAM_OFMARKER_EN) +#define ISCSI_TARGET_NAME (1 << ISCSI_PARAM_TARGET_NAME) +#define ISCSI_TPGT (1 << ISCSI_PARAM_TPGT) +#define ISCSI_PERSISTENT_ADDRESS (1 << ISCSI_PARAM_PERSISTENT_ADDRESS) +#define ISCSI_PERSISTENT_PORT (1 << ISCSI_PARAM_PERSISTENT_PORT) +#define ISCSI_CONN_PORT (1 << ISCSI_PARAM_CONN_PORT) +#define ISCSI_CONN_ADDRESS (1 << ISCSI_PARAM_CONN_ADDRESS) #define iscsi_ptr(_handle) ((void*)(unsigned long)_handle) #define iscsi_handle(_ptr) ((uint64_t)(unsigned long)_ptr) diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h index 631463cd4892..4b200645c84b 100644 --- a/include/scsi/scsi_transport_iscsi.h +++ b/include/scsi/scsi_transport_iscsi.h @@ -53,11 +53,11 @@ struct iscsi_transport { struct module *owner; char *name; unsigned int caps; + /* LLD sets this to indicate what values it can export to sysfs */ + unsigned int param_mask; struct scsi_host_template *host_template; /* LLD session/scsi_host data size */ int hostdata_size; - /* LLD iscsi_host data size */ - int ihostdata_size; /* LLD connection data size */ int conndata_size; /* LLD session data size */ @@ -79,10 +79,13 @@ struct iscsi_transport { int (*set_param) (struct iscsi_cls_conn *conn, enum iscsi_param param, uint32_t value); int (*get_conn_param) (struct iscsi_cls_conn *conn, - enum iscsi_param param, - uint32_t *value); + enum iscsi_param param, uint32_t *value); int (*get_session_param) (struct iscsi_cls_session *session, enum iscsi_param param, uint32_t *value); + int (*get_conn_str_param) (struct iscsi_cls_conn *conn, + enum iscsi_param param, char *buf); + int (*get_session_str_param) (struct iscsi_cls_session *session, + enum iscsi_param param, char *buf); int (*send_pdu) (struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr, char *data, uint32_t data_size); void (*get_stats) (struct iscsi_cls_conn *conn, @@ -107,6 +110,14 @@ struct iscsi_cls_conn { void *dd_data; /* LLD private data */ struct iscsi_transport *transport; uint32_t cid; /* connection id */ + + /* portal/group values we got during discovery */ + char *persistent_address; + int persistent_port; + /* portal/group values we are currently using */ + char *address; + int port; + int active; /* must be accessed with the connlock */ struct device dev; /* sysfs transport/container device */ struct mempool_zone *z_error; @@ -120,6 +131,11 @@ struct iscsi_cls_conn { struct iscsi_cls_session { struct list_head sess_list; /* item in session_list */ struct iscsi_transport *transport; + + /* iSCSI values used as unique id by userspace. */ + char *targetname; + int tpgt; + int sid; /* session id */ void *dd_data; /* LLD private data */ struct device dev; /* sysfs transport/container device */ -- cgit v1.2.3 From 30a6c65236f9d26e3325cae468f330b833a3878c Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Thu, 6 Apr 2006 21:13:39 -0500 Subject: [SCSI] iscsi: fix up iscsi eh The current iscsi_tcp eh is not nicely setup for dm-multipath and performs some extra task management functions when they are not needed. The attached patch: - Fixes the TMF issues. If a session is rebuilt then we do not send aborts. - Fixes the problem where if the host reset fired, we would return SUCCESS even though we had not really done anything yet. This ends up causing problem with scsi_error.c's TUR. - If someone has turned on the userspace nop daemon code to try and detect network problems before the scsi command timeout we can now drop and clean up the session before the scsi command timesout and fires the eh speeding up the time it takes for a command to go from one patch to another. For network problems we fail the command with DID_BUS_BUSY so if failfast is set scsi_decide_disposition fails the command up to dm for it to try on another path. - And we had to add some basic iscsi session block code. Previously if we were trying to repair a session we would retrun a MLQUEUE code in the queuecommand. This worked but it was not the most efficient or pretty thing to do since it would take a while to relogin to the target. For iscsi_tcp/open-iscsi a lot of the iscsi error handler is in userspace the block code is pretty bare. We will be adding to that for qla4xxx. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/iscsi_tcp.c | 659 +++++++++++++++++++++--------------- drivers/scsi/iscsi_tcp.h | 3 + drivers/scsi/scsi_transport_iscsi.c | 152 ++++++++- include/scsi/iscsi_if.h | 2 + include/scsi/scsi_transport_iscsi.h | 19 +- 5 files changed, 561 insertions(+), 274 deletions(-) (limited to 'include') diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 6e510f3cfbf6..aca3e23b1b9e 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -82,6 +82,9 @@ module_param_named(max_lun, iscsi_max_lun, uint, S_IRUGO); /* global data */ static kmem_cache_t *taskcache; +#define session_to_cls(_sess) \ + hostdata_session(_sess->host->hostdata) + static inline void iscsi_buf_init_virt(struct iscsi_buf *ibuf, char *vbuf, int size) { @@ -230,17 +233,19 @@ iscsi_hdr_extract(struct iscsi_conn *conn) return 0; } -static inline void -iscsi_ctask_cleanup(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) +/* + * must be called with session lock + */ +static void +__iscsi_ctask_cleanup(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) { - struct scsi_cmnd *sc = ctask->sc; struct iscsi_session *session = conn->session; + struct scsi_cmnd *sc; - spin_lock(&session->lock); - if (unlikely(!sc)) { - spin_unlock(&session->lock); + sc = ctask->sc; + if (unlikely(!sc)) return; - } + if (sc->sc_data_direction == DMA_TO_DEVICE) { struct iscsi_data_task *dtask, *n; /* WRITE: cleanup Data-Out's if any */ @@ -252,7 +257,20 @@ iscsi_ctask_cleanup(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) ctask->xmstate = XMSTATE_IDLE; ctask->r2t = NULL; ctask->sc = NULL; + list_del(&ctask->running); + __kfifo_put(session->cmdpool.queue, (void*)&ctask, sizeof(void*)); + + sc->scsi_done(sc); +} + +static void +iscsi_ctask_cleanup(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) +{ + struct iscsi_session *session = conn->session; + + spin_lock(&session->lock); + __iscsi_ctask_cleanup(conn, ctask); spin_unlock(&session->lock); } @@ -311,7 +329,6 @@ out: (long)sc, sc->result, ctask->itt); conn->scsirsp_pdus_cnt++; iscsi_ctask_cleanup(conn, ctask); - sc->scsi_done(sc); return rc; } @@ -395,6 +412,7 @@ iscsi_solicit_data_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, dtask = mempool_alloc(ctask->datapool, GFP_ATOMIC); BUG_ON(!dtask); + INIT_LIST_HEAD(&dtask->item); hdr = &dtask->hdr; memset(hdr, 0, sizeof(struct iscsi_data)); hdr->ttt = r2t->ttt; @@ -710,8 +728,6 @@ iscsi_hdr_recv(struct iscsi_conn *conn) conn->tmfrsp_pdus_cnt++; spin_lock(&session->lock); if (conn->tmabort_state == TMABORT_INITIAL) { - __kfifo_put(session->mgmtpool.queue, - (void*)&mtask, sizeof(void*)); conn->tmabort_state = ((struct iscsi_tm_rsp *)hdr)-> response == ISCSI_TMF_RSP_COMPLETE ? @@ -986,7 +1002,6 @@ done: (long)sc, sc->result, ctask->itt); conn->scsirsp_pdus_cnt++; iscsi_ctask_cleanup(conn, ctask); - sc->scsi_done(sc); } return rc; @@ -1460,6 +1475,7 @@ iscsi_solicit_data_cont(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, dtask = mempool_alloc(ctask->datapool, GFP_ATOMIC); BUG_ON(!dtask); + INIT_LIST_HEAD(&dtask->item); hdr = &dtask->hdr; memset(hdr, 0, sizeof(struct iscsi_data)); hdr->ttt = r2t->ttt; @@ -1506,6 +1522,7 @@ iscsi_unsolicit_data_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) dtask = mempool_alloc(ctask->datapool, GFP_ATOMIC); BUG_ON(!dtask); + INIT_LIST_HEAD(&dtask->item); hdr = &dtask->hdr; memset(hdr, 0, sizeof(struct iscsi_data)); hdr->ttt = cpu_to_be32(ISCSI_RESERVED_TAG); @@ -1550,6 +1567,7 @@ iscsi_cmd_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, BUG_ON(__kfifo_len(ctask->r2tqueue)); + INIT_LIST_HEAD(&ctask->running); ctask->sc = sc; ctask->conn = conn; ctask->hdr.opcode = ISCSI_OP_SCSI_CMD; @@ -1680,7 +1698,7 @@ iscsi_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask) if (mtask->data_count) mtask->xmstate |= XMSTATE_IMM_DATA; if (conn->c_stage != ISCSI_CONN_INITIAL_STAGE && - conn->stop_stage != STOP_CONN_RECOVER && + conn->stop_stage != STOP_CONN_RECOVER && conn->hdrdgst_en) iscsi_hdr_digest(conn, &mtask->headbuf, (u8*)mtask->hdrext); @@ -2226,6 +2244,7 @@ iscsi_data_xmit(struct iscsi_conn *conn) /* process command queue */ while (__kfifo_get(conn->xmitqueue, (void*)&conn->ctask, sizeof(void*))) { + list_add_tail(&conn->ctask->running, &conn->run_list); if (iscsi_ctask_xmit(conn, conn->ctask)) goto again; } @@ -2277,11 +2296,14 @@ iscsi_xmitworker(void *data) mutex_unlock(&conn->xmitmutex); } -#define FAILURE_BAD_HOST 1 -#define FAILURE_SESSION_FAILED 2 -#define FAILURE_SESSION_FREED 3 -#define FAILURE_WINDOW_CLOSED 4 -#define FAILURE_SESSION_TERMINATE 5 +enum { + FAILURE_BAD_HOST = 1, + FAILURE_SESSION_FAILED, + FAILURE_SESSION_FREED, + FAILURE_WINDOW_CLOSED, + FAILURE_SESSION_TERMINATE, + FAILURE_SESSION_RECOVERY_TIMEOUT, +}; static int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) @@ -2297,12 +2319,14 @@ iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) host = sc->device->host; session = iscsi_hostdata(host->hostdata); - BUG_ON(host != session->host); spin_lock(&session->lock); if (session->state != ISCSI_STATE_LOGGED_IN) { - if (session->state == ISCSI_STATE_FAILED) { + if (session->recovery_failed) { + reason = FAILURE_SESSION_RECOVERY_TIMEOUT; + goto fault; + } else if (session->state == ISCSI_STATE_FAILED) { reason = FAILURE_SESSION_FAILED; goto reject; } else if (session->state == ISCSI_STATE_TERMINATE) { @@ -2350,11 +2374,6 @@ fault: spin_unlock(&session->lock); printk(KERN_ERR "iscsi_tcp: cmd 0x%x is not queued (%d)\n", sc->cmnd[0], reason); - sc->sense_buffer[0] = 0x70; - sc->sense_buffer[2] = NOT_READY; - sc->sense_buffer[7] = 0x6; - sc->sense_buffer[12] = 0x08; - sc->sense_buffer[13] = 0x00; sc->result = (DID_NO_CONNECT << 16); sc->resid = sc->request_bufflen; sc->scsi_done(sc); @@ -2445,6 +2464,7 @@ iscsi_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx) conn->id = conn_idx; conn->exp_statsn = 0; conn->tmabort_state = TMABORT_INITIAL; + INIT_LIST_HEAD(&conn->run_list); /* initial operational parameters */ conn->hdr_size = sizeof(struct iscsi_hdr); @@ -2701,6 +2721,22 @@ iscsi_conn_bind(struct iscsi_cls_session *cls_session, return 0; } +static void +iscsi_session_recovery_timedout(struct iscsi_cls_session *csession) +{ + struct Scsi_Host *shost = iscsi_session_to_shost(csession); + struct iscsi_session *session = iscsi_hostdata(shost->hostdata); + struct iscsi_conn *conn = session->leadconn; + + spin_lock_bh(&session->lock); + if (session->state != ISCSI_STATE_LOGGED_IN) { + session->recovery_failed = 1; + if (conn) + wake_up(&conn->ehwait); + } + spin_unlock_bh(&session->lock); +} + static int iscsi_conn_start(struct iscsi_cls_conn *cls_conn) { @@ -2716,7 +2752,6 @@ iscsi_conn_start(struct iscsi_cls_conn *cls_conn) } sk = conn->sock->sk; - write_lock_bh(&sk->sk_callback_lock); spin_lock_bh(&session->lock); conn->c_stage = ISCSI_CONN_STARTED; @@ -2732,8 +2767,13 @@ iscsi_conn_start(struct iscsi_cls_conn *cls_conn) conn->stop_stage = 0; conn->tmabort_state = TMABORT_INITIAL; session->age++; + session->recovery_failed = 0; + spin_unlock_bh(&session->lock); + write_unlock_bh(&sk->sk_callback_lock); + + iscsi_unblock_session(session_to_cls(session)); wake_up(&conn->ehwait); - break; + return 0; case STOP_CONN_TERM: session->conn_cnt++; conn->stop_stage = 0; @@ -2752,105 +2792,199 @@ iscsi_conn_start(struct iscsi_cls_conn *cls_conn) return 0; } -static void -iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) +static int +iscsi_ctask_mtask_cleanup(struct iscsi_cmd_task *ctask) { - struct iscsi_conn *conn = cls_conn->dd_data; + struct iscsi_conn *conn = ctask->conn; struct iscsi_session *session = conn->session; + struct iscsi_mgmt_task *mtask; + + if (!ctask->mtask) + return -EINVAL; + + while (__kfifo_get(conn->immqueue, (void*)&mtask, sizeof(void*))) { + if (mtask == ctask->mtask) + break; + __kfifo_put(conn->immqueue, (void*)&mtask, sizeof(void*)); + } + + __kfifo_put(session->mgmtpool.queue, (void*)&ctask->mtask, + sizeof(void*)); + ctask->mtask = NULL; + return 0; +} + +static void +fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, int err) +{ + struct iscsi_r2t_info *r2t; + struct scsi_cmnd *sc; + + /* flush ctask's r2t queues */ + while (__kfifo_get(ctask->r2tqueue, (void*)&r2t, sizeof(void*))) + __kfifo_put(ctask->r2tpool.queue, (void*)&r2t, sizeof(void*)); + + iscsi_ctask_mtask_cleanup(ctask); + + sc = ctask->sc; + if (!sc) + return; + + sc->result = err; + sc->resid = sc->request_bufflen; + + __iscsi_ctask_cleanup(conn, ctask); +} + +/* Fail commands. Mutex and session lock held */ +static void +fail_all_commands(struct iscsi_session *session, struct iscsi_conn *conn) +{ + struct iscsi_cmd_task *ctask, *tmp; + + /* flush pending */ + while (__kfifo_get(conn->xmitqueue, (void*)&ctask, sizeof(void*))) { + debug_scsi("failing pending sc %p itt 0x%x\n", ctask->sc, + ctask->itt); + fail_command(conn, ctask, DID_BUS_BUSY << 16); + } + + /* fail running */ + list_for_each_entry_safe(ctask, tmp, &conn->run_list, running) { + debug_scsi("failing in progress sc %p itt 0x%x\n", + ctask->sc, ctask->itt); + fail_command(conn, ctask, DID_BUS_BUSY << 16); + } + + conn->ctask = NULL; +} + +static void +flush_control_queues(struct iscsi_session *session, struct iscsi_conn *conn) +{ + struct iscsi_mgmt_task *mtask; + + /* TODO: handle running pdus */ + while (__kfifo_get(conn->immqueue, (void*)&mtask, sizeof(void*)) || + __kfifo_get(conn->mgmtqueue, (void*)&mtask, sizeof(void*))) { + if (mtask == conn->login_mtask) + continue; + __kfifo_put(session->mgmtpool.queue, (void*)&mtask, + sizeof(void*)); + } + + if (conn->mtask && conn->mtask != conn->login_mtask) + __kfifo_put(session->mgmtpool.queue, (void*)&conn->mtask, + sizeof(void*)); + conn->mtask = NULL; +} + +static void +iscsi_suspend_conn_rx(struct iscsi_conn *conn) +{ struct sock *sk; - unsigned long flags; BUG_ON(!conn->sock); sk = conn->sock->sk; write_lock_bh(&sk->sk_callback_lock); set_bit(SUSPEND_BIT, &conn->suspend_rx); write_unlock_bh(&sk->sk_callback_lock); +} - mutex_lock(&conn->xmitmutex); - - spin_lock_irqsave(session->host->host_lock, flags); - spin_lock(&session->lock); +static void +iscsi_start_session_recovery(struct iscsi_session *session, + struct iscsi_conn *conn, int flag) +{ + spin_lock_bh(&session->lock); + if (conn->stop_stage == STOP_CONN_RECOVER || + conn->stop_stage == STOP_CONN_TERM) { + spin_unlock_bh(&session->lock); + return; + } conn->stop_stage = flag; + spin_unlock_bh(&session->lock); + + iscsi_suspend_conn_rx(conn); + + mutex_lock(&conn->xmitmutex); + spin_lock_bh(&session->lock); conn->c_stage = ISCSI_CONN_STOPPED; set_bit(SUSPEND_BIT, &conn->suspend_tx); - if (flag != STOP_CONN_SUSPEND) - session->conn_cnt--; - + session->conn_cnt--; if (session->conn_cnt == 0 || session->leadconn == conn) session->state = ISCSI_STATE_FAILED; - spin_unlock(&session->lock); - spin_unlock_irqrestore(session->host->host_lock, flags); - - if (flag == STOP_CONN_TERM || flag == STOP_CONN_RECOVER) { - struct iscsi_cmd_task *ctask; - struct iscsi_mgmt_task *mtask; + spin_unlock_bh(&session->lock); - /* - * Socket must go now. - */ - sock_hold(conn->sock->sk); - iscsi_conn_restore_callbacks(conn); - sock_put(conn->sock->sk); + /* + * Socket must go now. + */ + sock_hold(conn->sock->sk); + iscsi_conn_restore_callbacks(conn); + sock_put(conn->sock->sk); - /* - * flush xmit queues. - */ - spin_lock_bh(&session->lock); - while (__kfifo_get(conn->writequeue, (void*)&ctask, - sizeof(void*)) || - __kfifo_get(conn->xmitqueue, (void*)&ctask, - sizeof(void*))) { - struct iscsi_r2t_info *r2t; - - /* - * flush ctask's r2t queues - */ - while (__kfifo_get(ctask->r2tqueue, (void*)&r2t, - sizeof(void*))) - __kfifo_put(ctask->r2tpool.queue, (void*)&r2t, - sizeof(void*)); + /* + * flush queues. + */ + spin_lock_bh(&session->lock); + fail_all_commands(session, conn); + flush_control_queues(session, conn); + spin_unlock_bh(&session->lock); - spin_unlock_bh(&session->lock); - local_bh_disable(); - iscsi_ctask_cleanup(conn, ctask); - local_bh_enable(); - spin_lock_bh(&session->lock); - } - conn->ctask = NULL; - while (__kfifo_get(conn->immqueue, (void*)&mtask, - sizeof(void*)) || - __kfifo_get(conn->mgmtqueue, (void*)&mtask, - sizeof(void*))) { - __kfifo_put(session->mgmtpool.queue, - (void*)&mtask, sizeof(void*)); - } - conn->mtask = NULL; - spin_unlock_bh(&session->lock); + /* + * release socket only after we stopped data_xmit() + * activity and flushed all outstandings + */ + sock_release(conn->sock); + conn->sock = NULL; - /* - * release socket only after we stopped data_xmit() - * activity and flushed all outstandings - */ - sock_release(conn->sock); - conn->sock = NULL; + /* + * for connection level recovery we should not calculate + * header digest. conn->hdr_size used for optimization + * in hdr_extract() and will be re-negotiated at + * set_param() time. + */ + if (flag == STOP_CONN_RECOVER) { + conn->hdr_size = sizeof(struct iscsi_hdr); + conn->hdrdgst_en = 0; + conn->datadgst_en = 0; - /* - * for connection level recovery we should not calculate - * header digest. conn->hdr_size used for optimization - * in hdr_extract() and will be re-negotiated at - * set_param() time. - */ - if (flag == STOP_CONN_RECOVER) { - conn->hdr_size = sizeof(struct iscsi_hdr); - conn->hdrdgst_en = 0; - conn->datadgst_en = 0; - } + if (session->state == ISCSI_STATE_FAILED) + iscsi_block_session(session_to_cls(session)); } mutex_unlock(&conn->xmitmutex); } +static void +iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) +{ + struct iscsi_conn *conn = cls_conn->dd_data; + struct iscsi_session *session = conn->session; + + switch (flag) { + case STOP_CONN_RECOVER: + case STOP_CONN_TERM: + iscsi_start_session_recovery(session, conn, flag); + return; + case STOP_CONN_SUSPEND: + iscsi_suspend_conn_rx(conn); + + mutex_lock(&conn->xmitmutex); + spin_lock_bh(&session->lock); + + conn->stop_stage = flag; + conn->c_stage = ISCSI_CONN_STOPPED; + set_bit(SUSPEND_BIT, &conn->suspend_tx); + + spin_unlock_bh(&session->lock); + mutex_unlock(&conn->xmitmutex); + break; + default: + printk(KERN_ERR "invalid stop flag %d\n", flag); + } +} + static int iscsi_conn_send_generic(struct iscsi_conn *conn, struct iscsi_hdr *hdr, char *data, uint32_t data_size) @@ -2940,23 +3074,54 @@ iscsi_conn_send_generic(struct iscsi_conn *conn, struct iscsi_hdr *hdr, static int iscsi_eh_host_reset(struct scsi_cmnd *sc) { - struct iscsi_cmd_task *ctask = (struct iscsi_cmd_task *)sc->SCp.ptr; - struct iscsi_conn *conn = ctask->conn; - struct iscsi_session *session = conn->session; + struct Scsi_Host *host = sc->device->host; + struct iscsi_session *session = iscsi_hostdata(host->hostdata); + struct iscsi_conn *conn = session->leadconn; + int fail_session = 0; spin_lock_bh(&session->lock); if (session->state == ISCSI_STATE_TERMINATE) { +failed: debug_scsi("failing host reset: session terminated " "[CID %d age %d]", conn->id, session->age); spin_unlock_bh(&session->lock); return FAILED; } + + if (sc->SCp.phase == session->age) { + debug_scsi("failing connection CID %d due to SCSI host reset", + conn->id); + fail_session = 1; + } spin_unlock_bh(&session->lock); - debug_scsi("failing connection CID %d due to SCSI host reset " - "[itt 0x%x age %d]", conn->id, ctask->itt, - session->age); - iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); + /* + * we drop the lock here but the leadconn cannot be destoyed while + * we are in the scsi eh + */ + if (fail_session) { + iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); + /* + * if userspace cannot respond then we must kick this off + * here for it + */ + iscsi_start_session_recovery(session, conn, STOP_CONN_RECOVER); + } + + debug_scsi("iscsi_eh_host_reset wait for relogin\n"); + wait_event_interruptible(conn->ehwait, + session->state == ISCSI_STATE_TERMINATE || + session->state == ISCSI_STATE_LOGGED_IN || + session->recovery_failed); + if (signal_pending(current)) + flush_signals(current); + + spin_lock_bh(&session->lock); + if (session->state == ISCSI_STATE_LOGGED_IN) + printk(KERN_INFO "host reset succeeded\n"); + else + goto failed; + spin_unlock_bh(&session->lock); return SUCCESS; } @@ -2970,8 +3135,6 @@ iscsi_tmabort_timedout(unsigned long data) spin_lock(&session->lock); if (conn->tmabort_state == TMABORT_INITIAL) { - __kfifo_put(session->mgmtpool.queue, - (void*)&ctask->mtask, sizeof(void*)); conn->tmabort_state = TMABORT_TIMEDOUT; debug_scsi("tmabort timedout [sc %lx itt 0x%x]\n", (long)ctask->sc, ctask->itt); @@ -2981,186 +3144,163 @@ iscsi_tmabort_timedout(unsigned long data) spin_unlock(&session->lock); } +/* must be called with the mutex lock */ static int -iscsi_eh_abort(struct scsi_cmnd *sc) +iscsi_exec_abort_task(struct scsi_cmnd *sc, struct iscsi_cmd_task *ctask) { - int rc; - struct iscsi_cmd_task *ctask = (struct iscsi_cmd_task *)sc->SCp.ptr; struct iscsi_conn *conn = ctask->conn; struct iscsi_session *session = conn->session; - - conn->eh_abort_cnt++; - debug_scsi("aborting [sc %lx itt 0x%x]\n", (long)sc, ctask->itt); + struct iscsi_tm *hdr = &conn->tmhdr; + int rc; /* - * two cases for ERL=0 here: - * - * 1) connection-level failure; - * 2) recovery due protocol error; + * ctask timed out but session is OK requests must be serialized. */ - mutex_lock(&conn->xmitmutex); - spin_lock_bh(&session->lock); - if (session->state != ISCSI_STATE_LOGGED_IN) { - if (session->state == ISCSI_STATE_TERMINATE) { - spin_unlock_bh(&session->lock); - mutex_unlock(&conn->xmitmutex); - goto failed; - } - spin_unlock_bh(&session->lock); - } else { - struct iscsi_tm *hdr = &conn->tmhdr; + memset(hdr, 0, sizeof(struct iscsi_tm)); + hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE; + hdr->flags = ISCSI_TM_FUNC_ABORT_TASK; + hdr->flags |= ISCSI_FLAG_CMD_FINAL; + memcpy(hdr->lun, ctask->hdr.lun, sizeof(hdr->lun)); + hdr->rtt = ctask->hdr.itt; + hdr->refcmdsn = ctask->hdr.cmdsn; - /* - * Still LOGGED_IN... - */ + rc = iscsi_conn_send_generic(conn, (struct iscsi_hdr *)hdr, + NULL, 0); + if (rc) { + iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); + debug_scsi("abort sent failure [itt 0x%x] %d", ctask->itt, rc); + return rc; + } - if (!ctask->sc || sc->SCp.phase != session->age) { - /* - * 1) ctask completed before time out. But session - * is still ok => Happy Retry. - * 2) session was re-open during time out of ctask. - */ - spin_unlock_bh(&session->lock); - mutex_unlock(&conn->xmitmutex); - goto success; - } - conn->tmabort_state = TMABORT_INITIAL; - spin_unlock_bh(&session->lock); + debug_scsi("abort sent [itt 0x%x]\n", ctask->itt); - /* - * ctask timed out but session is OK - * ERL=0 requires task mgmt abort to be issued on each - * failed command. requests must be serialized. - */ - memset(hdr, 0, sizeof(struct iscsi_tm)); - hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE; - hdr->flags = ISCSI_TM_FUNC_ABORT_TASK; - hdr->flags |= ISCSI_FLAG_CMD_FINAL; - memcpy(hdr->lun, ctask->hdr.lun, sizeof(hdr->lun)); - hdr->rtt = ctask->hdr.itt; - hdr->refcmdsn = ctask->hdr.cmdsn; - - rc = iscsi_conn_send_generic(conn, (struct iscsi_hdr *)hdr, - NULL, 0); - if (rc) { - iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); - debug_scsi("abort sent failure [itt 0x%x]", ctask->itt); - } else { - struct iscsi_r2t_info *r2t; - - /* - * TMF abort vs. TMF response race logic - */ - spin_lock_bh(&session->lock); - ctask->mtask = (struct iscsi_mgmt_task *) - session->mgmt_cmds[(hdr->itt & ITT_MASK) - - ISCSI_MGMT_ITT_OFFSET]; - /* - * have to flush r2tqueue to avoid r2t leaks - */ - while (__kfifo_get(ctask->r2tqueue, (void*)&r2t, - sizeof(void*))) { - __kfifo_put(ctask->r2tpool.queue, (void*)&r2t, - sizeof(void*)); - } - if (conn->tmabort_state == TMABORT_INITIAL) { - conn->tmfcmd_pdus_cnt++; - conn->tmabort_timer.expires = 3*HZ + jiffies; - conn->tmabort_timer.function = - iscsi_tmabort_timedout; - conn->tmabort_timer.data = (unsigned long)ctask; - add_timer(&conn->tmabort_timer); - debug_scsi("abort sent [itt 0x%x]", ctask->itt); - } else { - if (!ctask->sc || - conn->tmabort_state == TMABORT_SUCCESS) { - conn->tmabort_state = TMABORT_INITIAL; - spin_unlock_bh(&session->lock); - mutex_unlock(&conn->xmitmutex); - goto success; - } - conn->tmabort_state = TMABORT_INITIAL; - iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); - } - spin_unlock_bh(&session->lock); - } + spin_lock_bh(&session->lock); + ctask->mtask = (struct iscsi_mgmt_task *) + session->mgmt_cmds[(hdr->itt & ITT_MASK) - + ISCSI_MGMT_ITT_OFFSET]; + + if (conn->tmabort_state == TMABORT_INITIAL) { + conn->tmfcmd_pdus_cnt++; + conn->tmabort_timer.expires = 10*HZ + jiffies; + conn->tmabort_timer.function = iscsi_tmabort_timedout; + conn->tmabort_timer.data = (unsigned long)ctask; + add_timer(&conn->tmabort_timer); + debug_scsi("abort set timeout [itt 0x%x]", ctask->itt); } + spin_unlock_bh(&session->lock); mutex_unlock(&conn->xmitmutex); - /* * block eh thread until: * - * 1) abort response; - * 2) abort timeout; - * 3) session re-opened; - * 4) session terminated; + * 1) abort response + * 2) abort timeout + * 3) session is terminated or restarted or userspace has + * given up on recovery */ - for (;;) { - int p_state = session->state; - - rc = wait_event_interruptible(conn->ehwait, - (p_state == ISCSI_STATE_LOGGED_IN ? - (session->state == ISCSI_STATE_TERMINATE || - conn->tmabort_state != TMABORT_INITIAL) : - (session->state == ISCSI_STATE_TERMINATE || - session->state == ISCSI_STATE_LOGGED_IN))); - if (rc) { - /* shutdown.. */ - session->state = ISCSI_STATE_TERMINATE; - goto failed; - } + wait_event_interruptible(conn->ehwait, + sc->SCp.phase != session->age || + session->state != ISCSI_STATE_LOGGED_IN || + conn->tmabort_state != TMABORT_INITIAL || + session->recovery_failed); + if (signal_pending(current)) + flush_signals(current); + del_timer_sync(&conn->tmabort_timer); - if (signal_pending(current)) - flush_signals(current); + mutex_lock(&conn->xmitmutex); + return 0; +} - if (session->state == ISCSI_STATE_TERMINATE) - goto failed; +static int +iscsi_eh_abort(struct scsi_cmnd *sc) +{ + struct iscsi_cmd_task *ctask = (struct iscsi_cmd_task *)sc->SCp.ptr; + struct iscsi_cmd_task *tmp_ctask; + struct iscsi_conn *conn = ctask->conn; + struct iscsi_session *session = conn->session; + int rc; - spin_lock_bh(&session->lock); - if (sc->SCp.phase == session->age && - (conn->tmabort_state == TMABORT_TIMEDOUT || - conn->tmabort_state == TMABORT_FAILED)) { - conn->tmabort_state = TMABORT_INITIAL; - if (!ctask->sc) { - /* - * ctask completed before tmf abort response or - * time out. - * But session is still ok => Happy Retry. - */ - spin_unlock_bh(&session->lock); - break; - } - spin_unlock_bh(&session->lock); - iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); - continue; + conn->eh_abort_cnt++; + debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt); + + mutex_lock(&conn->xmitmutex); + spin_lock_bh(&session->lock); + + /* + * If we are not logged in or we have started a new session + * then let the host reset code handle this + */ + if (session->state != ISCSI_STATE_LOGGED_IN || + sc->SCp.phase != session->age) + goto failed; + + /* ctask completed before time out */ + if (!ctask->sc) + goto success; + + /* what should we do here ? */ + if (conn->ctask == ctask) { + printk(KERN_INFO "sc %p itt 0x%x partially sent. Failing " + "abort\n", sc, ctask->itt); + goto failed; + } + + /* check for the easy pending cmd abort */ + while (__kfifo_get(conn->xmitqueue, (void*)&tmp_ctask, sizeof(void*))) { + if (tmp_ctask->itt == ctask->itt) { + debug_scsi("found pending task\n"); + goto success; } + __kfifo_put(conn->xmitqueue, (void*)&tmp_ctask, sizeof(void*)); + } + + conn->tmabort_state = TMABORT_INITIAL; + + spin_unlock_bh(&session->lock); + rc = iscsi_exec_abort_task(sc, ctask); + spin_lock_bh(&session->lock); + + iscsi_ctask_mtask_cleanup(ctask); + if (rc || sc->SCp.phase != session->age || + session->state != ISCSI_STATE_LOGGED_IN) + goto failed; + + /* ctask completed before tmf abort response */ + if (!ctask->sc) { + debug_scsi("sc completed while abort in progress\n"); + goto success; + } + + if (conn->tmabort_state != TMABORT_SUCCESS) { spin_unlock_bh(&session->lock); - break; + iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); + spin_lock_bh(&session->lock); + goto failed; } success: debug_scsi("abort success [sc %lx itt 0x%x]\n", (long)sc, ctask->itt); - rc = SUCCESS; - goto exit; - -failed: - debug_scsi("abort failed [sc %lx itt 0x%x]\n", (long)sc, ctask->itt); - rc = FAILED; - -exit: - del_timer_sync(&conn->tmabort_timer); + spin_unlock_bh(&session->lock); - mutex_lock(&conn->xmitmutex); + /* clean up task if aborted */ if (conn->sock) { struct sock *sk = conn->sock->sk; write_lock_bh(&sk->sk_callback_lock); - iscsi_ctask_cleanup(conn, ctask); + spin_lock(&session->lock); + fail_command(conn, ctask, DRIVER_TIMEOUT << 24); + spin_unlock(&session->lock); write_unlock_bh(&sk->sk_callback_lock); } mutex_unlock(&conn->xmitmutex); - return rc; + return SUCCESS; + +failed: + spin_unlock_bh(&session->lock); + mutex_unlock(&conn->xmitmutex); + + debug_scsi("abort failed [sc %lx itt 0x%x]\n", (long)sc, ctask->itt); + return FAILED; } static int @@ -3359,16 +3499,6 @@ iscsi_conn_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param, struct iscsi_conn *conn = cls_conn->dd_data; struct iscsi_session *session = conn->session; - spin_lock_bh(&session->lock); - if (conn->c_stage != ISCSI_CONN_INITIAL_STAGE && - conn->stop_stage != STOP_CONN_RECOVER) { - printk(KERN_ERR "iscsi_tcp: can not change parameter [%d]\n", - param); - spin_unlock_bh(&session->lock); - return 0; - } - spin_unlock_bh(&session->lock); - switch(param) { case ISCSI_PARAM_MAX_RECV_DLENGTH: { char *saveptr = conn->data; @@ -3691,6 +3821,7 @@ static struct iscsi_transport iscsi_tcp_transport = { .stop_conn = iscsi_conn_stop, .send_pdu = iscsi_conn_send_pdu, .get_stats = iscsi_conn_get_stats, + .session_recovery_timedout = iscsi_session_recovery_timedout, }; static int __init diff --git a/drivers/scsi/iscsi_tcp.h b/drivers/scsi/iscsi_tcp.h index ba26741ac154..12ef64179b4c 100644 --- a/drivers/scsi/iscsi_tcp.h +++ b/drivers/scsi/iscsi_tcp.h @@ -159,6 +159,7 @@ struct iscsi_conn { struct kfifo *immqueue; /* immediate xmit queue */ struct kfifo *mgmtqueue; /* mgmt (control) xmit queue */ struct kfifo *xmitqueue; /* data-path cmd queue */ + struct list_head run_list; /* list of cmds in progress */ struct work_struct xmitwork; /* per-conn. xmit workqueue */ struct mutex xmitmutex; /* serializes connection xmit, * access to kfifos: * @@ -228,6 +229,7 @@ struct iscsi_session { * - mgmtpool, * * - r2tpool */ int state; /* session state */ + int recovery_failed; struct list_head item; void *auth_client; int conn_cnt; @@ -310,6 +312,7 @@ struct iscsi_cmd_task { struct iscsi_conn *conn; /* used connection */ struct iscsi_mgmt_task *mtask; /* tmf mtask in progr */ + struct list_head running; /* running cmd list */ struct iscsi_r2t_info *r2t; /* in progress R2T */ struct iscsi_queue r2tpool; struct kfifo *r2tqueue; diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 72a71ebc9d03..e2b67e34d92e 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -31,17 +31,17 @@ #include #include -#define ISCSI_SESSION_ATTRS 10 +#define ISCSI_SESSION_ATTRS 11 #define ISCSI_CONN_ATTRS 10 +#define ISCSI_HOST_ATTRS 0 struct iscsi_internal { struct scsi_transport_template t; struct iscsi_transport *iscsi_transport; struct list_head list; struct class_device cdev; - /* - * We do not have any private or other attrs. - */ + + struct class_device_attribute *host_attrs[ISCSI_HOST_ATTRS + 1]; struct transport_container conn_cont; struct class_device_attribute *conn_attrs[ISCSI_CONN_ATTRS + 1]; struct transport_container session_cont; @@ -114,6 +114,24 @@ static struct attribute_group iscsi_transport_group = { .attrs = iscsi_transport_attrs, }; +static int iscsi_setup_host(struct transport_container *tc, struct device *dev, + struct class_device *cdev) +{ + struct Scsi_Host *shost = dev_to_shost(dev); + struct iscsi_host *ihost = shost->shost_data; + + memset(ihost, 0, sizeof(*ihost)); + INIT_LIST_HEAD(&ihost->sessions); + mutex_init(&ihost->mutex); + return 0; +} + +static DECLARE_TRANSPORT_CLASS(iscsi_host_class, + "iscsi_host", + iscsi_setup_host, + NULL, + NULL); + static DECLARE_TRANSPORT_CLASS(iscsi_session_class, "iscsi_session", NULL, @@ -225,6 +243,54 @@ static int iscsi_is_session_dev(const struct device *dev) return dev->release == iscsi_session_release; } +static int iscsi_user_scan(struct Scsi_Host *shost, uint channel, + uint id, uint lun) +{ + struct iscsi_host *ihost = shost->shost_data; + struct iscsi_cls_session *session; + + mutex_lock(&ihost->mutex); + list_for_each_entry(session, &ihost->sessions, host_list) { + if ((channel == SCAN_WILD_CARD || + channel == session->channel) && + (id == SCAN_WILD_CARD || id == session->target_id)) + scsi_scan_target(&session->dev, session->channel, + session->target_id, lun, 1); + } + mutex_unlock(&ihost->mutex); + + return 0; +} + +static void session_recovery_timedout(void *data) +{ + struct iscsi_cls_session *session = data; + + dev_printk(KERN_INFO, &session->dev, "session recovery timed out " + "after %d secs\n", session->recovery_tmo); + + if (session->transport->session_recovery_timedout) + session->transport->session_recovery_timedout(session); + + scsi_target_unblock(&session->dev); +} + +void iscsi_unblock_session(struct iscsi_cls_session *session) +{ + if (!cancel_delayed_work(&session->recovery_work)) + flush_scheduled_work(); + scsi_target_unblock(&session->dev); +} +EXPORT_SYMBOL_GPL(iscsi_unblock_session); + +void iscsi_block_session(struct iscsi_cls_session *session) +{ + scsi_target_block(&session->dev); + schedule_delayed_work(&session->recovery_work, + session->recovery_tmo * HZ); +} +EXPORT_SYMBOL_GPL(iscsi_block_session); + /** * iscsi_create_session - create iscsi class session * @shost: scsi host @@ -233,8 +299,10 @@ static int iscsi_is_session_dev(const struct device *dev) * This can be called from a LLD or iscsi_transport. **/ struct iscsi_cls_session * -iscsi_create_session(struct Scsi_Host *shost, struct iscsi_transport *transport) +iscsi_create_session(struct Scsi_Host *shost, + struct iscsi_transport *transport, int channel) { + struct iscsi_host *ihost; struct iscsi_cls_session *session; int err; @@ -246,13 +314,22 @@ iscsi_create_session(struct Scsi_Host *shost, struct iscsi_transport *transport) if (!session) goto module_put; session->transport = transport; + session->recovery_tmo = 120; + INIT_WORK(&session->recovery_work, session_recovery_timedout, session); + INIT_LIST_HEAD(&session->host_list); + INIT_LIST_HEAD(&session->sess_list); if (transport->sessiondata_size) session->dd_data = &session[1]; /* this is released in the dev's release function */ scsi_host_get(shost); + ihost = shost->shost_data; + session->sid = iscsi_session_nr++; + session->channel = channel; + session->target_id = ihost->next_target_id++; + snprintf(session->dev.bus_id, BUS_ID_SIZE, "session%u", session->sid); session->dev.parent = &shost->shost_gendev; @@ -265,6 +342,10 @@ iscsi_create_session(struct Scsi_Host *shost, struct iscsi_transport *transport) } transport_register_device(&session->dev); + mutex_lock(&ihost->mutex); + list_add(&session->host_list, &ihost->sessions); + mutex_unlock(&ihost->mutex); + return session; free_session: @@ -285,6 +366,16 @@ EXPORT_SYMBOL_GPL(iscsi_create_session); **/ int iscsi_destroy_session(struct iscsi_cls_session *session) { + struct Scsi_Host *shost = iscsi_session_to_shost(session); + struct iscsi_host *ihost = shost->shost_data; + + if (!cancel_delayed_work(&session->recovery_work)) + flush_scheduled_work(); + + mutex_lock(&ihost->mutex); + list_del(&session->host_list); + mutex_unlock(&ihost->mutex); + transport_unregister_device(&session->dev); device_unregister(&session->dev); return 0; @@ -435,7 +526,7 @@ iscsi_transport_create_session(struct scsi_transport_template *scsit, if (scsi_add_host(shost, NULL)) goto free_host; - session = iscsi_create_session(shost, transport); + session = iscsi_create_session(shost, transport, 0); if (!session) goto remove_host; @@ -466,12 +557,13 @@ int iscsi_transport_destroy_session(struct Scsi_Host *shost) struct iscsi_cls_session *session; unsigned long flags; - scsi_remove_host(shost); session = hostdata_session(shost->hostdata); spin_lock_irqsave(&sesslock, flags); list_del(&session->sess_list); spin_unlock_irqrestore(&sesslock, flags); iscsi_destroy_session(session); + + scsi_remove_host(shost); /* ref from host alloc */ scsi_host_put(shost); return 0; @@ -594,6 +686,7 @@ iscsi_unicast_skb(struct mempool_zone *zone, struct sk_buff *skb) } spin_lock_irqsave(&zone->freelock, flags); + INIT_LIST_HEAD(skb_to_lh(skb)); list_add(skb_to_lh(skb), &zone->freequeue); spin_unlock_irqrestore(&zone->freelock, flags); @@ -888,6 +981,11 @@ iscsi_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev) return -EINVAL; switch (ev->u.set_param.param) { + case ISCSI_PARAM_SESS_RECOVERY_TMO: + iscsi_copy_param(ev, &value, data); + if (value != 0) + session->recovery_tmo = value; + break; case ISCSI_PARAM_TARGET_NAME: /* this should not change between logins */ if (session->targetname) @@ -980,7 +1078,6 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) ev->r.retcode = transport->start_conn(conn); else err = -EINVAL; - break; case ISCSI_UEVENT_STOP_CONN: conn = iscsi_conn_lookup(ev->u.stop_conn.sid, ev->u.stop_conn.cid); @@ -1198,6 +1295,7 @@ static ISCSI_CLASS_ATTR(priv_sess, field, S_IRUGO, show_priv_session_##field, \ NULL) iscsi_priv_session_attr(targetname, "%s"); iscsi_priv_session_attr(tpgt, "%d"); +iscsi_priv_session_attr(recovery_tmo, "%d"); #define iscsi_priv_conn_attr_show(field, format) \ static ssize_t \ @@ -1289,6 +1387,24 @@ static int iscsi_conn_match(struct attribute_container *cont, return &priv->conn_cont.ac == cont; } +static int iscsi_host_match(struct attribute_container *cont, + struct device *dev) +{ + struct Scsi_Host *shost; + struct iscsi_internal *priv; + + if (!scsi_is_host_device(dev)) + return 0; + + shost = dev_to_shost(dev); + if (!shost->transportt || + shost->transportt->host_attrs.ac.class != &iscsi_host_class.class) + return 0; + + priv = to_iscsi_internal(shost->transportt); + return &priv->t.host_attrs.ac == cont; +} + struct scsi_transport_template * iscsi_register_transport(struct iscsi_transport *tt) { @@ -1307,6 +1423,7 @@ iscsi_register_transport(struct iscsi_transport *tt) return NULL; INIT_LIST_HEAD(&priv->list); priv->iscsi_transport = tt; + priv->t.user_scan = iscsi_user_scan; priv->cdev.class = &iscsi_transport_class; snprintf(priv->cdev.class_id, BUS_ID_SIZE, "%s", tt->name); @@ -1318,6 +1435,14 @@ iscsi_register_transport(struct iscsi_transport *tt) if (err) goto unregister_cdev; + /* host parameters */ + priv->t.host_attrs.ac.attrs = &priv->host_attrs[0]; + priv->t.host_attrs.ac.class = &iscsi_host_class.class; + priv->t.host_attrs.ac.match = iscsi_host_match; + priv->t.host_size = sizeof(struct iscsi_host); + priv->host_attrs[0] = NULL; + transport_container_register(&priv->t.host_attrs); + /* connection parameters */ priv->conn_cont.ac.attrs = &priv->conn_attrs[0]; priv->conn_cont.ac.class = &iscsi_connection_class.class; @@ -1361,6 +1486,7 @@ iscsi_register_transport(struct iscsi_transport *tt) SETUP_SESSION_RD_ATTR(data_pdu_in_order, ISCSI_PDU_INORDER_EN); SETUP_SESSION_RD_ATTR(data_seq_in_order, ISCSI_DATASEQ_INORDER_EN); SETUP_SESSION_RD_ATTR(erl, ISCSI_ERL); + SETUP_PRIV_SESSION_RD_ATTR(recovery_tmo); if (tt->param_mask & ISCSI_TARGET_NAME) SETUP_SESSION_RD_ATTR(targetname, ISCSI_TARGET_NAME); @@ -1408,6 +1534,7 @@ int iscsi_unregister_transport(struct iscsi_transport *tt) transport_container_unregister(&priv->conn_cont); transport_container_unregister(&priv->session_cont); + transport_container_unregister(&priv->t.host_attrs); sysfs_remove_group(&priv->cdev.kobj, &iscsi_transport_group); class_device_unregister(&priv->cdev); @@ -1451,10 +1578,14 @@ static __init int iscsi_transport_init(void) if (err) return err; - err = transport_class_register(&iscsi_connection_class); + err = transport_class_register(&iscsi_host_class); if (err) goto unregister_transport_class; + err = transport_class_register(&iscsi_connection_class); + if (err) + goto unregister_host_class; + err = transport_class_register(&iscsi_session_class); if (err) goto unregister_conn_class; @@ -1482,6 +1613,8 @@ unregister_session_class: transport_class_unregister(&iscsi_session_class); unregister_conn_class: transport_class_unregister(&iscsi_connection_class); +unregister_host_class: + transport_class_unregister(&iscsi_host_class); unregister_transport_class: class_unregister(&iscsi_transport_class); return err; @@ -1494,6 +1627,7 @@ static void __exit iscsi_transport_exit(void) netlink_unregister_notifier(&iscsi_nl_notifier); transport_class_unregister(&iscsi_connection_class); transport_class_unregister(&iscsi_session_class); + transport_class_unregister(&iscsi_host_class); class_unregister(&iscsi_transport_class); } diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h index 2c3a89b64e71..eebe2b15161b 100644 --- a/include/scsi/iscsi_if.h +++ b/include/scsi/iscsi_if.h @@ -174,6 +174,7 @@ enum iscsi_param { ISCSI_PARAM_TPGT, ISCSI_PARAM_PERSISTENT_ADDRESS, ISCSI_PARAM_PERSISTENT_PORT, + ISCSI_PARAM_SESS_RECOVERY_TMO, /* pased in through bind conn using transport_fd */ ISCSI_PARAM_CONN_PORT, @@ -201,6 +202,7 @@ enum iscsi_param { #define ISCSI_TPGT (1 << ISCSI_PARAM_TPGT) #define ISCSI_PERSISTENT_ADDRESS (1 << ISCSI_PARAM_PERSISTENT_ADDRESS) #define ISCSI_PERSISTENT_PORT (1 << ISCSI_PARAM_PERSISTENT_PORT) +#define ISCSI_SESS_RECOVERY_TMO (1 << ISCSI_PARAM_SESS_RECOVERY_TMO) #define ISCSI_CONN_PORT (1 << ISCSI_PARAM_CONN_PORT) #define ISCSI_CONN_ADDRESS (1 << ISCSI_PARAM_CONN_ADDRESS) diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h index 4b200645c84b..9d2b99159ee7 100644 --- a/include/scsi/scsi_transport_iscsi.h +++ b/include/scsi/scsi_transport_iscsi.h @@ -90,6 +90,7 @@ struct iscsi_transport { char *data, uint32_t data_size); void (*get_stats) (struct iscsi_cls_conn *conn, struct iscsi_stats *stats); + void (*session_recovery_timedout) (struct iscsi_cls_session *session); }; /* @@ -130,12 +131,20 @@ struct iscsi_cls_conn { struct iscsi_cls_session { struct list_head sess_list; /* item in session_list */ + struct list_head host_list; struct iscsi_transport *transport; /* iSCSI values used as unique id by userspace. */ char *targetname; int tpgt; + /* recovery fields */ + int recovery_tmo; + struct work_struct recovery_work; + + int target_id; + int channel; + int sid; /* session id */ void *dd_data; /* LLD private data */ struct device dev; /* sysfs transport/container device */ @@ -147,15 +156,23 @@ struct iscsi_cls_session { #define iscsi_session_to_shost(_session) \ dev_to_shost(_session->dev.parent) +struct iscsi_host { + int next_target_id; + struct list_head sessions; + struct mutex mutex; +}; + /* * session and connection functions that can be used by HW iSCSI LLDs */ extern struct iscsi_cls_session *iscsi_create_session(struct Scsi_Host *shost, - struct iscsi_transport *t); + struct iscsi_transport *t, int channel); extern int iscsi_destroy_session(struct iscsi_cls_session *session); extern struct iscsi_cls_conn *iscsi_create_conn(struct iscsi_cls_session *sess, uint32_t cid); extern int iscsi_destroy_conn(struct iscsi_cls_conn *conn); +extern void iscsi_unblock_session(struct iscsi_cls_session *session); +extern void iscsi_block_session(struct iscsi_cls_session *session); /* * session functions used by software iscsi -- cgit v1.2.3 From 7996a778ff8c717cb1a7a294475c59cc8f1e9fb8 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Thu, 6 Apr 2006 21:13:41 -0500 Subject: [SCSI] iscsi: add libiscsi There is a lot of code duplcited between iscsi_tcp and the upcoming iscsi_iser driver. This patch puts the duplicated code in a lib. There is more code to move around but this takes care of the basics. For iscsi_offload if they use the lib we will probably move some things around. For example in the queuecommand we will not assume that the LLD wants to do queue_work, but it is better to handle that later when we know for sure what iscsi_offload looks like (we could probably do this for iscsi_iser though to). Ideally I would like to get the iscsi_transports modules to a place where all they really have to do is put data on the wire, but how to do that will hopefully be more clear when we see other modules like iscsi_offload. Or maybe iscsi_offload will not use the lib and it will just be iscsi_iser and iscsi_tcp and maybe the iscsi_tcp_tgt if that is allowed in mainline. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/Makefile | 2 +- drivers/scsi/libiscsi.c | 1697 +++++++++++++++++++++++++++++++++++ drivers/scsi/scsi_transport_iscsi.c | 116 +-- include/scsi/iscsi_if.h | 3 +- include/scsi/libiscsi.h | 286 ++++++ include/scsi/scsi_transport_iscsi.h | 59 +- 6 files changed, 2045 insertions(+), 118 deletions(-) create mode 100644 drivers/scsi/libiscsi.c create mode 100644 include/scsi/libiscsi.h (limited to 'include') diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index e513c3158ad9..efdff61c5808 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -33,7 +33,7 @@ obj-$(CONFIG_SCSI_FC_ATTRS) += scsi_transport_fc.o obj-$(CONFIG_SCSI_ISCSI_ATTRS) += scsi_transport_iscsi.o obj-$(CONFIG_SCSI_SAS_ATTRS) += scsi_transport_sas.o -obj-$(CONFIG_ISCSI_TCP) += iscsi_tcp.o +obj-$(CONFIG_ISCSI_TCP) += libiscsi.o iscsi_tcp.o obj-$(CONFIG_SCSI_AMIGA7XX) += amiga7xx.o 53c7xx.o obj-$(CONFIG_A3000_SCSI) += a3000.o wd33c93.o obj-$(CONFIG_A2091_SCSI) += a2091.o wd33c93.o diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c new file mode 100644 index 000000000000..274a1374ab64 --- /dev/null +++ b/drivers/scsi/libiscsi.c @@ -0,0 +1,1697 @@ +/* + * iSCSI lib functions + * + * Copyright (C) 2006 Red Hat, Inc. All rights reserved. + * Copyright (C) 2004 - 2006 Mike Christie + * Copyright (C) 2004 - 2005 Dmitry Yusupov + * Copyright (C) 2004 - 2005 Alex Aizman + * maintained by open-iscsi@googlegroups.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct iscsi_session * +class_to_transport_session(struct iscsi_cls_session *cls_session) +{ + struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); + return iscsi_hostdata(shost->hostdata); +} +EXPORT_SYMBOL_GPL(class_to_transport_session); + +#define INVALID_SN_DELTA 0xffff + +int +iscsi_check_assign_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr) +{ + uint32_t max_cmdsn = be32_to_cpu(hdr->max_cmdsn); + uint32_t exp_cmdsn = be32_to_cpu(hdr->exp_cmdsn); + + if (max_cmdsn < exp_cmdsn -1 && + max_cmdsn > exp_cmdsn - INVALID_SN_DELTA) + return ISCSI_ERR_MAX_CMDSN; + if (max_cmdsn > session->max_cmdsn || + max_cmdsn < session->max_cmdsn - INVALID_SN_DELTA) + session->max_cmdsn = max_cmdsn; + if (exp_cmdsn > session->exp_cmdsn || + exp_cmdsn < session->exp_cmdsn - INVALID_SN_DELTA) + session->exp_cmdsn = exp_cmdsn; + + return 0; +} +EXPORT_SYMBOL_GPL(iscsi_check_assign_cmdsn); + +void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *ctask, + struct iscsi_data *hdr, + int transport_data_cnt) +{ + struct iscsi_conn *conn = ctask->conn; + + memset(hdr, 0, sizeof(struct iscsi_data)); + hdr->ttt = cpu_to_be32(ISCSI_RESERVED_TAG); + hdr->datasn = cpu_to_be32(ctask->unsol_datasn); + ctask->unsol_datasn++; + hdr->opcode = ISCSI_OP_SCSI_DATA_OUT; + memcpy(hdr->lun, ctask->hdr->lun, sizeof(hdr->lun)); + + hdr->itt = ctask->hdr->itt; + hdr->exp_statsn = cpu_to_be32(conn->exp_statsn); + + hdr->offset = cpu_to_be32(ctask->total_length - + transport_data_cnt - + ctask->unsol_count); + + if (ctask->unsol_count > conn->max_xmit_dlength) { + hton24(hdr->dlength, conn->max_xmit_dlength); + ctask->data_count = conn->max_xmit_dlength; + hdr->flags = 0; + } else { + hton24(hdr->dlength, ctask->unsol_count); + ctask->data_count = ctask->unsol_count; + hdr->flags = ISCSI_FLAG_CMD_FINAL; + } +} +EXPORT_SYMBOL_GPL(iscsi_prep_unsolicit_data_pdu); + +/** + * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu + * @ctask: iscsi cmd task + * + * Prep basic iSCSI PDU fields for a scsi cmd pdu. The LLD should set + * fields like dlength or final based on how much data it sends + */ +static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) +{ + struct iscsi_conn *conn = ctask->conn; + struct iscsi_session *session = conn->session; + struct iscsi_cmd *hdr = ctask->hdr; + struct scsi_cmnd *sc = ctask->sc; + + hdr->opcode = ISCSI_OP_SCSI_CMD; + hdr->flags = ISCSI_ATTR_SIMPLE; + int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun); + hdr->itt = ctask->itt | (conn->id << ISCSI_CID_SHIFT) | + (session->age << ISCSI_AGE_SHIFT); + hdr->data_length = cpu_to_be32(sc->request_bufflen); + hdr->cmdsn = cpu_to_be32(session->cmdsn); + session->cmdsn++; + hdr->exp_statsn = cpu_to_be32(conn->exp_statsn); + memcpy(hdr->cdb, sc->cmnd, sc->cmd_len); + memset(&hdr->cdb[sc->cmd_len], 0, MAX_COMMAND_SIZE - sc->cmd_len); + + if (sc->sc_data_direction == DMA_TO_DEVICE) { + hdr->flags |= ISCSI_FLAG_CMD_WRITE; + /* + * Write counters: + * + * imm_count bytes to be sent right after + * SCSI PDU Header + * + * unsol_count bytes(as Data-Out) to be sent + * without R2T ack right after + * immediate data + * + * r2t_data_count bytes to be sent via R2T ack's + * + * pad_count bytes to be sent as zero-padding + */ + ctask->imm_count = 0; + ctask->unsol_count = 0; + ctask->unsol_datasn = 0; + + if (session->imm_data_en) { + if (ctask->total_length >= session->first_burst) + ctask->imm_count = min(session->first_burst, + conn->max_xmit_dlength); + else + ctask->imm_count = min(ctask->total_length, + conn->max_xmit_dlength); + hton24(ctask->hdr->dlength, ctask->imm_count); + } else + zero_data(ctask->hdr->dlength); + + if (!session->initial_r2t_en) + ctask->unsol_count = min(session->first_burst, + ctask->total_length) - ctask->imm_count; + if (!ctask->unsol_count) + /* No unsolicit Data-Out's */ + ctask->hdr->flags |= ISCSI_FLAG_CMD_FINAL; + } else { + ctask->datasn = 0; + hdr->flags |= ISCSI_FLAG_CMD_FINAL; + zero_data(hdr->dlength); + + if (sc->sc_data_direction == DMA_FROM_DEVICE) + hdr->flags |= ISCSI_FLAG_CMD_READ; + } + + conn->scsicmd_pdus_cnt++; +} +EXPORT_SYMBOL_GPL(iscsi_prep_scsi_cmd_pdu); + +/** + * iscsi_complete_command - return command back to scsi-ml + * @session: iscsi session + * @ctask: iscsi cmd task + * + * Must be called with session lock. + * This function returns the scsi command to scsi-ml and returns + * the cmd task to the pool of available cmd tasks. + */ +static void iscsi_complete_command(struct iscsi_session *session, + struct iscsi_cmd_task *ctask) +{ + struct scsi_cmnd *sc = ctask->sc; + + ctask->sc = NULL; + list_del_init(&ctask->running); + __kfifo_put(session->cmdpool.queue, (void*)&ctask, sizeof(void*)); + sc->scsi_done(sc); +} + +/** + * iscsi_cmd_rsp - SCSI Command Response processing + * @conn: iscsi connection + * @hdr: iscsi header + * @ctask: scsi command task + * @data: cmd data buffer + * @datalen: len of buffer + * + * iscsi_cmd_rsp sets up the scsi_cmnd fields based on the PDU and + * then completes the command and task. + **/ +static int iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr, + struct iscsi_cmd_task *ctask, char *data, + int datalen) +{ + int rc; + struct iscsi_cmd_rsp *rhdr = (struct iscsi_cmd_rsp *)hdr; + struct iscsi_session *session = conn->session; + struct scsi_cmnd *sc = ctask->sc; + + rc = iscsi_check_assign_cmdsn(session, (struct iscsi_nopin*)rhdr); + if (rc) { + sc->result = DID_ERROR << 16; + goto out; + } + + conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1; + + sc->result = (DID_OK << 16) | rhdr->cmd_status; + + if (rhdr->response != ISCSI_STATUS_CMD_COMPLETED) { + sc->result = DID_ERROR << 16; + goto out; + } + + if (rhdr->cmd_status == SAM_STAT_CHECK_CONDITION) { + int senselen; + + if (datalen < 2) { +invalid_datalen: + printk(KERN_ERR "Got CHECK_CONDITION but invalid " + "data buffer size of %d\n", datalen); + sc->result = DID_BAD_TARGET << 16; + goto out; + } + + senselen = (data[0] << 8) | data[1]; + if (datalen < senselen) + goto invalid_datalen; + + memcpy(sc->sense_buffer, data + 2, + min(senselen, SCSI_SENSE_BUFFERSIZE)); + debug_scsi("copied %d bytes of sense\n", + min(senselen, SCSI_SENSE_BUFFERSIZE)); + } + + if (sc->sc_data_direction == DMA_TO_DEVICE) + goto out; + + if (rhdr->flags & ISCSI_FLAG_CMD_UNDERFLOW) { + int res_count = be32_to_cpu(rhdr->residual_count); + + if (res_count > 0 && res_count <= sc->request_bufflen) + sc->resid = res_count; + else + sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; + } else if (rhdr->flags & ISCSI_FLAG_CMD_BIDI_UNDERFLOW) + sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; + else if (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW) + sc->resid = be32_to_cpu(rhdr->residual_count); + +out: + debug_scsi("done [sc %lx res %d itt 0x%x]\n", + (long)sc, sc->result, ctask->itt); + conn->scsirsp_pdus_cnt++; + + iscsi_complete_command(conn->session, ctask); + return rc; +} + +/** + * __iscsi_complete_pdu - complete pdu + * @conn: iscsi conn + * @hdr: iscsi header + * @data: data buffer + * @datalen: len of data buffer + * + * Completes pdu processing by freeing any resources allocated at + * queuecommand or send generic. session lock must be held and verify + * itt must have been called. + */ +int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, + char *data, int datalen) +{ + struct iscsi_session *session = conn->session; + int opcode = hdr->opcode & ISCSI_OPCODE_MASK, rc = 0; + struct iscsi_cmd_task *ctask; + struct iscsi_mgmt_task *mtask; + uint32_t itt; + + if (hdr->itt != cpu_to_be32(ISCSI_RESERVED_TAG)) + itt = hdr->itt & ISCSI_ITT_MASK; + else + itt = hdr->itt; + + if (itt < session->cmds_max) { + ctask = session->cmds[itt]; + + debug_scsi("cmdrsp [op 0x%x cid %d itt 0x%x len %d]\n", + opcode, conn->id, ctask->itt, datalen); + + switch(opcode) { + case ISCSI_OP_SCSI_CMD_RSP: + BUG_ON((void*)ctask != ctask->sc->SCp.ptr); + rc = iscsi_scsi_cmd_rsp(conn, hdr, ctask, data, + datalen); + break; + case ISCSI_OP_SCSI_DATA_IN: + BUG_ON((void*)ctask != ctask->sc->SCp.ptr); + if (hdr->flags & ISCSI_FLAG_DATA_STATUS) { + conn->scsirsp_pdus_cnt++; + iscsi_complete_command(session, ctask); + } + break; + case ISCSI_OP_R2T: + /* LLD handles this for now */ + break; + default: + rc = ISCSI_ERR_BAD_OPCODE; + break; + } + } else if (itt >= ISCSI_MGMT_ITT_OFFSET && + itt < ISCSI_MGMT_ITT_OFFSET + session->mgmtpool_max) { + mtask = session->mgmt_cmds[itt - ISCSI_MGMT_ITT_OFFSET]; + + debug_scsi("immrsp [op 0x%x cid %d itt 0x%x len %d]\n", + opcode, conn->id, mtask->itt, datalen); + + switch(opcode) { + case ISCSI_OP_LOGIN_RSP: + case ISCSI_OP_TEXT_RSP: + case ISCSI_OP_LOGOUT_RSP: + rc = iscsi_check_assign_cmdsn(session, + (struct iscsi_nopin*)hdr); + if (rc) + break; + + rc = iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen); + list_del(&mtask->running); + if (conn->login_mtask != mtask) + __kfifo_put(session->mgmtpool.queue, + (void*)&mtask, sizeof(void*)); + break; + case ISCSI_OP_SCSI_TMFUNC_RSP: + rc = iscsi_check_assign_cmdsn(session, + (struct iscsi_nopin*)hdr); + if (rc) + break; + + if (datalen) { + rc = ISCSI_ERR_PROTO; + break; + } + conn->tmfrsp_pdus_cnt++; + if (conn->tmabort_state == TMABORT_INITIAL) { + conn->tmabort_state = + ((struct iscsi_tm_rsp *)hdr)-> + response == ISCSI_TMF_RSP_COMPLETE ? + TMABORT_SUCCESS:TMABORT_FAILED; + /* unblock eh_abort() */ + wake_up(&conn->ehwait); + } + break; + case ISCSI_OP_NOOP_IN: + if (hdr->ttt != ISCSI_RESERVED_TAG) { + rc = ISCSI_ERR_PROTO; + break; + } + rc = iscsi_check_assign_cmdsn(session, + (struct iscsi_nopin*)hdr); + if (rc) + break; + conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; + + rc = iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen); + list_del(&mtask->running); + if (conn->login_mtask != mtask) + __kfifo_put(session->mgmtpool.queue, + (void*)&mtask, sizeof(void*)); + break; + default: + rc = ISCSI_ERR_BAD_OPCODE; + break; + } + } else if (itt == ISCSI_RESERVED_TAG) { + switch(opcode) { + case ISCSI_OP_NOOP_IN: + if (!datalen) { + rc = iscsi_check_assign_cmdsn(session, + (struct iscsi_nopin*)hdr); + if (!rc && hdr->ttt != ISCSI_RESERVED_TAG) + rc = iscsi_recv_pdu(conn->cls_conn, + hdr, NULL, 0); + } else + rc = ISCSI_ERR_PROTO; + break; + case ISCSI_OP_REJECT: + /* we need sth like iscsi_reject_rsp()*/ + case ISCSI_OP_ASYNC_EVENT: + /* we need sth like iscsi_async_event_rsp() */ + rc = ISCSI_ERR_BAD_OPCODE; + break; + default: + rc = ISCSI_ERR_BAD_OPCODE; + break; + } + } else + rc = ISCSI_ERR_BAD_ITT; + + return rc; +} +EXPORT_SYMBOL_GPL(__iscsi_complete_pdu); + +int iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, + char *data, int datalen) +{ + int rc; + + spin_lock(&conn->session->lock); + rc = __iscsi_complete_pdu(conn, hdr, data, datalen); + spin_unlock(&conn->session->lock); + return rc; +} +EXPORT_SYMBOL_GPL(iscsi_complete_pdu); + +/* verify itt (itt encoding: age+cid+itt) */ +int iscsi_verify_itt(struct iscsi_conn *conn, struct iscsi_hdr *hdr, + uint32_t *ret_itt) +{ + struct iscsi_session *session = conn->session; + struct iscsi_cmd_task *ctask; + uint32_t itt; + + if (hdr->itt != cpu_to_be32(ISCSI_RESERVED_TAG)) { + if ((hdr->itt & ISCSI_AGE_MASK) != + (session->age << ISCSI_AGE_SHIFT)) { + printk(KERN_ERR "iscsi_tcp: received itt %x expected " + "session age (%x)\n", hdr->itt, + session->age & ISCSI_AGE_MASK); + return ISCSI_ERR_BAD_ITT; + } + + if ((hdr->itt & ISCSI_CID_MASK) != + (conn->id << ISCSI_CID_SHIFT)) { + printk(KERN_ERR "iscsi_tcp: received itt %x, expected " + "CID (%x)\n", hdr->itt, conn->id); + return ISCSI_ERR_BAD_ITT; + } + itt = hdr->itt & ISCSI_ITT_MASK; + } else + itt = hdr->itt; + + if (itt < session->cmds_max) { + ctask = session->cmds[itt]; + + if (!ctask->sc) { + printk(KERN_INFO "iscsi_tcp: dropping ctask with " + "itt 0x%x\n", ctask->itt); + /* force drop */ + return ISCSI_ERR_NO_SCSI_CMD; + } + + if (ctask->sc->SCp.phase != session->age) { + printk(KERN_ERR "iscsi_tcp: ctask's session age %d, " + "expected %d\n", ctask->sc->SCp.phase, + session->age); + return ISCSI_ERR_SESSION_FAILED; + } + } + + *ret_itt = itt; + return 0; +} +EXPORT_SYMBOL_GPL(iscsi_verify_itt); + +void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err) +{ + struct iscsi_session *session = conn->session; + unsigned long flags; + + spin_lock_irqsave(&session->lock, flags); + if (session->conn_cnt == 1 || session->leadconn == conn) + session->state = ISCSI_STATE_FAILED; + spin_unlock_irqrestore(&session->lock, flags); + set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); + set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx); + iscsi_conn_error(conn->cls_conn, err); +} +EXPORT_SYMBOL_GPL(iscsi_conn_failure); + +/** + * iscsi_data_xmit - xmit any command into the scheduled connection + * @conn: iscsi connection + * + * Notes: + * The function can return -EAGAIN in which case the caller must + * re-schedule it again later or recover. '0' return code means + * successful xmit. + **/ +static int iscsi_data_xmit(struct iscsi_conn *conn) +{ + struct iscsi_transport *tt; + + if (unlikely(conn->suspend_tx)) { + debug_scsi("conn %d Tx suspended!\n", conn->id); + return 0; + } + tt = conn->session->tt; + + /* + * Transmit in the following order: + * + * 1) un-finished xmit (ctask or mtask) + * 2) immediate control PDUs + * 3) write data + * 4) SCSI commands + * 5) non-immediate control PDUs + * + * No need to lock around __kfifo_get as long as + * there's one producer and one consumer. + */ + + BUG_ON(conn->ctask && conn->mtask); + + if (conn->ctask) { + if (tt->xmit_cmd_task(conn, conn->ctask)) + goto again; + /* done with this in-progress ctask */ + conn->ctask = NULL; + } + if (conn->mtask) { + if (tt->xmit_mgmt_task(conn, conn->mtask)) + goto again; + /* done with this in-progress mtask */ + conn->mtask = NULL; + } + + /* process immediate first */ + if (unlikely(__kfifo_len(conn->immqueue))) { + while (__kfifo_get(conn->immqueue, (void*)&conn->mtask, + sizeof(void*))) { + list_add_tail(&conn->mtask->running, + &conn->mgmt_run_list); + if (tt->xmit_mgmt_task(conn, conn->mtask)) + goto again; + } + /* done with this mtask */ + conn->mtask = NULL; + } + + /* process command queue */ + while (__kfifo_get(conn->xmitqueue, (void*)&conn->ctask, + sizeof(void*))) { + /* + * iscsi tcp may readd the task to the xmitqueue to send + * write data + */ + if (list_empty(&conn->ctask->running)) + list_add_tail(&conn->ctask->running, &conn->run_list); + if (tt->xmit_cmd_task(conn, conn->ctask)) + goto again; + } + /* done with this ctask */ + conn->ctask = NULL; + + /* process the rest control plane PDUs, if any */ + if (unlikely(__kfifo_len(conn->mgmtqueue))) { + while (__kfifo_get(conn->mgmtqueue, (void*)&conn->mtask, + sizeof(void*))) { + list_add_tail(&conn->mtask->running, + &conn->mgmt_run_list); + if (tt->xmit_mgmt_task(conn, conn->mtask)) + goto again; + } + /* done with this mtask */ + conn->mtask = NULL; + } + + return 0; + +again: + if (unlikely(conn->suspend_tx)) + return 0; + + return -EAGAIN; +} + +static void iscsi_xmitworker(void *data) +{ + struct iscsi_conn *conn = data; + + /* + * serialize Xmit worker on a per-connection basis. + */ + mutex_lock(&conn->xmitmutex); + if (iscsi_data_xmit(conn)) + scsi_queue_work(conn->session->host, &conn->xmitwork); + mutex_unlock(&conn->xmitmutex); +} + +enum { + FAILURE_BAD_HOST = 1, + FAILURE_SESSION_FAILED, + FAILURE_SESSION_FREED, + FAILURE_WINDOW_CLOSED, + FAILURE_SESSION_TERMINATE, + FAILURE_SESSION_RECOVERY_TIMEOUT, +}; + +int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) +{ + struct Scsi_Host *host; + int reason = 0; + struct iscsi_session *session; + struct iscsi_conn *conn; + struct iscsi_cmd_task *ctask = NULL; + + sc->scsi_done = done; + sc->result = 0; + + host = sc->device->host; + session = iscsi_hostdata(host->hostdata); + + spin_lock(&session->lock); + + if (session->state != ISCSI_STATE_LOGGED_IN) { + if (session->recovery_failed) { + reason = FAILURE_SESSION_RECOVERY_TIMEOUT; + goto fault; + } else if (session->state == ISCSI_STATE_FAILED) { + reason = FAILURE_SESSION_FAILED; + goto reject; + } else if (session->state == ISCSI_STATE_TERMINATE) { + reason = FAILURE_SESSION_TERMINATE; + goto fault; + } + reason = FAILURE_SESSION_FREED; + goto fault; + } + + /* + * Check for iSCSI window and take care of CmdSN wrap-around + */ + if ((int)(session->max_cmdsn - session->cmdsn) < 0) { + reason = FAILURE_WINDOW_CLOSED; + goto reject; + } + + conn = session->leadconn; + + __kfifo_get(session->cmdpool.queue, (void*)&ctask, sizeof(void*)); + sc->SCp.phase = session->age; + sc->SCp.ptr = (char *)ctask; + + ctask->mtask = NULL; + ctask->conn = conn; + ctask->sc = sc; + INIT_LIST_HEAD(&ctask->running); + ctask->total_length = sc->request_bufflen; + iscsi_prep_scsi_cmd_pdu(ctask); + + session->tt->init_cmd_task(ctask); + + __kfifo_put(conn->xmitqueue, (void*)&ctask, sizeof(void*)); + debug_scsi( + "ctask enq [%s cid %d sc %lx itt 0x%x len %d cmdsn %d win %d]\n", + sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read", + conn->id, (long)sc, ctask->itt, sc->request_bufflen, + session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1); + spin_unlock(&session->lock); + + scsi_queue_work(host, &conn->xmitwork); + return 0; + +reject: + spin_unlock(&session->lock); + debug_scsi("cmd 0x%x rejected (%d)\n", sc->cmnd[0], reason); + return SCSI_MLQUEUE_HOST_BUSY; + +fault: + spin_unlock(&session->lock); + printk(KERN_ERR "iscsi_tcp: cmd 0x%x is not queued (%d)\n", + sc->cmnd[0], reason); + sc->result = (DID_NO_CONNECT << 16); + sc->resid = sc->request_bufflen; + sc->scsi_done(sc); + return 0; +} +EXPORT_SYMBOL_GPL(iscsi_queuecommand); + +int iscsi_change_queue_depth(struct scsi_device *sdev, int depth) +{ + if (depth > ISCSI_MAX_CMD_PER_LUN) + depth = ISCSI_MAX_CMD_PER_LUN; + scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth); + return sdev->queue_depth; +} +EXPORT_SYMBOL_GPL(iscsi_change_queue_depth); + +static int +iscsi_conn_send_generic(struct iscsi_conn *conn, struct iscsi_hdr *hdr, + char *data, uint32_t data_size) +{ + struct iscsi_session *session = conn->session; + struct iscsi_nopout *nop = (struct iscsi_nopout *)hdr; + struct iscsi_mgmt_task *mtask; + + spin_lock_bh(&session->lock); + if (session->state == ISCSI_STATE_TERMINATE) { + spin_unlock_bh(&session->lock); + return -EPERM; + } + if (hdr->opcode == (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) || + hdr->opcode == (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE)) + /* + * Login and Text are sent serially, in + * request-followed-by-response sequence. + * Same mtask can be used. Same ITT must be used. + * Note that login_mtask is preallocated at conn_create(). + */ + mtask = conn->login_mtask; + else { + BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE); + BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED); + + if (!__kfifo_get(session->mgmtpool.queue, + (void*)&mtask, sizeof(void*))) { + spin_unlock_bh(&session->lock); + return -ENOSPC; + } + } + + /* + * pre-format CmdSN and ExpStatSN for outgoing PDU. + */ + if (hdr->itt != cpu_to_be32(ISCSI_RESERVED_TAG)) { + hdr->itt = mtask->itt | (conn->id << ISCSI_CID_SHIFT) | + (session->age << ISCSI_AGE_SHIFT); + nop->cmdsn = cpu_to_be32(session->cmdsn); + if (conn->c_stage == ISCSI_CONN_STARTED && + !(hdr->opcode & ISCSI_OP_IMMEDIATE)) + session->cmdsn++; + } else + /* do not advance CmdSN */ + nop->cmdsn = cpu_to_be32(session->cmdsn); + + nop->exp_statsn = cpu_to_be32(conn->exp_statsn); + + if (data_size) { + memcpy(mtask->data, data, data_size); + mtask->data_count = data_size; + } else + mtask->data_count = 0; + + INIT_LIST_HEAD(&mtask->running); + memcpy(mtask->hdr, hdr, sizeof(struct iscsi_hdr)); + if (session->tt->init_mgmt_task) + session->tt->init_mgmt_task(conn, mtask, data, data_size); + spin_unlock_bh(&session->lock); + + debug_scsi("mgmtpdu [op 0x%x hdr->itt 0x%x datalen %d]\n", + hdr->opcode, hdr->itt, data_size); + + /* + * since send_pdu() could be called at least from two contexts, + * we need to serialize __kfifo_put, so we don't have to take + * additional lock on fast data-path + */ + if (hdr->opcode & ISCSI_OP_IMMEDIATE) + __kfifo_put(conn->immqueue, (void*)&mtask, sizeof(void*)); + else + __kfifo_put(conn->mgmtqueue, (void*)&mtask, sizeof(void*)); + + scsi_queue_work(session->host, &conn->xmitwork); + return 0; +} + +int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr, + char *data, uint32_t data_size) +{ + struct iscsi_conn *conn = cls_conn->dd_data; + int rc; + + mutex_lock(&conn->xmitmutex); + rc = iscsi_conn_send_generic(conn, hdr, data, data_size); + mutex_unlock(&conn->xmitmutex); + + return rc; +} +EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu); + +void iscsi_session_recovery_timedout(struct iscsi_cls_session *cls_session) +{ + struct iscsi_session *session = class_to_transport_session(cls_session); + struct iscsi_conn *conn = session->leadconn; + + spin_lock_bh(&session->lock); + if (session->state != ISCSI_STATE_LOGGED_IN) { + session->recovery_failed = 1; + if (conn) + wake_up(&conn->ehwait); + } + spin_unlock_bh(&session->lock); +} +EXPORT_SYMBOL_GPL(iscsi_session_recovery_timedout); + +int iscsi_eh_host_reset(struct scsi_cmnd *sc) +{ + struct Scsi_Host *host = sc->device->host; + struct iscsi_session *session = iscsi_hostdata(host->hostdata); + struct iscsi_conn *conn = session->leadconn; + int fail_session = 0; + + spin_lock_bh(&session->lock); + if (session->state == ISCSI_STATE_TERMINATE) { +failed: + debug_scsi("failing host reset: session terminated " + "[CID %d age %d]", conn->id, session->age); + spin_unlock_bh(&session->lock); + return FAILED; + } + + if (sc->SCp.phase == session->age) { + debug_scsi("failing connection CID %d due to SCSI host reset", + conn->id); + fail_session = 1; + } + spin_unlock_bh(&session->lock); + + /* + * we drop the lock here but the leadconn cannot be destoyed while + * we are in the scsi eh + */ + if (fail_session) { + iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); + /* + * if userspace cannot respond then we must kick this off + * here for it + */ + iscsi_start_session_recovery(session, conn, STOP_CONN_RECOVER); + } + + debug_scsi("iscsi_eh_host_reset wait for relogin\n"); + wait_event_interruptible(conn->ehwait, + session->state == ISCSI_STATE_TERMINATE || + session->state == ISCSI_STATE_LOGGED_IN || + session->recovery_failed); + if (signal_pending(current)) + flush_signals(current); + + spin_lock_bh(&session->lock); + if (session->state == ISCSI_STATE_LOGGED_IN) + printk(KERN_INFO "host reset succeeded\n"); + else + goto failed; + spin_unlock_bh(&session->lock); + + return SUCCESS; +} +EXPORT_SYMBOL_GPL(iscsi_eh_host_reset); + +static void iscsi_tmabort_timedout(unsigned long data) +{ + struct iscsi_cmd_task *ctask = (struct iscsi_cmd_task *)data; + struct iscsi_conn *conn = ctask->conn; + struct iscsi_session *session = conn->session; + + spin_lock(&session->lock); + if (conn->tmabort_state == TMABORT_INITIAL) { + conn->tmabort_state = TMABORT_TIMEDOUT; + debug_scsi("tmabort timedout [sc %p itt 0x%x]\n", + ctask->sc, ctask->itt); + /* unblock eh_abort() */ + wake_up(&conn->ehwait); + } + spin_unlock(&session->lock); +} + +/* must be called with the mutex lock */ +static int iscsi_exec_abort_task(struct scsi_cmnd *sc, + struct iscsi_cmd_task *ctask) +{ + struct iscsi_conn *conn = ctask->conn; + struct iscsi_session *session = conn->session; + struct iscsi_tm *hdr = &conn->tmhdr; + int rc; + + /* + * ctask timed out but session is OK requests must be serialized. + */ + memset(hdr, 0, sizeof(struct iscsi_tm)); + hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE; + hdr->flags = ISCSI_TM_FUNC_ABORT_TASK; + hdr->flags |= ISCSI_FLAG_CMD_FINAL; + memcpy(hdr->lun, ctask->hdr->lun, sizeof(hdr->lun)); + hdr->rtt = ctask->hdr->itt; + hdr->refcmdsn = ctask->hdr->cmdsn; + + rc = iscsi_conn_send_generic(conn, (struct iscsi_hdr *)hdr, + NULL, 0); + if (rc) { + iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); + debug_scsi("abort sent failure [itt 0x%x] %d", ctask->itt, rc); + return rc; + } + + debug_scsi("abort sent [itt 0x%x]\n", ctask->itt); + + spin_lock_bh(&session->lock); + ctask->mtask = (struct iscsi_mgmt_task *) + session->mgmt_cmds[(hdr->itt & ISCSI_ITT_MASK) - + ISCSI_MGMT_ITT_OFFSET]; + + if (conn->tmabort_state == TMABORT_INITIAL) { + conn->tmfcmd_pdus_cnt++; + conn->tmabort_timer.expires = 10*HZ + jiffies; + conn->tmabort_timer.function = iscsi_tmabort_timedout; + conn->tmabort_timer.data = (unsigned long)ctask; + add_timer(&conn->tmabort_timer); + debug_scsi("abort set timeout [itt 0x%x]", ctask->itt); + } + spin_unlock_bh(&session->lock); + mutex_unlock(&conn->xmitmutex); + + /* + * block eh thread until: + * + * 1) abort response + * 2) abort timeout + * 3) session is terminated or restarted or userspace has + * given up on recovery + */ + wait_event_interruptible(conn->ehwait, + sc->SCp.phase != session->age || + session->state != ISCSI_STATE_LOGGED_IN || + conn->tmabort_state != TMABORT_INITIAL || + session->recovery_failed); + if (signal_pending(current)) + flush_signals(current); + del_timer_sync(&conn->tmabort_timer); + + mutex_lock(&conn->xmitmutex); + return 0; +} + +/* + * xmit mutex and session lock must be held + */ +#define iscsi_remove_task(tasktype) \ +static struct iscsi_##tasktype * \ +iscsi_remove_##tasktype(struct kfifo *fifo, uint32_t itt) \ +{ \ + int i, nr_tasks = __kfifo_len(fifo) / sizeof(void*); \ + struct iscsi_##tasktype *task; \ + \ + debug_scsi("searching %d tasks\n", nr_tasks); \ + \ + for (i = 0; i < nr_tasks; i++) { \ + __kfifo_get(fifo, (void*)&task, sizeof(void*)); \ + debug_scsi("check task %u\n", task->itt); \ + \ + if (task->itt == itt) { \ + debug_scsi("matched task\n"); \ + break; \ + } \ + \ + __kfifo_put(fifo, (void*)&task, sizeof(void*)); \ + } \ + return NULL; \ +} + +iscsi_remove_task(mgmt_task); +iscsi_remove_task(cmd_task); + +static int iscsi_ctask_mtask_cleanup(struct iscsi_cmd_task *ctask) +{ + struct iscsi_conn *conn = ctask->conn; + struct iscsi_session *session = conn->session; + + if (!ctask->mtask) + return -EINVAL; + + if (!iscsi_remove_mgmt_task(conn->immqueue, ctask->mtask->itt)) + list_del(&ctask->mtask->running); + __kfifo_put(session->mgmtpool.queue, (void*)&ctask->mtask, + sizeof(void*)); + ctask->mtask = NULL; + return 0; +} + +/* + * session lock and xmitmutex must be held + */ +static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, + int err) +{ + struct scsi_cmnd *sc; + + conn->session->tt->cleanup_cmd_task(conn, ctask); + iscsi_ctask_mtask_cleanup(ctask); + + sc = ctask->sc; + if (!sc) + return; + sc->result = err; + sc->resid = sc->request_bufflen; + iscsi_complete_command(conn->session, ctask); +} + +int iscsi_eh_abort(struct scsi_cmnd *sc) +{ + struct iscsi_cmd_task *ctask = (struct iscsi_cmd_task *)sc->SCp.ptr; + struct iscsi_conn *conn = ctask->conn; + struct iscsi_session *session = conn->session; + struct iscsi_cmd_task *pending_ctask; + int rc; + + conn->eh_abort_cnt++; + debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt); + + mutex_lock(&conn->xmitmutex); + spin_lock_bh(&session->lock); + + /* + * If we are not logged in or we have started a new session + * then let the host reset code handle this + */ + if (session->state != ISCSI_STATE_LOGGED_IN || + sc->SCp.phase != session->age) + goto failed; + + /* ctask completed before time out */ + if (!ctask->sc) + goto success; + + /* what should we do here ? */ + if (conn->ctask == ctask) { + printk(KERN_INFO "sc %p itt 0x%x partially sent. Failing " + "abort\n", sc, ctask->itt); + goto failed; + } + + /* check for the easy pending cmd abort */ + pending_ctask = iscsi_remove_cmd_task(conn->xmitqueue, ctask->itt); + if (pending_ctask) { + /* iscsi_tcp queues write transfers on the xmitqueue */ + if (list_empty(&pending_ctask->running)) { + debug_scsi("found pending task\n"); + goto success; + } else + __kfifo_put(conn->xmitqueue, (void*)&pending_ctask, + sizeof(void*)); + } + + conn->tmabort_state = TMABORT_INITIAL; + + spin_unlock_bh(&session->lock); + rc = iscsi_exec_abort_task(sc, ctask); + spin_lock_bh(&session->lock); + + iscsi_ctask_mtask_cleanup(ctask); + if (rc || sc->SCp.phase != session->age || + session->state != ISCSI_STATE_LOGGED_IN) + goto failed; + + /* ctask completed before tmf abort response */ + if (!ctask->sc) { + debug_scsi("sc completed while abort in progress\n"); + goto success; + } + + if (conn->tmabort_state != TMABORT_SUCCESS) { + spin_unlock_bh(&session->lock); + iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); + spin_lock_bh(&session->lock); + goto failed; + } + +success: + debug_scsi("abort success [sc %lx itt 0x%x]\n", (long)sc, ctask->itt); + spin_unlock_bh(&session->lock); + + /* + * clean up task if aborted. we have the xmitmutex so grab + * the recv lock as a writer + */ + write_lock_bh(conn->recv_lock); + spin_lock(&session->lock); + fail_command(conn, ctask, DID_ABORT << 16); + spin_unlock(&session->lock); + write_unlock_bh(conn->recv_lock); + + mutex_unlock(&conn->xmitmutex); + return SUCCESS; + +failed: + spin_unlock_bh(&session->lock); + mutex_unlock(&conn->xmitmutex); + + debug_scsi("abort failed [sc %lx itt 0x%x]\n", (long)sc, ctask->itt); + return FAILED; +} +EXPORT_SYMBOL_GPL(iscsi_eh_abort); + +int +iscsi_pool_init(struct iscsi_queue *q, int max, void ***items, int item_size) +{ + int i; + + *items = kmalloc(max * sizeof(void*), GFP_KERNEL); + if (*items == NULL) + return -ENOMEM; + + q->max = max; + q->pool = kmalloc(max * sizeof(void*), GFP_KERNEL); + if (q->pool == NULL) { + kfree(*items); + return -ENOMEM; + } + + q->queue = kfifo_init((void*)q->pool, max * sizeof(void*), + GFP_KERNEL, NULL); + if (q->queue == ERR_PTR(-ENOMEM)) { + kfree(q->pool); + kfree(*items); + return -ENOMEM; + } + + for (i = 0; i < max; i++) { + q->pool[i] = kmalloc(item_size, GFP_KERNEL); + if (q->pool[i] == NULL) { + int j; + + for (j = 0; j < i; j++) + kfree(q->pool[j]); + + kfifo_free(q->queue); + kfree(q->pool); + kfree(*items); + return -ENOMEM; + } + memset(q->pool[i], 0, item_size); + (*items)[i] = q->pool[i]; + __kfifo_put(q->queue, (void*)&q->pool[i], sizeof(void*)); + } + return 0; +} +EXPORT_SYMBOL_GPL(iscsi_pool_init); + +void iscsi_pool_free(struct iscsi_queue *q, void **items) +{ + int i; + + for (i = 0; i < q->max; i++) + kfree(items[i]); + kfree(q->pool); + kfree(items); +} +EXPORT_SYMBOL_GPL(iscsi_pool_free); + +/* + * iSCSI Session's hostdata organization: + * + * *------------------* <== hostdata_session(host->hostdata) + * | ptr to class sess| + * |------------------| <== iscsi_hostdata(host->hostdata) + * | iscsi_session | + * *------------------* + */ + +#define hostdata_privsize(_sz) (sizeof(unsigned long) + _sz + \ + _sz % sizeof(unsigned long)) + +#define hostdata_session(_hostdata) (iscsi_ptr(*(unsigned long *)_hostdata)) + +/** + * iscsi_session_setup - create iscsi cls session and host and session + * @scsit: scsi transport template + * @iscsit: iscsi transport template + * @initial_cmdsn: initial CmdSN + * @hostno: host no allocated + * + * This can be used by software iscsi_transports that allocate + * a session per scsi host. + **/ +struct iscsi_cls_session * +iscsi_session_setup(struct iscsi_transport *iscsit, + struct scsi_transport_template *scsit, + int cmd_task_size, int mgmt_task_size, + uint32_t initial_cmdsn, uint32_t *hostno) +{ + struct Scsi_Host *shost; + struct iscsi_session *session; + struct iscsi_cls_session *cls_session; + int cmd_i; + + shost = scsi_host_alloc(iscsit->host_template, + hostdata_privsize(sizeof(*session))); + if (!shost) + return NULL; + + shost->max_id = 1; + shost->max_channel = 0; + shost->max_lun = iscsit->max_lun; + shost->max_cmd_len = iscsit->max_cmd_len; + shost->transportt = scsit; + shost->transportt->create_work_queue = 1; + *hostno = shost->host_no; + + session = iscsi_hostdata(shost->hostdata); + memset(session, 0, sizeof(struct iscsi_session)); + session->host = shost; + session->state = ISCSI_STATE_FREE; + session->mgmtpool_max = ISCSI_MGMT_CMDS_MAX; + session->cmds_max = ISCSI_XMIT_CMDS_MAX; + session->cmdsn = initial_cmdsn; + session->exp_cmdsn = initial_cmdsn + 1; + session->max_cmdsn = initial_cmdsn + 1; + session->max_r2t = 1; + session->tt = iscsit; + + /* initialize SCSI PDU commands pool */ + if (iscsi_pool_init(&session->cmdpool, session->cmds_max, + (void***)&session->cmds, + cmd_task_size + sizeof(struct iscsi_cmd_task))) + goto cmdpool_alloc_fail; + + /* pre-format cmds pool with ITT */ + for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) { + struct iscsi_cmd_task *ctask = session->cmds[cmd_i]; + + if (cmd_task_size) + ctask->dd_data = &ctask[1]; + ctask->itt = cmd_i; + } + + spin_lock_init(&session->lock); + INIT_LIST_HEAD(&session->connections); + + /* initialize immediate command pool */ + if (iscsi_pool_init(&session->mgmtpool, session->mgmtpool_max, + (void***)&session->mgmt_cmds, + mgmt_task_size + sizeof(struct iscsi_mgmt_task))) + goto mgmtpool_alloc_fail; + + + /* pre-format immediate cmds pool with ITT */ + for (cmd_i = 0; cmd_i < session->mgmtpool_max; cmd_i++) { + struct iscsi_mgmt_task *mtask = session->mgmt_cmds[cmd_i]; + + if (mgmt_task_size) + mtask->dd_data = &mtask[1]; + mtask->itt = ISCSI_MGMT_ITT_OFFSET + cmd_i; + mtask->data = kmalloc(DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH, + GFP_KERNEL); + if (!mtask->data) { + int j; + + for (j = 0; j < cmd_i; j++) + kfree(session->mgmt_cmds[j]->data); + goto immdata_alloc_fail; + } + } + + if (scsi_add_host(shost, NULL)) + goto add_host_fail; + + cls_session = iscsi_create_session(shost, iscsit, 0); + if (!cls_session) + goto cls_session_fail; + *(unsigned long*)shost->hostdata = (unsigned long)cls_session; + + return cls_session; + +cls_session_fail: + scsi_remove_host(shost); +add_host_fail: + for (cmd_i = 0; cmd_i < session->mgmtpool_max; cmd_i++) + kfree(session->mgmt_cmds[cmd_i]->data); +immdata_alloc_fail: + iscsi_pool_free(&session->mgmtpool, (void**)session->mgmt_cmds); +mgmtpool_alloc_fail: + iscsi_pool_free(&session->cmdpool, (void**)session->cmds); +cmdpool_alloc_fail: + scsi_host_put(shost); + return NULL; +} +EXPORT_SYMBOL_GPL(iscsi_session_setup); + +/** + * iscsi_session_teardown - destroy session, host, and cls_session + * shost: scsi host + * + * This can be used by software iscsi_transports that allocate + * a session per scsi host. + **/ +void iscsi_session_teardown(struct iscsi_cls_session *cls_session) +{ + struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); + struct iscsi_session *session = iscsi_hostdata(shost->hostdata); + int cmd_i; + + scsi_remove_host(shost); + + for (cmd_i = 0; cmd_i < session->mgmtpool_max; cmd_i++) + kfree(session->mgmt_cmds[cmd_i]->data); + + iscsi_pool_free(&session->mgmtpool, (void**)session->mgmt_cmds); + iscsi_pool_free(&session->cmdpool, (void**)session->cmds); + + iscsi_destroy_session(cls_session); + scsi_host_put(shost); +} +EXPORT_SYMBOL_GPL(iscsi_session_teardown); + +/** + * iscsi_conn_setup - create iscsi_cls_conn and iscsi_conn + * @cls_session: iscsi_cls_session + * @conn_idx: cid + **/ +struct iscsi_cls_conn * +iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx) +{ + struct iscsi_session *session = class_to_transport_session(cls_session); + struct iscsi_conn *conn; + struct iscsi_cls_conn *cls_conn; + + cls_conn = iscsi_create_conn(cls_session, conn_idx); + if (!cls_conn) + return NULL; + conn = cls_conn->dd_data; + memset(conn, 0, sizeof(*conn)); + + conn->session = session; + conn->cls_conn = cls_conn; + conn->c_stage = ISCSI_CONN_INITIAL_STAGE; + conn->id = conn_idx; + conn->exp_statsn = 0; + conn->tmabort_state = TMABORT_INITIAL; + INIT_LIST_HEAD(&conn->run_list); + INIT_LIST_HEAD(&conn->mgmt_run_list); + + /* initialize general xmit PDU commands queue */ + conn->xmitqueue = kfifo_alloc(session->cmds_max * sizeof(void*), + GFP_KERNEL, NULL); + if (conn->xmitqueue == ERR_PTR(-ENOMEM)) + goto xmitqueue_alloc_fail; + + /* initialize general immediate & non-immediate PDU commands queue */ + conn->immqueue = kfifo_alloc(session->mgmtpool_max * sizeof(void*), + GFP_KERNEL, NULL); + if (conn->immqueue == ERR_PTR(-ENOMEM)) + goto immqueue_alloc_fail; + + conn->mgmtqueue = kfifo_alloc(session->mgmtpool_max * sizeof(void*), + GFP_KERNEL, NULL); + if (conn->mgmtqueue == ERR_PTR(-ENOMEM)) + goto mgmtqueue_alloc_fail; + + INIT_WORK(&conn->xmitwork, iscsi_xmitworker, conn); + + /* allocate login_mtask used for the login/text sequences */ + spin_lock_bh(&session->lock); + if (!__kfifo_get(session->mgmtpool.queue, + (void*)&conn->login_mtask, + sizeof(void*))) { + spin_unlock_bh(&session->lock); + goto login_mtask_alloc_fail; + } + spin_unlock_bh(&session->lock); + + init_timer(&conn->tmabort_timer); + mutex_init(&conn->xmitmutex); + init_waitqueue_head(&conn->ehwait); + + return cls_conn; + +login_mtask_alloc_fail: + kfifo_free(conn->mgmtqueue); +mgmtqueue_alloc_fail: + kfifo_free(conn->immqueue); +immqueue_alloc_fail: + kfifo_free(conn->xmitqueue); +xmitqueue_alloc_fail: + iscsi_destroy_conn(cls_conn); + return NULL; +} +EXPORT_SYMBOL_GPL(iscsi_conn_setup); + +/** + * iscsi_conn_teardown - teardown iscsi connection + * cls_conn: iscsi class connection + * + * TODO: we may need to make this into a two step process + * like scsi-mls remove + put host + */ +void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) +{ + struct iscsi_conn *conn = cls_conn->dd_data; + struct iscsi_session *session = conn->session; + unsigned long flags; + + mutex_lock(&conn->xmitmutex); + set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); + if (conn->c_stage == ISCSI_CONN_INITIAL_STAGE) { + if (session->tt->suspend_conn_recv) + session->tt->suspend_conn_recv(conn); + + session->tt->terminate_conn(conn); + } + + spin_lock_bh(&session->lock); + conn->c_stage = ISCSI_CONN_CLEANUP_WAIT; + if (session->leadconn == conn) { + /* + * leading connection? then give up on recovery. + */ + session->state = ISCSI_STATE_TERMINATE; + wake_up(&conn->ehwait); + } + spin_unlock_bh(&session->lock); + + mutex_unlock(&conn->xmitmutex); + + /* + * Block until all in-progress commands for this connection + * time out or fail. + */ + for (;;) { + spin_lock_irqsave(session->host->host_lock, flags); + if (!session->host->host_busy) { /* OK for ERL == 0 */ + spin_unlock_irqrestore(session->host->host_lock, flags); + break; + } + spin_unlock_irqrestore(session->host->host_lock, flags); + msleep_interruptible(500); + printk("conn_destroy(): host_busy %d host_failed %d\n", + session->host->host_busy, session->host->host_failed); + /* + * force eh_abort() to unblock + */ + wake_up(&conn->ehwait); + } + + spin_lock_bh(&session->lock); + __kfifo_put(session->mgmtpool.queue, (void*)&conn->login_mtask, + sizeof(void*)); + list_del(&conn->item); + if (list_empty(&session->connections)) + session->leadconn = NULL; + if (session->leadconn && session->leadconn == conn) + session->leadconn = container_of(session->connections.next, + struct iscsi_conn, item); + + if (session->leadconn == NULL) + /* no connections exits.. reset sequencing */ + session->cmdsn = session->max_cmdsn = session->exp_cmdsn = 1; + spin_unlock_bh(&session->lock); + + kfifo_free(conn->xmitqueue); + kfifo_free(conn->immqueue); + kfifo_free(conn->mgmtqueue); + + iscsi_destroy_conn(cls_conn); +} +EXPORT_SYMBOL_GPL(iscsi_conn_teardown); + +int iscsi_conn_start(struct iscsi_cls_conn *cls_conn) +{ + struct iscsi_conn *conn = cls_conn->dd_data; + struct iscsi_session *session = conn->session; + + if (session == NULL) { + printk(KERN_ERR "iscsi: can't start unbound connection\n"); + return -EPERM; + } + + spin_lock_bh(&session->lock); + conn->c_stage = ISCSI_CONN_STARTED; + session->state = ISCSI_STATE_LOGGED_IN; + + switch(conn->stop_stage) { + case STOP_CONN_RECOVER: + /* + * unblock eh_abort() if it is blocked. re-try all + * commands after successful recovery + */ + session->conn_cnt++; + conn->stop_stage = 0; + conn->tmabort_state = TMABORT_INITIAL; + session->age++; + session->recovery_failed = 0; + spin_unlock_bh(&session->lock); + + iscsi_unblock_session(session_to_cls(session)); + wake_up(&conn->ehwait); + return 0; + case STOP_CONN_TERM: + session->conn_cnt++; + conn->stop_stage = 0; + break; + case STOP_CONN_SUSPEND: + conn->stop_stage = 0; + clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx); + clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); + break; + default: + break; + } + spin_unlock_bh(&session->lock); + + return 0; +} +EXPORT_SYMBOL_GPL(iscsi_conn_start); + +static void +flush_control_queues(struct iscsi_session *session, struct iscsi_conn *conn) +{ + struct iscsi_mgmt_task *mtask, *tmp; + + /* handle pending */ + while (__kfifo_get(conn->immqueue, (void*)&mtask, sizeof(void*)) || + __kfifo_get(conn->mgmtqueue, (void*)&mtask, sizeof(void*))) { + if (mtask == conn->login_mtask) + continue; + debug_scsi("flushing pending mgmt task itt 0x%x\n", mtask->itt); + __kfifo_put(session->mgmtpool.queue, (void*)&mtask, + sizeof(void*)); + } + + /* handle running */ + list_for_each_entry_safe(mtask, tmp, &conn->mgmt_run_list, running) { + debug_scsi("flushing running mgmt task itt 0x%x\n", mtask->itt); + if (mtask == conn->login_mtask) + continue; + list_del(&mtask->running); + __kfifo_put(session->mgmtpool.queue, (void*)&conn->mtask, + sizeof(void*)); + } + + conn->mtask = NULL; +} + +/* Fail commands. Mutex and session lock held and recv side suspended */ +static void fail_all_commands(struct iscsi_conn *conn) +{ + struct iscsi_cmd_task *ctask, *tmp; + + /* flush pending */ + while (__kfifo_get(conn->xmitqueue, (void*)&ctask, sizeof(void*))) { + debug_scsi("failing pending sc %p itt 0x%x\n", ctask->sc, + ctask->itt); + fail_command(conn, ctask, DID_BUS_BUSY << 16); + } + + /* fail all other running */ + list_for_each_entry_safe(ctask, tmp, &conn->run_list, running) { + debug_scsi("failing in progress sc %p itt 0x%x\n", + ctask->sc, ctask->itt); + fail_command(conn, ctask, DID_BUS_BUSY << 16); + } + + conn->ctask = NULL; +} + +void iscsi_start_session_recovery(struct iscsi_session *session, + struct iscsi_conn *conn, int flag) +{ + spin_lock_bh(&session->lock); + if (conn->stop_stage == STOP_CONN_RECOVER || + conn->stop_stage == STOP_CONN_TERM) { + spin_unlock_bh(&session->lock); + return; + } + conn->stop_stage = flag; + spin_unlock_bh(&session->lock); + + if (session->tt->suspend_conn_recv) + session->tt->suspend_conn_recv(conn); + + mutex_lock(&conn->xmitmutex); + spin_lock_bh(&session->lock); + conn->c_stage = ISCSI_CONN_STOPPED; + set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); + + session->conn_cnt--; + if (session->conn_cnt == 0 || session->leadconn == conn) + session->state = ISCSI_STATE_FAILED; + + spin_unlock_bh(&session->lock); + + session->tt->terminate_conn(conn); + /* + * flush queues. + */ + spin_lock_bh(&session->lock); + fail_all_commands(conn); + flush_control_queues(session, conn); + spin_unlock_bh(&session->lock); + + /* + * for connection level recovery we should not calculate + * header digest. conn->hdr_size used for optimization + * in hdr_extract() and will be re-negotiated at + * set_param() time. + */ + if (flag == STOP_CONN_RECOVER) { + conn->hdrdgst_en = 0; + conn->datadgst_en = 0; + + if (session->state == ISCSI_STATE_FAILED) + iscsi_block_session(session_to_cls(session)); + } + mutex_unlock(&conn->xmitmutex); +} +EXPORT_SYMBOL_GPL(iscsi_start_session_recovery); + +void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) +{ + struct iscsi_conn *conn = cls_conn->dd_data; + struct iscsi_session *session = conn->session; + + switch (flag) { + case STOP_CONN_RECOVER: + case STOP_CONN_TERM: + iscsi_start_session_recovery(session, conn, flag); + return; + case STOP_CONN_SUSPEND: + if (session->tt->suspend_conn_recv) + session->tt->suspend_conn_recv(conn); + + mutex_lock(&conn->xmitmutex); + spin_lock_bh(&session->lock); + + conn->stop_stage = flag; + conn->c_stage = ISCSI_CONN_STOPPED; + set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); + + spin_unlock_bh(&session->lock); + mutex_unlock(&conn->xmitmutex); + break; + default: + printk(KERN_ERR "invalid stop flag %d\n", flag); + } +} +EXPORT_SYMBOL_GPL(iscsi_conn_stop); + +int iscsi_conn_bind(struct iscsi_cls_session *cls_session, + struct iscsi_cls_conn *cls_conn, int is_leading) +{ + struct iscsi_session *session = class_to_transport_session(cls_session); + struct iscsi_conn *tmp = ERR_PTR(-EEXIST), *conn = cls_conn->dd_data; + + /* lookup for existing connection */ + spin_lock_bh(&session->lock); + list_for_each_entry(tmp, &session->connections, item) { + if (tmp == conn) { + if (conn->c_stage != ISCSI_CONN_STOPPED || + conn->stop_stage == STOP_CONN_TERM) { + printk(KERN_ERR "iscsi_tcp: can't bind " + "non-stopped connection (%d:%d)\n", + conn->c_stage, conn->stop_stage); + spin_unlock_bh(&session->lock); + return -EIO; + } + break; + } + } + if (tmp != conn) { + /* bind new iSCSI connection to session */ + conn->session = session; + list_add(&conn->item, &session->connections); + } + spin_unlock_bh(&session->lock); + + if (is_leading) + session->leadconn = conn; + + /* + * Unblock xmitworker(), Login Phase will pass through. + */ + clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx); + clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); + return 0; +} +EXPORT_SYMBOL_GPL(iscsi_conn_bind); + +MODULE_AUTHOR("Mike Christie"); +MODULE_DESCRIPTION("iSCSI library functions"); +MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index e2b67e34d92e..bc9071d2d212 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -471,106 +471,6 @@ int iscsi_destroy_conn(struct iscsi_cls_conn *conn) EXPORT_SYMBOL_GPL(iscsi_destroy_conn); -/* - * These functions are used only by software iscsi_transports - * which do not allocate and more their scsi_hosts since this - * is initiated from userspace. - */ - -/* - * iSCSI Session's hostdata organization: - * - * *------------------* <== hostdata_session(host->hostdata) - * | ptr to class sess| - * |------------------| <== iscsi_hostdata(host->hostdata) - * | transport's data | - * *------------------* - */ - -#define hostdata_privsize(_t) (sizeof(unsigned long) + _t->hostdata_size + \ - _t->hostdata_size % sizeof(unsigned long)) - -#define hostdata_session(_hostdata) (iscsi_ptr(*(unsigned long *)_hostdata)) - -/** - * iscsi_transport_create_session - create iscsi cls session and host - * scsit: scsi transport template - * transport: iscsi transport template - * - * This can be used by software iscsi_transports that allocate - * a session per scsi host. - **/ -struct Scsi_Host * -iscsi_transport_create_session(struct scsi_transport_template *scsit, - struct iscsi_transport *transport) -{ - struct iscsi_cls_session *session; - struct Scsi_Host *shost; - unsigned long flags; - - shost = scsi_host_alloc(transport->host_template, - hostdata_privsize(transport)); - if (!shost) { - printk(KERN_ERR "iscsi: can not allocate SCSI host for " - "session\n"); - return NULL; - } - - shost->max_id = 1; - shost->max_channel = 0; - shost->max_lun = transport->max_lun; - shost->max_cmd_len = transport->max_cmd_len; - shost->transportt = scsit; - shost->transportt->create_work_queue = 1; - - if (scsi_add_host(shost, NULL)) - goto free_host; - - session = iscsi_create_session(shost, transport, 0); - if (!session) - goto remove_host; - - *(unsigned long*)shost->hostdata = (unsigned long)session; - spin_lock_irqsave(&sesslock, flags); - list_add(&session->sess_list, &sesslist); - spin_unlock_irqrestore(&sesslock, flags); - return shost; - -remove_host: - scsi_remove_host(shost); -free_host: - scsi_host_put(shost); - return NULL; -} - -EXPORT_SYMBOL_GPL(iscsi_transport_create_session); - -/** - * iscsi_transport_destroy_session - destroy session and scsi host - * shost: scsi host - * - * This can be used by software iscsi_transports that allocate - * a session per scsi host. - **/ -int iscsi_transport_destroy_session(struct Scsi_Host *shost) -{ - struct iscsi_cls_session *session; - unsigned long flags; - - session = hostdata_session(shost->hostdata); - spin_lock_irqsave(&sesslock, flags); - list_del(&session->sess_list); - spin_unlock_irqrestore(&sesslock, flags); - iscsi_destroy_session(session); - - scsi_remove_host(shost); - /* ref from host alloc */ - scsi_host_put(shost); - return 0; -} - -EXPORT_SYMBOL_GPL(iscsi_transport_destroy_session); - /* * iscsi interface functions */ @@ -857,14 +757,19 @@ iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_uevent *ev) { struct iscsi_transport *transport = priv->iscsi_transport; struct iscsi_cls_session *session; + unsigned long flags; uint32_t hostno; - session = transport->create_session(&priv->t, + session = transport->create_session(transport, &priv->t, ev->u.c_session.initial_cmdsn, &hostno); if (!session) return -ENOMEM; + spin_lock_irqsave(&sesslock, flags); + list_add(&session->sess_list, &sesslist); + spin_unlock_irqrestore(&sesslock, flags); + ev->r.c_session_ret.host_no = hostno; ev->r.c_session_ret.sid = session->sid; return 0; @@ -1032,6 +937,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) struct iscsi_internal *priv; struct iscsi_cls_session *session; struct iscsi_cls_conn *conn; + unsigned long flags; priv = iscsi_if_transport_lookup(iscsi_ptr(ev->transport_handle)); if (!priv) @@ -1047,9 +953,13 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) break; case ISCSI_UEVENT_DESTROY_SESSION: session = iscsi_session_lookup(ev->u.d_session.sid); - if (session) + if (session) { + spin_lock_irqsave(&sesslock, flags); + list_del(&session->sess_list); + spin_unlock_irqrestore(&sesslock, flags); + transport->destroy_session(session); - else + } else err = -EINVAL; break; case ISCSI_UEVENT_CREATE_CONN: diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h index eebe2b15161b..47524c726ee8 100644 --- a/include/scsi/iscsi_if.h +++ b/include/scsi/iscsi_if.h @@ -148,7 +148,8 @@ enum iscsi_err { ISCSI_ERR_SESSION_FAILED = ISCSI_ERR_BASE + 13, ISCSI_ERR_HDR_DGST = ISCSI_ERR_BASE + 14, ISCSI_ERR_DATA_DGST = ISCSI_ERR_BASE + 15, - ISCSI_ERR_PARAM_NOT_FOUND = ISCSI_ERR_BASE + 16 + ISCSI_ERR_PARAM_NOT_FOUND = ISCSI_ERR_BASE + 16, + ISCSI_ERR_NO_SCSI_CMD = ISCSI_ERR_BASE + 17, }; /* diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h new file mode 100644 index 000000000000..830700a4ed69 --- /dev/null +++ b/include/scsi/libiscsi.h @@ -0,0 +1,286 @@ +/* + * iSCSI lib definitions + * + * Copyright (C) 2006 Red Hat, Inc. All rights reserved. + * Copyright (C) 2004 - 2006 Mike Christie + * Copyright (C) 2004 - 2005 Dmitry Yusupov + * Copyright (C) 2004 - 2005 Alex Aizman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef LIBISCSI_H +#define LIBISCSI_H + +#include +#include +#include +#include + +struct scsi_transport_template; +struct scsi_device; +struct Scsi_Host; +struct scsi_cmnd; +struct socket; +struct iscsi_transport; +struct iscsi_cls_session; +struct iscsi_cls_conn; +struct iscsi_session; +struct iscsi_nopin; + +/* #define DEBUG_SCSI */ +#ifdef DEBUG_SCSI +#define debug_scsi(fmt...) printk(KERN_INFO "scsi: " fmt) +#else +#define debug_scsi(fmt...) +#endif + +#define ISCSI_XMIT_CMDS_MAX 128 /* must be power of 2 */ +#define ISCSI_MGMT_CMDS_MAX 32 /* must be power of 2 */ +#define ISCSI_CONN_MAX 1 + +#define ISCSI_MGMT_ITT_OFFSET 0xa00 + +#define ISCSI_DEF_CMD_PER_LUN 32 +#define ISCSI_MAX_CMD_PER_LUN 128 + +/* Task Mgmt states */ +#define TMABORT_INITIAL 0x0 +#define TMABORT_SUCCESS 0x1 +#define TMABORT_FAILED 0x2 +#define TMABORT_TIMEDOUT 0x3 + +/* Connection suspend "bit" */ +#define ISCSI_SUSPEND_BIT 1 + +#define ISCSI_ITT_MASK (0xfff) +#define ISCSI_CID_SHIFT 12 +#define ISCSI_CID_MASK (0xffff << ISCSI_CID_SHIFT) +#define ISCSI_AGE_SHIFT 28 +#define ISCSI_AGE_MASK (0xf << ISCSI_AGE_SHIFT) + +struct iscsi_mgmt_task { + /* + * Becuae LLDs allocate their hdr differently, this is a pointer to + * that storage. It must be setup at session creation time. + */ + struct iscsi_hdr *hdr; + char *data; /* mgmt payload */ + int data_count; /* counts data to be sent */ + uint32_t itt; /* this ITT */ + void *dd_data; /* driver/transport data */ + struct list_head running; +}; + +struct iscsi_cmd_task { + /* + * Becuae LLDs allocate their hdr differently, this is a pointer to + * that storage. It must be setup at session creation time. + */ + struct iscsi_cmd *hdr; + int itt; /* this ITT */ + int datasn; /* DataSN */ + + uint32_t unsol_datasn; + int imm_count; /* imm-data (bytes) */ + int unsol_count; /* unsolicited (bytes)*/ + int data_count; /* remaining Data-Out */ + struct scsi_cmnd *sc; /* associated SCSI cmd*/ + int total_length; + struct iscsi_conn *conn; /* used connection */ + struct iscsi_mgmt_task *mtask; /* tmf mtask in progr */ + + struct list_head running; /* running cmd list */ + void *dd_data; /* driver/transport data */ +}; + +struct iscsi_conn { + struct iscsi_cls_conn *cls_conn; /* ptr to class connection */ + void *dd_data; /* iscsi_transport data */ + struct iscsi_session *session; /* parent session */ + /* + * LLDs should set this lock. It protects the transport recv + * code + */ + rwlock_t *recv_lock; + /* + * conn_stop() flag: stop to recover, stop to terminate + */ + int stop_stage; + + /* iSCSI connection-wide sequencing */ + uint32_t exp_statsn; + + /* control data */ + int id; /* CID */ + struct list_head item; /* maintains list of conns */ + int c_stage; /* connection state */ + struct iscsi_mgmt_task *login_mtask; /* mtask used for login/text */ + struct iscsi_mgmt_task *mtask; /* xmit mtask in progress */ + struct iscsi_cmd_task *ctask; /* xmit ctask in progress */ + + /* xmit */ + struct kfifo *immqueue; /* immediate xmit queue */ + struct kfifo *mgmtqueue; /* mgmt (control) xmit queue */ + struct list_head mgmt_run_list; /* list of control tasks */ + struct kfifo *xmitqueue; /* data-path cmd queue */ + struct list_head run_list; /* list of cmds in progress */ + struct work_struct xmitwork; /* per-conn. xmit workqueue */ + /* + * serializes connection xmit, access to kfifos: + * xmitqueue, immqueue, mgmtqueue + */ + struct mutex xmitmutex; + + unsigned long suspend_tx; /* suspend Tx */ + unsigned long suspend_rx; /* suspend Rx */ + + /* abort */ + wait_queue_head_t ehwait; /* used in eh_abort() */ + struct iscsi_tm tmhdr; + struct timer_list tmabort_timer; + int tmabort_state; /* see TMABORT_INITIAL, etc.*/ + + /* negotiated params */ + int max_recv_dlength; /* initiator_max_recv_dsl*/ + int max_xmit_dlength; /* target_max_recv_dsl */ + int hdrdgst_en; + int datadgst_en; + + /* MIB-statistics */ + uint64_t txdata_octets; + uint64_t rxdata_octets; + uint32_t scsicmd_pdus_cnt; + uint32_t dataout_pdus_cnt; + uint32_t scsirsp_pdus_cnt; + uint32_t datain_pdus_cnt; + uint32_t r2t_pdus_cnt; + uint32_t tmfcmd_pdus_cnt; + int32_t tmfrsp_pdus_cnt; + + /* custom statistics */ + uint32_t eh_abort_cnt; +}; + +struct iscsi_queue { + struct kfifo *queue; /* FIFO Queue */ + void **pool; /* Pool of elements */ + int max; /* Max number of elements */ +}; + +struct iscsi_session { + /* iSCSI session-wide sequencing */ + uint32_t cmdsn; + uint32_t exp_cmdsn; + uint32_t max_cmdsn; + + /* configuration */ + int initial_r2t_en; + int max_r2t; + int imm_data_en; + int first_burst; + int max_burst; + int time2wait; + int time2retain; + int pdu_inorder_en; + int dataseq_inorder_en; + int erl; + int ifmarker_en; + int ofmarker_en; + + /* control data */ + struct iscsi_transport *tt; + struct Scsi_Host *host; + struct iscsi_conn *leadconn; /* leading connection */ + spinlock_t lock; /* protects session state, * + * sequence numbers, * + * session resources: * + * - cmdpool, * + * - mgmtpool, * + * - r2tpool */ + int state; /* session state */ + int recovery_failed; + struct list_head item; + int conn_cnt; + int age; /* counts session re-opens */ + + struct list_head connections; /* list of connections */ + int cmds_max; /* size of cmds array */ + struct iscsi_cmd_task **cmds; /* Original Cmds arr */ + struct iscsi_queue cmdpool; /* PDU's pool */ + int mgmtpool_max; /* size of mgmt array */ + struct iscsi_mgmt_task **mgmt_cmds; /* Original mgmt arr */ + struct iscsi_queue mgmtpool; /* Mgmt PDU's pool */ +}; + +/* + * scsi host template + */ +extern int iscsi_change_queue_depth(struct scsi_device *sdev, int depth); +extern int iscsi_eh_abort(struct scsi_cmnd *sc); +extern int iscsi_eh_host_reset(struct scsi_cmnd *sc); +extern int iscsi_queuecommand(struct scsi_cmnd *sc, + void (*done)(struct scsi_cmnd *)); + +/* + * session management + */ +extern struct iscsi_cls_session * +iscsi_session_setup(struct iscsi_transport *, struct scsi_transport_template *, + int, int, uint32_t, uint32_t *); +extern void iscsi_session_teardown(struct iscsi_cls_session *); +extern struct iscsi_session *class_to_transport_session(struct iscsi_cls_session *); +extern void iscsi_start_session_recovery(struct iscsi_session *, + struct iscsi_conn *, int); +extern void iscsi_session_recovery_timedout(struct iscsi_cls_session *); + +#define session_to_cls(_sess) \ + hostdata_session(_sess->host->hostdata) + +/* + * connection management + */ +extern struct iscsi_cls_conn *iscsi_conn_setup(struct iscsi_cls_session *, + uint32_t); +extern void iscsi_conn_teardown(struct iscsi_cls_conn *); +extern int iscsi_conn_start(struct iscsi_cls_conn *); +extern void iscsi_conn_stop(struct iscsi_cls_conn *, int); +extern int iscsi_conn_bind(struct iscsi_cls_session *, struct iscsi_cls_conn *, + int); +extern void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err); + +/* + * pdu and task processing + */ +extern int iscsi_check_assign_cmdsn(struct iscsi_session *, + struct iscsi_nopin *); +extern void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *, + struct iscsi_data *hdr, + int transport_data_cnt); +extern int iscsi_conn_send_pdu(struct iscsi_cls_conn *, struct iscsi_hdr *, + char *, uint32_t); +extern int iscsi_complete_pdu(struct iscsi_conn *, struct iscsi_hdr *, + char *, int); +extern int __iscsi_complete_pdu(struct iscsi_conn *, struct iscsi_hdr *, + char *, int); +extern int iscsi_verify_itt(struct iscsi_conn *, struct iscsi_hdr *, + uint32_t *); + +/* + * generic helpers + */ +extern void iscsi_pool_free(struct iscsi_queue *, void **); +extern int iscsi_pool_init(struct iscsi_queue *, int, void ***, int); + +#endif diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h index 9d2b99159ee7..b332d6e839fe 100644 --- a/include/scsi/scsi_transport_iscsi.h +++ b/include/scsi/scsi_transport_iscsi.h @@ -2,7 +2,7 @@ * iSCSI transport class definitions * * Copyright (C) IBM Corporation, 2004 - * Copyright (C) Mike Christie, 2004 - 2005 + * Copyright (C) Mike Christie, 2004 - 2006 * Copyright (C) Dmitry Yusupov, 2004 - 2005 * Copyright (C) Alex Aizman, 2004 - 2005 * @@ -27,9 +27,13 @@ #include struct scsi_transport_template; +struct iscsi_transport; struct Scsi_Host; struct mempool_zone; struct iscsi_cls_conn; +struct iscsi_conn; +struct iscsi_cmd_task; +struct iscsi_mgmt_task; /** * struct iscsi_transport - iSCSI Transport template @@ -46,6 +50,20 @@ struct iscsi_cls_conn; * @start_conn: set connection to be operational * @stop_conn: suspend/recover/terminate connection * @send_pdu: send iSCSI PDU, Login, Logout, NOP-Out, Reject, Text. + * @session_recovery_timedout: notify LLD a block during recovery timed out + * @suspend_conn_recv: susepend the recv side of the connection + * @termincate_conn: destroy socket connection. Called with mutex lock. + * @init_cmd_task: Initialize a iscsi_cmd_task and any internal structs. + * Called from queuecommand with session lock held. + * @init_mgmt_task: Initialize a iscsi_mgmt_task and any internal structs. + * Called from iscsi_conn_send_generic with xmitmutex. + * @xmit_cmd_task: requests LLD to transfer cmd task + * @xmit_mgmt_task: requests LLD to transfer mgmt task + * @cleanup_cmd_task: requests LLD to fail cmd task. Called with xmitmutex + * and session->lock after the connection has been + * suspended and terminated during recovery. If called + * from abort task then connection is not suspended + * or terminated but sk_callback_lock is held * * Template API provided by iSCSI Transport */ @@ -56,8 +74,6 @@ struct iscsi_transport { /* LLD sets this to indicate what values it can export to sysfs */ unsigned int param_mask; struct scsi_host_template *host_template; - /* LLD session/scsi_host data size */ - int hostdata_size; /* LLD connection data size */ int conndata_size; /* LLD session data size */ @@ -65,8 +81,8 @@ struct iscsi_transport { int max_lun; unsigned int max_conn; unsigned int max_cmd_len; - struct iscsi_cls_session *(*create_session) - (struct scsi_transport_template *t, uint32_t sn, uint32_t *hn); + struct iscsi_cls_session *(*create_session) (struct iscsi_transport *it, + struct scsi_transport_template *t, uint32_t sn, uint32_t *hn); void (*destroy_session) (struct iscsi_cls_session *session); struct iscsi_cls_conn *(*create_conn) (struct iscsi_cls_session *sess, uint32_t cid); @@ -90,6 +106,18 @@ struct iscsi_transport { char *data, uint32_t data_size); void (*get_stats) (struct iscsi_cls_conn *conn, struct iscsi_stats *stats); + void (*suspend_conn_recv) (struct iscsi_conn *conn); + void (*terminate_conn) (struct iscsi_conn *conn); + void (*init_cmd_task) (struct iscsi_cmd_task *ctask); + void (*init_mgmt_task) (struct iscsi_conn *conn, + struct iscsi_mgmt_task *mtask, + char *data, uint32_t data_size); + int (*xmit_cmd_task) (struct iscsi_conn *conn, + struct iscsi_cmd_task *ctask); + void (*cleanup_cmd_task) (struct iscsi_conn *conn, + struct iscsi_cmd_task *ctask); + int (*xmit_mgmt_task) (struct iscsi_conn *conn, + struct iscsi_mgmt_task *mtask); void (*session_recovery_timedout) (struct iscsi_cls_session *session); }; @@ -106,6 +134,13 @@ extern void iscsi_conn_error(struct iscsi_cls_conn *conn, enum iscsi_err error); extern int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr, char *data, uint32_t data_size); + +/* Connection's states */ +#define ISCSI_CONN_INITIAL_STAGE 0 +#define ISCSI_CONN_STARTED 1 +#define ISCSI_CONN_STOPPED 2 +#define ISCSI_CONN_CLEANUP_WAIT 3 + struct iscsi_cls_conn { struct list_head conn_list; /* item in connlist */ void *dd_data; /* LLD private data */ @@ -129,6 +164,12 @@ struct iscsi_cls_conn { #define iscsi_dev_to_conn(_dev) \ container_of(_dev, struct iscsi_cls_conn, dev) +/* Session's states */ +#define ISCSI_STATE_FREE 1 +#define ISCSI_STATE_LOGGED_IN 2 +#define ISCSI_STATE_FAILED 3 +#define ISCSI_STATE_TERMINATE 4 + struct iscsi_cls_session { struct list_head sess_list; /* item in session_list */ struct list_head host_list; @@ -174,12 +215,4 @@ extern int iscsi_destroy_conn(struct iscsi_cls_conn *conn); extern void iscsi_unblock_session(struct iscsi_cls_session *session); extern void iscsi_block_session(struct iscsi_cls_session *session); -/* - * session functions used by software iscsi - */ -extern struct Scsi_Host * -iscsi_transport_create_session(struct scsi_transport_template *scsit, - struct iscsi_transport *transport); -extern int iscsi_transport_destroy_session(struct Scsi_Host *shost); - #endif -- cgit v1.2.3 From cdb8c2a6d848deb9eeefffff42974478fbb51b8c Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Sun, 2 Apr 2006 21:57:43 +0200 Subject: [SCSI] dc395x: dynamically map scatter-gather for PIO The current dc395x driver uses PIO to transfer up to 4 bytes which do not get transferred by DMA (under unclear circumstances). For this the driver uses page_address() which is broken on highmem. Apart from this the actual calculation of the virtual address is wrong (even without highmem). So, e.g., for reading it reads bytes from the driver to a wrong address and returns wrong data, I guess, for writing it would just output random data to the device. The proper fix, as suggested by many, is to dynamically map data using kmap_atomic(page, KM_BIO_SRC_IRQ) / kunmap_atomic(virt). The reason why it has not been done until now, although I've done some preliminary patches more than a year ago was that nobody interested in fixing this problem was able to reliably reproduce it. Now it changed - with the help from Sebastian Frei (CC'ed) I was able to trigger the PIO path. Thus, I was also able to test and debug it. There are 4 cases when PIO is used in dc395x - data-in / -out with and without scatter-gather. I was able to reproduce and test only data-in with and without SG. So, the data-out path is still untested, but it is also somewhat simpler than the data-in. Fredrik Roubert (also CC'ed) also had PIO triggering on his system, and in his case it was data-out without SG. It would be great if he could test the attached patch on his system, but even if he cannot, I would still request to apply the patch and just wait if anybody cries... Implementation: I put 2 new functions in scsi_lib.c and their declarations in scsi_cmnd.h. I exported them without _GPL, although, I don't feel strongly about that - not many drivers are likely to use them. But there is at least one more - I want to use them in tmscsim.c. Whether these are the right files for the functions and their declarations - not sure either. Actually, they are not scsi-specific, so, might go somewhere around other scattergather magic? They are not platform specific either, and most SG functions are defined under arch/*/... As these issues were discussed previously there were some more routines suggested to manipulate scattergather buffers, I think, some of them were needed around crypto code... So, might be a common place reasonable, like lib/scattergather.c? I am open here. Signed-off-by: James Bottomley --- drivers/scsi/dc395x.c | 217 +++++++++++++++++++++++++---------------------- drivers/scsi/scsi_lib.c | 57 +++++++++++++ include/scsi/scsi_cmnd.h | 4 + 3 files changed, 176 insertions(+), 102 deletions(-) (limited to 'include') diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c index cbf825263f3b..0c56095f8140 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c @@ -230,13 +230,12 @@ struct ScsiReqBlk { struct scsi_cmnd *cmd; struct SGentry *segment_x; /* Linear array of hw sg entries (up to 64 entries) */ - u32 sg_bus_addr; /* Bus address of sg list (ie, of segment_x) */ + dma_addr_t sg_bus_addr; /* Bus address of sg list (ie, of segment_x) */ u8 sg_count; /* No of HW sg entries for this request */ u8 sg_index; /* Index of HW sg entry for this request */ - u32 total_xfer_length; /* Total number of bytes remaining to be transfered */ - unsigned char *virt_addr; /* Virtual address of current transfer position */ - + size_t total_xfer_length; /* Total number of bytes remaining to be transfered */ + size_t request_length; /* Total number of bytes in this request */ /* * The sense buffer handling function, request_sense, uses * the first hw sg entry (segment_x[0]) and the transfer @@ -246,8 +245,7 @@ struct ScsiReqBlk { * total_xfer_length in xferred. These values are restored in * pci_unmap_srb_sense. This is the only place xferred is used. */ - unsigned char *virt_addr_req; /* Saved virtual address of the request buffer */ - u32 xferred; /* Saved copy of total_xfer_length */ + size_t xferred; /* Saved copy of total_xfer_length */ u16 state; @@ -977,17 +975,6 @@ static void send_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) } } -static inline void pio_trigger(void) -{ - static int feedback_requested; - - if (!feedback_requested) { - feedback_requested = 1; - printk(KERN_WARNING "%s: Please, contact " - "to help improve support for your system.\n", __FILE__); - } -} - /* Prepare SRB for being sent to Device DCB w/ command *cmd */ static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) @@ -1001,7 +988,6 @@ static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb, srb->sg_count = 0; srb->total_xfer_length = 0; srb->sg_bus_addr = 0; - srb->virt_addr = NULL; srb->sg_index = 0; srb->adapter_status = 0; srb->target_status = 0; @@ -1032,7 +1018,6 @@ static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb, reqlen, cmd->request_buffer, cmd->use_sg, srb->sg_count); - srb->virt_addr = page_address(sl->page); for (i = 0; i < srb->sg_count; i++) { u32 busaddr = (u32)sg_dma_address(&sl[i]); u32 seglen = (u32)sl[i].length; @@ -1077,12 +1062,14 @@ static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb, srb->total_xfer_length++; srb->segment_x[0].length = srb->total_xfer_length; - srb->virt_addr = cmd->request_buffer; + dprintkdbg(DBG_0, "build_srb: [1] len=%d buf=%p use_sg=%d map=%08x\n", srb->total_xfer_length, cmd->request_buffer, cmd->use_sg, srb->segment_x[0].address); } + + srb->request_length = srb->total_xfer_length; } @@ -1414,10 +1401,10 @@ static int dc395x_eh_abort(struct scsi_cmnd *cmd) } srb = find_cmd(cmd, &dcb->srb_going_list); if (srb) { - dprintkl(KERN_DEBUG, "eh_abort: Command in progress"); + dprintkl(KERN_DEBUG, "eh_abort: Command in progress\n"); /* XXX: Should abort the command here */ } else { - dprintkl(KERN_DEBUG, "eh_abort: Command not found"); + dprintkl(KERN_DEBUG, "eh_abort: Command not found\n"); } return FAILED; } @@ -1976,14 +1963,11 @@ static void sg_verify_length(struct ScsiReqBlk *srb) /* * Compute the next Scatter Gather list index and adjust its length - * and address if necessary; also compute virt_addr + * and address if necessary */ static void sg_update_list(struct ScsiReqBlk *srb, u32 left) { u8 idx; - struct scatterlist *sg; - struct scsi_cmnd *cmd = srb->cmd; - int segment = cmd->use_sg; u32 xferred = srb->total_xfer_length - left; /* bytes transfered */ struct SGentry *psge = srb->segment_x + srb->sg_index; @@ -2016,29 +2000,6 @@ static void sg_update_list(struct ScsiReqBlk *srb, u32 left) psge++; } sg_verify_length(srb); - - /* we need the corresponding virtual address */ - if (!segment || (srb->flag & AUTO_REQSENSE)) { - srb->virt_addr += xferred; - return; - } - - /* We have to walk the scatterlist to find it */ - sg = (struct scatterlist *)cmd->request_buffer; - while (segment--) { - unsigned long mask = - ~((unsigned long)sg->length - 1) & PAGE_MASK; - if ((sg_dma_address(sg) & mask) == (psge->address & mask)) { - srb->virt_addr = (page_address(sg->page) - + psge->address - - (psge->address & PAGE_MASK)); - return; - } - ++sg; - } - - dprintkl(KERN_ERR, "sg_update_list: sg_to_virt failed\n"); - srb->virt_addr = NULL; } @@ -2050,15 +2011,7 @@ static void sg_update_list(struct ScsiReqBlk *srb, u32 left) */ static void sg_subtract_one(struct ScsiReqBlk *srb) { - srb->total_xfer_length--; - srb->segment_x[srb->sg_index].length--; - if (srb->total_xfer_length && - !srb->segment_x[srb->sg_index].length) { - if (debug_enabled(DBG_PIO)) - printk(" (next segment)"); - srb->sg_index++; - sg_update_list(srb, srb->total_xfer_length); - } + sg_update_list(srb, srb->total_xfer_length - 1); } @@ -2118,7 +2071,7 @@ static void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, * If we need more data, the DMA SG list will be freshly set up, anyway */ dprintkdbg(DBG_PIO, "data_out_phase0: " - "DMA{fifcnt=0x%02x fifostat=0x%02x} " + "DMA{fifocnt=0x%02x fifostat=0x%02x} " "SCSI{fifocnt=0x%02x cnt=0x%06x status=0x%04x} total=0x%06x\n", DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT), DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT), @@ -2239,12 +2192,11 @@ static void data_out_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, data_io_transfer(acb, srb, XFERDATAOUT); } - static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, u16 *pscsi_status) { u16 scsi_status = *pscsi_status; - u32 d_left_counter = 0; + dprintkdbg(DBG_0, "data_in_phase0: (pid#%li) <%02i-%i>\n", srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun); @@ -2262,6 +2214,9 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, * seem to be a bad idea, actually. */ if (!(srb->state & SRB_XFERPAD)) { + u32 d_left_counter; + unsigned int sc, fc; + if (scsi_status & PARITYERROR) { dprintkl(KERN_INFO, "data_in_phase0: (pid#%li) " "Parity Error\n", srb->cmd->pid); @@ -2298,18 +2253,19 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT)); } /* Now: Check remainig data: The SCSI counters should tell us ... */ - d_left_counter = DC395x_read32(acb, TRM_S1040_SCSI_COUNTER) - + ((DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & 0x1f) + sc = DC395x_read32(acb, TRM_S1040_SCSI_COUNTER); + fc = DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT); + d_left_counter = sc + ((fc & 0x1f) << ((srb->dcb->sync_period & WIDE_SYNC) ? 1 : 0)); dprintkdbg(DBG_KG, "data_in_phase0: " "SCSI{fifocnt=0x%02x%s ctr=0x%08x} " "DMA{fifocnt=0x%02x fifostat=0x%02x ctr=0x%08x} " "Remain{totxfer=%i scsi_fifo+ctr=%i}\n", - DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT), + fc, (srb->dcb->sync_period & WIDE_SYNC) ? "words" : "bytes", - DC395x_read32(acb, TRM_S1040_SCSI_COUNTER), - DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT), + sc, + fc, DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT), DC395x_read32(acb, TRM_S1040_DMA_CXCNT), srb->total_xfer_length, d_left_counter); @@ -2317,40 +2273,79 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, /* KG: Less than or equal to 4 bytes can not be transfered via DMA, it seems. */ if (d_left_counter && srb->total_xfer_length <= DC395x_LASTPIO) { + size_t left_io = srb->total_xfer_length; + /*u32 addr = (srb->segment_x[srb->sg_index].address); */ /*sg_update_list (srb, d_left_counter); */ - dprintkdbg(DBG_PIO, "data_in_phase0: PIO (%i %s) to " - "%p for remaining %i bytes:", - DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & 0x1f, + dprintkdbg(DBG_PIO, "data_in_phase0: PIO (%i %s) " + "for remaining %i bytes:", + fc & 0x1f, (srb->dcb->sync_period & WIDE_SYNC) ? "words" : "bytes", - srb->virt_addr, srb->total_xfer_length); if (srb->dcb->sync_period & WIDE_SYNC) DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, CFG2_WIDEFIFO); - while (DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) != 0x40) { - u8 byte = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); - pio_trigger(); - *(srb->virt_addr)++ = byte; - if (debug_enabled(DBG_PIO)) - printk(" %02x", byte); - d_left_counter--; - sg_subtract_one(srb); - } - if (srb->dcb->sync_period & WIDE_SYNC) { -#if 1 - /* Read the last byte ... */ - if (srb->total_xfer_length > 0) { - u8 byte = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); - pio_trigger(); - *(srb->virt_addr)++ = byte; - srb->total_xfer_length--; + while (left_io) { + unsigned char *virt, *base = NULL; + unsigned long flags = 0; + size_t len = left_io; + + if (srb->cmd->use_sg) { + size_t offset = srb->request_length - left_io; + local_irq_save(flags); + /* Assumption: it's inside one page as it's at most 4 bytes and + I just assume it's on a 4-byte boundary */ + base = scsi_kmap_atomic_sg((struct scatterlist *)srb->cmd->request_buffer, + srb->sg_count, &offset, &len); + virt = base + offset; + } else { + virt = srb->cmd->request_buffer + srb->cmd->request_bufflen - left_io; + len = left_io; + } + left_io -= len; + + while (len) { + u8 byte; + byte = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); + *virt++ = byte; + if (debug_enabled(DBG_PIO)) printk(" %02x", byte); + + d_left_counter--; + sg_subtract_one(srb); + + len--; + + fc = DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT); + + if (fc == 0x40) { + left_io = 0; + break; + } + } + + WARN_ON((fc != 0x40) == !d_left_counter); + + if (fc == 0x40 && (srb->dcb->sync_period & WIDE_SYNC)) { + /* Read the last byte ... */ + if (srb->total_xfer_length > 0) { + u8 byte = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); + + *virt++ = byte; + srb->total_xfer_length--; + if (debug_enabled(DBG_PIO)) + printk(" %02x", byte); + } + + DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, 0); + } + + if (srb->cmd->use_sg) { + scsi_kunmap_atomic_sg(base); + local_irq_restore(flags); } -#endif - DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, 0); } /*printk(" %08x", *(u32*)(bus_to_virt (addr))); */ /*srb->total_xfer_length = 0; */ @@ -2509,22 +2504,43 @@ static void data_io_transfer(struct AdapterCtlBlk *acb, SCMD_FIFO_IN); } else { /* write */ int ln = srb->total_xfer_length; + size_t left_io = srb->total_xfer_length; + if (srb->dcb->sync_period & WIDE_SYNC) DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, CFG2_WIDEFIFO); - dprintkdbg(DBG_PIO, - "data_io_transfer: PIO %i bytes from %p:", - srb->total_xfer_length, srb->virt_addr); - while (srb->total_xfer_length) { - if (debug_enabled(DBG_PIO)) - printk(" %02x", (unsigned char) *(srb->virt_addr)); + while (left_io) { + unsigned char *virt, *base = NULL; + unsigned long flags = 0; + size_t len = left_io; + + if (srb->cmd->use_sg) { + size_t offset = srb->request_length - left_io; + local_irq_save(flags); + /* Again, max 4 bytes */ + base = scsi_kmap_atomic_sg((struct scatterlist *)srb->cmd->request_buffer, + srb->sg_count, &offset, &len); + virt = base + offset; + } else { + virt = srb->cmd->request_buffer + srb->cmd->request_bufflen - left_io; + len = left_io; + } + left_io -= len; + + while (len--) { + if (debug_enabled(DBG_PIO)) + printk(" %02x", *virt); - pio_trigger(); - DC395x_write8(acb, TRM_S1040_SCSI_FIFO, - *(srb->virt_addr)++); + DC395x_write8(acb, TRM_S1040_SCSI_FIFO, *virt++); - sg_subtract_one(srb); + sg_subtract_one(srb); + } + + if (srb->cmd->use_sg) { + scsi_kunmap_atomic_sg(base); + local_irq_restore(flags); + } } if (srb->dcb->sync_period & WIDE_SYNC) { if (ln % 2) { @@ -3319,7 +3335,6 @@ static void pci_unmap_srb_sense(struct AdapterCtlBlk *acb, srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1].address; srb->segment_x[0].length = srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1].length; - srb->virt_addr = srb->virt_addr_req; } @@ -3713,8 +3728,6 @@ static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, srb->xferred = srb->total_xfer_length; /* srb->segment_x : a one entry of S/G list table */ srb->total_xfer_length = sizeof(cmd->sense_buffer); - srb->virt_addr_req = srb->virt_addr; - srb->virt_addr = cmd->sense_buffer; srb->segment_x[0].length = sizeof(cmd->sense_buffer); /* Map sense buffer */ srb->segment_x[0].address = diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 7b0f9a3810d2..57453ca09700 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -2350,3 +2350,60 @@ scsi_target_unblock(struct device *dev) device_for_each_child(dev, NULL, target_unblock); } EXPORT_SYMBOL_GPL(scsi_target_unblock); + +/** + * scsi_kmap_atomic_sg - find and atomically map an sg-elemnt + * @sg: scatter-gather list + * @sg_count: number of segments in sg + * @offset: offset in bytes into sg, on return offset into the mapped area + * @len: bytes to map, on return number of bytes mapped + * + * Returns virtual address of the start of the mapped page + */ +void *scsi_kmap_atomic_sg(struct scatterlist *sg, int sg_count, + size_t *offset, size_t *len) +{ + int i; + size_t sg_len = 0, len_complete = 0; + struct page *page; + + for (i = 0; i < sg_count; i++) { + len_complete = sg_len; /* Complete sg-entries */ + sg_len += sg[i].length; + if (sg_len > *offset) + break; + } + + if (unlikely(i == sg_count)) { + printk(KERN_ERR "%s: Bytes in sg: %u, requested offset %u, elements %d\n", + __FUNCTION__, sg_len, *offset, sg_count); + WARN_ON(1); + return NULL; + } + + /* Offset starting from the beginning of first page in this sg-entry */ + *offset = *offset - len_complete + sg[i].offset; + + /* Assumption: contiguous pages can be accessed as "page + i" */ + page = nth_page(sg[i].page, (*offset >> PAGE_SHIFT)); + *offset &= ~PAGE_MASK; + + /* Bytes in this sg-entry from *offset to the end of the page */ + sg_len = PAGE_SIZE - *offset; + if (*len > sg_len) + *len = sg_len; + + return kmap_atomic(page, KM_BIO_SRC_IRQ); +} +EXPORT_SYMBOL(scsi_kmap_atomic_sg); + +/** + * scsi_kunmap_atomic_sg - atomically unmap a virtual address, previously + * mapped with scsi_kmap_atomic_sg + * @virt: virtual address to be unmapped + */ +void scsi_kunmap_atomic_sg(void *virt) +{ + kunmap_atomic(virt, KM_BIO_SRC_IRQ); +} +EXPORT_SYMBOL(scsi_kunmap_atomic_sg); diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h index 1ace1b9fe537..7602b9b15a03 100644 --- a/include/scsi/scsi_cmnd.h +++ b/include/scsi/scsi_cmnd.h @@ -152,4 +152,8 @@ extern void scsi_put_command(struct scsi_cmnd *); extern void scsi_io_completion(struct scsi_cmnd *, unsigned int, unsigned int); extern void scsi_finish_command(struct scsi_cmnd *cmd); +extern void *scsi_kmap_atomic_sg(struct scatterlist *sg, int sg_count, + size_t *offset, size_t *len); +extern void scsi_kunmap_atomic_sg(void *virt); + #endif /* _SCSI_SCSI_CMND_H */ -- cgit v1.2.3 From c256f4b9598c71afd8eb0b7d3d3790a38734cf43 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Fri, 7 Apr 2006 15:23:03 +1000 Subject: [PATCH] powerpc: remove io_page_mask Cleanup patch which removes the io_page_mask. It fixes the reset on some e1000 devices which is needed for clean kexec reboots. The legacy devices which broke with this patch (parallel port and PC speaker) have now been fixed in Linus' tree. Signed-off-by: Anton Blanchard Acked-by: Michael Neuling Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/iomap.c | 2 -- arch/powerpc/kernel/pci_64.c | 30 +++--------------------------- arch/powerpc/platforms/iseries/pci.c | 3 --- arch/powerpc/platforms/maple/pci.c | 3 --- arch/powerpc/platforms/powermac/pci.c | 3 --- include/asm-powerpc/eeh.h | 15 +++------------ include/asm-powerpc/io.h | 6 ------ 7 files changed, 6 insertions(+), 56 deletions(-) (limited to 'include') diff --git a/arch/powerpc/kernel/iomap.c b/arch/powerpc/kernel/iomap.c index fd8214caedee..a13a93dfc655 100644 --- a/arch/powerpc/kernel/iomap.c +++ b/arch/powerpc/kernel/iomap.c @@ -106,8 +106,6 @@ EXPORT_SYMBOL(iowrite32_rep); void __iomem *ioport_map(unsigned long port, unsigned int len) { - if (!_IO_IS_VALID(port)) - return NULL; return (void __iomem *) (port+pci_io_base); } diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c index 4c4449be81ce..18cc15468fd6 100644 --- a/arch/powerpc/kernel/pci_64.c +++ b/arch/powerpc/kernel/pci_64.c @@ -42,14 +42,6 @@ unsigned long pci_probe_only = 1; int pci_assign_all_buses = 0; -/* - * legal IO pages under MAX_ISA_PORT. This is to ensure we don't touch - * devices we don't have access to. - */ -unsigned long io_page_mask; - -EXPORT_SYMBOL(io_page_mask); - #ifdef CONFIG_PPC_MULTIPLATFORM static void fixup_resource(struct resource *res, struct pci_dev *dev); static void do_bus_setup(struct pci_bus *bus); @@ -1104,8 +1096,6 @@ void __init pci_setup_phb_io(struct pci_controller *hose, int primary) pci_process_ISA_OF_ranges(isa_dn, hose->io_base_phys, hose->io_base_virt); of_node_put(isa_dn); - /* Allow all IO */ - io_page_mask = -1; } } @@ -1232,27 +1222,13 @@ static void phbs_remap_io(void) static void __devinit fixup_resource(struct resource *res, struct pci_dev *dev) { struct pci_controller *hose = pci_bus_to_host(dev->bus); - unsigned long start, end, mask, offset; + unsigned long offset; if (res->flags & IORESOURCE_IO) { offset = (unsigned long)hose->io_base_virt - pci_io_base; - start = res->start += offset; - end = res->end += offset; - - /* Need to allow IO access to pages that are in the - ISA range */ - if (start < MAX_ISA_PORT) { - if (end > MAX_ISA_PORT) - end = MAX_ISA_PORT; - - start >>= PAGE_SHIFT; - end >>= PAGE_SHIFT; - - /* get the range of pages for the map */ - mask = ((1 << (end+1)) - 1) ^ ((1 << start) - 1); - io_page_mask |= mask; - } + res->start += offset; + res->end += offset; } else if (res->flags & IORESOURCE_MEM) { res->start += hose->pci_mem_offset; res->end += hose->pci_mem_offset; diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c index a19833b880e4..5a61c6fdb33a 100644 --- a/arch/powerpc/platforms/iseries/pci.c +++ b/arch/powerpc/platforms/iseries/pci.c @@ -45,8 +45,6 @@ #include "call_pci.h" #include "iommu.h" -extern unsigned long io_page_mask; - /* * Forward declares of prototypes. */ @@ -277,7 +275,6 @@ void iSeries_pcibios_init(void) { iomm_table_initialize(); find_and_init_phbs(); - io_page_mask = -1; } /* diff --git a/arch/powerpc/platforms/maple/pci.c b/arch/powerpc/platforms/maple/pci.c index 85d6c93659cc..9a4efc0c3b29 100644 --- a/arch/powerpc/platforms/maple/pci.c +++ b/arch/powerpc/platforms/maple/pci.c @@ -437,9 +437,6 @@ void __init maple_pci_init(void) /* Tell pci.c to not change any resource allocations. */ pci_probe_only = 1; - - /* Allow all IO */ - io_page_mask = -1; } int maple_pci_get_legacy_ide_irq(struct pci_dev *pdev, int channel) diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c index f5d8d15d74fa..3212618e7909 100644 --- a/arch/powerpc/platforms/powermac/pci.c +++ b/arch/powerpc/platforms/powermac/pci.c @@ -1068,9 +1068,6 @@ void __init pmac_pci_init(void) /* Tell pci.c to not use the common resource allocation mechanism */ pci_probe_only = 1; - /* Allow all IO */ - io_page_mask = -1; - #else /* CONFIG_PPC64 */ init_p2pbridge(); fixup_nec_usb2(); diff --git a/include/asm-powerpc/eeh.h b/include/asm-powerpc/eeh.h index 868c7139dbff..2c3dc4a2b12a 100644 --- a/include/asm-powerpc/eeh.h +++ b/include/asm-powerpc/eeh.h @@ -293,8 +293,6 @@ static inline void eeh_memcpy_toio(volatile void __iomem *dest, const void *src, static inline u8 eeh_inb(unsigned long port) { u8 val; - if (!_IO_IS_VALID(port)) - return ~0; val = in_8((u8 __iomem *)(port+pci_io_base)); if (EEH_POSSIBLE_ERROR(val, u8)) return eeh_check_failure((void __iomem *)(port), val); @@ -303,15 +301,12 @@ static inline u8 eeh_inb(unsigned long port) static inline void eeh_outb(u8 val, unsigned long port) { - if (_IO_IS_VALID(port)) - out_8((u8 __iomem *)(port+pci_io_base), val); + out_8((u8 __iomem *)(port+pci_io_base), val); } static inline u16 eeh_inw(unsigned long port) { u16 val; - if (!_IO_IS_VALID(port)) - return ~0; val = in_le16((u16 __iomem *)(port+pci_io_base)); if (EEH_POSSIBLE_ERROR(val, u16)) return eeh_check_failure((void __iomem *)(port), val); @@ -320,15 +315,12 @@ static inline u16 eeh_inw(unsigned long port) static inline void eeh_outw(u16 val, unsigned long port) { - if (_IO_IS_VALID(port)) - out_le16((u16 __iomem *)(port+pci_io_base), val); + out_le16((u16 __iomem *)(port+pci_io_base), val); } static inline u32 eeh_inl(unsigned long port) { u32 val; - if (!_IO_IS_VALID(port)) - return ~0; val = in_le32((u32 __iomem *)(port+pci_io_base)); if (EEH_POSSIBLE_ERROR(val, u32)) return eeh_check_failure((void __iomem *)(port), val); @@ -337,8 +329,7 @@ static inline u32 eeh_inl(unsigned long port) static inline void eeh_outl(u32 val, unsigned long port) { - if (_IO_IS_VALID(port)) - out_le32((u32 __iomem *)(port+pci_io_base), val); + out_le32((u32 __iomem *)(port+pci_io_base), val); } /* in-string eeh macros */ diff --git a/include/asm-powerpc/io.h b/include/asm-powerpc/io.h index 68efbea379c9..4840fbf89c32 100644 --- a/include/asm-powerpc/io.h +++ b/include/asm-powerpc/io.h @@ -37,12 +37,6 @@ extern unsigned long isa_io_base; extern unsigned long pci_io_base; -extern unsigned long io_page_mask; - -#define MAX_ISA_PORT 0x10000 - -#define _IO_IS_VALID(port) ((port) >= MAX_ISA_PORT || (1 << (port>>PAGE_SHIFT)) \ - & io_page_mask) #ifdef CONFIG_PPC_ISERIES /* __raw_* accessors aren't supported on iSeries */ -- cgit v1.2.3 From ac325acd50013fa8f4953208cbb96504dec9b12a Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Tue, 18 Apr 2006 21:05:21 -0700 Subject: [PATCH] powerpc/pseries: clear PCI failure counter if no new failures The current PCI error recovery system keeps track of the number of PCI card resets, and refuses to bring a card back up if this number is too large. The goal of doing this was to avoid an infinite loop of resets if a card is obviously dead. However, if the failures are rare, but the machine has a high uptime, this mechanism might still be triggered; this is too harsh. This patch will avoids this problem by decrementing the fail count after an hour. Thus, as long as a pci card BSOD's less than 6 times an hour, it will continue to be reset indefinitely. If it's failure rate is greater than that, it will be taken off-line permanently. This patch is larger than it might otherwise be because it changes indentation by removing a pointless while-loop. The while loop is not needed, as the handler is invoked once fo each event (by schedule_work()); the loop is leftover cruft from an earlier implementation. Signed-off-by: Linas Vepstas Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pseries/eeh_driver.c | 13 ++++---- arch/powerpc/platforms/pseries/eeh_event.c | 50 ++++++++++++++++------------- include/asm-powerpc/eeh_event.h | 10 +++--- 3 files changed, 40 insertions(+), 33 deletions(-) (limited to 'include') diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c index 1fba695e32e8..2a9eb2630730 100644 --- a/arch/powerpc/platforms/pseries/eeh_driver.c +++ b/arch/powerpc/platforms/pseries/eeh_driver.c @@ -23,9 +23,8 @@ * */ #include -#include #include -#include +#include #include #include #include @@ -250,7 +249,7 @@ static int eeh_reset_device (struct pci_dn *pe_dn, struct pci_bus *bus) */ #define MAX_WAIT_FOR_RECOVERY 15 -void handle_eeh_events (struct eeh_event *event) +struct pci_dn * handle_eeh_events (struct eeh_event *event) { struct device_node *frozen_dn; struct pci_dn *frozen_pdn; @@ -265,7 +264,7 @@ void handle_eeh_events (struct eeh_event *event) if (!frozen_dn) { printk(KERN_ERR "EEH: Error: Cannot find partition endpoint for %s\n", pci_name(event->dev)); - return; + return NULL; } /* There are two different styles for coming up with the PE. @@ -280,7 +279,7 @@ void handle_eeh_events (struct eeh_event *event) if (!frozen_bus) { printk(KERN_ERR "EEH: Cannot find PCI bus for %s\n", frozen_dn->full_name); - return; + return NULL; } #if 0 @@ -355,7 +354,7 @@ void handle_eeh_events (struct eeh_event *event) /* Tell all device drivers that they can resume operations */ pci_walk_bus(frozen_bus, eeh_report_resume, NULL); - return; + return frozen_pdn; excess_failures: /* @@ -384,6 +383,8 @@ perm_error: /* Shut down the device drivers for good. */ pcibios_remove_pci_devices(frozen_bus); + + return NULL; } /* ---------- end of file ---------- */ diff --git a/arch/powerpc/platforms/pseries/eeh_event.c b/arch/powerpc/platforms/pseries/eeh_event.c index a1bda6f96fd1..a0b39640a00f 100644 --- a/arch/powerpc/platforms/pseries/eeh_event.c +++ b/arch/powerpc/platforms/pseries/eeh_event.c @@ -18,6 +18,7 @@ * Copyright (c) 2005 Linas Vepstas */ +#include #include #include #include @@ -56,38 +57,43 @@ static int eeh_event_handler(void * dummy) { unsigned long flags; struct eeh_event *event; + struct pci_dn *pdn; daemonize ("eehd"); + set_current_state(TASK_INTERRUPTIBLE); - while (1) { - set_current_state(TASK_INTERRUPTIBLE); + spin_lock_irqsave(&eeh_eventlist_lock, flags); + event = NULL; - spin_lock_irqsave(&eeh_eventlist_lock, flags); - event = NULL; + /* Unqueue the event, get ready to process. */ + if (!list_empty(&eeh_eventlist)) { + event = list_entry(eeh_eventlist.next, struct eeh_event, list); + list_del(&event->list); + } + spin_unlock_irqrestore(&eeh_eventlist_lock, flags); - /* Unqueue the event, get ready to process. */ - if (!list_empty(&eeh_eventlist)) { - event = list_entry(eeh_eventlist.next, struct eeh_event, list); - list_del(&event->list); - } - spin_unlock_irqrestore(&eeh_eventlist_lock, flags); + if (event == NULL) + return 0; - if (event == NULL) - break; + /* Serialize processing of EEH events */ + mutex_lock(&eeh_event_mutex); + eeh_mark_slot(event->dn, EEH_MODE_RECOVERING); - /* Serialize processing of EEH events */ - mutex_lock(&eeh_event_mutex); - eeh_mark_slot(event->dn, EEH_MODE_RECOVERING); + printk(KERN_INFO "EEH: Detected PCI bus error on device %s\n", + pci_name(event->dev)); - printk(KERN_INFO "EEH: Detected PCI bus error on device %s\n", - pci_name(event->dev)); + pdn = handle_eeh_events(event); - handle_eeh_events(event); + eeh_clear_slot(event->dn, EEH_MODE_RECOVERING); + pci_dev_put(event->dev); + kfree(event); + mutex_unlock(&eeh_event_mutex); - eeh_clear_slot(event->dn, EEH_MODE_RECOVERING); - pci_dev_put(event->dev); - kfree(event); - mutex_unlock(&eeh_event_mutex); + /* If there are no new errors after an hour, clear the counter. */ + if (pdn && pdn->eeh_freeze_count>0) { + msleep_interruptible (3600*1000); + if (pdn->eeh_freeze_count>0) + pdn->eeh_freeze_count--; } return 0; diff --git a/include/asm-powerpc/eeh_event.h b/include/asm-powerpc/eeh_event.h index 93d55a2bebfd..dc6bf0ffb796 100644 --- a/include/asm-powerpc/eeh_event.h +++ b/include/asm-powerpc/eeh_event.h @@ -18,8 +18,8 @@ * Copyright (c) 2005 Linas Vepstas */ -#ifndef ASM_PPC64_EEH_EVENT_H -#define ASM_PPC64_EEH_EVENT_H +#ifndef ASM_POWERPC_EEH_EVENT_H +#define ASM_POWERPC_EEH_EVENT_H #ifdef __KERNEL__ /** EEH event -- structure holding pci controller data that describes @@ -39,7 +39,7 @@ struct eeh_event { * @dev pci device * * This routine builds a PCI error event which will be delivered - * to all listeners on the peh_notifier_chain. + * to all listeners on the eeh_notifier_chain. * * This routine can be called within an interrupt context; * the actual event will be delivered in a normal context @@ -51,7 +51,7 @@ int eeh_send_failure_event (struct device_node *dn, int time_unavail); /* Main recovery function */ -void handle_eeh_events (struct eeh_event *); +struct pci_dn * handle_eeh_events (struct eeh_event *); #endif /* __KERNEL__ */ -#endif /* ASM_PPC64_EEH_EVENT_H */ +#endif /* ASM_POWERPC_EEH_EVENT_H */ -- cgit v1.2.3 From e10fa77368dff31140451fac04d78d9f51f0f3ac Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 27 Apr 2006 17:18:21 +1000 Subject: [PATCH] powerpc: use the device tree for the iSeries vio bus probe As an added bonus, since every vio_dev now has a device_node associated with it, hotplug now works. Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/vio.c | 171 +++++++++++++++++++++++++++------ arch/powerpc/platforms/iseries/setup.c | 4 + arch/powerpc/platforms/iseries/vio.c | 70 ++------------ arch/powerpc/platforms/pseries/vio.c | 147 ++-------------------------- include/asm-powerpc/vio.h | 9 +- 5 files changed, 169 insertions(+), 232 deletions(-) (limited to 'include') diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index 971020cf3f7d..9b46eed5e637 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c @@ -22,9 +22,7 @@ #include #include #include - -static const struct vio_device_id *vio_match_device( - const struct vio_device_id *, const struct vio_dev *); +#include struct vio_dev vio_bus_device = { /* fake "parent" device */ .name = vio_bus_device.dev.bus_id, @@ -35,6 +33,27 @@ struct vio_dev vio_bus_device = { /* fake "parent" device */ static struct vio_bus_ops vio_bus_ops; +/** + * vio_match_device: - Tell if a VIO device has a matching + * VIO device id structure. + * @ids: array of VIO device id structures to search in + * @dev: the VIO device structure to match against + * + * Used by a driver to check whether a VIO device present in the + * system is in its list of supported devices. Returns the matching + * vio_device_id structure or NULL if there is no match. + */ +static const struct vio_device_id *vio_match_device( + const struct vio_device_id *ids, const struct vio_dev *dev) +{ + while (ids->type[0] != '\0') { + if (vio_bus_ops.match(ids, dev)) + return ids; + ids++; + } + return NULL; +} + /* * Convert from struct device to struct vio_dev and pass to driver. * dev->driver has already been set by generic code because vio_bus_match @@ -107,25 +126,76 @@ void vio_unregister_driver(struct vio_driver *viodrv) EXPORT_SYMBOL(vio_unregister_driver); /** - * vio_match_device: - Tell if a VIO device has a matching - * VIO device id structure. - * @ids: array of VIO device id structures to search in - * @dev: the VIO device structure to match against + * vio_register_device_node: - Register a new vio device. + * @of_node: The OF node for this device. * - * Used by a driver to check whether a VIO device present in the - * system is in its list of supported devices. Returns the matching - * vio_device_id structure or NULL if there is no match. + * Creates and initializes a vio_dev structure from the data in + * of_node (dev.platform_data) and adds it to the list of virtual devices. + * Returns a pointer to the created vio_dev or NULL if node has + * NULL device_type or compatible fields. */ -static const struct vio_device_id *vio_match_device( - const struct vio_device_id *ids, const struct vio_dev *dev) +struct vio_dev * __devinit vio_register_device_node(struct device_node *of_node) { - while (ids->type[0] != '\0') { - if (vio_bus_ops.match(ids, dev)) - return ids; - ids++; + struct vio_dev *viodev; + unsigned int *unit_address; + unsigned int *irq_p; + + /* we need the 'device_type' property, in order to match with drivers */ + if (of_node->type == NULL) { + printk(KERN_WARNING "%s: node %s missing 'device_type'\n", + __FUNCTION__, + of_node->name ? of_node->name : ""); + return NULL; } - return NULL; + + unit_address = (unsigned int *)get_property(of_node, "reg", NULL); + if (unit_address == NULL) { + printk(KERN_WARNING "%s: node %s missing 'reg'\n", + __FUNCTION__, + of_node->name ? of_node->name : ""); + return NULL; + } + + /* allocate a vio_dev for this node */ + viodev = kzalloc(sizeof(struct vio_dev), GFP_KERNEL); + if (viodev == NULL) + return NULL; + + viodev->dev.platform_data = of_node_get(of_node); + + viodev->irq = NO_IRQ; + irq_p = (unsigned int *)get_property(of_node, "interrupts", NULL); + if (irq_p) { + int virq = virt_irq_create_mapping(*irq_p); + if (virq == NO_IRQ) { + printk(KERN_ERR "Unable to allocate interrupt " + "number for %s\n", of_node->full_name); + } else + viodev->irq = irq_offset_up(virq); + } + + snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%x", *unit_address); + viodev->name = of_node->name; + viodev->type = of_node->type; + viodev->unit_address = *unit_address; + if (firmware_has_feature(FW_FEATURE_ISERIES)) { + unit_address = (unsigned int *)get_property(of_node, + "linux,unit_address", NULL); + if (unit_address != NULL) + viodev->unit_address = *unit_address; + } + viodev->iommu_table = vio_bus_ops.build_iommu_table(viodev); + + /* register with generic device framework */ + if (vio_register_device(viodev) == NULL) { + /* XXX free TCE table */ + kfree(viodev); + return NULL; + } + + return viodev; } +EXPORT_SYMBOL(vio_register_device_node); /** * vio_bus_init: - Initialize the virtual IO bus @@ -133,6 +203,7 @@ static const struct vio_device_id *vio_match_device( int __init vio_bus_init(struct vio_bus_ops *ops) { int err; + struct device_node *node_vroot; vio_bus_ops = *ops; @@ -153,23 +224,54 @@ int __init vio_bus_init(struct vio_bus_ops *ops) return err; } + node_vroot = find_devices("vdevice"); + if (node_vroot) { + struct device_node *of_node; + + /* + * Create struct vio_devices for each virtual device in + * the device tree. Drivers will associate with them later. + */ + for (of_node = node_vroot->child; of_node != NULL; + of_node = of_node->sibling) { + printk(KERN_DEBUG "%s: processing %p\n", + __FUNCTION__, of_node); + vio_register_device_node(of_node); + } + } + return 0; } /* vio_dev refcount hit 0 */ static void __devinit vio_dev_release(struct device *dev) { - if (vio_bus_ops.release_device) - vio_bus_ops.release_device(dev); + if (dev->platform_data) { + /* XXX free TCE table */ + of_node_put(dev->platform_data); + } kfree(to_vio_dev(dev)); } -static ssize_t viodev_show_name(struct device *dev, +static ssize_t name_show(struct device *dev, struct device_attribute *attr, char *buf) { return sprintf(buf, "%s\n", to_vio_dev(dev)->name); } -DEVICE_ATTR(name, S_IRUSR | S_IRGRP | S_IROTH, viodev_show_name, NULL); + +static ssize_t devspec_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct device_node *of_node = dev->platform_data; + + return sprintf(buf, "%s\n", of_node ? of_node->full_name : "none"); +} + +static struct device_attribute vio_dev_attrs[] = { + __ATTR_RO(name), + __ATTR_RO(devspec), + __ATTR_NULL +}; struct vio_dev * __devinit vio_register_device(struct vio_dev *viodev) { @@ -184,16 +286,12 @@ struct vio_dev * __devinit vio_register_device(struct vio_dev *viodev) __FUNCTION__, viodev->dev.bus_id); return NULL; } - device_create_file(&viodev->dev, &dev_attr_name); return viodev; } void __devinit vio_unregister_device(struct vio_dev *viodev) { - if (vio_bus_ops.unregister_device) - vio_bus_ops.unregister_device(viodev); - device_remove_file(&viodev->dev, &dev_attr_name); device_unregister(&viodev->dev); } EXPORT_SYMBOL(vio_unregister_device); @@ -267,22 +365,23 @@ static int vio_hotplug(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size) { const struct vio_dev *vio_dev = to_vio_dev(dev); + struct device_node *dn = dev->platform_data; char *cp; int length; if (!num_envp) return -ENOMEM; - if (!vio_dev->dev.platform_data) + if (!dn) return -ENODEV; - cp = (char *)get_property(vio_dev->dev.platform_data, "compatible", &length); + cp = (char *)get_property(dn, "compatible", &length); if (!cp) return -ENODEV; envp[0] = buffer; length = scnprintf(buffer, buffer_size, "MODALIAS=vio:T%sS%s", vio_dev->type, cp); - if (buffer_size - length <= 0) + if ((buffer_size - length) <= 0) return -ENOMEM; envp[1] = NULL; return 0; @@ -290,9 +389,25 @@ static int vio_hotplug(struct device *dev, char **envp, int num_envp, struct bus_type vio_bus_type = { .name = "vio", + .dev_attrs = vio_dev_attrs, .uevent = vio_hotplug, .match = vio_bus_match, .probe = vio_bus_probe, .remove = vio_bus_remove, .shutdown = vio_bus_shutdown, }; + +/** + * vio_get_attribute: - get attribute for virtual device + * @vdev: The vio device to get property. + * @which: The property/attribute to be extracted. + * @length: Pointer to length of returned data size (unused if NULL). + * + * Calls prom.c's get_property() to return the value of the + * attribute specified by @which +*/ +const void *vio_get_attribute(struct vio_dev *vdev, char *which, int *length) +{ + return get_property(vdev->dev.platform_data, which, length); +} +EXPORT_SYMBOL(vio_get_attribute); diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c index 4862b8e7c78c..901acbcc0888 100644 --- a/arch/powerpc/platforms/iseries/setup.c +++ b/arch/powerpc/platforms/iseries/setup.c @@ -951,6 +951,7 @@ void dt_vdevices(struct iseries_flat_dt *dt) dt_prop_str(dt, "device_type", "vlan"); dt_prop_empty(dt, "compatible"); dt_prop_u32(dt, "reg", reg + i); + dt_prop_u32(dt, "linux,unit_address", i); mac_addr[0] = 0x02; mac_addr[1] = 0x01; @@ -971,6 +972,7 @@ void dt_vdevices(struct iseries_flat_dt *dt) dt_prop_str(dt, "device_type", "viodasd"); dt_prop_empty(dt, "compatible"); dt_prop_u32(dt, "reg", reg + i); + dt_prop_u32(dt, "linux,unit_address", i); dt_end_node(dt); } reg += HVMAXARCHITECTEDVIRTUALDISKS; @@ -980,6 +982,7 @@ void dt_vdevices(struct iseries_flat_dt *dt) dt_prop_str(dt, "device_type", "viocd"); dt_prop_empty(dt, "compatible"); dt_prop_u32(dt, "reg", reg + i); + dt_prop_u32(dt, "linux,unit_address", i); dt_end_node(dt); } reg += HVMAXARCHITECTEDVIRTUALCDROMS; @@ -989,6 +992,7 @@ void dt_vdevices(struct iseries_flat_dt *dt) dt_prop_str(dt, "device_type", "viotape"); dt_prop_empty(dt, "compatible"); dt_prop_u32(dt, "reg", reg + i); + dt_prop_u32(dt, "linux,unit_address", i); dt_end_node(dt); } diff --git a/arch/powerpc/platforms/iseries/vio.c b/arch/powerpc/platforms/iseries/vio.c index 22045a2829a9..a689da6f2b07 100644 --- a/arch/powerpc/platforms/iseries/vio.c +++ b/arch/powerpc/platforms/iseries/vio.c @@ -43,58 +43,11 @@ static void __init iommu_vio_init(void) printk("Virtual Bus VIO TCE table failed.\n"); } -/** - * vio_register_device_iseries: - Register a new iSeries vio device. - * @voidev: The device to register. - */ -static struct vio_dev *__init vio_register_device_iseries(char *type, - uint32_t unit_num) +static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev) { - struct vio_dev *viodev; - - /* allocate a vio_dev for this device */ - viodev = kmalloc(sizeof(struct vio_dev), GFP_KERNEL); - if (!viodev) - return NULL; - memset(viodev, 0, sizeof(struct vio_dev)); - - snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%s%d", type, unit_num); - - viodev->name = viodev->dev.bus_id; - viodev->type = type; - viodev->unit_address = unit_num; - viodev->iommu_table = &vio_iommu_table; - if (vio_register_device(viodev) == NULL) { - kfree(viodev); - return NULL; - } - return viodev; -} - -static void __init probe_bus_iseries(void) -{ - HvLpIndexMap vlan_map; - struct vio_dev *viodev; - int i; - - /* there is only one of each of these */ - vio_register_device_iseries("viocons", 0); - vio_register_device_iseries("vscsi", 0); - - vlan_map = HvLpConfig_getVirtualLanIndexMap(); - for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++) { - if ((vlan_map & (0x8000 >> i)) == 0) - continue; - viodev = vio_register_device_iseries("vlan", i); - /* veth is special and has it own iommu_table */ - viodev->iommu_table = &veth_iommu_table; - } - for (i = 0; i < HVMAXARCHITECTEDVIRTUALDISKS; i++) - vio_register_device_iseries("viodasd", i); - for (i = 0; i < HVMAXARCHITECTEDVIRTUALCDROMS; i++) - vio_register_device_iseries("viocd", i); - for (i = 0; i < HVMAXARCHITECTEDVIRTUALTAPES; i++) - vio_register_device_iseries("viotape", i); + if (strcmp(dev->type, "vlan") == 0) + return &veth_iommu_table; + return &vio_iommu_table; } /** @@ -109,6 +62,7 @@ static int vio_match_device_iseries(const struct vio_device_id *id, static struct vio_bus_ops vio_bus_ops_iseries = { .match = vio_match_device_iseries, + .build_iommu_table = vio_build_iommu_table, }; /** @@ -116,16 +70,10 @@ static struct vio_bus_ops vio_bus_ops_iseries = { */ static int __init vio_bus_init_iseries(void) { - int err; - - err = vio_bus_init(&vio_bus_ops_iseries); - if (err == 0) { - iommu_vio_init(); - vio_bus_device.iommu_table = &vio_iommu_table; - iSeries_vio_dev = &vio_bus_device.dev; - probe_bus_iseries(); - } - return err; + iommu_vio_init(); + vio_bus_device.iommu_table = &vio_iommu_table; + iSeries_vio_dev = &vio_bus_device.dev; + return vio_bus_init(&vio_bus_ops_iseries); } __initcall(vio_bus_init_iseries); diff --git a/arch/powerpc/platforms/pseries/vio.c b/arch/powerpc/platforms/pseries/vio.c index 8e53e04ada8b..b3925aefdac6 100644 --- a/arch/powerpc/platforms/pseries/vio.c +++ b/arch/powerpc/platforms/pseries/vio.c @@ -26,26 +26,6 @@ extern struct subsystem devices_subsys; /* needed for vio_find_name() */ -static void probe_bus_pseries(void) -{ - struct device_node *node_vroot, *of_node; - - node_vroot = find_devices("vdevice"); - if ((node_vroot == NULL) || (node_vroot->child == NULL)) - /* this machine doesn't do virtual IO, and that's ok */ - return; - - /* - * Create struct vio_devices for each virtual device in the device tree. - * Drivers will associate with them later. - */ - for (of_node = node_vroot->child; of_node != NULL; - of_node = of_node->sibling) { - printk(KERN_DEBUG "%s: processing %p\n", __FUNCTION__, of_node); - vio_register_device_node(of_node); - } -} - /** * vio_match_device_pseries: - Tell if a pSeries VIO device matches a * vio_device_id @@ -57,47 +37,6 @@ static int vio_match_device_pseries(const struct vio_device_id *id, device_is_compatible(dev->dev.platform_data, id->compat); } -static void vio_release_device_pseries(struct device *dev) -{ - /* XXX free TCE table */ - of_node_put(dev->platform_data); -} - -static ssize_t viodev_show_devspec(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct device_node *of_node = dev->platform_data; - - return sprintf(buf, "%s\n", of_node->full_name); -} -DEVICE_ATTR(devspec, S_IRUSR | S_IRGRP | S_IROTH, viodev_show_devspec, NULL); - -static void vio_unregister_device_pseries(struct vio_dev *viodev) -{ - device_remove_file(&viodev->dev, &dev_attr_devspec); -} - -static struct vio_bus_ops vio_bus_ops_pseries = { - .match = vio_match_device_pseries, - .unregister_device = vio_unregister_device_pseries, - .release_device = vio_release_device_pseries, -}; - -/** - * vio_bus_init_pseries: - Initialize the pSeries virtual IO bus - */ -static int __init vio_bus_init_pseries(void) -{ - int err; - - err = vio_bus_init(&vio_bus_ops_pseries); - if (err == 0) - probe_bus_pseries(); - return err; -} - -__initcall(vio_bus_init_pseries); - /** * vio_build_iommu_table: - gets the dma information from OF and * builds the TCE tree. @@ -136,88 +75,20 @@ static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev) return iommu_init_table(newTceTable); } +static struct vio_bus_ops vio_bus_ops_pseries = { + .match = vio_match_device_pseries, + .build_iommu_table = vio_build_iommu_table, +}; + /** - * vio_register_device_node: - Register a new vio device. - * @of_node: The OF node for this device. - * - * Creates and initializes a vio_dev structure from the data in - * of_node (dev.platform_data) and adds it to the list of virtual devices. - * Returns a pointer to the created vio_dev or NULL if node has - * NULL device_type or compatible fields. + * vio_bus_init_pseries: - Initialize the pSeries virtual IO bus */ -struct vio_dev * __devinit vio_register_device_node(struct device_node *of_node) +static int __init vio_bus_init_pseries(void) { - struct vio_dev *viodev; - unsigned int *unit_address; - unsigned int *irq_p; - - /* we need the 'device_type' property, in order to match with drivers */ - if ((NULL == of_node->type)) { - printk(KERN_WARNING - "%s: node %s missing 'device_type'\n", __FUNCTION__, - of_node->name ? of_node->name : ""); - return NULL; - } - - unit_address = (unsigned int *)get_property(of_node, "reg", NULL); - if (!unit_address) { - printk(KERN_WARNING "%s: node %s missing 'reg'\n", __FUNCTION__, - of_node->name ? of_node->name : ""); - return NULL; - } - - /* allocate a vio_dev for this node */ - viodev = kmalloc(sizeof(struct vio_dev), GFP_KERNEL); - if (!viodev) { - return NULL; - } - memset(viodev, 0, sizeof(struct vio_dev)); - - viodev->dev.platform_data = of_node_get(of_node); - - viodev->irq = NO_IRQ; - irq_p = (unsigned int *)get_property(of_node, "interrupts", NULL); - if (irq_p) { - int virq = virt_irq_create_mapping(*irq_p); - if (virq == NO_IRQ) { - printk(KERN_ERR "Unable to allocate interrupt " - "number for %s\n", of_node->full_name); - } else - viodev->irq = irq_offset_up(virq); - } - - snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%x", *unit_address); - viodev->name = of_node->name; - viodev->type = of_node->type; - viodev->unit_address = *unit_address; - viodev->iommu_table = vio_build_iommu_table(viodev); - - /* register with generic device framework */ - if (vio_register_device(viodev) == NULL) { - /* XXX free TCE table */ - kfree(viodev); - return NULL; - } - device_create_file(&viodev->dev, &dev_attr_devspec); - - return viodev; + return vio_bus_init(&vio_bus_ops_pseries); } -EXPORT_SYMBOL(vio_register_device_node); -/** - * vio_get_attribute: - get attribute for virtual device - * @vdev: The vio device to get property. - * @which: The property/attribute to be extracted. - * @length: Pointer to length of returned data size (unused if NULL). - * - * Calls prom.c's get_property() to return the value of the - * attribute specified by the preprocessor constant @which -*/ -const void * vio_get_attribute(struct vio_dev *vdev, void* which, int* length) -{ - return get_property(vdev->dev.platform_data, (char*)which, length); -} -EXPORT_SYMBOL(vio_get_attribute); +__initcall(vio_bus_init_pseries); /* vio_find_name() - internal because only vio.c knows how we formatted the * kobject name diff --git a/include/asm-powerpc/vio.h b/include/asm-powerpc/vio.h index 0544ece51761..0055d8e6102d 100644 --- a/include/asm-powerpc/vio.h +++ b/include/asm-powerpc/vio.h @@ -66,8 +66,7 @@ struct vio_driver { struct vio_bus_ops { int (*match)(const struct vio_device_id *id, const struct vio_dev *dev); - void (*unregister_device)(struct vio_dev *); - void (*release_device)(struct device *); + struct iommu_table *(*build_iommu_table)(struct vio_dev *dev); }; extern struct dma_mapping_ops vio_dma_ops; @@ -82,14 +81,14 @@ extern void __devinit vio_unregister_device(struct vio_dev *dev); extern int vio_bus_init(struct vio_bus_ops *); -#ifdef CONFIG_PPC_PSERIES struct device_node; extern struct vio_dev * __devinit vio_register_device_node( struct device_node *node_vdev); -extern struct vio_dev *vio_find_node(struct device_node *vnode); -extern const void *vio_get_attribute(struct vio_dev *vdev, void *which, +extern const void *vio_get_attribute(struct vio_dev *vdev, char *which, int *length); +#ifdef CONFIG_PPC_PSERIES +extern struct vio_dev *vio_find_node(struct device_node *vnode); extern int vio_enable_interrupts(struct vio_dev *dev); extern int vio_disable_interrupts(struct vio_dev *dev); #endif -- cgit v1.2.3 From dd721ffd95d5e1516380da0b254ef737582a258f Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 27 Apr 2006 17:21:46 +1000 Subject: [PATCH] powerpc: use a common vio_match_device routine This requires the compatible properties having vaules that are empty strings instead of just being empty properties. Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/vio.c | 3 ++- arch/powerpc/platforms/iseries/setup.c | 10 +++++----- arch/powerpc/platforms/iseries/vio.c | 12 ------------ arch/powerpc/platforms/pseries/vio.c | 12 ------------ include/asm-powerpc/vio.h | 1 - 5 files changed, 7 insertions(+), 31 deletions(-) (limited to 'include') diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index 9b46eed5e637..19529297a2dc 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c @@ -47,7 +47,8 @@ static const struct vio_device_id *vio_match_device( const struct vio_device_id *ids, const struct vio_dev *dev) { while (ids->type[0] != '\0') { - if (vio_bus_ops.match(ids, dev)) + if ((strncmp(dev->type, ids->type, strlen(ids->type)) == 0) && + device_is_compatible(dev->dev.platform_data, ids->compat)) return ids; ids++; } diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c index 901acbcc0888..befd36af7e32 100644 --- a/arch/powerpc/platforms/iseries/setup.c +++ b/arch/powerpc/platforms/iseries/setup.c @@ -927,7 +927,7 @@ void dt_vdevices(struct iseries_flat_dt *dt) snprintf(buf, sizeof(buf), "viocons@%08x", reg); dt_start_node(dt, buf); dt_prop_str(dt, "device_type", "serial"); - dt_prop_empty(dt, "compatible"); + dt_prop_str(dt, "compatible", ""); dt_prop_u32(dt, "reg", reg); dt_end_node(dt); reg++; @@ -949,7 +949,7 @@ void dt_vdevices(struct iseries_flat_dt *dt) snprintf(buf, 32, "vlan@%08x", reg + i); dt_start_node(dt, buf); dt_prop_str(dt, "device_type", "vlan"); - dt_prop_empty(dt, "compatible"); + dt_prop_str(dt, "compatible", ""); dt_prop_u32(dt, "reg", reg + i); dt_prop_u32(dt, "linux,unit_address", i); @@ -970,7 +970,7 @@ void dt_vdevices(struct iseries_flat_dt *dt) snprintf(buf, 32, "viodasd@%08x", reg + i); dt_start_node(dt, buf); dt_prop_str(dt, "device_type", "viodasd"); - dt_prop_empty(dt, "compatible"); + dt_prop_str(dt, "compatible", ""); dt_prop_u32(dt, "reg", reg + i); dt_prop_u32(dt, "linux,unit_address", i); dt_end_node(dt); @@ -980,7 +980,7 @@ void dt_vdevices(struct iseries_flat_dt *dt) snprintf(buf, 32, "viocd@%08x", reg + i); dt_start_node(dt, buf); dt_prop_str(dt, "device_type", "viocd"); - dt_prop_empty(dt, "compatible"); + dt_prop_str(dt, "compatible", ""); dt_prop_u32(dt, "reg", reg + i); dt_prop_u32(dt, "linux,unit_address", i); dt_end_node(dt); @@ -990,7 +990,7 @@ void dt_vdevices(struct iseries_flat_dt *dt) snprintf(buf, 32, "viotape@%08x", reg + i); dt_start_node(dt, buf); dt_prop_str(dt, "device_type", "viotape"); - dt_prop_empty(dt, "compatible"); + dt_prop_str(dt, "compatible", ""); dt_prop_u32(dt, "reg", reg + i); dt_prop_u32(dt, "linux,unit_address", i); dt_end_node(dt); diff --git a/arch/powerpc/platforms/iseries/vio.c b/arch/powerpc/platforms/iseries/vio.c index a689da6f2b07..bdd2b7d97d15 100644 --- a/arch/powerpc/platforms/iseries/vio.c +++ b/arch/powerpc/platforms/iseries/vio.c @@ -50,18 +50,7 @@ static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev) return &vio_iommu_table; } -/** - * vio_match_device_iseries: - Tell if a iSeries VIO device matches a - * vio_device_id - */ -static int vio_match_device_iseries(const struct vio_device_id *id, - const struct vio_dev *dev) -{ - return strncmp(dev->type, id->type, strlen(id->type)) == 0; -} - static struct vio_bus_ops vio_bus_ops_iseries = { - .match = vio_match_device_iseries, .build_iommu_table = vio_build_iommu_table, }; @@ -75,5 +64,4 @@ static int __init vio_bus_init_iseries(void) iSeries_vio_dev = &vio_bus_device.dev; return vio_bus_init(&vio_bus_ops_iseries); } - __initcall(vio_bus_init_iseries); diff --git a/arch/powerpc/platforms/pseries/vio.c b/arch/powerpc/platforms/pseries/vio.c index b3925aefdac6..d2891661d87b 100644 --- a/arch/powerpc/platforms/pseries/vio.c +++ b/arch/powerpc/platforms/pseries/vio.c @@ -26,17 +26,6 @@ extern struct subsystem devices_subsys; /* needed for vio_find_name() */ -/** - * vio_match_device_pseries: - Tell if a pSeries VIO device matches a - * vio_device_id - */ -static int vio_match_device_pseries(const struct vio_device_id *id, - const struct vio_dev *dev) -{ - return (strncmp(dev->type, id->type, strlen(id->type)) == 0) && - device_is_compatible(dev->dev.platform_data, id->compat); -} - /** * vio_build_iommu_table: - gets the dma information from OF and * builds the TCE tree. @@ -76,7 +65,6 @@ static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev) } static struct vio_bus_ops vio_bus_ops_pseries = { - .match = vio_match_device_pseries, .build_iommu_table = vio_build_iommu_table, }; diff --git a/include/asm-powerpc/vio.h b/include/asm-powerpc/vio.h index 0055d8e6102d..9c09a8ffa128 100644 --- a/include/asm-powerpc/vio.h +++ b/include/asm-powerpc/vio.h @@ -65,7 +65,6 @@ struct vio_driver { }; struct vio_bus_ops { - int (*match)(const struct vio_device_id *id, const struct vio_dev *dev); struct iommu_table *(*build_iommu_table)(struct vio_dev *dev); }; -- cgit v1.2.3 From c7f0e8cb5654a50986c6097b3c0cca972e406899 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 27 Apr 2006 17:23:32 +1000 Subject: [PATCH] powerpc: merge the rest of the vio code Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/vio.c | 198 ++++++++++++++++++++++++++------ arch/powerpc/platforms/iseries/Makefile | 1 - arch/powerpc/platforms/iseries/iommu.c | 3 +- arch/powerpc/platforms/iseries/iommu.h | 35 ------ arch/powerpc/platforms/iseries/pci.c | 2 +- arch/powerpc/platforms/iseries/vio.c | 67 ----------- arch/powerpc/platforms/pseries/Makefile | 1 - arch/powerpc/platforms/pseries/vio.c | 133 --------------------- include/asm-powerpc/iseries/iommu.h | 35 ++++++ include/asm-powerpc/vio.h | 8 -- 10 files changed, 201 insertions(+), 282 deletions(-) delete mode 100644 arch/powerpc/platforms/iseries/iommu.h delete mode 100644 arch/powerpc/platforms/iseries/vio.c delete mode 100644 arch/powerpc/platforms/pseries/vio.c create mode 100644 include/asm-powerpc/iseries/iommu.h (limited to 'include') diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index 19529297a2dc..ac5c7bf907f5 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c @@ -13,25 +13,102 @@ * 2 of the License, or (at your option) any later version. */ +#include +#include #include #include #include #include #include +#include + #include #include #include #include #include - -struct vio_dev vio_bus_device = { /* fake "parent" device */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern struct subsystem devices_subsys; /* needed for vio_find_name() */ + +static struct vio_dev vio_bus_device = { /* fake "parent" device */ .name = vio_bus_device.dev.bus_id, .type = "", .dev.bus_id = "vio", .dev.bus = &vio_bus_type, }; -static struct vio_bus_ops vio_bus_ops; +#ifdef CONFIG_PPC_ISERIES +struct device *iSeries_vio_dev = &vio_bus_device.dev; +EXPORT_SYMBOL(iSeries_vio_dev); + +static struct iommu_table veth_iommu_table; +static struct iommu_table vio_iommu_table; + +static void __init iommu_vio_init(void) +{ + iommu_table_getparms_iSeries(255, 0, 0xff, &veth_iommu_table); + veth_iommu_table.it_size /= 2; + vio_iommu_table = veth_iommu_table; + vio_iommu_table.it_offset += veth_iommu_table.it_size; + + if (!iommu_init_table(&veth_iommu_table)) + printk("Virtual Bus VETH TCE table failed.\n"); + if (!iommu_init_table(&vio_iommu_table)) + printk("Virtual Bus VIO TCE table failed.\n"); +} +#endif + +static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev) +{ +#ifdef CONFIG_PPC_ISERIES + if (firmware_has_feature(FW_FEATURE_ISERIES)) { + if (strcmp(dev->type, "vlan") == 0) + return &veth_iommu_table; + return &vio_iommu_table; + } else +#endif + { + unsigned int *dma_window; + struct iommu_table *newTceTable; + unsigned long offset; + int dma_window_property_size; + + dma_window = (unsigned int *)get_property( + dev->dev.platform_data, "ibm,my-dma-window", + &dma_window_property_size); + if (!dma_window) + return NULL; + + newTceTable = kmalloc(sizeof(struct iommu_table), GFP_KERNEL); + + /* + * There should be some code to extract the phys-encoded + * offset using prom_n_addr_cells(). However, according to + * a comment on earlier versions, it's always zero, so we + * don't bother + */ + offset = dma_window[1] >> PAGE_SHIFT; + + /* TCE table size - measured in tce entries */ + newTceTable->it_size = dma_window[4] >> PAGE_SHIFT; + /* offset for VIO should always be 0 */ + newTceTable->it_offset = offset; + newTceTable->it_busno = 0; + newTceTable->it_index = (unsigned long)dma_window[0]; + newTceTable->it_type = TCE_VB; + + return iommu_init_table(newTceTable); + } +} /** * vio_match_device: - Tell if a VIO device has a matching @@ -126,6 +203,16 @@ void vio_unregister_driver(struct vio_driver *viodrv) } EXPORT_SYMBOL(vio_unregister_driver); +/* vio_dev refcount hit 0 */ +static void __devinit vio_dev_release(struct device *dev) +{ + if (dev->platform_data) { + /* XXX free TCE table */ + of_node_put(dev->platform_data); + } + kfree(to_vio_dev(dev)); +} + /** * vio_register_device_node: - Register a new vio device. * @of_node: The OF node for this device. @@ -185,10 +272,17 @@ struct vio_dev * __devinit vio_register_device_node(struct device_node *of_node) if (unit_address != NULL) viodev->unit_address = *unit_address; } - viodev->iommu_table = vio_bus_ops.build_iommu_table(viodev); + viodev->iommu_table = vio_build_iommu_table(viodev); + + /* init generic 'struct device' fields: */ + viodev->dev.parent = &vio_bus_device.dev; + viodev->dev.bus = &vio_bus_type; + viodev->dev.release = vio_dev_release; /* register with generic device framework */ - if (vio_register_device(viodev) == NULL) { + if (device_register(&viodev->dev)) { + printk(KERN_ERR "%s: failed to register device %s\n", + __FUNCTION__, viodev->dev.bus_id); /* XXX free TCE table */ kfree(viodev); return NULL; @@ -201,12 +295,18 @@ EXPORT_SYMBOL(vio_register_device_node); /** * vio_bus_init: - Initialize the virtual IO bus */ -int __init vio_bus_init(struct vio_bus_ops *ops) +static int __init vio_bus_init(void) { int err; struct device_node *node_vroot; - vio_bus_ops = *ops; +#ifdef CONFIG_PPC_ISERIES + if (firmware_has_feature(FW_FEATURE_ISERIES)) { + iommu_vio_init(); + vio_bus_device.iommu_table = &vio_iommu_table; + iSeries_vio_dev = &vio_bus_device.dev; + } +#endif err = bus_register(&vio_bus_type); if (err) { @@ -243,16 +343,7 @@ int __init vio_bus_init(struct vio_bus_ops *ops) return 0; } - -/* vio_dev refcount hit 0 */ -static void __devinit vio_dev_release(struct device *dev) -{ - if (dev->platform_data) { - /* XXX free TCE table */ - of_node_put(dev->platform_data); - } - kfree(to_vio_dev(dev)); -} +__initcall(vio_bus_init); static ssize_t name_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -274,23 +365,6 @@ static struct device_attribute vio_dev_attrs[] = { __ATTR_NULL }; -struct vio_dev * __devinit vio_register_device(struct vio_dev *viodev) -{ - /* init generic 'struct device' fields: */ - viodev->dev.parent = &vio_bus_device.dev; - viodev->dev.bus = &vio_bus_type; - viodev->dev.release = vio_dev_release; - - /* register with generic device framework */ - if (device_register(&viodev->dev)) { - printk(KERN_ERR "%s: failed to register device %s\n", - __FUNCTION__, viodev->dev.bus_id); - return NULL; - } - - return viodev; -} - void __devinit vio_unregister_device(struct vio_dev *viodev) { device_unregister(&viodev->dev); @@ -412,3 +486,59 @@ const void *vio_get_attribute(struct vio_dev *vdev, char *which, int *length) return get_property(vdev->dev.platform_data, which, length); } EXPORT_SYMBOL(vio_get_attribute); + +#ifdef CONFIG_PPC_PSERIES +/* vio_find_name() - internal because only vio.c knows how we formatted the + * kobject name + * XXX once vio_bus_type.devices is actually used as a kset in + * drivers/base/bus.c, this function should be removed in favor of + * "device_find(kobj_name, &vio_bus_type)" + */ +static struct vio_dev *vio_find_name(const char *kobj_name) +{ + struct kobject *found; + + found = kset_find_obj(&devices_subsys.kset, kobj_name); + if (!found) + return NULL; + + return to_vio_dev(container_of(found, struct device, kobj)); +} + +/** + * vio_find_node - find an already-registered vio_dev + * @vnode: device_node of the virtual device we're looking for + */ +struct vio_dev *vio_find_node(struct device_node *vnode) +{ + uint32_t *unit_address; + char kobj_name[BUS_ID_SIZE]; + + /* construct the kobject name from the device node */ + unit_address = (uint32_t *)get_property(vnode, "reg", NULL); + if (!unit_address) + return NULL; + snprintf(kobj_name, BUS_ID_SIZE, "%x", *unit_address); + + return vio_find_name(kobj_name); +} +EXPORT_SYMBOL(vio_find_node); + +int vio_enable_interrupts(struct vio_dev *dev) +{ + int rc = h_vio_signal(dev->unit_address, VIO_IRQ_ENABLE); + if (rc != H_SUCCESS) + printk(KERN_ERR "vio: Error 0x%x enabling interrupts\n", rc); + return rc; +} +EXPORT_SYMBOL(vio_enable_interrupts); + +int vio_disable_interrupts(struct vio_dev *dev) +{ + int rc = h_vio_signal(dev->unit_address, VIO_IRQ_DISABLE); + if (rc != H_SUCCESS) + printk(KERN_ERR "vio: Error 0x%x disabling interrupts\n", rc); + return rc; +} +EXPORT_SYMBOL(vio_disable_interrupts); +#endif /* CONFIG_PPC_PSERIES */ diff --git a/arch/powerpc/platforms/iseries/Makefile b/arch/powerpc/platforms/iseries/Makefile index ce8c0b943fa0..7e67a20c18ab 100644 --- a/arch/powerpc/platforms/iseries/Makefile +++ b/arch/powerpc/platforms/iseries/Makefile @@ -3,7 +3,6 @@ EXTRA_CFLAGS += -mno-minimal-toc obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o mf.o lpevents.o \ hvcall.o proc.o htab.o iommu.o misc.o irq.o obj-$(CONFIG_PCI) += pci.o vpdinfo.o -obj-$(CONFIG_IBMVIO) += vio.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_VIOPATH) += viopath.o obj-$(CONFIG_MODULES) += ksyms.o diff --git a/arch/powerpc/platforms/iseries/iommu.c b/arch/powerpc/platforms/iseries/iommu.c index bea0b703f409..a8d96314c982 100644 --- a/arch/powerpc/platforms/iseries/iommu.c +++ b/arch/powerpc/platforms/iseries/iommu.c @@ -33,8 +33,7 @@ #include #include #include - -#include "iommu.h" +#include extern struct list_head iSeries_Global_Device_List; diff --git a/arch/powerpc/platforms/iseries/iommu.h b/arch/powerpc/platforms/iseries/iommu.h deleted file mode 100644 index cb5658fbe657..000000000000 --- a/arch/powerpc/platforms/iseries/iommu.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef _PLATFORMS_ISERIES_IOMMU_H -#define _PLATFORMS_ISERIES_IOMMU_H - -/* - * Copyright (C) 2005 Stephen Rothwell, IBM Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the: - * Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, - * Boston, MA 02111-1307 USA - */ - -struct device_node; -struct iommu_table; - -/* Creates table for an individual device node */ -extern void iommu_devnode_init_iSeries(struct device_node *dn); - -/* Get table parameters from HV */ -extern void iommu_table_getparms_iSeries(unsigned long busno, - unsigned char slotno, unsigned char virtbus, - struct iommu_table *tbl); - -#endif /* _PLATFORMS_ISERIES_IOMMU_H */ diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c index 5a61c6fdb33a..428ffb5cf044 100644 --- a/arch/powerpc/platforms/iseries/pci.c +++ b/arch/powerpc/platforms/iseries/pci.c @@ -37,13 +37,13 @@ #include #include +#include #include #include "irq.h" #include "pci.h" #include "call_pci.h" -#include "iommu.h" /* * Forward declares of prototypes. diff --git a/arch/powerpc/platforms/iseries/vio.c b/arch/powerpc/platforms/iseries/vio.c deleted file mode 100644 index bdd2b7d97d15..000000000000 --- a/arch/powerpc/platforms/iseries/vio.c +++ /dev/null @@ -1,67 +0,0 @@ -/* - * IBM PowerPC iSeries Virtual I/O Infrastructure Support. - * - * Copyright (c) 2005 Stephen Rothwell, IBM Corp. - * - * 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 -#include -#include -#include - -#include "iommu.h" - -struct device *iSeries_vio_dev = &vio_bus_device.dev; -EXPORT_SYMBOL(iSeries_vio_dev); - -static struct iommu_table veth_iommu_table; -static struct iommu_table vio_iommu_table; - -static void __init iommu_vio_init(void) -{ - iommu_table_getparms_iSeries(255, 0, 0xff, &veth_iommu_table); - veth_iommu_table.it_size /= 2; - vio_iommu_table = veth_iommu_table; - vio_iommu_table.it_offset += veth_iommu_table.it_size; - - if (!iommu_init_table(&veth_iommu_table)) - printk("Virtual Bus VETH TCE table failed.\n"); - if (!iommu_init_table(&vio_iommu_table)) - printk("Virtual Bus VIO TCE table failed.\n"); -} - -static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev) -{ - if (strcmp(dev->type, "vlan") == 0) - return &veth_iommu_table; - return &vio_iommu_table; -} - -static struct vio_bus_ops vio_bus_ops_iseries = { - .build_iommu_table = vio_build_iommu_table, -}; - -/** - * vio_bus_init_iseries: - Initialize the iSeries virtual IO bus - */ -static int __init vio_bus_init_iseries(void) -{ - iommu_vio_init(); - vio_bus_device.iommu_table = &vio_iommu_table; - iSeries_vio_dev = &vio_bus_device.dev; - return vio_bus_init(&vio_bus_ops_iseries); -} -__initcall(vio_bus_init_iseries); diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile index 930898635c9f..b46ce3b9bb3c 100644 --- a/arch/powerpc/platforms/pseries/Makefile +++ b/arch/powerpc/platforms/pseries/Makefile @@ -2,7 +2,6 @@ obj-y := pci.o lpar.o hvCall.o nvram.o reconfig.o \ setup.o iommu.o ras.o rtasd.o pci_dlpar.o \ firmware.o obj-$(CONFIG_SMP) += smp.o -obj-$(CONFIG_IBMVIO) += vio.o obj-$(CONFIG_XICS) += xics.o obj-$(CONFIG_SCANLOG) += scanlog.o obj-$(CONFIG_EEH) += eeh.o eeh_cache.o eeh_driver.o eeh_event.o diff --git a/arch/powerpc/platforms/pseries/vio.c b/arch/powerpc/platforms/pseries/vio.c deleted file mode 100644 index d2891661d87b..000000000000 --- a/arch/powerpc/platforms/pseries/vio.c +++ /dev/null @@ -1,133 +0,0 @@ -/* - * IBM PowerPC pSeries Virtual I/O Infrastructure Support. - * - * Copyright (c) 2003-2005 IBM Corp. - * Dave Engebretsen engebret@us.ibm.com - * Santiago Leon santil@us.ibm.com - * Hollis Blanchard - * Stephen Rothwell - * - * 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 -#include - -extern struct subsystem devices_subsys; /* needed for vio_find_name() */ - -/** - * vio_build_iommu_table: - gets the dma information from OF and - * builds the TCE tree. - * @dev: the virtual device. - * - * Returns a pointer to the built tce tree, or NULL if it can't - * find property. -*/ -static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev) -{ - unsigned int *dma_window; - struct iommu_table *newTceTable; - unsigned long offset; - int dma_window_property_size; - - dma_window = (unsigned int *) get_property(dev->dev.platform_data, "ibm,my-dma-window", &dma_window_property_size); - if(!dma_window) { - return NULL; - } - - newTceTable = (struct iommu_table *) kmalloc(sizeof(struct iommu_table), GFP_KERNEL); - - /* There should be some code to extract the phys-encoded offset - using prom_n_addr_cells(). However, according to a comment - on earlier versions, it's always zero, so we don't bother */ - offset = dma_window[1] >> PAGE_SHIFT; - - /* TCE table size - measured in tce entries */ - newTceTable->it_size = dma_window[4] >> PAGE_SHIFT; - /* offset for VIO should always be 0 */ - newTceTable->it_offset = offset; - newTceTable->it_busno = 0; - newTceTable->it_index = (unsigned long)dma_window[0]; - newTceTable->it_type = TCE_VB; - - return iommu_init_table(newTceTable); -} - -static struct vio_bus_ops vio_bus_ops_pseries = { - .build_iommu_table = vio_build_iommu_table, -}; - -/** - * vio_bus_init_pseries: - Initialize the pSeries virtual IO bus - */ -static int __init vio_bus_init_pseries(void) -{ - return vio_bus_init(&vio_bus_ops_pseries); -} - -__initcall(vio_bus_init_pseries); - -/* vio_find_name() - internal because only vio.c knows how we formatted the - * kobject name - * XXX once vio_bus_type.devices is actually used as a kset in - * drivers/base/bus.c, this function should be removed in favor of - * "device_find(kobj_name, &vio_bus_type)" - */ -static struct vio_dev *vio_find_name(const char *kobj_name) -{ - struct kobject *found; - - found = kset_find_obj(&devices_subsys.kset, kobj_name); - if (!found) - return NULL; - - return to_vio_dev(container_of(found, struct device, kobj)); -} - -/** - * vio_find_node - find an already-registered vio_dev - * @vnode: device_node of the virtual device we're looking for - */ -struct vio_dev *vio_find_node(struct device_node *vnode) -{ - uint32_t *unit_address; - char kobj_name[BUS_ID_SIZE]; - - /* construct the kobject name from the device node */ - unit_address = (uint32_t *)get_property(vnode, "reg", NULL); - if (!unit_address) - return NULL; - snprintf(kobj_name, BUS_ID_SIZE, "%x", *unit_address); - - return vio_find_name(kobj_name); -} -EXPORT_SYMBOL(vio_find_node); - -int vio_enable_interrupts(struct vio_dev *dev) -{ - int rc = h_vio_signal(dev->unit_address, VIO_IRQ_ENABLE); - if (rc != H_SUCCESS) - printk(KERN_ERR "vio: Error 0x%x enabling interrupts\n", rc); - return rc; -} -EXPORT_SYMBOL(vio_enable_interrupts); - -int vio_disable_interrupts(struct vio_dev *dev) -{ - int rc = h_vio_signal(dev->unit_address, VIO_IRQ_DISABLE); - if (rc != H_SUCCESS) - printk(KERN_ERR "vio: Error 0x%x disabling interrupts\n", rc); - return rc; -} -EXPORT_SYMBOL(vio_disable_interrupts); diff --git a/include/asm-powerpc/iseries/iommu.h b/include/asm-powerpc/iseries/iommu.h new file mode 100644 index 000000000000..0edbfe10cb37 --- /dev/null +++ b/include/asm-powerpc/iseries/iommu.h @@ -0,0 +1,35 @@ +#ifndef _ASM_POWERPC_ISERIES_IOMMU_H +#define _ASM_POWERPC_ISERIES_IOMMU_H + +/* + * Copyright (C) 2005 Stephen Rothwell, IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + */ + +struct device_node; +struct iommu_table; + +/* Creates table for an individual device node */ +extern void iommu_devnode_init_iSeries(struct device_node *dn); + +/* Get table parameters from HV */ +extern void iommu_table_getparms_iSeries(unsigned long busno, + unsigned char slotno, unsigned char virtbus, + struct iommu_table *tbl); + +#endif /* _ASM_POWERPC_ISERIES_IOMMU_H */ diff --git a/include/asm-powerpc/vio.h b/include/asm-powerpc/vio.h index 9c09a8ffa128..10da7f3af938 100644 --- a/include/asm-powerpc/vio.h +++ b/include/asm-powerpc/vio.h @@ -64,22 +64,14 @@ struct vio_driver { struct device_driver driver; }; -struct vio_bus_ops { - struct iommu_table *(*build_iommu_table)(struct vio_dev *dev); -}; - extern struct dma_mapping_ops vio_dma_ops; extern struct bus_type vio_bus_type; -extern struct vio_dev vio_bus_device; extern int vio_register_driver(struct vio_driver *drv); extern void vio_unregister_driver(struct vio_driver *drv); -extern struct vio_dev * __devinit vio_register_device(struct vio_dev *viodev); extern void __devinit vio_unregister_device(struct vio_dev *dev); -extern int vio_bus_init(struct vio_bus_ops *); - struct device_node; extern struct vio_dev * __devinit vio_register_device_node( -- cgit v1.2.3 From bc97ce951cfb697eaac9d5b6a2fbe4544fdf1a7c Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Fri, 28 Apr 2006 22:51:59 -0500 Subject: [PATCH] powerpc: kill union tce_entry It's been long overdue to kill the union tce_entry in the pSeries/iSeries TCE code, especially since I asked the Summit guys to do it on the code they copied from us. Also, while I was at it, I cleaned up some whitespace. Built and booted on pSeries, built on iSeries. Signed-off-by: Olof Johansson Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/iseries/iommu.c | 21 +++--- arch/powerpc/platforms/pseries/iommu.c | 122 ++++++++++++++------------------- include/asm-powerpc/tce.h | 35 +++------- 3 files changed, 71 insertions(+), 107 deletions(-) (limited to 'include') diff --git a/arch/powerpc/platforms/iseries/iommu.c b/arch/powerpc/platforms/iseries/iommu.c index a8d96314c982..3ac22065c424 100644 --- a/arch/powerpc/platforms/iseries/iommu.c +++ b/arch/powerpc/platforms/iseries/iommu.c @@ -4,6 +4,7 @@ * Rewrite, cleanup: * * Copyright (C) 2004 Olof Johansson , IBM Corporation + * Copyright (C) 2006 Olof Johansson * * Dynamic DMA mapping support, iSeries-specific parts. * @@ -42,30 +43,28 @@ static void tce_build_iSeries(struct iommu_table *tbl, long index, long npages, unsigned long uaddr, enum dma_data_direction direction) { u64 rc; - union tce_entry tce; + u64 tce, rpn; index <<= TCE_PAGE_FACTOR; npages <<= TCE_PAGE_FACTOR; while (npages--) { - tce.te_word = 0; - tce.te_bits.tb_rpn = virt_to_abs(uaddr) >> TCE_SHIFT; + rpn = virt_to_abs(uaddr) >> TCE_SHIFT; + tce = (rpn & TCE_RPN_MASK) << TCE_RPN_SHIFT; if (tbl->it_type == TCE_VB) { /* Virtual Bus */ - tce.te_bits.tb_valid = 1; - tce.te_bits.tb_allio = 1; + tce |= TCE_VALID|TCE_ALLIO; if (direction != DMA_TO_DEVICE) - tce.te_bits.tb_rdwr = 1; + tce |= TCE_VB_WRITE; } else { /* PCI Bus */ - tce.te_bits.tb_rdwr = 1; /* Read allowed */ + tce |= TCE_PCI_READ; /* Read allowed */ if (direction != DMA_TO_DEVICE) - tce.te_bits.tb_pciwr = 1; + tce |= TCE_PCI_WRITE; } - rc = HvCallXm_setTce((u64)tbl->it_index, (u64)index, - tce.te_word); + rc = HvCallXm_setTce((u64)tbl->it_index, (u64)index, tce); if (rc) panic("PCI_DMA: HvCallXm_setTce failed, Rc: 0x%lx\n", rc); @@ -123,7 +122,7 @@ void iommu_table_getparms_iSeries(unsigned long busno, /* itc_size is in pages worth of table, it_size is in # of entries */ tbl->it_size = ((parms->itc_size * TCE_PAGE_SIZE) / - sizeof(union tce_entry)) >> TCE_PAGE_FACTOR; + TCE_ENTRY_SIZE) >> TCE_PAGE_FACTOR; tbl->it_busno = parms->itc_busno; tbl->it_offset = parms->itc_offset >> TCE_PAGE_FACTOR; tbl->it_index = parms->itc_index; diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index 2643078433f0..ed102f390689 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -1,23 +1,24 @@ /* * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation * - * Rewrite, cleanup: + * Rewrite, cleanup: * * Copyright (C) 2004 Olof Johansson , IBM Corporation + * Copyright (C) 2006 Olof Johansson * * Dynamic DMA mapping support, pSeries-specific parts, both SMP and LPAR. * - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA @@ -49,52 +50,46 @@ #define DBG(fmt...) -static void tce_build_pSeries(struct iommu_table *tbl, long index, - long npages, unsigned long uaddr, +static void tce_build_pSeries(struct iommu_table *tbl, long index, + long npages, unsigned long uaddr, enum dma_data_direction direction) { - union tce_entry t; - union tce_entry *tp; + u64 proto_tce; + u64 *tcep; + u64 rpn; index <<= TCE_PAGE_FACTOR; npages <<= TCE_PAGE_FACTOR; - t.te_word = 0; - t.te_rdwr = 1; // Read allowed + proto_tce = TCE_PCI_READ; // Read allowed if (direction != DMA_TO_DEVICE) - t.te_pciwr = 1; + proto_tce |= TCE_PCI_WRITE; - tp = ((union tce_entry *)tbl->it_base) + index; + tcep = ((u64 *)tbl->it_base) + index; while (npages--) { /* can't move this out since we might cross LMB boundary */ - t.te_rpn = (virt_to_abs(uaddr)) >> TCE_SHIFT; - - tp->te_word = t.te_word; + rpn = (virt_to_abs(uaddr)) >> TCE_SHIFT; + *tcep = proto_tce | (rpn & TCE_RPN_MASK) << TCE_RPN_SHIFT; uaddr += TCE_PAGE_SIZE; - tp++; + tcep++; } } static void tce_free_pSeries(struct iommu_table *tbl, long index, long npages) { - union tce_entry t; - union tce_entry *tp; + u64 *tcep; npages <<= TCE_PAGE_FACTOR; index <<= TCE_PAGE_FACTOR; - t.te_word = 0; - tp = ((union tce_entry *)tbl->it_base) + index; - - while (npages--) { - tp->te_word = t.te_word; - - tp++; - } + tcep = ((u64 *)tbl->it_base) + index; + + while (npages--) + *(tcep++) = 0; } @@ -103,43 +98,44 @@ static void tce_build_pSeriesLP(struct iommu_table *tbl, long tcenum, enum dma_data_direction direction) { u64 rc; - union tce_entry tce; + u64 proto_tce, tce; + u64 rpn; tcenum <<= TCE_PAGE_FACTOR; npages <<= TCE_PAGE_FACTOR; - tce.te_word = 0; - tce.te_rpn = (virt_to_abs(uaddr)) >> TCE_SHIFT; - tce.te_rdwr = 1; + rpn = (virt_to_abs(uaddr)) >> TCE_SHIFT; + proto_tce = TCE_PCI_READ; if (direction != DMA_TO_DEVICE) - tce.te_pciwr = 1; + proto_tce |= TCE_PCI_WRITE; while (npages--) { - rc = plpar_tce_put((u64)tbl->it_index, - (u64)tcenum << 12, - tce.te_word ); - + tce = proto_tce | (rpn & TCE_RPN_MASK) << TCE_RPN_SHIFT; + rc = plpar_tce_put((u64)tbl->it_index, (u64)tcenum << 12, tce); + if (rc && printk_ratelimit()) { printk("tce_build_pSeriesLP: plpar_tce_put failed. rc=%ld\n", rc); printk("\tindex = 0x%lx\n", (u64)tbl->it_index); printk("\ttcenum = 0x%lx\n", (u64)tcenum); - printk("\ttce val = 0x%lx\n", tce.te_word ); + printk("\ttce val = 0x%lx\n", tce ); show_stack(current, (unsigned long *)__get_SP()); } - + tcenum++; - tce.te_rpn++; + rpn++; } } -static DEFINE_PER_CPU(void *, tce_page) = NULL; +static DEFINE_PER_CPU(u64 *, tce_page) = NULL; static void tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, long npages, unsigned long uaddr, enum dma_data_direction direction) { u64 rc; - union tce_entry tce, *tcep; + u64 proto_tce; + u64 *tcep; + u64 rpn; long l, limit; if (TCE_PAGE_FACTOR == 0 && npages == 1) @@ -152,7 +148,7 @@ static void tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, * from iommu_alloc{,_sg}() */ if (!tcep) { - tcep = (void *)__get_free_page(GFP_ATOMIC); + tcep = (u64 *)__get_free_page(GFP_ATOMIC); /* If allocation fails, fall back to the loop implementation */ if (!tcep) return tce_build_pSeriesLP(tbl, tcenum, npages, @@ -163,11 +159,10 @@ static void tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, tcenum <<= TCE_PAGE_FACTOR; npages <<= TCE_PAGE_FACTOR; - tce.te_word = 0; - tce.te_rpn = (virt_to_abs(uaddr)) >> TCE_SHIFT; - tce.te_rdwr = 1; + rpn = (virt_to_abs(uaddr)) >> TCE_SHIFT; + proto_tce = TCE_PCI_READ; if (direction != DMA_TO_DEVICE) - tce.te_pciwr = 1; + proto_tce |= TCE_PCI_WRITE; /* We can map max one pageful of TCEs at a time */ do { @@ -175,11 +170,11 @@ static void tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, * Set up the page with TCE data, looping through and setting * the values. */ - limit = min_t(long, npages, 4096/sizeof(union tce_entry)); + limit = min_t(long, npages, 4096/TCE_ENTRY_SIZE); for (l = 0; l < limit; l++) { - tcep[l] = tce; - tce.te_rpn++; + tcep[l] = proto_tce | (rpn & TCE_RPN_MASK) << TCE_RPN_SHIFT; + rpn++; } rc = plpar_tce_put_indirect((u64)tbl->it_index, @@ -195,7 +190,7 @@ static void tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, printk("tce_buildmulti_pSeriesLP: plpar_tce_put failed. rc=%ld\n", rc); printk("\tindex = 0x%lx\n", (u64)tbl->it_index); printk("\tnpages = 0x%lx\n", (u64)npages); - printk("\ttce[0] val = 0x%lx\n", tcep[0].te_word); + printk("\ttce[0] val = 0x%lx\n", tcep[0]); show_stack(current, (unsigned long *)__get_SP()); } } @@ -203,23 +198,17 @@ static void tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, static void tce_free_pSeriesLP(struct iommu_table *tbl, long tcenum, long npages) { u64 rc; - union tce_entry tce; tcenum <<= TCE_PAGE_FACTOR; npages <<= TCE_PAGE_FACTOR; - tce.te_word = 0; - while (npages--) { - rc = plpar_tce_put((u64)tbl->it_index, - (u64)tcenum << 12, - tce.te_word); + rc = plpar_tce_put((u64)tbl->it_index, (u64)tcenum << 12, 0); if (rc && printk_ratelimit()) { printk("tce_free_pSeriesLP: plpar_tce_put failed. rc=%ld\n", rc); printk("\tindex = 0x%lx\n", (u64)tbl->it_index); printk("\ttcenum = 0x%lx\n", (u64)tcenum); - printk("\ttce val = 0x%lx\n", tce.te_word ); show_stack(current, (unsigned long *)__get_SP()); } @@ -231,31 +220,24 @@ static void tce_free_pSeriesLP(struct iommu_table *tbl, long tcenum, long npages static void tce_freemulti_pSeriesLP(struct iommu_table *tbl, long tcenum, long npages) { u64 rc; - union tce_entry tce; tcenum <<= TCE_PAGE_FACTOR; npages <<= TCE_PAGE_FACTOR; - tce.te_word = 0; - - rc = plpar_tce_stuff((u64)tbl->it_index, - (u64)tcenum << 12, - tce.te_word, - npages); + rc = plpar_tce_stuff((u64)tbl->it_index, (u64)tcenum << 12, 0, npages); if (rc && printk_ratelimit()) { printk("tce_freemulti_pSeriesLP: plpar_tce_stuff failed\n"); printk("\trc = %ld\n", rc); printk("\tindex = 0x%lx\n", (u64)tbl->it_index); printk("\tnpages = 0x%lx\n", (u64)npages); - printk("\ttce val = 0x%lx\n", tce.te_word ); show_stack(current, (unsigned long *)__get_SP()); } } static void iommu_table_setparms(struct pci_controller *phb, struct device_node *dn, - struct iommu_table *tbl) + struct iommu_table *tbl) { struct device_node *node; unsigned long *basep; @@ -275,16 +257,16 @@ static void iommu_table_setparms(struct pci_controller *phb, memset((void *)tbl->it_base, 0, *sizep); tbl->it_busno = phb->bus->number; - + /* Units of tce entries */ tbl->it_offset = phb->dma_window_base_cur >> PAGE_SHIFT; - + /* Test if we are going over 2GB of DMA space */ if (phb->dma_window_base_cur + phb->dma_window_size > 0x80000000ul) { udbg_printf("PCI_DMA: Unexpected number of IOAs under this PHB.\n"); - panic("PCI_DMA: Unexpected number of IOAs under this PHB.\n"); + panic("PCI_DMA: Unexpected number of IOAs under this PHB.\n"); } - + phb->dma_window_base_cur += phb->dma_window_size; /* Set the tce table size - measured in entries */ @@ -442,7 +424,7 @@ static void iommu_bus_setup_pSeriesLP(struct pci_bus *bus) tbl = (struct iommu_table *)kmalloc(sizeof(struct iommu_table), GFP_KERNEL); - + iommu_table_setparms_lpar(ppci->phb, pdn, tbl, dma_window); ppci->iommu_table = iommu_init_table(tbl); diff --git a/include/asm-powerpc/tce.h b/include/asm-powerpc/tce.h index 6fa200ad7a7f..c9483adbf599 100644 --- a/include/asm-powerpc/tce.h +++ b/include/asm-powerpc/tce.h @@ -35,32 +35,15 @@ #define TCE_PAGE_SIZE (1 << TCE_SHIFT) #define TCE_PAGE_FACTOR (PAGE_SHIFT - TCE_SHIFT) - -/* tce_entry - * Used by pSeries (SMP) and iSeries/pSeries LPAR, but there it's - * abstracted so layout is irrelevant. - */ -union tce_entry { - unsigned long te_word; - struct { - unsigned int tb_cacheBits :6; /* Cache hash bits - not used */ - unsigned int tb_rsvd :6; - unsigned long tb_rpn :40; /* Real page number */ - unsigned int tb_valid :1; /* Tce is valid (vb only) */ - unsigned int tb_allio :1; /* Tce is valid for all lps (vb only) */ - unsigned int tb_lpindex :8; /* LpIndex for user of TCE (vb only) */ - unsigned int tb_pciwr :1; /* Write allowed (pci only) */ - unsigned int tb_rdwr :1; /* Read allowed (pci), Write allowed (vb) */ - } te_bits; -#define te_cacheBits te_bits.tb_cacheBits -#define te_rpn te_bits.tb_rpn -#define te_valid te_bits.tb_valid -#define te_allio te_bits.tb_allio -#define te_lpindex te_bits.tb_lpindex -#define te_pciwr te_bits.tb_pciwr -#define te_rdwr te_bits.tb_rdwr -}; - +#define TCE_ENTRY_SIZE 8 /* each TCE is 64 bits */ + +#define TCE_RPN_MASK 0xfffffffffful /* 40-bit RPN (4K pages) */ +#define TCE_RPN_SHIFT 12 +#define TCE_VALID 0x800 /* TCE valid */ +#define TCE_ALLIO 0x400 /* TCE valid for all lpars */ +#define TCE_PCI_WRITE 0x2 /* write from PCI allowed */ +#define TCE_PCI_READ 0x1 /* read from PCI allowed */ +#define TCE_VB_WRITE 0x1 /* write from VB allowed */ #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_TCE_H */ -- cgit v1.2.3 From 32e62c636a728cb39c0b3bd191286f2ca65d4028 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 5 May 2006 17:19:50 -0600 Subject: [IA64] rework memory attribute aliasing This closes a couple holes in our attribute aliasing avoidance scheme: - The current kernel fails mmaps of some /dev/mem MMIO regions because they don't appear in the EFI memory map. This keeps X from working on the Intel Tiger box. - The current kernel allows UC mmap of the 0-1MB region of /sys/.../legacy_mem even when the chipset doesn't support UC access. This causes an MCA when starting X on HP rx7620 and rx8620 boxes in the default configuration. There's more detail in the Documentation/ia64/aliasing.txt file this adds, but the general idea is that if a region might be covered by a granule-sized kernel identity mapping, any access via /dev/mem or mmap must use the same attribute as the identity mapping. Otherwise, we fall back to using an attribute that is supported according to the EFI memory map, or to using UC if the EFI memory map doesn't mention the region. Signed-off-by: Bjorn Helgaas Signed-off-by: Tony Luck --- Documentation/ia64/aliasing.txt | 208 ++++++++++++++++++++++++++++++++++++++++ arch/ia64/kernel/efi.c | 156 +++++++++++++++++++----------- arch/ia64/mm/ioremap.c | 27 +++++- arch/ia64/pci/pci.c | 17 +++- include/asm-ia64/io.h | 1 + include/asm-ia64/pgtable.h | 22 ++--- include/linux/efi.h | 1 + 7 files changed, 359 insertions(+), 73 deletions(-) create mode 100644 Documentation/ia64/aliasing.txt (limited to 'include') diff --git a/Documentation/ia64/aliasing.txt b/Documentation/ia64/aliasing.txt new file mode 100644 index 000000000000..38f9a52d1820 --- /dev/null +++ b/Documentation/ia64/aliasing.txt @@ -0,0 +1,208 @@ + MEMORY ATTRIBUTE ALIASING ON IA-64 + + Bjorn Helgaas + + May 4, 2006 + + +MEMORY ATTRIBUTES + + Itanium supports several attributes for virtual memory references. + The attribute is part of the virtual translation, i.e., it is + contained in the TLB entry. The ones of most interest to the Linux + kernel are: + + WB Write-back (cacheable) + UC Uncacheable + WC Write-coalescing + + System memory typically uses the WB attribute. The UC attribute is + used for memory-mapped I/O devices. The WC attribute is uncacheable + like UC is, but writes may be delayed and combined to increase + performance for things like frame buffers. + + The Itanium architecture requires that we avoid accessing the same + page with both a cacheable mapping and an uncacheable mapping[1]. + + The design of the chipset determines which attributes are supported + on which regions of the address space. For example, some chipsets + support either WB or UC access to main memory, while others support + only WB access. + +MEMORY MAP + + Platform firmware describes the physical memory map and the + supported attributes for each region. At boot-time, the kernel uses + the EFI GetMemoryMap() interface. ACPI can also describe memory + devices and the attributes they support, but Linux/ia64 currently + doesn't use this information. + + The kernel uses the efi_memmap table returned from GetMemoryMap() to + learn the attributes supported by each region of physical address + space. Unfortunately, this table does not completely describe the + address space because some machines omit some or all of the MMIO + regions from the map. + + The kernel maintains another table, kern_memmap, which describes the + memory Linux is actually using and the attribute for each region. + This contains only system memory; it does not contain MMIO space. + + The kern_memmap table typically contains only a subset of the system + memory described by the efi_memmap. Linux/ia64 can't use all memory + in the system because of constraints imposed by the identity mapping + scheme. + + The efi_memmap table is preserved unmodified because the original + boot-time information is required for kexec. + +KERNEL IDENTITY MAPPINGS + + Linux/ia64 identity mappings are done with large pages, currently + either 16MB or 64MB, referred to as "granules." Cacheable mappings + are speculative[2], so the processor can read any location in the + page at any time, independent of the programmer's intentions. This + means that to avoid attribute aliasing, Linux can create a cacheable + identity mapping only when the entire granule supports cacheable + access. + + Therefore, kern_memmap contains only full granule-sized regions that + can referenced safely by an identity mapping. + + Uncacheable mappings are not speculative, so the processor will + generate UC accesses only to locations explicitly referenced by + software. This allows UC identity mappings to cover granules that + are only partially populated, or populated with a combination of UC + and WB regions. + +USER MAPPINGS + + User mappings are typically done with 16K or 64K pages. The smaller + page size allows more flexibility because only 16K or 64K has to be + homogeneous with respect to memory attributes. + +POTENTIAL ATTRIBUTE ALIASING CASES + + There are several ways the kernel creates new mappings: + + mmap of /dev/mem + + This uses remap_pfn_range(), which creates user mappings. These + mappings may be either WB or UC. If the region being mapped + happens to be in kern_memmap, meaning that it may also be mapped + by a kernel identity mapping, the user mapping must use the same + attribute as the kernel mapping. + + If the region is not in kern_memmap, the user mapping should use + an attribute reported as being supported in the EFI memory map. + + Since the EFI memory map does not describe MMIO on some + machines, this should use an uncacheable mapping as a fallback. + + mmap of /sys/class/pci_bus/.../legacy_mem + + This is very similar to mmap of /dev/mem, except that legacy_mem + only allows mmap of the one megabyte "legacy MMIO" area for a + specific PCI bus. Typically this is the first megabyte of + physical address space, but it may be different on machines with + several VGA devices. + + "X" uses this to access VGA frame buffers. Using legacy_mem + rather than /dev/mem allows multiple instances of X to talk to + different VGA cards. + + The /dev/mem mmap constraints apply. + + However, since this is for mapping legacy MMIO space, WB access + does not make sense. This matters on machines without legacy + VGA support: these machines may have WB memory for the entire + first megabyte (or even the entire first granule). + + On these machines, we could mmap legacy_mem as WB, which would + be safe in terms of attribute aliasing, but X has no way of + knowing that it is accessing regular memory, not a frame buffer, + so the kernel should fail the mmap rather than doing it with WB. + + read/write of /dev/mem + + This uses copy_from_user(), which implicitly uses a kernel + identity mapping. This is obviously safe for things in + kern_memmap. + + There may be corner cases of things that are not in kern_memmap, + but could be accessed this way. For example, registers in MMIO + space are not in kern_memmap, but could be accessed with a UC + mapping. This would not cause attribute aliasing. But + registers typically can be accessed only with four-byte or + eight-byte accesses, and the copy_from_user() path doesn't allow + any control over the access size, so this would be dangerous. + + ioremap() + + This returns a kernel identity mapping for use inside the + kernel. + + If the region is in kern_memmap, we should use the attribute + specified there. Otherwise, if the EFI memory map reports that + the entire granule supports WB, we should use that (granules + that are partially reserved or occupied by firmware do not appear + in kern_memmap). Otherwise, we should use a UC mapping. + +PAST PROBLEM CASES + + mmap of various MMIO regions from /dev/mem by "X" on Intel platforms + + The EFI memory map may not report these MMIO regions. + + These must be allowed so that X will work. This means that + when the EFI memory map is incomplete, every /dev/mem mmap must + succeed. It may create either WB or UC user mappings, depending + on whether the region is in kern_memmap or the EFI memory map. + + mmap of 0x0-0xA0000 /dev/mem by "hwinfo" on HP sx1000 with VGA enabled + + See https://bugzilla.novell.com/show_bug.cgi?id=140858. + + The EFI memory map reports the following attributes: + 0x00000-0x9FFFF WB only + 0xA0000-0xBFFFF UC only (VGA frame buffer) + 0xC0000-0xFFFFF WB only + + This mmap is done with user pages, not kernel identity mappings, + so it is safe to use WB mappings. + + The kernel VGA driver may ioremap the VGA frame buffer at 0xA0000, + which will use a granule-sized UC mapping covering 0-0xFFFFF. This + granule covers some WB-only memory, but since UC is non-speculative, + the processor will never generate an uncacheable reference to the + WB-only areas unless the driver explicitly touches them. + + mmap of 0x0-0xFFFFF legacy_mem by "X" + + If the EFI memory map reports this entire range as WB, there + is no VGA MMIO hole, and the mmap should fail or be done with + a WB mapping. + + There's no easy way for X to determine whether the 0xA0000-0xBFFFF + region is a frame buffer or just memory, so I think it's best to + just fail this mmap request rather than using a WB mapping. As + far as I know, there's no need to map legacy_mem with WB + mappings. + + Otherwise, a UC mapping of the entire region is probably safe. + The VGA hole means the region will not be in kern_memmap. The + HP sx1000 chipset doesn't support UC access to the memory surrounding + the VGA hole, but X doesn't need that area anyway and should not + reference it. + + mmap of 0xA0000-0xBFFFF legacy_mem by "X" on HP sx1000 with VGA disabled + + The EFI memory map reports the following attributes: + 0x00000-0xFFFFF WB only (no VGA MMIO hole) + + This is a special case of the previous case, and the mmap should + fail for the same reason as above. + +NOTES + + [1] SDM rev 2.2, vol 2, sec 4.4.1. + [2] SDM rev 2.2, vol 2, sec 4.4.6. diff --git a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c index 12cfedce73b1..c33d0ba7e300 100644 --- a/arch/ia64/kernel/efi.c +++ b/arch/ia64/kernel/efi.c @@ -8,6 +8,8 @@ * Copyright (C) 1999-2003 Hewlett-Packard Co. * David Mosberger-Tang * Stephane Eranian + * (c) Copyright 2006 Hewlett-Packard Development Company, L.P. + * Bjorn Helgaas * * All EFI Runtime Services are not implemented yet as EFI only * supports physical mode addressing on SoftSDV. This is to be fixed @@ -622,28 +624,20 @@ efi_get_iobase (void) return 0; } -static efi_memory_desc_t * -efi_memory_descriptor (unsigned long phys_addr) +static struct kern_memdesc * +kern_memory_descriptor (unsigned long phys_addr) { - void *efi_map_start, *efi_map_end, *p; - efi_memory_desc_t *md; - u64 efi_desc_size; - - efi_map_start = __va(ia64_boot_param->efi_memmap); - efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size; - efi_desc_size = ia64_boot_param->efi_memdesc_size; + struct kern_memdesc *md; - for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) { - md = p; - - if (phys_addr - md->phys_addr < (md->num_pages << EFI_PAGE_SHIFT)) + for (md = kern_memmap; md->start != ~0UL; md++) { + if (phys_addr - md->start < (md->num_pages << EFI_PAGE_SHIFT)) return md; } return 0; } -static int -efi_memmap_has_mmio (void) +static efi_memory_desc_t * +efi_memory_descriptor (unsigned long phys_addr) { void *efi_map_start, *efi_map_end, *p; efi_memory_desc_t *md; @@ -656,8 +650,8 @@ efi_memmap_has_mmio (void) for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) { md = p; - if (md->type == EFI_MEMORY_MAPPED_IO) - return 1; + if (phys_addr - md->phys_addr < (md->num_pages << EFI_PAGE_SHIFT)) + return md; } return 0; } @@ -683,71 +677,125 @@ efi_mem_attributes (unsigned long phys_addr) } EXPORT_SYMBOL(efi_mem_attributes); -/* - * Determines whether the memory at phys_addr supports the desired - * attribute (WB, UC, etc). If this returns 1, the caller can safely - * access size bytes at phys_addr with the specified attribute. - */ -int -efi_mem_attribute_range (unsigned long phys_addr, unsigned long size, u64 attr) +u64 +efi_mem_attribute (unsigned long phys_addr, unsigned long size) { unsigned long end = phys_addr + size; efi_memory_desc_t *md = efi_memory_descriptor(phys_addr); + u64 attr; + + if (!md) + return 0; + + /* + * EFI_MEMORY_RUNTIME is not a memory attribute; it just tells + * the kernel that firmware needs this region mapped. + */ + attr = md->attribute & ~EFI_MEMORY_RUNTIME; + do { + unsigned long md_end = efi_md_end(md); + + if (end <= md_end) + return attr; + + md = efi_memory_descriptor(md_end); + if (!md || (md->attribute & ~EFI_MEMORY_RUNTIME) != attr) + return 0; + } while (md); + return 0; +} + +u64 +kern_mem_attribute (unsigned long phys_addr, unsigned long size) +{ + unsigned long end = phys_addr + size; + struct kern_memdesc *md; + u64 attr; /* - * Some firmware doesn't report MMIO regions in the EFI memory - * map. The Intel BigSur (a.k.a. HP i2000) has this problem. - * On those platforms, we have to assume UC is valid everywhere. + * This is a hack for ioremap calls before we set up kern_memmap. + * Maybe we should do efi_memmap_init() earlier instead. */ - if (!md || (md->attribute & attr) != attr) { - if (attr == EFI_MEMORY_UC && !efi_memmap_has_mmio()) - return 1; + if (!kern_memmap) { + attr = efi_mem_attribute(phys_addr, size); + if (attr & EFI_MEMORY_WB) + return EFI_MEMORY_WB; return 0; } + md = kern_memory_descriptor(phys_addr); + if (!md) + return 0; + + attr = md->attribute; do { - unsigned long md_end = efi_md_end(md); + unsigned long md_end = kmd_end(md); if (end <= md_end) - return 1; + return attr; - md = efi_memory_descriptor(md_end); - if (!md || (md->attribute & attr) != attr) + md = kern_memory_descriptor(md_end); + if (!md || md->attribute != attr) return 0; } while (md); return 0; } +EXPORT_SYMBOL(kern_mem_attribute); -/* - * For /dev/mem, we only allow read & write system calls to access - * write-back memory, because read & write don't allow the user to - * control access size. - */ int valid_phys_addr_range (unsigned long phys_addr, unsigned long size) { - return efi_mem_attribute_range(phys_addr, size, EFI_MEMORY_WB); + u64 attr; + + /* + * /dev/mem reads and writes use copy_to_user(), which implicitly + * uses a granule-sized kernel identity mapping. It's really + * only safe to do this for regions in kern_memmap. For more + * details, see Documentation/ia64/aliasing.txt. + */ + attr = kern_mem_attribute(phys_addr, size); + if (attr & EFI_MEMORY_WB || attr & EFI_MEMORY_UC) + return 1; + return 0; } -/* - * We allow mmap of anything in the EFI memory map that supports - * either write-back or uncacheable access. For uncacheable regions, - * the supported access sizes are system-dependent, and the user is - * responsible for using the correct size. - * - * Note that this doesn't currently allow access to hot-added memory, - * because that doesn't appear in the boot-time EFI memory map. - */ int valid_mmap_phys_addr_range (unsigned long phys_addr, unsigned long size) { - if (efi_mem_attribute_range(phys_addr, size, EFI_MEMORY_WB)) - return 1; + /* + * MMIO regions are often missing from the EFI memory map. + * We must allow mmap of them for programs like X, so we + * currently can't do any useful validation. + */ + return 1; +} - if (efi_mem_attribute_range(phys_addr, size, EFI_MEMORY_UC)) - return 1; +pgprot_t +phys_mem_access_prot(struct file *file, unsigned long pfn, unsigned long size, + pgprot_t vma_prot) +{ + unsigned long phys_addr = pfn << PAGE_SHIFT; + u64 attr; - return 0; + /* + * For /dev/mem mmap, we use user mappings, but if the region is + * in kern_memmap (and hence may be covered by a kernel mapping), + * we must use the same attribute as the kernel mapping. + */ + attr = kern_mem_attribute(phys_addr, size); + if (attr & EFI_MEMORY_WB) + return pgprot_cacheable(vma_prot); + else if (attr & EFI_MEMORY_UC) + return pgprot_noncached(vma_prot); + + /* + * Some chipsets don't support UC access to memory. If + * WB is supported, we prefer that. + */ + if (efi_mem_attribute(phys_addr, size) & EFI_MEMORY_WB) + return pgprot_cacheable(vma_prot); + + return pgprot_noncached(vma_prot); } int __init diff --git a/arch/ia64/mm/ioremap.c b/arch/ia64/mm/ioremap.c index 643ccc6960ce..07bd02b6c372 100644 --- a/arch/ia64/mm/ioremap.c +++ b/arch/ia64/mm/ioremap.c @@ -11,6 +11,7 @@ #include #include #include +#include static inline void __iomem * __ioremap (unsigned long offset, unsigned long size) @@ -21,16 +22,29 @@ __ioremap (unsigned long offset, unsigned long size) void __iomem * ioremap (unsigned long offset, unsigned long size) { - if (efi_mem_attribute_range(offset, size, EFI_MEMORY_WB)) - return phys_to_virt(offset); + u64 attr; + unsigned long gran_base, gran_size; - if (efi_mem_attribute_range(offset, size, EFI_MEMORY_UC)) + /* + * For things in kern_memmap, we must use the same attribute + * as the rest of the kernel. For more details, see + * Documentation/ia64/aliasing.txt. + */ + attr = kern_mem_attribute(offset, size); + if (attr & EFI_MEMORY_WB) + return phys_to_virt(offset); + else if (attr & EFI_MEMORY_UC) return __ioremap(offset, size); /* - * Someday this should check ACPI resources so we - * can do the right thing for hot-plugged regions. + * Some chipsets don't support UC access to memory. If + * WB is supported for the whole granule, we prefer that. */ + gran_base = GRANULEROUNDDOWN(offset); + gran_size = GRANULEROUNDUP(offset + size) - gran_base; + if (efi_mem_attribute(gran_base, gran_size) & EFI_MEMORY_WB) + return phys_to_virt(offset); + return __ioremap(offset, size); } EXPORT_SYMBOL(ioremap); @@ -38,6 +52,9 @@ EXPORT_SYMBOL(ioremap); void __iomem * ioremap_nocache (unsigned long offset, unsigned long size) { + if (kern_mem_attribute(offset, size) & EFI_MEMORY_WB) + return 0; + return __ioremap(offset, size); } EXPORT_SYMBOL(ioremap_nocache); diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c index ab829a22f8a4..30d148f34042 100644 --- a/arch/ia64/pci/pci.c +++ b/arch/ia64/pci/pci.c @@ -645,18 +645,31 @@ char *ia64_pci_get_legacy_mem(struct pci_bus *bus) int pci_mmap_legacy_page_range(struct pci_bus *bus, struct vm_area_struct *vma) { + unsigned long size = vma->vm_end - vma->vm_start; + pgprot_t prot; char *addr; + /* + * Avoid attribute aliasing. See Documentation/ia64/aliasing.txt + * for more details. + */ + if (!valid_mmap_phys_addr_range(vma->vm_pgoff << PAGE_SHIFT, size)) + return -EINVAL; + prot = phys_mem_access_prot(NULL, vma->vm_pgoff, size, + vma->vm_page_prot); + if (pgprot_val(prot) != pgprot_val(pgprot_noncached(vma->vm_page_prot))) + return -EINVAL; + addr = pci_get_legacy_mem(bus); if (IS_ERR(addr)) return PTR_ERR(addr); vma->vm_pgoff += (unsigned long)addr >> PAGE_SHIFT; - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + vma->vm_page_prot = prot; vma->vm_flags |= (VM_SHM | VM_RESERVED | VM_IO); if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, - vma->vm_end - vma->vm_start, vma->vm_page_prot)) + size, vma->vm_page_prot)) return -EAGAIN; return 0; diff --git a/include/asm-ia64/io.h b/include/asm-ia64/io.h index c2e3742108bb..781ee2c7e8c3 100644 --- a/include/asm-ia64/io.h +++ b/include/asm-ia64/io.h @@ -88,6 +88,7 @@ phys_to_virt (unsigned long address) } #define ARCH_HAS_VALID_PHYS_ADDR_RANGE +extern u64 kern_mem_attribute (unsigned long phys_addr, unsigned long size); extern int valid_phys_addr_range (unsigned long addr, size_t count); /* efi.c */ extern int valid_mmap_phys_addr_range (unsigned long addr, size_t count); diff --git a/include/asm-ia64/pgtable.h b/include/asm-ia64/pgtable.h index c0f8144f2349..90f3a2329232 100644 --- a/include/asm-ia64/pgtable.h +++ b/include/asm-ia64/pgtable.h @@ -317,22 +317,20 @@ ia64_phys_addr_valid (unsigned long addr) #define pte_mkhuge(pte) (__pte(pte_val(pte))) /* - * Macro to a page protection value as "uncacheable". Note that "protection" is really a - * misnomer here as the protection value contains the memory attribute bits, dirty bits, - * and various other bits as well. + * Make page protection values cacheable, uncacheable, or write- + * combining. Note that "protection" is really a misnomer here as the + * protection value contains the memory attribute bits, dirty bits, and + * various other bits as well. */ +#define pgprot_cacheable(prot) __pgprot((pgprot_val(prot) & ~_PAGE_MA_MASK) | _PAGE_MA_WB) #define pgprot_noncached(prot) __pgprot((pgprot_val(prot) & ~_PAGE_MA_MASK) | _PAGE_MA_UC) - -/* - * Macro to make mark a page protection value as "write-combining". - * Note that "protection" is really a misnomer here as the protection - * value contains the memory attribute bits, dirty bits, and various - * other bits as well. Accesses through a write-combining translation - * works bypasses the caches, but does allow for consecutive writes to - * be combined into single (but larger) write transactions. - */ #define pgprot_writecombine(prot) __pgprot((pgprot_val(prot) & ~_PAGE_MA_MASK) | _PAGE_MA_WC) +struct file; +extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, + unsigned long size, pgprot_t vma_prot); +#define __HAVE_PHYS_MEM_ACCESS_PROT + static inline unsigned long pgd_index (unsigned long address) { diff --git a/include/linux/efi.h b/include/linux/efi.h index e203613d3aec..66d621dbcb6c 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -294,6 +294,7 @@ extern void efi_enter_virtual_mode (void); /* switch EFI to virtual mode, if pos extern u64 efi_get_iobase (void); extern u32 efi_mem_type (unsigned long phys_addr); extern u64 efi_mem_attributes (unsigned long phys_addr); +extern u64 efi_mem_attribute (unsigned long phys_addr, unsigned long size); extern int efi_mem_attribute_range (unsigned long phys_addr, unsigned long size, u64 attr); extern int __init efi_uart_console_only (void); -- cgit v1.2.3 From 264faaaa12544e7914928ad57ccba21907cad56b Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Tue, 2 May 2006 19:46:36 -0500 Subject: [SCSI] iscsi: add transport end point callbacks add transport end point callbacks so iscsi drivers that cannot connect from userspace, like iscsi tcp, using sockets do not have to implement their own socket infrastructure. Signed-off-by: Or Gerlitz Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/iscsi_tcp.c | 4 ++-- drivers/scsi/scsi_transport_iscsi.c | 41 ++++++++++++++++++++++++++++++++++++- include/scsi/iscsi_if.h | 19 ++++++++++++++++- include/scsi/scsi_transport_iscsi.h | 6 +++++- 4 files changed, 65 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index fe00a3f6d204..ac507daacfeb 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -1975,7 +1975,7 @@ iscsi_tcp_conn_destroy(struct iscsi_cls_conn *cls_conn) static int iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session, - struct iscsi_cls_conn *cls_conn, uint32_t transport_fd, + struct iscsi_cls_conn *cls_conn, uint64_t transport_eph, int is_leading) { struct iscsi_conn *conn = cls_conn->dd_data; @@ -1985,7 +1985,7 @@ iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session, int err; /* lookup for existing socket */ - sock = sockfd_lookup(transport_fd, &err); + sock = sockfd_lookup((int)transport_eph, &err); if (!sock) { printk(KERN_ERR "iscsi_tcp: sockfd_lookup failed %d\n", err); return -EEXIST; diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index bc9071d2d212..7b7a194822da 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -928,6 +928,40 @@ iscsi_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev) return err; } +static int +iscsi_if_transport_ep(struct iscsi_transport *transport, + struct iscsi_uevent *ev, int msg_type) +{ + struct sockaddr *dst_addr; + int rc = 0; + + switch (msg_type) { + case ISCSI_UEVENT_TRANSPORT_EP_CONNECT: + if (!transport->ep_connect) + return -EINVAL; + + dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev)); + rc = transport->ep_connect(dst_addr, + ev->u.ep_connect.non_blocking, + &ev->r.ep_connect_ret.handle); + break; + case ISCSI_UEVENT_TRANSPORT_EP_POLL: + if (!transport->ep_poll) + return -EINVAL; + + ev->r.retcode = transport->ep_poll(ev->u.ep_poll.ep_handle, + ev->u.ep_poll.timeout_ms); + break; + case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT: + if (!transport->ep_disconnect) + return -EINVAL; + + transport->ep_disconnect(ev->u.ep_disconnect.ep_handle); + break; + } + return rc; +} + static int iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) { @@ -974,7 +1008,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) if (session && conn) ev->r.retcode = transport->bind_conn(session, conn, - ev->u.b_conn.transport_fd, + ev->u.b_conn.transport_eph, ev->u.b_conn.is_leading); else err = -EINVAL; @@ -1009,6 +1043,11 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) case ISCSI_UEVENT_GET_STATS: err = iscsi_if_get_stats(transport, nlh); break; + case ISCSI_UEVENT_TRANSPORT_EP_CONNECT: + case ISCSI_UEVENT_TRANSPORT_EP_POLL: + case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT: + err = iscsi_if_transport_ep(transport, ev, nlh->nlmsg_type); + break; default: err = -EINVAL; break; diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h index 47524c726ee8..feff74e544b7 100644 --- a/include/scsi/iscsi_if.h +++ b/include/scsi/iscsi_if.h @@ -43,6 +43,10 @@ enum iscsi_uevent_e { ISCSI_UEVENT_GET_STATS = UEVENT_BASE + 10, ISCSI_UEVENT_GET_PARAM = UEVENT_BASE + 11, + ISCSI_UEVENT_TRANSPORT_EP_CONNECT = UEVENT_BASE + 12, + ISCSI_UEVENT_TRANSPORT_EP_POLL = UEVENT_BASE + 13, + ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT = UEVENT_BASE + 14, + /* up events */ ISCSI_KEVENT_RECV_PDU = KEVENT_BASE + 1, ISCSI_KEVENT_CONN_ERROR = KEVENT_BASE + 2, @@ -69,7 +73,7 @@ struct iscsi_uevent { struct msg_bind_conn { uint32_t sid; uint32_t cid; - uint32_t transport_fd; + uint64_t transport_eph; uint32_t is_leading; } b_conn; struct msg_destroy_conn { @@ -102,6 +106,16 @@ struct iscsi_uevent { uint32_t sid; uint32_t cid; } get_stats; + struct msg_transport_connect { + uint32_t non_blocking; + } ep_connect; + struct msg_transport_poll { + uint64_t ep_handle; + uint32_t timeout_ms; + } ep_poll; + struct msg_transport_disconnect { + uint64_t ep_handle; + } ep_disconnect; } u; union { /* messages k -> u */ @@ -124,6 +138,9 @@ struct iscsi_uevent { uint32_t cid; uint32_t error; /* enum iscsi_err */ } connerror; + struct msg_transport_connect_ret { + uint64_t handle; + } ep_connect_ret; } r; } __attribute__ ((aligned (sizeof(uint64_t)))); diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h index b332d6e839fe..c9e9475c6dff 100644 --- a/include/scsi/scsi_transport_iscsi.h +++ b/include/scsi/scsi_transport_iscsi.h @@ -88,7 +88,7 @@ struct iscsi_transport { uint32_t cid); int (*bind_conn) (struct iscsi_cls_session *session, struct iscsi_cls_conn *cls_conn, - uint32_t transport_fd, int is_leading); + uint64_t transport_eph, int is_leading); int (*start_conn) (struct iscsi_cls_conn *conn); void (*stop_conn) (struct iscsi_cls_conn *conn, int flag); void (*destroy_conn) (struct iscsi_cls_conn *conn); @@ -119,6 +119,10 @@ struct iscsi_transport { int (*xmit_mgmt_task) (struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask); void (*session_recovery_timedout) (struct iscsi_cls_session *session); + int (*ep_connect) (struct sockaddr *dst_addr, int non_blocking, + uint64_t *ep_handle); + int (*ep_poll) (uint64_t ep_handle, int timeout_ms); + void (*ep_disconnect) (uint64_t ep_handle); }; /* -- cgit v1.2.3 From be2df72e7ec5fa5e6e1ccccab6cef97ecbb9c191 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Tue, 2 May 2006 19:46:43 -0500 Subject: [SCSI] iscsi: align printks align printk output Signed-off-by: Or Gerlitz Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/iscsi_tcp.c | 3 ++- drivers/scsi/libiscsi.c | 29 +++++++++++++++-------------- drivers/scsi/scsi_transport_iscsi.c | 4 ++-- include/scsi/libiscsi.h | 2 +- 4 files changed, 20 insertions(+), 18 deletions(-) (limited to 'include') diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index ac507daacfeb..41f4bb557ea6 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -2585,7 +2585,8 @@ static int __init iscsi_tcp_init(void) { if (iscsi_max_lun < 1) { - printk(KERN_ERR "Invalid max_lun value of %u\n", iscsi_max_lun); + printk(KERN_ERR "iscsi_tcp: Invalid max_lun value of %u\n", + iscsi_max_lun); return -EINVAL; } iscsi_tcp_transport.max_lun = iscsi_max_lun; diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 8c51f6c36661..a99f2ef44e87 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -235,8 +235,8 @@ static int iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr, if (datalen < 2) { invalid_datalen: - printk(KERN_ERR "Got CHECK_CONDITION but invalid " - "data buffer size of %d\n", datalen); + printk(KERN_ERR "iscsi: Got CHECK_CONDITION but " + "invalid data buffer size of %d\n", datalen); sc->result = DID_BAD_TARGET << 16; goto out; } @@ -441,7 +441,7 @@ int iscsi_verify_itt(struct iscsi_conn *conn, struct iscsi_hdr *hdr, if (hdr->itt != cpu_to_be32(ISCSI_RESERVED_TAG)) { if ((hdr->itt & ISCSI_AGE_MASK) != (session->age << ISCSI_AGE_SHIFT)) { - printk(KERN_ERR "iscsi_tcp: received itt %x expected " + printk(KERN_ERR "iscsi: received itt %x expected " "session age (%x)\n", hdr->itt, session->age & ISCSI_AGE_MASK); return ISCSI_ERR_BAD_ITT; @@ -449,7 +449,7 @@ int iscsi_verify_itt(struct iscsi_conn *conn, struct iscsi_hdr *hdr, if ((hdr->itt & ISCSI_CID_MASK) != (conn->id << ISCSI_CID_SHIFT)) { - printk(KERN_ERR "iscsi_tcp: received itt %x, expected " + printk(KERN_ERR "iscsi: received itt %x, expected " "CID (%x)\n", hdr->itt, conn->id); return ISCSI_ERR_BAD_ITT; } @@ -461,14 +461,14 @@ int iscsi_verify_itt(struct iscsi_conn *conn, struct iscsi_hdr *hdr, ctask = session->cmds[itt]; if (!ctask->sc) { - printk(KERN_INFO "iscsi_tcp: dropping ctask with " + printk(KERN_INFO "iscsi: dropping ctask with " "itt 0x%x\n", ctask->itt); /* force drop */ return ISCSI_ERR_NO_SCSI_CMD; } if (ctask->sc->SCp.phase != session->age) { - printk(KERN_ERR "iscsi_tcp: ctask's session age %d, " + printk(KERN_ERR "iscsi: ctask's session age %d, " "expected %d\n", ctask->sc->SCp.phase, session->age); return ISCSI_ERR_SESSION_FAILED; @@ -686,7 +686,7 @@ reject: fault: spin_unlock(&session->lock); - printk(KERN_ERR "iscsi_tcp: cmd 0x%x is not queued (%d)\n", + printk(KERN_ERR "iscsi: cmd 0x%x is not queued (%d)\n", sc->cmnd[0], reason); sc->result = (DID_NO_CONNECT << 16); sc->resid = sc->request_bufflen; @@ -857,7 +857,7 @@ failed: spin_lock_bh(&session->lock); if (session->state == ISCSI_STATE_LOGGED_IN) - printk(KERN_INFO "host reset succeeded\n"); + printk(KERN_INFO "iscsi: host reset succeeded\n"); else goto failed; spin_unlock_bh(&session->lock); @@ -1042,8 +1042,8 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) /* what should we do here ? */ if (conn->ctask == ctask) { - printk(KERN_INFO "sc %p itt 0x%x partially sent. Failing " - "abort\n", sc, ctask->itt); + printk(KERN_INFO "iscsi: sc %p itt 0x%x partially sent. " + "Failing abort\n", sc, ctask->itt); goto failed; } @@ -1441,8 +1441,9 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) } spin_unlock_irqrestore(session->host->host_lock, flags); msleep_interruptible(500); - printk("conn_destroy(): host_busy %d host_failed %d\n", - session->host->host_busy, session->host->host_failed); + printk(KERN_INFO "iscsi: scsi conn_destroy(): host_busy %d " + "host_failed %d\n", session->host->host_busy, + session->host->host_failed); /* * force eh_abort() to unblock */ @@ -1662,7 +1663,7 @@ void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) mutex_unlock(&conn->xmitmutex); break; default: - printk(KERN_ERR "invalid stop flag %d\n", flag); + printk(KERN_ERR "iscsi: invalid stop flag %d\n", flag); } } EXPORT_SYMBOL_GPL(iscsi_conn_stop); @@ -1679,7 +1680,7 @@ int iscsi_conn_bind(struct iscsi_cls_session *cls_session, if (tmp == conn) { if (conn->c_stage != ISCSI_CONN_STOPPED || conn->stop_stage == STOP_CONN_TERM) { - printk(KERN_ERR "iscsi_tcp: can't bind " + printk(KERN_ERR "iscsi: can't bind " "non-stopped connection (%d:%d)\n", conn->c_stage, conn->stop_stage); spin_unlock_bh(&session->lock); diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 7b7a194822da..1b96f7c4ce7a 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -266,8 +266,8 @@ static void session_recovery_timedout(void *data) { struct iscsi_cls_session *session = data; - dev_printk(KERN_INFO, &session->dev, "session recovery timed out " - "after %d secs\n", session->recovery_tmo); + dev_printk(KERN_INFO, &session->dev, "iscsi: session recovery timed " + "out after %d secs\n", session->recovery_tmo); if (session->transport->session_recovery_timedout) session->transport->session_recovery_timedout(session); diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h index 830700a4ed69..2dba929a2a05 100644 --- a/include/scsi/libiscsi.h +++ b/include/scsi/libiscsi.h @@ -41,7 +41,7 @@ struct iscsi_nopin; /* #define DEBUG_SCSI */ #ifdef DEBUG_SCSI -#define debug_scsi(fmt...) printk(KERN_INFO "scsi: " fmt) +#define debug_scsi(fmt...) printk(KERN_INFO "iscsi: " fmt) #else #define debug_scsi(fmt...) #endif -- cgit v1.2.3 From 8d2860b3c3e933304f49171770658c00ed26fd79 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Tue, 2 May 2006 19:46:47 -0500 Subject: [SCSI] iscsi: increment expstatsn during login debugged by Ming and Rohan: The problem Ming and Rohan debugged was that during a normal session login, open-iscsi is not incrementing the exp_statsn counter. It was stuck at zero. From the RFC, it looks like if the login response PDU has a successful status then we should be incrementing that value. Also from the RFC, it looks like if when we drop a connection then reconnect, we should be using the exp_statsn from the old connection in the next relogin attempt. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/iscsi_tcp.c | 9 ++++++++- drivers/scsi/libiscsi.c | 38 ++++++++++++++++++------------------- drivers/scsi/scsi_transport_iscsi.c | 4 +++- include/scsi/iscsi_if.h | 2 ++ 4 files changed, 32 insertions(+), 21 deletions(-) (limited to 'include') diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 41f4bb557ea6..c0ce6ab81a9d 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -2298,6 +2298,9 @@ iscsi_conn_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param, BUG_ON(value); session->ofmarker_en = value; break; + case ISCSI_PARAM_EXP_STATSN: + conn->exp_statsn = value; + break; default: break; } @@ -2381,6 +2384,9 @@ iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn, inet = inet_sk(tcp_conn->sock->sk); *value = be16_to_cpu(inet->dport); mutex_unlock(&conn->xmitmutex); + case ISCSI_PARAM_EXP_STATSN: + *value = conn->exp_statsn; + break; default: return -EINVAL; } @@ -2548,7 +2554,8 @@ static struct iscsi_transport iscsi_tcp_transport = { ISCSI_DATASEQ_INORDER_EN | ISCSI_ERL | ISCSI_CONN_PORT | - ISCSI_CONN_ADDRESS, + ISCSI_CONN_ADDRESS | + ISCSI_EXP_STATSN, .host_template = &iscsi_sht, .conndata_size = sizeof(struct iscsi_conn), .max_conn = 1, diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index a99f2ef44e87..4750d4888100 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -333,15 +333,21 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, debug_scsi("immrsp [op 0x%x cid %d itt 0x%x len %d]\n", opcode, conn->id, mtask->itt, datalen); + rc = iscsi_check_assign_cmdsn(session, + (struct iscsi_nopin*)hdr); + if (rc) + goto done; + switch(opcode) { + case ISCSI_OP_LOGOUT_RSP: + conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; + /* fall through */ case ISCSI_OP_LOGIN_RSP: case ISCSI_OP_TEXT_RSP: - case ISCSI_OP_LOGOUT_RSP: - rc = iscsi_check_assign_cmdsn(session, - (struct iscsi_nopin*)hdr); - if (rc) - break; - + /* + * login related PDU's exp_statsn is handled in + * userspace + */ rc = iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen); list_del(&mtask->running); if (conn->login_mtask != mtask) @@ -349,15 +355,12 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, (void*)&mtask, sizeof(void*)); break; case ISCSI_OP_SCSI_TMFUNC_RSP: - rc = iscsi_check_assign_cmdsn(session, - (struct iscsi_nopin*)hdr); - if (rc) - break; - if (datalen) { rc = ISCSI_ERR_PROTO; break; } + + conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; conn->tmfrsp_pdus_cnt++; if (conn->tmabort_state == TMABORT_INITIAL) { conn->tmabort_state = @@ -373,10 +376,6 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, rc = ISCSI_ERR_PROTO; break; } - rc = iscsi_check_assign_cmdsn(session, - (struct iscsi_nopin*)hdr); - if (rc) - break; conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; rc = iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen); @@ -404,6 +403,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, case ISCSI_OP_REJECT: /* we need sth like iscsi_reject_rsp()*/ case ISCSI_OP_ASYNC_EVENT: + conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; /* we need sth like iscsi_async_event_rsp() */ rc = ISCSI_ERR_BAD_OPCODE; break; @@ -414,6 +414,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, } else rc = ISCSI_ERR_BAD_ITT; +done: return rc; } EXPORT_SYMBOL_GPL(__iscsi_complete_pdu); @@ -730,6 +731,7 @@ iscsi_conn_send_generic(struct iscsi_conn *conn, struct iscsi_hdr *hdr, BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE); BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED); + nop->exp_statsn = cpu_to_be32(conn->exp_statsn); if (!__kfifo_get(session->mgmtpool.queue, (void*)&mtask, sizeof(void*))) { spin_unlock_bh(&session->lock); @@ -738,7 +740,7 @@ iscsi_conn_send_generic(struct iscsi_conn *conn, struct iscsi_hdr *hdr, } /* - * pre-format CmdSN and ExpStatSN for outgoing PDU. + * pre-format CmdSN for outgoing PDU. */ if (hdr->itt != cpu_to_be32(ISCSI_RESERVED_TAG)) { hdr->itt = mtask->itt | (conn->id << ISCSI_CID_SHIFT) | @@ -751,8 +753,6 @@ iscsi_conn_send_generic(struct iscsi_conn *conn, struct iscsi_hdr *hdr, /* do not advance CmdSN */ nop->cmdsn = cpu_to_be32(session->cmdsn); - nop->exp_statsn = cpu_to_be32(conn->exp_statsn); - if (data_size) { memcpy(mtask->data, data, data_size); mtask->data_count = data_size; @@ -1647,7 +1647,7 @@ void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) case STOP_CONN_RECOVER: case STOP_CONN_TERM: iscsi_start_session_recovery(session, conn, flag); - return; + break; case STOP_CONN_SUSPEND: if (session->tt->suspend_conn_recv) session->tt->suspend_conn_recv(conn); diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 1b96f7c4ce7a..44adafac861f 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -32,7 +32,7 @@ #include #define ISCSI_SESSION_ATTRS 11 -#define ISCSI_CONN_ATTRS 10 +#define ISCSI_CONN_ATTRS 11 #define ISCSI_HOST_ATTRS 0 struct iscsi_internal { @@ -1156,6 +1156,7 @@ iscsi_conn_int_attr(ifmarker, ISCSI_PARAM_IFMARKER_EN, "%d"); iscsi_conn_int_attr(ofmarker, ISCSI_PARAM_OFMARKER_EN, "%d"); iscsi_conn_int_attr(persistent_port, ISCSI_PARAM_PERSISTENT_PORT, "%d"); iscsi_conn_int_attr(port, ISCSI_PARAM_CONN_PORT, "%d"); +iscsi_conn_int_attr(exp_statsn, ISCSI_PARAM_EXP_STATSN, "%u"); #define iscsi_conn_str_attr_show(param) \ static ssize_t \ @@ -1406,6 +1407,7 @@ iscsi_register_transport(struct iscsi_transport *tt) SETUP_CONN_RD_ATTR(ofmarker, ISCSI_OFMARKER_EN); SETUP_CONN_RD_ATTR(address, ISCSI_CONN_ADDRESS); SETUP_CONN_RD_ATTR(port, ISCSI_CONN_PORT); + SETUP_CONN_RD_ATTR(exp_statsn, ISCSI_EXP_STATSN); if (tt->param_mask & ISCSI_PERSISTENT_ADDRESS) SETUP_CONN_RD_ATTR(persistent_address, ISCSI_PERSISTENT_ADDRESS); diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h index feff74e544b7..253797c60095 100644 --- a/include/scsi/iscsi_if.h +++ b/include/scsi/iscsi_if.h @@ -188,6 +188,7 @@ enum iscsi_param { ISCSI_PARAM_ERL, ISCSI_PARAM_IFMARKER_EN, ISCSI_PARAM_OFMARKER_EN, + ISCSI_PARAM_EXP_STATSN, ISCSI_PARAM_TARGET_NAME, ISCSI_PARAM_TPGT, ISCSI_PARAM_PERSISTENT_ADDRESS, @@ -216,6 +217,7 @@ enum iscsi_param { #define ISCSI_ERL (1 << ISCSI_PARAM_ERL) #define ISCSI_IFMARKER_EN (1 << ISCSI_PARAM_IFMARKER_EN) #define ISCSI_OFMARKER_EN (1 << ISCSI_PARAM_OFMARKER_EN) +#define ISCSI_EXP_STATSN (1 << ISCSI_PARAM_EXP_STATSN) #define ISCSI_TARGET_NAME (1 << ISCSI_PARAM_TARGET_NAME) #define ISCSI_TPGT (1 << ISCSI_PARAM_TPGT) #define ISCSI_PERSISTENT_ADDRESS (1 << ISCSI_PARAM_PERSISTENT_ADDRESS) -- cgit v1.2.3 From 06ea8e08ae7e7e450b6a78e7ce5e10b3c5f954ea Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 27 Apr 2006 05:25:00 -0400 Subject: ACPI: acpi_bus_unregister_driver() returns void Nobody looks at the return value, and this brings it into line with pci_unregister_driver(), etc. Also removed validation of the driver pointer passed in to register and unregister. More consistent, and we'll find bugs faster if we fault rather than returning an error that's ignored. Also makes internal functions acpi_device_unregister() and acpi_driver_detach() void, since nobody uses their returns either. Signed-off-by: Bjorn Helgaas Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/acpi/scan.c | 32 ++++++++++---------------------- include/acpi/acpi_bus.h | 2 +- 2 files changed, 11 insertions(+), 23 deletions(-) (limited to 'include') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 669553553fbb..e8efaac71e74 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -142,7 +142,7 @@ static void acpi_device_register(struct acpi_device *device, create_sysfs_device_files(device); } -static int acpi_device_unregister(struct acpi_device *device, int type) +static void acpi_device_unregister(struct acpi_device *device, int type) { spin_lock(&acpi_device_lock); if (device->parent) { @@ -158,7 +158,6 @@ static int acpi_device_unregister(struct acpi_device *device, int type) acpi_detach_data(device->handle, acpi_bus_data_handler); remove_sysfs_device_files(device); kobject_unregister(&device->kobj); - return 0; } void acpi_bus_data_handler(acpi_handle handle, u32 function, void *context) @@ -577,7 +576,7 @@ static void acpi_driver_attach(struct acpi_driver *drv) spin_unlock(&acpi_device_lock); } -static int acpi_driver_detach(struct acpi_driver *drv) +static void acpi_driver_detach(struct acpi_driver *drv) { struct list_head *node, *next; @@ -599,7 +598,6 @@ static int acpi_driver_detach(struct acpi_driver *drv) } } spin_unlock(&acpi_device_lock); - return_VALUE(0); } /** @@ -617,9 +615,6 @@ int acpi_bus_register_driver(struct acpi_driver *driver) if (acpi_disabled) return_VALUE(-ENODEV); - if (!driver) - return_VALUE(-EINVAL); - spin_lock(&acpi_device_lock); list_add_tail(&driver->node, &acpi_bus_drivers); spin_unlock(&acpi_device_lock); @@ -637,23 +632,16 @@ EXPORT_SYMBOL(acpi_bus_register_driver); * Unregisters a driver with the ACPI bus. Searches the namespace for all * devices that match the driver's criteria and unbinds. */ -int acpi_bus_unregister_driver(struct acpi_driver *driver) +void acpi_bus_unregister_driver(struct acpi_driver *driver) { - int error = 0; - - ACPI_FUNCTION_TRACE("acpi_bus_unregister_driver"); - - if (driver) { - acpi_driver_detach(driver); + acpi_driver_detach(driver); - if (!atomic_read(&driver->references)) { - spin_lock(&acpi_device_lock); - list_del_init(&driver->node); - spin_unlock(&acpi_device_lock); - } - } else - error = -EINVAL; - return_VALUE(error); + if (!atomic_read(&driver->references)) { + spin_lock(&acpi_device_lock); + list_del_init(&driver->node); + spin_unlock(&acpi_device_lock); + } + return; } EXPORT_SYMBOL(acpi_bus_unregister_driver); diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 6dca3d542080..809eb501a22b 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -327,7 +327,7 @@ int acpi_bus_set_power(acpi_handle handle, int state); int acpi_bus_generate_event(struct acpi_device *device, u8 type, int data); int acpi_bus_receive_event(struct acpi_bus_event *event); int acpi_bus_register_driver(struct acpi_driver *driver); -int acpi_bus_unregister_driver(struct acpi_driver *driver); +void acpi_bus_unregister_driver(struct acpi_driver *driver); int acpi_bus_add(struct acpi_device **child, struct acpi_device *parent, acpi_handle handle, int type); int acpi_bus_trim(struct acpi_device *start, int rmdevice); -- cgit v1.2.3 From 5b3272655a8e8a9a6e2503bc5a88fc9d9c8292a4 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Wed, 10 May 2006 10:33:00 -0400 Subject: ACPI: create acpi_device_suspend()/acpi_device_resume() updated and tested by Konstantin Karasyov http://bugzilla.kernel.org/show_bug.cgi?id=5000 Signed-off-by: Patrick Mochel Signed-off-by: Konstantin Karasyov Signed-off-by: Len Brown --- drivers/acpi/scan.c | 118 ++++++++++++++++++++++++++++++++++++++++++++++++ include/acpi/acpi_bus.h | 3 +- 2 files changed, 120 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index a0ab828b2cc5..19ae9ff10210 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1371,6 +1371,108 @@ static int acpi_bus_scan_fixed(struct acpi_device *root) return_VALUE(result); } + +static struct acpi_device * to_acpi_dev(struct device * dev) +{ + return container_of(dev, struct acpi_device, dev); +} + + +static int root_suspend(struct acpi_device * acpi_dev) +{ + struct acpi_device * dev, * next; + int result; + + spin_lock(&acpi_device_lock); + list_for_each_entry_safe_reverse(dev, next, &acpi_device_list, g_list) { + if (dev->driver && dev->driver->ops.suspend) { + spin_unlock(&acpi_device_lock); + + /* TBD: What suspend state should be passed + * to device? + */ + result = dev->driver->ops.suspend(dev, 0); + if (result) { + printk(KERN_ERR PREFIX "[%s - %s] Suspend failed: %d\n", + acpi_device_name(dev), + acpi_device_bid(dev), result); + } + spin_lock(&acpi_device_lock); + } + } + spin_unlock(&acpi_device_lock); + return 0; +} + + +static int acpi_device_suspend(struct device * dev, pm_message_t state) +{ + struct acpi_device * acpi_dev = to_acpi_dev(dev); + + /* + * For now, we should only register 1 generic device - + * the ACPI root device - and from there, we walk the + * tree of ACPI devices to suspend each one using the + * ACPI driver methods. + */ + if (acpi_dev->handle == ACPI_ROOT_OBJECT) + root_suspend(acpi_dev); + return 0; +} + + + +static int root_resume(struct acpi_device * acpi_dev) +{ + struct acpi_device * dev, * next; + int result; + + spin_lock(&acpi_device_lock); + list_for_each_entry_safe(dev, next, &acpi_device_list, g_list) { + if (dev->driver && dev->driver->ops.resume) { + spin_unlock(&acpi_device_lock); + + /* TBD: What suspend state should be passed + * to device? + */ + result = dev->driver->ops.resume(dev, 0); + if (result) { + printk(KERN_ERR PREFIX "[%s - %s] resume failed: %d\n", + acpi_device_name(dev), + acpi_device_bid(dev), result); + } + spin_lock(&acpi_device_lock); + } + } + spin_unlock(&acpi_device_lock); + return 0; +} + + +static int acpi_device_resume(struct device * dev) +{ + struct acpi_device * acpi_dev = to_acpi_dev(dev); + + /* + * For now, we should only register 1 generic device - + * the ACPI root device - and from there, we walk the + * tree of ACPI devices to resume each one using the + * ACPI driver methods. + */ + if (acpi_dev->handle == ACPI_ROOT_OBJECT) + root_resume(acpi_dev); + return 0; +} + + +struct bus_type acpi_bus_type = { + .name = "acpi", + .suspend = acpi_device_suspend, + .resume = acpi_device_resume, +}; + + + static int __init acpi_scan_init(void) { int result; @@ -1383,6 +1485,12 @@ static int __init acpi_scan_init(void) kset_register(&acpi_namespace_kset); + result = bus_register(&acpi_bus_type); + if (result) { + /* We don't want to quit even if we failed to add suspend/resume */ + printk(KERN_ERR PREFIX "Could not register bus type\n"); + } + /* * Create the root device in the bus's device tree */ @@ -1392,6 +1500,16 @@ static int __init acpi_scan_init(void) goto Done; result = acpi_start_single_object(acpi_root); + if (result) + goto Done; + + acpi_root->dev.bus = &acpi_bus_type; + snprintf(acpi_root->dev.bus_id, BUS_ID_SIZE, "%s", acpi_bus_type.name); + result = device_register(&acpi_root->dev); + if (result) { + /* We don't want to quit even if we failed to add suspend/resume */ + printk(KERN_ERR PREFIX "Could not register device\n"); + } /* * Enumerate devices in the ACPI namespace. diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 6dca3d542080..0de199aa6b94 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -26,7 +26,7 @@ #ifndef __ACPI_BUS_H__ #define __ACPI_BUS_H__ -#include +#include #include @@ -296,6 +296,7 @@ struct acpi_device { struct acpi_driver *driver; void *driver_data; struct kobject kobj; + struct device dev; }; #define acpi_driver_data(d) ((d)->driver_data) -- cgit v1.2.3 From 0feabb01d93e5801d1127416a66cfc3963280bca Mon Sep 17 00:00:00 2001 From: Konstantin Karasyov Date: Mon, 8 May 2006 00:00:00 -0400 Subject: ACPI: create acpi_fan_suspend()/acpi_fan_resume() http://bugzilla.kernel.org/show_bug.cgi?id=5000 Signed-off-by: Len Brown --- drivers/acpi/bus.c | 14 ++++++++------ drivers/acpi/fan.c | 40 ++++++++++++++++++++++++++++++++++++++++ include/acpi/acpi_bus.h | 3 ++- 3 files changed, 50 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 606f8733a776..eff696f2b6bb 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -205,12 +205,14 @@ int acpi_bus_set_power(acpi_handle handle, int state) * Get device's current power state if it's unknown * This means device power state isn't initialized or previous setting failed */ - if (device->power.state == ACPI_STATE_UNKNOWN) - acpi_bus_get_power(device->handle, &device->power.state); - if (state == device->power.state) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n", - state)); - return_VALUE(0); + if (!device->flags.force_power_state) { + if (device->power.state == ACPI_STATE_UNKNOWN) + acpi_bus_get_power(device->handle, &device->power.state); + if (state == device->power.state) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n", + state)); + return_VALUE(0); + } } if (!device->power.states[state].flags.valid) { ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Device does not support D%d\n", diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c index e8165c4f162a..1cd25784b7a4 100644 --- a/drivers/acpi/fan.c +++ b/drivers/acpi/fan.c @@ -48,6 +48,8 @@ MODULE_LICENSE("GPL"); static int acpi_fan_add(struct acpi_device *device); static int acpi_fan_remove(struct acpi_device *device, int type); +static int acpi_fan_suspend(struct acpi_device *device, int state); +static int acpi_fan_resume(struct acpi_device *device, int state); static struct acpi_driver acpi_fan_driver = { .name = ACPI_FAN_DRIVER_NAME, @@ -56,6 +58,8 @@ static struct acpi_driver acpi_fan_driver = { .ops = { .add = acpi_fan_add, .remove = acpi_fan_remove, + .suspend = acpi_fan_suspend, + .resume = acpi_fan_resume, }, }; @@ -206,6 +210,10 @@ static int acpi_fan_add(struct acpi_device *device) goto end; } + device->flags.force_power_state = 1; + acpi_bus_set_power(device->handle, state); + device->flags.force_power_state = 0; + result = acpi_fan_add_fs(device); if (result) goto end; @@ -239,6 +247,38 @@ static int acpi_fan_remove(struct acpi_device *device, int type) return_VALUE(0); } +static int acpi_fan_suspend(struct acpi_device *device, int state) +{ + if (!device) + return -EINVAL; + + acpi_bus_set_power(device->handle, ACPI_STATE_D0); + + return AE_OK; +} + +static int acpi_fan_resume(struct acpi_device *device, int state) +{ + int result = 0; + int power_state = 0; + + if (!device) + return -EINVAL; + + result = acpi_bus_get_power(device->handle, &power_state); + if (result) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Error reading fan power state\n")); + return result; + } + + device->flags.force_power_state = 1; + acpi_bus_set_power(device->handle, power_state); + device->flags.force_power_state = 0; + + return result; +} + static int __init acpi_fan_init(void) { int result = 0; diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 0de199aa6b94..7f8ed9dbc7b2 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -169,7 +169,8 @@ struct acpi_device_flags { u32 power_manageable:1; u32 performance_manageable:1; u32 wake_capable:1; /* Wakeup(_PRW) supported? */ - u32 reserved:20; + u32 force_power_state:1; + u32 reserved:19; }; /* File System */ -- cgit v1.2.3 From 89f48c4d67dd875cf2216d4402bf77eda41fbdd9 Mon Sep 17 00:00:00 2001 From: Luben Tuikov Date: Mon, 15 May 2006 20:57:18 +0900 Subject: [PATCH] SCSI: Introduce scsi_req_abort_cmd (REPOST) Introduce scsi_req_abort_cmd(struct scsi_cmnd *). This function requests that SCSI Core start recovery for the command by deleting the timer and adding the command to the eh queue. It can be called by either LLDDs or SCSI Core. LLDDs who implement their own error recovery MAY ignore the timeout event if they generated scsi_req_abort_cmd. First post: http://marc.theaimsgroup.com/?l=linux-scsi&m=113833937421677&w=2 Signed-off-by: Luben Tuikov Signed-off-by: Tejun Heo --- drivers/scsi/scsi.c | 18 ++++++++++++++++++ include/scsi/scsi_cmnd.h | 1 + 2 files changed, 19 insertions(+) (limited to 'include') diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 73994e2ac2cb..dae4f08adde0 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -719,6 +719,24 @@ void scsi_init_cmd_from_req(struct scsi_cmnd *cmd, struct scsi_request *sreq) */ static DEFINE_PER_CPU(struct list_head, scsi_done_q); +/** + * scsi_req_abort_cmd -- Request command recovery for the specified command + * cmd: pointer to the SCSI command of interest + * + * This function requests that SCSI Core start recovery for the + * command by deleting the timer and adding the command to the eh + * queue. It can be called by either LLDDs or SCSI Core. LLDDs who + * implement their own error recovery MAY ignore the timeout event if + * they generated scsi_req_abort_cmd. + */ +void scsi_req_abort_cmd(struct scsi_cmnd *cmd) +{ + if (!scsi_delete_timer(cmd)) + return; + scsi_times_out(cmd); +} +EXPORT_SYMBOL(scsi_req_abort_cmd); + /** * scsi_done - Enqueue the finished SCSI command into the done queue. * @cmd: The SCSI Command for which a low-level device driver (LLDD) gives diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h index 1ace1b9fe537..88c6c4da6c05 100644 --- a/include/scsi/scsi_cmnd.h +++ b/include/scsi/scsi_cmnd.h @@ -151,5 +151,6 @@ extern struct scsi_cmnd *scsi_get_command(struct scsi_device *, gfp_t); extern void scsi_put_command(struct scsi_cmnd *); extern void scsi_io_completion(struct scsi_cmnd *, unsigned int, unsigned int); extern void scsi_finish_command(struct scsi_cmnd *cmd); +extern void scsi_req_abort_cmd(struct scsi_cmnd *cmd); #endif /* _SCSI_SCSI_CMND_H */ -- cgit v1.2.3 From ee7863bc68fa6ad6fe7cfcc0e5ebe9efe0c0664e Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:57:20 +0900 Subject: [PATCH] SCSI: implement shost->host_eh_scheduled libata needs to invoke EH without scmd. This patch adds shost->host_eh_scheduled to implement such behavior. Currently the only user of this feature is libata and no general interface is defined. This patch simply adds handling for host_eh_scheduled where needed and exports scsi_eh_wakeup() to modules. The rest is upto libata. This is the result of the following discussion. http://thread.gmane.org/gmane.linux.scsi/23853/focus=9760 In short, SCSI host is not supposed to know about exceptions unrelated to specific device or command. Such exceptions should be handled by transport layer proper. However, the distinction is not essential to ATA and libata is planning to depart from SCSI, so, for the time being, libata will be using SCSI EH to handle such exceptions. Signed-off-by: Tejun Heo --- drivers/scsi/scsi_error.c | 3 ++- drivers/scsi/scsi_lib.c | 2 +- drivers/scsi/scsi_priv.h | 1 - include/scsi/scsi_eh.h | 1 + include/scsi/scsi_host.h | 1 + 5 files changed, 5 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 1c75646f9689..9ca71cbefce0 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -56,6 +56,7 @@ void scsi_eh_wakeup(struct Scsi_Host *shost) printk("Waking error handler thread\n")); } } +EXPORT_SYMBOL_GPL(scsi_eh_wakeup); /** * scsi_eh_scmd_add - add scsi cmd to error handling. @@ -1517,7 +1518,7 @@ int scsi_error_handler(void *data) */ set_current_state(TASK_INTERRUPTIBLE); while (!kthread_should_stop()) { - if (shost->host_failed == 0 || + if ((shost->host_failed == 0 && shost->host_eh_scheduled == 0) || shost->host_failed != shost->host_busy) { SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler scsi_eh_%d sleeping\n", diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 7b0f9a3810d2..c55d195b6f4f 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -566,7 +566,7 @@ void scsi_device_unbusy(struct scsi_device *sdev) spin_lock_irqsave(shost->host_lock, flags); shost->host_busy--; if (unlikely(scsi_host_in_recovery(shost) && - shost->host_failed)) + (shost->host_failed || shost->host_eh_scheduled))) scsi_eh_wakeup(shost); spin_unlock(shost->host_lock); spin_lock(sdev->request_queue->queue_lock); diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index 27c48274e8cb..0b39081113be 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -63,7 +63,6 @@ extern int scsi_delete_timer(struct scsi_cmnd *); extern void scsi_times_out(struct scsi_cmnd *cmd); extern int scsi_error_handler(void *host); extern int scsi_decide_disposition(struct scsi_cmnd *cmd); -extern void scsi_eh_wakeup(struct Scsi_Host *shost); extern int scsi_eh_scmd_add(struct scsi_cmnd *, int); /* scsi_lib.c */ diff --git a/include/scsi/scsi_eh.h b/include/scsi/scsi_eh.h index d160880b2a87..212c983a6a18 100644 --- a/include/scsi/scsi_eh.h +++ b/include/scsi/scsi_eh.h @@ -35,6 +35,7 @@ static inline int scsi_sense_valid(struct scsi_sense_hdr *sshdr) } +extern void scsi_eh_wakeup(struct Scsi_Host *shost); extern void scsi_eh_finish_cmd(struct scsi_cmnd *scmd, struct list_head *done_q); extern void scsi_eh_flush_done_q(struct list_head *done_q); diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index de6ce541a046..a42efd6e4be8 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -472,6 +472,7 @@ struct Scsi_Host { */ unsigned int host_busy; /* commands actually active on low-level */ unsigned int host_failed; /* commands that failed. */ + unsigned int host_eh_scheduled; /* EH scheduled without command */ unsigned short host_no; /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */ int resetting; /* if set, it means that last_reset is a valid value */ -- cgit v1.2.3 From 3c567b7d1137633f3ff67cd1df94abc5fd497a85 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:57:23 +0900 Subject: [PATCH] libata: rename ata_down_sata_spd_limit() and friends Rename ata_down_sata_spd_limit() and friends to sata_down_spd_limit() and likewise for simplicity & consistency. Signed-off-by: Tejun Heo --- drivers/scsi/libata-core.c | 32 ++++++++++++++++---------------- drivers/scsi/libata.h | 4 ++-- drivers/scsi/sata_sil24.c | 2 +- include/linux/libata.h | 2 +- 4 files changed, 20 insertions(+), 20 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 509178c3700c..196c09ff5e71 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -1465,7 +1465,7 @@ static int ata_bus_probe(struct ata_port *ap) tries[dev->devno] = 0; break; case -EIO: - ata_down_sata_spd_limit(ap); + sata_down_spd_limit(ap); /* fall through */ default: tries[dev->devno]--; @@ -1640,12 +1640,12 @@ void ata_port_disable(struct ata_port *ap) } /** - * ata_down_sata_spd_limit - adjust SATA spd limit downward + * sata_down_spd_limit - adjust SATA spd limit downward * @ap: Port to adjust SATA spd limit for * * Adjust SATA spd limit of @ap downward. Note that this * function only adjusts the limit. The change must be applied - * using ata_set_sata_spd(). + * using sata_set_spd(). * * LOCKING: * Inherited from caller. @@ -1653,7 +1653,7 @@ void ata_port_disable(struct ata_port *ap) * RETURNS: * 0 on success, negative errno on failure */ -int ata_down_sata_spd_limit(struct ata_port *ap) +int sata_down_spd_limit(struct ata_port *ap) { u32 spd, mask; int highbit; @@ -1683,7 +1683,7 @@ int ata_down_sata_spd_limit(struct ata_port *ap) return 0; } -static int __ata_set_sata_spd_needed(struct ata_port *ap, u32 *scontrol) +static int __sata_set_spd_needed(struct ata_port *ap, u32 *scontrol) { u32 spd, limit; @@ -1699,7 +1699,7 @@ static int __ata_set_sata_spd_needed(struct ata_port *ap, u32 *scontrol) } /** - * ata_set_sata_spd_needed - is SATA spd configuration needed + * sata_set_spd_needed - is SATA spd configuration needed * @ap: Port in question * * Test whether the spd limit in SControl matches @@ -1713,7 +1713,7 @@ static int __ata_set_sata_spd_needed(struct ata_port *ap, u32 *scontrol) * RETURNS: * 1 if SATA spd configuration is needed, 0 otherwise. */ -int ata_set_sata_spd_needed(struct ata_port *ap) +int sata_set_spd_needed(struct ata_port *ap) { u32 scontrol; @@ -1722,11 +1722,11 @@ int ata_set_sata_spd_needed(struct ata_port *ap) scontrol = scr_read(ap, SCR_CONTROL); - return __ata_set_sata_spd_needed(ap, &scontrol); + return __sata_set_spd_needed(ap, &scontrol); } /** - * ata_set_sata_spd - set SATA spd according to spd limit + * sata_set_spd - set SATA spd according to spd limit * @ap: Port to set SATA spd for * * Set SATA spd of @ap according to sata_spd_limit. @@ -1738,7 +1738,7 @@ int ata_set_sata_spd_needed(struct ata_port *ap) * 0 if spd doesn't need to be changed, 1 if spd has been * changed. -EOPNOTSUPP if SCR registers are inaccessible. */ -int ata_set_sata_spd(struct ata_port *ap) +int sata_set_spd(struct ata_port *ap) { u32 scontrol; @@ -1746,7 +1746,7 @@ int ata_set_sata_spd(struct ata_port *ap) return -EOPNOTSUPP; scontrol = scr_read(ap, SCR_CONTROL); - if (!__ata_set_sata_spd_needed(ap, &scontrol)) + if (!__sata_set_spd_needed(ap, &scontrol)) return 0; scr_write(ap, SCR_CONTROL, scontrol); @@ -2464,7 +2464,7 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class) DPRINTK("ENTER\n"); - if (ata_set_sata_spd_needed(ap)) { + if (sata_set_spd_needed(ap)) { /* SATA spec says nothing about how to reconfigure * spd. To be on the safe side, turn off phy during * reconfiguration. This works for at least ICH7 AHCI @@ -2474,7 +2474,7 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class) scontrol = (scontrol & 0x0f0) | 0x302; scr_write_flush(ap, SCR_CONTROL, scontrol); - ata_set_sata_spd(ap); + sata_set_spd(ap); } /* issue phy wake/reset */ @@ -2657,7 +2657,7 @@ int ata_drive_probe_reset(struct ata_port *ap, ata_probeinit_fn_t probeinit, if (probeinit) probeinit(ap); - if (softreset && !ata_set_sata_spd_needed(ap)) { + if (softreset && !sata_set_spd_needed(ap)) { rc = ata_do_reset(ap, softreset, postreset, classes); if (rc == 0 && classes[0] != ATA_DEV_UNKNOWN) goto done; @@ -2677,7 +2677,7 @@ int ata_drive_probe_reset(struct ata_port *ap, ata_probeinit_fn_t probeinit, break; } - if (ata_down_sata_spd_limit(ap)) + if (sata_down_spd_limit(ap)) goto done; printk(KERN_INFO "ata%u: hardreset failed, will retry " @@ -5113,7 +5113,7 @@ EXPORT_SYMBOL_GPL(ata_bmdma_irq_clear); EXPORT_SYMBOL_GPL(ata_bmdma_status); EXPORT_SYMBOL_GPL(ata_bmdma_stop); EXPORT_SYMBOL_GPL(ata_port_probe); -EXPORT_SYMBOL_GPL(ata_set_sata_spd); +EXPORT_SYMBOL_GPL(sata_set_spd); EXPORT_SYMBOL_GPL(sata_phy_reset); EXPORT_SYMBOL_GPL(__sata_phy_reset); EXPORT_SYMBOL_GPL(ata_bus_reset); diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h index 3f8b0a863781..26975df9a3fc 100644 --- a/drivers/scsi/libata.h +++ b/drivers/scsi/libata.h @@ -51,8 +51,8 @@ extern void ata_port_flush_task(struct ata_port *ap); extern unsigned ata_exec_internal(struct ata_port *ap, struct ata_device *dev, struct ata_taskfile *tf, const u8 *cdb, int dma_dir, void *buf, unsigned int buflen); -extern int ata_down_sata_spd_limit(struct ata_port *ap); -extern int ata_set_sata_spd_needed(struct ata_port *ap); +extern int sata_down_spd_limit(struct ata_port *ap); +extern int sata_set_spd_needed(struct ata_port *ap); extern int ata_down_xfermask_limit(struct ata_port *ap, struct ata_device *dev, int force_pio0); extern int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev); diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c index e9fd869140c5..8c167250f4c9 100644 --- a/drivers/scsi/sata_sil24.c +++ b/drivers/scsi/sata_sil24.c @@ -528,7 +528,7 @@ static int sil24_hardreset(struct ata_port *ap, unsigned int *class) u32 tmp; /* sil24 does the right thing(tm) without any protection */ - ata_set_sata_spd(ap); + sata_set_spd(ap); tout_msec = 100; if (sata_dev_present(ap)) diff --git a/include/linux/libata.h b/include/linux/libata.h index d35b1e3bb7e0..0b67aafd3878 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -504,7 +504,7 @@ extern void ata_port_probe(struct ata_port *); extern void __sata_phy_reset(struct ata_port *ap); extern void sata_phy_reset(struct ata_port *ap); extern void ata_bus_reset(struct ata_port *ap); -extern int ata_set_sata_spd(struct ata_port *ap); +extern int sata_set_spd(struct ata_port *ap); extern int ata_drive_probe_reset(struct ata_port *ap, ata_probeinit_fn_t probeinit, ata_reset_fn_t softreset, ata_reset_fn_t hardreset, -- cgit v1.2.3 From 6cd727b14f1a6cdcb088d1067c1ba0ba124806a7 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:57:28 +0900 Subject: [PATCH] libata: kill duplicate prototypes Kill duplicate prototypes for ata_eh_qc_complete/retry() in libata.h. Signed-off-by: Tejun Heo --- include/linux/libata.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'include') diff --git a/include/linux/libata.h b/include/linux/libata.h index 0b67aafd3878..220b9d7bfc28 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -530,8 +530,6 @@ extern void ata_host_set_remove(struct ata_host_set *host_set); extern int ata_scsi_detect(struct scsi_host_template *sht); extern int ata_scsi_ioctl(struct scsi_device *dev, int cmd, void __user *arg); extern int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)); -extern void ata_eh_qc_complete(struct ata_queued_cmd *qc); -extern void ata_eh_qc_retry(struct ata_queued_cmd *qc); extern int ata_scsi_release(struct Scsi_Host *host); extern unsigned int ata_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc); extern int ata_scsi_device_resume(struct scsi_device *); -- cgit v1.2.3 From fe635c7e91036282e4fd0cc5b4eebc712e43270d Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:57:35 +0900 Subject: [PATCH] libata: use preallocated buffers It's not a very good idea to allocate memory during EH. Use statically allocated buffer for dev->id[] and add 512byte buffer ap->sector_buf. This buffer is owned by EH (or probing) and to be used as temporary buffer for various purposes (IDENTIFY, NCQ log page 10h, PM GSCR block). Signed-off-by: Tejun Heo --- drivers/scsi/libata-core.c | 32 ++++++++------------------------ include/linux/libata.h | 4 +++- 2 files changed, 11 insertions(+), 25 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 13bce43f1915..af55861a96e2 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -1099,7 +1099,7 @@ unsigned int ata_pio_need_iordy(const struct ata_device *adev) * @dev: target device * @p_class: pointer to class of the target device (may be changed) * @post_reset: is this read ID post-reset? - * @p_id: read IDENTIFY page (newly allocated) + * @id: buffer to read IDENTIFY data into * * Read ID data from the specified device. ATA_CMD_ID_ATA is * performed on ATA devices and ATA_CMD_ID_ATAPI on ATAPI @@ -1113,12 +1113,11 @@ unsigned int ata_pio_need_iordy(const struct ata_device *adev) * 0 on success, -errno otherwise. */ static int ata_dev_read_id(struct ata_port *ap, struct ata_device *dev, - unsigned int *p_class, int post_reset, u16 **p_id) + unsigned int *p_class, int post_reset, u16 *id) { unsigned int class = *p_class; struct ata_taskfile tf; unsigned int err_mask = 0; - u16 *id; const char *reason; int rc; @@ -1126,13 +1125,6 @@ static int ata_dev_read_id(struct ata_port *ap, struct ata_device *dev, ata_dev_select(ap, dev->devno, 1, 1); /* select device 0/1 */ - id = kmalloc(sizeof(id[0]) * ATA_ID_WORDS, GFP_KERNEL); - if (id == NULL) { - rc = -ENOMEM; - reason = "out of memory"; - goto err_out; - } - retry: ata_tf_init(ap, &tf, dev->devno); @@ -1194,13 +1186,12 @@ static int ata_dev_read_id(struct ata_port *ap, struct ata_device *dev, } *p_class = class; - *p_id = id; + return 0; err_out: printk(KERN_WARNING "ata%u: dev %u failed to IDENTIFY (%s)\n", ap->id, dev->devno, reason); - kfree(id); return rc; } @@ -1425,9 +1416,7 @@ static int ata_bus_probe(struct ata_port *ap) if (!ata_dev_enabled(dev)) continue; - kfree(dev->id); - dev->id = NULL; - rc = ata_dev_read_id(ap, dev, &dev->class, 1, &dev->id); + rc = ata_dev_read_id(ap, dev, &dev->class, 1, dev->id); if (rc) goto fail; @@ -2788,7 +2777,7 @@ int ata_dev_revalidate(struct ata_port *ap, struct ata_device *dev, int post_reset) { unsigned int class = dev->class; - u16 *id = NULL; + u16 *id = (void *)ap->sector_buf; int rc; if (!ata_dev_enabled(dev)) { @@ -2796,8 +2785,8 @@ int ata_dev_revalidate(struct ata_port *ap, struct ata_device *dev, goto fail; } - /* allocate & read ID data */ - rc = ata_dev_read_id(ap, dev, &class, post_reset, &id); + /* read ID data */ + rc = ata_dev_read_id(ap, dev, &class, post_reset, id); if (rc) goto fail; @@ -2807,8 +2796,7 @@ int ata_dev_revalidate(struct ata_port *ap, struct ata_device *dev, goto fail; } - kfree(dev->id); - dev->id = id; + memcpy(dev->id, id, sizeof(id[0]) * ATA_ID_WORDS); /* configure device according to the new ID */ rc = ata_dev_configure(ap, dev, 0); @@ -2818,7 +2806,6 @@ int ata_dev_revalidate(struct ata_port *ap, struct ata_device *dev, fail: printk(KERN_ERR "ata%u: dev %u revalidation failed (errno=%d)\n", ap->id, dev->devno, rc); - kfree(id); return rc; } @@ -4873,14 +4860,11 @@ void ata_host_set_remove(struct ata_host_set *host_set) int ata_scsi_release(struct Scsi_Host *host) { struct ata_port *ap = ata_shost_to_port(host); - int i; DPRINTK("ENTER\n"); ap->ops->port_disable(ap); ata_host_remove(ap, 0); - for (i = 0; i < ATA_MAX_DEVICES; i++) - kfree(ap->device[i].id); DPRINTK("EXIT\n"); return 1; diff --git a/include/linux/libata.h b/include/linux/libata.h index 220b9d7bfc28..0e1a3be39475 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -360,7 +360,7 @@ struct ata_device { unsigned long flags; /* ATA_DFLAG_xxx */ unsigned int class; /* ATA_DEV_xxx */ unsigned int devno; /* 0 or 1 */ - u16 *id; /* IDENTIFY xxx DEVICE data */ + u16 id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */ u8 pio_mode; u8 dma_mode; u8 xfer_mode; @@ -425,6 +425,8 @@ struct ata_port { struct list_head eh_done_q; void *private_data; + + u8 sector_buf[ATA_SECT_SIZE]; /* owned by EH */ }; struct ata_port_operations { -- cgit v1.2.3 From e61e067227bc76b4d9411a50d735c9d87f27b0e2 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:57:40 +0900 Subject: [PATCH] libata: implement qc->result_tf Add qc->result_tf and ATA_QCFLAG_RESULT_TF. This moves the responsibility of loading result TF from post-compltion path to qc execution path. qc->result_tf is loaded if explicitly requested or the qc failsa. This allows more efficient completion implementation and correct handling of result TF for controllers which don't have global TF representation such as sil3124/32. Signed-off-by: Tejun Heo --- drivers/scsi/libata-core.c | 4 ++-- drivers/scsi/libata-scsi.c | 18 +++++++----------- include/linux/libata.h | 16 ++++++++++++++-- 3 files changed, 23 insertions(+), 15 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 19ae3fa1cfcb..51cb9ca5519c 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -955,7 +955,6 @@ void ata_qc_complete_internal(struct ata_queued_cmd *qc) { struct completion *waiting = qc->private_data; - qc->ap->ops->tf_read(qc->ap, &qc->tf); complete(waiting); } @@ -997,6 +996,7 @@ unsigned ata_exec_internal(struct ata_port *ap, struct ata_device *dev, qc->tf = *tf; if (cdb) memcpy(qc->cdb, cdb, ATAPI_CDB_LEN); + qc->flags |= ATA_QCFLAG_RESULT_TF; qc->dma_dir = dma_dir; if (dma_dir != DMA_NONE) { ata_sg_init_one(qc, buf, buflen); @@ -1034,7 +1034,7 @@ unsigned ata_exec_internal(struct ata_port *ap, struct ata_device *dev, /* finish up */ spin_lock_irqsave(&ap->host_set->lock, flags); - *tf = qc->tf; + *tf = qc->result_tf; err_mask = qc->err_mask; ata_qc_free(qc); diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index b0c83c28d578..ce90b6352a81 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -537,7 +537,7 @@ void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, u8 *asc, void ata_gen_ata_desc_sense(struct ata_queued_cmd *qc) { struct scsi_cmnd *cmd = qc->scsicmd; - struct ata_taskfile *tf = &qc->tf; + struct ata_taskfile *tf = &qc->result_tf; unsigned char *sb = cmd->sense_buffer; unsigned char *desc = sb + 8; @@ -608,7 +608,7 @@ void ata_gen_ata_desc_sense(struct ata_queued_cmd *qc) void ata_gen_fixed_sense(struct ata_queued_cmd *qc) { struct scsi_cmnd *cmd = qc->scsicmd; - struct ata_taskfile *tf = &qc->tf; + struct ata_taskfile *tf = &qc->result_tf; unsigned char *sb = cmd->sense_buffer; memset(sb, 0, SCSI_SENSE_BUFFERSIZE); @@ -1199,14 +1199,11 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) */ if (((cdb[0] == ATA_16) || (cdb[0] == ATA_12)) && ((cdb[2] & 0x20) || need_sense)) { - qc->ap->ops->tf_read(qc->ap, &qc->tf); ata_gen_ata_desc_sense(qc); } else { if (!need_sense) { cmd->result = SAM_STAT_GOOD; } else { - qc->ap->ops->tf_read(qc->ap, &qc->tf); - /* TODO: decide which descriptor format to use * for 48b LBA devices and call that here * instead of the fixed desc, which is only @@ -1217,10 +1214,8 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) } } - if (need_sense) { - /* The ata_gen_..._sense routines fill in tf */ - ata_dump_status(qc->ap->id, &qc->tf); - } + if (need_sense) + ata_dump_status(qc->ap->id, &qc->result_tf); qc->scsidone(cmd); @@ -2004,7 +1999,6 @@ static void atapi_sense_complete(struct ata_queued_cmd *qc) * a sense descriptors, since that's only * correct for ATA, not ATAPI */ - qc->ap->ops->tf_read(qc->ap, &qc->tf); ata_gen_ata_desc_sense(qc); } @@ -2080,7 +2074,6 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc) * a sense descriptors, since that's only * correct for ATA, not ATAPI */ - qc->ap->ops->tf_read(qc->ap, &qc->tf); ata_gen_ata_desc_sense(qc); } else { u8 *scsicmd = cmd->cmnd; @@ -2361,6 +2354,9 @@ ata_scsi_pass_thru(struct ata_queued_cmd *qc, const u8 *scsicmd) */ qc->nsect = cmd->bufflen / ATA_SECT_SIZE; + /* request result TF */ + qc->flags |= ATA_QCFLAG_RESULT_TF; + return 0; invalid_fld: diff --git a/include/linux/libata.h b/include/linux/libata.h index 0e1a3be39475..a4b8a419caad 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -162,7 +162,9 @@ enum { ATA_QCFLAG_SINGLE = (1 << 2), /* no s/g, just a single buffer */ ATA_QCFLAG_DMAMAP = ATA_QCFLAG_SG | ATA_QCFLAG_SINGLE, ATA_QCFLAG_IO = (1 << 3), /* standard IO command */ - ATA_QCFLAG_EH_SCHEDULED = (1 << 4), /* EH scheduled */ + ATA_QCFLAG_RESULT_TF = (1 << 4), /* result TF requested */ + + ATA_QCFLAG_EH_SCHEDULED = (1 << 16), /* EH scheduled */ /* host set flags */ ATA_HOST_SIMPLEX = (1 << 0), /* Host is simplex, one DMA channel per host_set only */ @@ -343,7 +345,7 @@ struct ata_queued_cmd { struct scatterlist *__sg; unsigned int err_mask; - + struct ata_taskfile result_tf; ata_qc_cb_t complete_fn; void *private_data; @@ -824,6 +826,10 @@ static inline void ata_qc_reinit(struct ata_queued_cmd *qc) qc->err_mask = 0; ata_tf_init(qc->ap, &qc->tf, qc->dev->devno); + + /* init result_tf such that it indicates normal completion */ + qc->result_tf.command = ATA_DRDY; + qc->result_tf.feature = 0; } /** @@ -839,9 +845,15 @@ static inline void ata_qc_reinit(struct ata_queued_cmd *qc) */ static inline void ata_qc_complete(struct ata_queued_cmd *qc) { + struct ata_port *ap = qc->ap; + if (unlikely(qc->flags & ATA_QCFLAG_EH_SCHEDULED)) return; + /* read result TF if failed or requested */ + if (qc->err_mask || qc->flags & ATA_QCFLAG_RESULT_TF) + ap->ops->tf_read(ap, &qc->result_tf); + __ata_qc_complete(qc); } -- cgit v1.2.3 From 34bf21704c848fe00c516d1c8f163db08b70b137 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:57:46 +0900 Subject: [PATCH] libata: implement new SCR handling and port on/offline functions Implement ata_scr_{valid|read|write|write_flush}() and ata_port_{online|offline}(). These functions replace scr_{read|write}() and sata_dev_present(). Major difference between between the new SCR functions and the old ones is that the new ones have a way to signal error to the caller. This makes handling SCR-available and SCR-unavailable cases in the same path easier. Also, it eases later PM implementation where SCR access can fail due to various reasons. ata_port_{online|offline}() functions return 1 only when they are affirmitive of the condition. e.g. if SCR is unaccessible or presence cannot be determined for other reasons, these functions return 0. So, ata_port_online() != !ata_port_offline(). This distinction is useful in many exception handling cases. Signed-off-by: Tejun Heo --- drivers/scsi/libata-core.c | 143 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/libata.h | 6 ++ 2 files changed, 149 insertions(+) (limited to 'include') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index f29d43cb6991..b9c5cbf0b786 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -4365,6 +4365,143 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs) return IRQ_RETVAL(handled); } +/** + * sata_scr_valid - test whether SCRs are accessible + * @ap: ATA port to test SCR accessibility for + * + * Test whether SCRs are accessible for @ap. + * + * LOCKING: + * None. + * + * RETURNS: + * 1 if SCRs are accessible, 0 otherwise. + */ +int sata_scr_valid(struct ata_port *ap) +{ + return ap->cbl == ATA_CBL_SATA && ap->ops->scr_read; +} + +/** + * sata_scr_read - read SCR register of the specified port + * @ap: ATA port to read SCR for + * @reg: SCR to read + * @val: Place to store read value + * + * Read SCR register @reg of @ap into *@val. This function is + * guaranteed to succeed if the cable type of the port is SATA + * and the port implements ->scr_read. + * + * LOCKING: + * None. + * + * RETURNS: + * 0 on success, negative errno on failure. + */ +int sata_scr_read(struct ata_port *ap, int reg, u32 *val) +{ + if (sata_scr_valid(ap)) { + *val = ap->ops->scr_read(ap, reg); + return 0; + } + return -EOPNOTSUPP; +} + +/** + * sata_scr_write - write SCR register of the specified port + * @ap: ATA port to write SCR for + * @reg: SCR to write + * @val: value to write + * + * Write @val to SCR register @reg of @ap. This function is + * guaranteed to succeed if the cable type of the port is SATA + * and the port implements ->scr_read. + * + * LOCKING: + * None. + * + * RETURNS: + * 0 on success, negative errno on failure. + */ +int sata_scr_write(struct ata_port *ap, int reg, u32 val) +{ + if (sata_scr_valid(ap)) { + ap->ops->scr_write(ap, reg, val); + return 0; + } + return -EOPNOTSUPP; +} + +/** + * sata_scr_write_flush - write SCR register of the specified port and flush + * @ap: ATA port to write SCR for + * @reg: SCR to write + * @val: value to write + * + * This function is identical to sata_scr_write() except that this + * function performs flush after writing to the register. + * + * LOCKING: + * None. + * + * RETURNS: + * 0 on success, negative errno on failure. + */ +int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val) +{ + if (sata_scr_valid(ap)) { + ap->ops->scr_write(ap, reg, val); + ap->ops->scr_read(ap, reg); + return 0; + } + return -EOPNOTSUPP; +} + +/** + * ata_port_online - test whether the given port is online + * @ap: ATA port to test + * + * Test whether @ap is online. Note that this function returns 0 + * if online status of @ap cannot be obtained, so + * ata_port_online(ap) != !ata_port_offline(ap). + * + * LOCKING: + * None. + * + * RETURNS: + * 1 if the port online status is available and online. + */ +int ata_port_online(struct ata_port *ap) +{ + u32 sstatus; + + if (!sata_scr_read(ap, SCR_STATUS, &sstatus) && (sstatus & 0xf) == 0x3) + return 1; + return 0; +} + +/** + * ata_port_offline - test whether the given port is offline + * @ap: ATA port to test + * + * Test whether @ap is offline. Note that this function returns + * 0 if offline status of @ap cannot be obtained, so + * ata_port_online(ap) != !ata_port_offline(ap). + * + * LOCKING: + * None. + * + * RETURNS: + * 1 if the port offline status is available and offline. + */ +int ata_port_offline(struct ata_port *ap) +{ + u32 sstatus; + + if (!sata_scr_read(ap, SCR_STATUS, &sstatus) && (sstatus & 0xf) != 0x3) + return 1; + return 0; +} /* * Execute a 'simple' command, that only consists of the opcode 'cmd' itself, @@ -5133,6 +5270,12 @@ EXPORT_SYMBOL_GPL(ata_scsi_queuecmd); EXPORT_SYMBOL_GPL(ata_scsi_slave_config); EXPORT_SYMBOL_GPL(ata_scsi_release); EXPORT_SYMBOL_GPL(ata_host_intr); +EXPORT_SYMBOL_GPL(sata_scr_valid); +EXPORT_SYMBOL_GPL(sata_scr_read); +EXPORT_SYMBOL_GPL(sata_scr_write); +EXPORT_SYMBOL_GPL(sata_scr_write_flush); +EXPORT_SYMBOL_GPL(ata_port_online); +EXPORT_SYMBOL_GPL(ata_port_offline); EXPORT_SYMBOL_GPL(ata_id_string); EXPORT_SYMBOL_GPL(ata_id_c_string); EXPORT_SYMBOL_GPL(ata_scsi_simulate); diff --git a/include/linux/libata.h b/include/linux/libata.h index a4b8a419caad..47b97157995d 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -536,6 +536,12 @@ extern int ata_scsi_ioctl(struct scsi_device *dev, int cmd, void __user *arg); extern int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)); extern int ata_scsi_release(struct Scsi_Host *host); extern unsigned int ata_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc); +extern int sata_scr_valid(struct ata_port *ap); +extern int sata_scr_read(struct ata_port *ap, int reg, u32 *val); +extern int sata_scr_write(struct ata_port *ap, int reg, u32 val); +extern int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val); +extern int ata_port_online(struct ata_port *ap); +extern int ata_port_offline(struct ata_port *ap); extern int ata_scsi_device_resume(struct scsi_device *); extern int ata_scsi_device_suspend(struct scsi_device *, pm_message_t state); extern int ata_device_resume(struct ata_port *, struct ata_device *); -- cgit v1.2.3 From a0ab51cefc95cb7756c4914603fea2b1a0f813c5 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:57:49 +0900 Subject: [PATCH] libata: kill old SCR functions and sata_dev_present() Kill now unused scr_{read|write|write_flush}() and sata_dev_present(). Signed-off-by: Tejun Heo --- include/linux/libata.h | 22 ---------------------- 1 file changed, 22 deletions(-) (limited to 'include') diff --git a/include/linux/libata.h b/include/linux/libata.h index 47b97157995d..cd467cd54473 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -939,28 +939,6 @@ static inline u8 ata_irq_ack(struct ata_port *ap, unsigned int chk_drq) return status; } -static inline u32 scr_read(struct ata_port *ap, unsigned int reg) -{ - return ap->ops->scr_read(ap, reg); -} - -static inline void scr_write(struct ata_port *ap, unsigned int reg, u32 val) -{ - ap->ops->scr_write(ap, reg, val); -} - -static inline void scr_write_flush(struct ata_port *ap, unsigned int reg, - u32 val) -{ - ap->ops->scr_write(ap, reg, val); - (void) ap->ops->scr_read(ap, reg); -} - -static inline unsigned int sata_dev_present(struct ata_port *ap) -{ - return ((scr_read(ap, SCR_STATUS) & 0xf) == 0x3) ? 1 : 0; -} - static inline int ata_try_flush_cache(const struct ata_device *dev) { return ata_id_wcache_enabled(dev->id) || -- cgit v1.2.3 From 38d87234d6c47ca487fc6344100323d5adc6f32c Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:57:51 +0900 Subject: [PATCH] libata: add dev->ap Add dev->ap which points back to the port the device belongs to. This makes it unnecessary to pass @ap for silly reasons (e.g. printks). Also, this change is necessary to accomodate later PM support which will introduce ATA link inbetween port and device. Signed-off-by: Tejun Heo --- drivers/scsi/libata-core.c | 1 + include/linux/libata.h | 1 + 2 files changed, 2 insertions(+) (limited to 'include') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 56f0af208345..31b65e0da0b1 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -4749,6 +4749,7 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host, for (i = 0; i < ATA_MAX_DEVICES; i++) { struct ata_device *dev = &ap->device[i]; + dev->ap = ap; dev->devno = i; dev->pio_mask = UINT_MAX; dev->mwdma_mask = UINT_MAX; diff --git a/include/linux/libata.h b/include/linux/libata.h index cd467cd54473..ac2d2cc78b10 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -358,6 +358,7 @@ struct ata_host_stats { }; struct ata_device { + struct ata_port *ap; u64 n_sectors; /* size of device, if ATA */ unsigned long flags; /* ATA_DFLAG_xxx */ unsigned int class; /* ATA_DEV_xxx */ -- cgit v1.2.3 From 3373efd89dead4ce7818d685729e0431448357c9 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:57:53 +0900 Subject: [PATCH] libata: use dev->ap Use dev->ap where possible and eliminate superflous @ap from functions and structures. Signed-off-by: Tejun Heo --- drivers/scsi/ahci.c | 2 +- drivers/scsi/libata-core.c | 160 +++++++++++++++++++++------------------------ drivers/scsi/libata-scsi.c | 40 +++++------- drivers/scsi/libata.h | 11 ++-- include/linux/libata.h | 21 +++--- 5 files changed, 106 insertions(+), 128 deletions(-) (limited to 'include') diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index c2298fb131d8..f6e4c8ea74e3 100644 --- a/drivers/scsi/ahci.c +++ b/drivers/scsi/ahci.c @@ -597,7 +597,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class) /* restart engine */ ahci_start_engine(ap); - ata_tf_init(ap, &tf, 0); + ata_tf_init(ap->device, &tf); fis = pp->cmd_tbl; /* issue the first D2H Register FIS */ diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 31b65e0da0b1..4ced962db812 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -61,13 +61,10 @@ #include "libata.h" -static unsigned int ata_dev_init_params(struct ata_port *ap, - struct ata_device *dev, - u16 heads, - u16 sectors); -static unsigned int ata_dev_set_xfermode(struct ata_port *ap, - struct ata_device *dev); -static void ata_dev_xfermask(struct ata_port *ap, struct ata_device *dev); +static unsigned int ata_dev_init_params(struct ata_device *dev, + u16 heads, u16 sectors); +static unsigned int ata_dev_set_xfermode(struct ata_device *dev); +static void ata_dev_xfermask(struct ata_device *dev); static unsigned int ata_unique_id = 1; static struct workqueue_struct *ata_wq; @@ -412,11 +409,11 @@ static const char *sata_spd_string(unsigned int spd) return spd_str[spd - 1]; } -void ata_dev_disable(struct ata_port *ap, struct ata_device *dev) +void ata_dev_disable(struct ata_device *dev) { if (ata_dev_enabled(dev)) { printk(KERN_WARNING "ata%u: dev %u disabled\n", - ap->id, dev->devno); + dev->ap->id, dev->devno); dev->class++; } } @@ -960,7 +957,6 @@ void ata_qc_complete_internal(struct ata_queued_cmd *qc) /** * ata_exec_internal - execute libata internal command - * @ap: Port to which the command is sent * @dev: Device to which the command is sent * @tf: Taskfile registers for the command and the result * @cdb: CDB for packet command @@ -978,10 +974,11 @@ void ata_qc_complete_internal(struct ata_queued_cmd *qc) * None. Should be called with kernel context, might sleep. */ -unsigned ata_exec_internal(struct ata_port *ap, struct ata_device *dev, +unsigned ata_exec_internal(struct ata_device *dev, struct ata_taskfile *tf, const u8 *cdb, int dma_dir, void *buf, unsigned int buflen) { + struct ata_port *ap = dev->ap; u8 command = tf->command; struct ata_queued_cmd *qc; DECLARE_COMPLETION(wait); @@ -990,7 +987,7 @@ unsigned ata_exec_internal(struct ata_port *ap, struct ata_device *dev, spin_lock_irqsave(&ap->host_set->lock, flags); - qc = ata_qc_new_init(ap, dev); + qc = ata_qc_new_init(dev); BUG_ON(qc == NULL); qc->tf = *tf; @@ -1095,7 +1092,6 @@ unsigned int ata_pio_need_iordy(const struct ata_device *adev) /** * ata_dev_read_id - Read ID data from the specified device - * @ap: port on which target device resides * @dev: target device * @p_class: pointer to class of the target device (may be changed) * @post_reset: is this read ID post-reset? @@ -1112,9 +1108,10 @@ unsigned int ata_pio_need_iordy(const struct ata_device *adev) * RETURNS: * 0 on success, -errno otherwise. */ -static int ata_dev_read_id(struct ata_port *ap, struct ata_device *dev, - unsigned int *p_class, int post_reset, u16 *id) +static int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, + int post_reset, u16 *id) { + struct ata_port *ap = dev->ap; unsigned int class = *p_class; struct ata_taskfile tf; unsigned int err_mask = 0; @@ -1126,7 +1123,7 @@ static int ata_dev_read_id(struct ata_port *ap, struct ata_device *dev, ata_dev_select(ap, dev->devno, 1, 1); /* select device 0/1 */ retry: - ata_tf_init(ap, &tf, dev->devno); + ata_tf_init(dev, &tf); switch (class) { case ATA_DEV_ATA: @@ -1143,7 +1140,7 @@ static int ata_dev_read_id(struct ata_port *ap, struct ata_device *dev, tf.protocol = ATA_PROT_PIO; - err_mask = ata_exec_internal(ap, dev, &tf, NULL, DMA_FROM_DEVICE, + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, id, sizeof(id[0]) * ATA_ID_WORDS); if (err_mask) { rc = -EIO; @@ -1170,7 +1167,7 @@ static int ata_dev_read_id(struct ata_port *ap, struct ata_device *dev, * Some drives were very specific about that exact sequence. */ if (ata_id_major_version(id) < 4 || !ata_id_has_lba(id)) { - err_mask = ata_dev_init_params(ap, dev, id[3], id[6]); + err_mask = ata_dev_init_params(dev, id[3], id[6]); if (err_mask) { rc = -EIO; reason = "INIT_DEV_PARAMS failed"; @@ -1195,15 +1192,13 @@ static int ata_dev_read_id(struct ata_port *ap, struct ata_device *dev, return rc; } -static inline u8 ata_dev_knobble(const struct ata_port *ap, - struct ata_device *dev) +static inline u8 ata_dev_knobble(struct ata_device *dev) { - return ((ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(dev->id))); + return ((dev->ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(dev->id))); } /** * ata_dev_configure - Configure the specified ATA/ATAPI device - * @ap: Port on which target device resides * @dev: Target device to configure * @print_info: Enable device info printout * @@ -1216,9 +1211,9 @@ static inline u8 ata_dev_knobble(const struct ata_port *ap, * RETURNS: * 0 on success, -errno otherwise */ -static int ata_dev_configure(struct ata_port *ap, struct ata_device *dev, - int print_info) +static int ata_dev_configure(struct ata_device *dev, int print_info) { + struct ata_port *ap = dev->ap; const u16 *id = dev->id; unsigned int xfer_mask; int i, rc; @@ -1331,7 +1326,7 @@ static int ata_dev_configure(struct ata_port *ap, struct ata_device *dev, ap->device[i].cdb_len); /* limit bridge transfers to udma5, 200 sectors */ - if (ata_dev_knobble(ap, dev)) { + if (ata_dev_knobble(dev)) { if (print_info) printk(KERN_INFO "ata%u(%u): applying bridge limits\n", ap->id, dev->devno); @@ -1416,11 +1411,11 @@ static int ata_bus_probe(struct ata_port *ap) if (!ata_dev_enabled(dev)) continue; - rc = ata_dev_read_id(ap, dev, &dev->class, 1, dev->id); + rc = ata_dev_read_id(dev, &dev->class, 1, dev->id); if (rc) goto fail; - rc = ata_dev_configure(ap, dev, 1); + rc = ata_dev_configure(dev, 1); if (rc) goto fail; } @@ -1453,13 +1448,13 @@ static int ata_bus_probe(struct ata_port *ap) default: tries[dev->devno]--; if (down_xfermask && - ata_down_xfermask_limit(ap, dev, tries[dev->devno] == 1)) + ata_down_xfermask_limit(dev, tries[dev->devno] == 1)) tries[dev->devno] = 0; } if (!tries[dev->devno]) { - ata_down_xfermask_limit(ap, dev, 1); - ata_dev_disable(ap, dev); + ata_down_xfermask_limit(dev, 1); + ata_dev_disable(dev); } goto retry; @@ -1586,15 +1581,15 @@ void sata_phy_reset(struct ata_port *ap) /** * ata_dev_pair - return other device on cable - * @ap: port * @adev: device * * Obtain the other device on the same cable, or if none is * present NULL is returned */ -struct ata_device *ata_dev_pair(struct ata_port *ap, struct ata_device *adev) +struct ata_device *ata_dev_pair(struct ata_device *adev) { + struct ata_port *ap = adev->ap; struct ata_device *pair = &ap->device[1 - adev->devno]; if (!ata_dev_enabled(pair)) return NULL; @@ -1886,7 +1881,6 @@ int ata_timing_compute(struct ata_device *adev, unsigned short speed, /** * ata_down_xfermask_limit - adjust dev xfer masks downward - * @ap: Port associated with device @dev * @dev: Device to adjust xfer masks * @force_pio0: Force PIO0 * @@ -1900,9 +1894,9 @@ int ata_timing_compute(struct ata_device *adev, unsigned short speed, * RETURNS: * 0 on success, negative errno on failure */ -int ata_down_xfermask_limit(struct ata_port *ap, struct ata_device *dev, - int force_pio0) +int ata_down_xfermask_limit(struct ata_device *dev, int force_pio0) { + struct ata_port *ap = dev->ap; unsigned long xfer_mask; int highbit; @@ -1934,8 +1928,9 @@ int ata_down_xfermask_limit(struct ata_port *ap, struct ata_device *dev, return -EINVAL; } -static int ata_dev_set_mode(struct ata_port *ap, struct ata_device *dev) +static int ata_dev_set_mode(struct ata_device *dev) { + struct ata_port *ap = dev->ap; unsigned int err_mask; int rc; @@ -1943,7 +1938,7 @@ static int ata_dev_set_mode(struct ata_port *ap, struct ata_device *dev) if (dev->xfer_shift == ATA_SHIFT_PIO) dev->flags |= ATA_DFLAG_PIO; - err_mask = ata_dev_set_xfermode(ap, dev); + err_mask = ata_dev_set_xfermode(dev); if (err_mask) { printk(KERN_ERR "ata%u: failed to set xfermode (err_mask=0x%x)\n", @@ -1951,7 +1946,7 @@ static int ata_dev_set_mode(struct ata_port *ap, struct ata_device *dev) return -EIO; } - rc = ata_dev_revalidate(ap, dev, 0); + rc = ata_dev_revalidate(dev, 0); if (rc) return rc; @@ -2007,7 +2002,7 @@ int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) if (!ata_dev_enabled(dev)) continue; - ata_dev_xfermask(ap, dev); + ata_dev_xfermask(dev); pio_mask = ata_pack_xfermask(dev->pio_mask, 0, 0); dma_mask = ata_pack_xfermask(0, dev->mwdma_mask, dev->udma_mask); @@ -2060,7 +2055,7 @@ int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) if (!ata_dev_enabled(dev)) continue; - rc = ata_dev_set_mode(ap, dev); + rc = ata_dev_set_mode(dev); if (rc) goto out; } @@ -2712,7 +2707,6 @@ int ata_drive_probe_reset(struct ata_port *ap, ata_probeinit_fn_t probeinit, /** * ata_dev_same_device - Determine whether new ID matches configured device - * @ap: port on which the device to compare against resides * @dev: device to compare against * @new_class: class of the new device * @new_id: IDENTIFY page of the new device @@ -2727,9 +2721,10 @@ int ata_drive_probe_reset(struct ata_port *ap, ata_probeinit_fn_t probeinit, * RETURNS: * 1 if @dev matches @new_class and @new_id, 0 otherwise. */ -static int ata_dev_same_device(struct ata_port *ap, struct ata_device *dev, - unsigned int new_class, const u16 *new_id) +static int ata_dev_same_device(struct ata_device *dev, unsigned int new_class, + const u16 *new_id) { + struct ata_port *ap = dev->ap; const u16 *old_id = dev->id; unsigned char model[2][41], serial[2][21]; u64 new_n_sectors; @@ -2774,7 +2769,6 @@ static int ata_dev_same_device(struct ata_port *ap, struct ata_device *dev, /** * ata_dev_revalidate - Revalidate ATA device - * @ap: port on which the device to revalidate resides * @dev: device to revalidate * @post_reset: is this revalidation after reset? * @@ -2787,9 +2781,9 @@ static int ata_dev_same_device(struct ata_port *ap, struct ata_device *dev, * RETURNS: * 0 on success, negative errno otherwise */ -int ata_dev_revalidate(struct ata_port *ap, struct ata_device *dev, - int post_reset) +int ata_dev_revalidate(struct ata_device *dev, int post_reset) { + struct ata_port *ap = dev->ap; unsigned int class = dev->class; u16 *id = (void *)ap->sector_buf; int rc; @@ -2800,12 +2794,12 @@ int ata_dev_revalidate(struct ata_port *ap, struct ata_device *dev, } /* read ID data */ - rc = ata_dev_read_id(ap, dev, &class, post_reset, id); + rc = ata_dev_read_id(dev, &class, post_reset, id); if (rc) goto fail; /* is the device still there? */ - if (!ata_dev_same_device(ap, dev, class, id)) { + if (!ata_dev_same_device(dev, class, id)) { rc = -ENODEV; goto fail; } @@ -2813,7 +2807,7 @@ int ata_dev_revalidate(struct ata_port *ap, struct ata_device *dev, memcpy(dev->id, id, sizeof(id[0]) * ATA_ID_WORDS); /* configure device according to the new ID */ - rc = ata_dev_configure(ap, dev, 0); + rc = ata_dev_configure(dev, 0); if (rc == 0) return 0; @@ -2895,7 +2889,6 @@ static int ata_dma_blacklisted(const struct ata_device *dev) /** * ata_dev_xfermask - Compute supported xfermask of the given device - * @ap: Port on which the device to compute xfermask for resides * @dev: Device to compute xfermask for * * Compute supported xfermask of @dev and store it in @@ -2910,8 +2903,9 @@ static int ata_dma_blacklisted(const struct ata_device *dev) * LOCKING: * None. */ -static void ata_dev_xfermask(struct ata_port *ap, struct ata_device *dev) +static void ata_dev_xfermask(struct ata_device *dev) { + struct ata_port *ap = dev->ap; struct ata_host_set *hs = ap->host_set; unsigned long xfer_mask; int i; @@ -2964,7 +2958,6 @@ static void ata_dev_xfermask(struct ata_port *ap, struct ata_device *dev) /** * ata_dev_set_xfermode - Issue SET FEATURES - XFER MODE command - * @ap: Port associated with device @dev * @dev: Device to which command will be sent * * Issue SET FEATURES - XFER MODE command to device @dev @@ -2977,8 +2970,7 @@ static void ata_dev_xfermask(struct ata_port *ap, struct ata_device *dev) * 0 on success, AC_ERR_* mask otherwise. */ -static unsigned int ata_dev_set_xfermode(struct ata_port *ap, - struct ata_device *dev) +static unsigned int ata_dev_set_xfermode(struct ata_device *dev) { struct ata_taskfile tf; unsigned int err_mask; @@ -2986,14 +2978,14 @@ static unsigned int ata_dev_set_xfermode(struct ata_port *ap, /* set up set-features taskfile */ DPRINTK("set features - xfer mode\n"); - ata_tf_init(ap, &tf, dev->devno); + ata_tf_init(dev, &tf); tf.command = ATA_CMD_SET_FEATURES; tf.feature = SETFEATURES_XFER; tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; tf.protocol = ATA_PROT_NODATA; tf.nsect = dev->xfer_mode; - err_mask = ata_exec_internal(ap, dev, &tf, NULL, DMA_NONE, NULL, 0); + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); DPRINTK("EXIT, err_mask=%x\n", err_mask); return err_mask; @@ -3001,8 +2993,9 @@ static unsigned int ata_dev_set_xfermode(struct ata_port *ap, /** * ata_dev_init_params - Issue INIT DEV PARAMS command - * @ap: Port associated with device @dev * @dev: Device to which command will be sent + * @heads: Number of heads + * @sectors: Number of sectors * * LOCKING: * Kernel thread context (may sleep) @@ -3010,11 +3003,8 @@ static unsigned int ata_dev_set_xfermode(struct ata_port *ap, * RETURNS: * 0 on success, AC_ERR_* mask otherwise. */ - -static unsigned int ata_dev_init_params(struct ata_port *ap, - struct ata_device *dev, - u16 heads, - u16 sectors) +static unsigned int ata_dev_init_params(struct ata_device *dev, + u16 heads, u16 sectors) { struct ata_taskfile tf; unsigned int err_mask; @@ -3026,14 +3016,14 @@ static unsigned int ata_dev_init_params(struct ata_port *ap, /* set up init dev params taskfile */ DPRINTK("init dev params \n"); - ata_tf_init(ap, &tf, dev->devno); + ata_tf_init(dev, &tf); tf.command = ATA_CMD_INIT_DEV_PARAMS; tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; tf.protocol = ATA_PROT_NODATA; tf.nsect = sectors; tf.device |= (heads - 1) & 0x0f; /* max head = num. of heads - 1 */ - err_mask = ata_exec_internal(ap, dev, &tf, NULL, DMA_NONE, NULL, 0); + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); DPRINTK("EXIT, err_mask=%x\n", err_mask); return err_mask; @@ -4045,16 +4035,15 @@ static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap) /** * ata_qc_new_init - Request an available ATA command, and initialize it - * @ap: Port associated with device @dev * @dev: Device from whom we request an available command structure * * LOCKING: * None. */ -struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap, - struct ata_device *dev) +struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev) { + struct ata_port *ap = dev->ap; struct ata_queued_cmd *qc; qc = ata_qc_new(ap); @@ -4520,19 +4509,18 @@ int ata_port_offline(struct ata_port *ap) * Execute a 'simple' command, that only consists of the opcode 'cmd' itself, * without filling any other registers */ -static int ata_do_simple_cmd(struct ata_port *ap, struct ata_device *dev, - u8 cmd) +static int ata_do_simple_cmd(struct ata_device *dev, u8 cmd) { struct ata_taskfile tf; int err; - ata_tf_init(ap, &tf, dev->devno); + ata_tf_init(dev, &tf); tf.command = cmd; tf.flags |= ATA_TFLAG_DEVICE; tf.protocol = ATA_PROT_NODATA; - err = ata_exec_internal(ap, dev, &tf, NULL, DMA_NONE, NULL, 0); + err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); if (err) printk(KERN_ERR "%s: ata command failed: %d\n", __FUNCTION__, err); @@ -4540,7 +4528,7 @@ static int ata_do_simple_cmd(struct ata_port *ap, struct ata_device *dev, return err; } -static int ata_flush_cache(struct ata_port *ap, struct ata_device *dev) +static int ata_flush_cache(struct ata_device *dev) { u8 cmd; @@ -4552,22 +4540,21 @@ static int ata_flush_cache(struct ata_port *ap, struct ata_device *dev) else cmd = ATA_CMD_FLUSH; - return ata_do_simple_cmd(ap, dev, cmd); + return ata_do_simple_cmd(dev, cmd); } -static int ata_standby_drive(struct ata_port *ap, struct ata_device *dev) +static int ata_standby_drive(struct ata_device *dev) { - return ata_do_simple_cmd(ap, dev, ATA_CMD_STANDBYNOW1); + return ata_do_simple_cmd(dev, ATA_CMD_STANDBYNOW1); } -static int ata_start_drive(struct ata_port *ap, struct ata_device *dev) +static int ata_start_drive(struct ata_device *dev) { - return ata_do_simple_cmd(ap, dev, ATA_CMD_IDLEIMMEDIATE); + return ata_do_simple_cmd(dev, ATA_CMD_IDLEIMMEDIATE); } /** * ata_device_resume - wakeup a previously suspended devices - * @ap: port the device is connected to * @dev: the device to resume * * Kick the drive back into action, by sending it an idle immediate @@ -4575,39 +4562,42 @@ static int ata_start_drive(struct ata_port *ap, struct ata_device *dev) * and host. * */ -int ata_device_resume(struct ata_port *ap, struct ata_device *dev) +int ata_device_resume(struct ata_device *dev) { + struct ata_port *ap = dev->ap; + if (ap->flags & ATA_FLAG_SUSPENDED) { struct ata_device *failed_dev; ap->flags &= ~ATA_FLAG_SUSPENDED; while (ata_set_mode(ap, &failed_dev)) - ata_dev_disable(ap, failed_dev); + ata_dev_disable(failed_dev); } if (!ata_dev_enabled(dev)) return 0; if (dev->class == ATA_DEV_ATA) - ata_start_drive(ap, dev); + ata_start_drive(dev); return 0; } /** * ata_device_suspend - prepare a device for suspend - * @ap: port the device is connected to * @dev: the device to suspend * * Flush the cache on the drive, if appropriate, then issue a * standbynow command. */ -int ata_device_suspend(struct ata_port *ap, struct ata_device *dev, pm_message_t state) +int ata_device_suspend(struct ata_device *dev, pm_message_t state) { + struct ata_port *ap = dev->ap; + if (!ata_dev_enabled(dev)) return 0; if (dev->class == ATA_DEV_ATA) - ata_flush_cache(ap, dev); + ata_flush_cache(dev); if (state.event != PM_EVENT_FREEZE) - ata_standby_drive(ap, dev); + ata_standby_drive(dev); ap->flags |= ATA_FLAG_SUSPENDED; return 0; } diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index ce90b6352a81..fcbf64e741bb 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -302,7 +302,6 @@ int ata_scsi_ioctl(struct scsi_device *scsidev, int cmd, void __user *arg) /** * ata_scsi_qc_new - acquire new ata_queued_cmd reference - * @ap: ATA port to which the new command is attached * @dev: ATA device to which the new command is attached * @cmd: SCSI command that originated this ATA command * @done: SCSI command completion function @@ -321,14 +320,13 @@ int ata_scsi_ioctl(struct scsi_device *scsidev, int cmd, void __user *arg) * RETURNS: * Command allocated, or %NULL if none available. */ -struct ata_queued_cmd *ata_scsi_qc_new(struct ata_port *ap, - struct ata_device *dev, +struct ata_queued_cmd *ata_scsi_qc_new(struct ata_device *dev, struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) { struct ata_queued_cmd *qc; - qc = ata_qc_new_init(ap, dev); + qc = ata_qc_new_init(dev); if (qc) { qc->scsicmd = cmd; qc->scsidone = done; @@ -398,7 +396,7 @@ int ata_scsi_device_resume(struct scsi_device *sdev) struct ata_port *ap = ata_shost_to_port(sdev->host); struct ata_device *dev = &ap->device[sdev->id]; - return ata_device_resume(ap, dev); + return ata_device_resume(dev); } int ata_scsi_device_suspend(struct scsi_device *sdev, pm_message_t state) @@ -406,7 +404,7 @@ int ata_scsi_device_suspend(struct scsi_device *sdev, pm_message_t state) struct ata_port *ap = ata_shost_to_port(sdev->host); struct ata_device *dev = &ap->device[sdev->id]; - return ata_device_suspend(ap, dev, state); + return ata_device_suspend(dev, state); } /** @@ -1224,7 +1222,6 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) /** * ata_scsi_translate - Translate then issue SCSI command to ATA device - * @ap: ATA port to which the command is addressed * @dev: ATA device to which the command is addressed * @cmd: SCSI command to execute * @done: SCSI command completion function @@ -1247,17 +1244,16 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) * spin_lock_irqsave(host_set lock) */ -static void ata_scsi_translate(struct ata_port *ap, struct ata_device *dev, - struct scsi_cmnd *cmd, - void (*done)(struct scsi_cmnd *), - ata_xlat_func_t xlat_func) +static void ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd, + void (*done)(struct scsi_cmnd *), + ata_xlat_func_t xlat_func) { struct ata_queued_cmd *qc; u8 *scsicmd = cmd->cmnd; VPRINTK("ENTER\n"); - qc = ata_scsi_qc_new(ap, dev, cmd, done); + qc = ata_scsi_qc_new(dev, cmd, done); if (!qc) goto err_mem; @@ -1266,7 +1262,7 @@ static void ata_scsi_translate(struct ata_port *ap, struct ata_device *dev, cmd->sc_data_direction == DMA_TO_DEVICE) { if (unlikely(cmd->request_bufflen < 1)) { printk(KERN_WARNING "ata%u(%u): WARNING: zero len r/w req\n", - ap->id, dev->devno); + dev->ap->id, dev->devno); goto err_did; } @@ -2433,19 +2429,20 @@ static inline void ata_scsi_dump_cdb(struct ata_port *ap, #endif } -static inline void __ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), - struct ata_port *ap, struct ata_device *dev) +static inline void __ata_scsi_queuecmd(struct scsi_cmnd *cmd, + void (*done)(struct scsi_cmnd *), + struct ata_device *dev) { if (dev->class == ATA_DEV_ATA) { ata_xlat_func_t xlat_func = ata_get_xlat_func(dev, cmd->cmnd[0]); if (xlat_func) - ata_scsi_translate(ap, dev, cmd, done, xlat_func); + ata_scsi_translate(dev, cmd, done, xlat_func); else - ata_scsi_simulate(ap, dev, cmd, done); + ata_scsi_simulate(dev, cmd, done); } else - ata_scsi_translate(ap, dev, cmd, done, atapi_xlat); + ata_scsi_translate(dev, cmd, done, atapi_xlat); } /** @@ -2483,7 +2480,7 @@ int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) dev = ata_scsi_find_dev(ap, scsidev); if (likely(dev)) - __ata_scsi_queuecmd(cmd, done, ap, dev); + __ata_scsi_queuecmd(cmd, done, dev); else { cmd->result = (DID_BAD_TARGET << 16); done(cmd); @@ -2496,7 +2493,6 @@ int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) /** * ata_scsi_simulate - simulate SCSI command on ATA device - * @ap: port the device is connected to * @dev: the target device * @cmd: SCSI command being sent to device. * @done: SCSI command completion function. @@ -2508,14 +2504,12 @@ int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) * spin_lock_irqsave(host_set lock) */ -void ata_scsi_simulate(struct ata_port *ap, struct ata_device *dev, - struct scsi_cmnd *cmd, +void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) { struct ata_scsi_args args; const u8 *scsicmd = cmd->cmnd; - args.ap = ap; args.dev = dev; args.id = dev->id; args.cmd = cmd; diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h index 6442c2f1a80c..c9ff83bbcfae 100644 --- a/drivers/scsi/libata.h +++ b/drivers/scsi/libata.h @@ -32,7 +32,6 @@ #define DRV_VERSION "1.30" /* must be exactly four chars */ struct ata_scsi_args { - struct ata_port *ap; struct ata_device *dev; u16 *id; struct scsi_cmnd *cmd; @@ -43,18 +42,16 @@ struct ata_scsi_args { extern int atapi_enabled; extern int atapi_dmadir; extern int libata_fua; -extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap, - struct ata_device *dev); +extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev); extern int ata_rwcmd_protocol(struct ata_queued_cmd *qc); -extern void ata_dev_disable(struct ata_port *ap, struct ata_device *dev); +extern void ata_dev_disable(struct ata_device *dev); extern void ata_port_flush_task(struct ata_port *ap); -extern unsigned ata_exec_internal(struct ata_port *ap, struct ata_device *dev, +extern unsigned ata_exec_internal(struct ata_device *dev, struct ata_taskfile *tf, const u8 *cdb, int dma_dir, void *buf, unsigned int buflen); extern int sata_down_spd_limit(struct ata_port *ap); extern int sata_set_spd_needed(struct ata_port *ap); -extern int ata_down_xfermask_limit(struct ata_port *ap, struct ata_device *dev, - int force_pio0); +extern int ata_down_xfermask_limit(struct ata_device *dev, int force_pio0); extern int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev); extern int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset, unsigned int *classes); diff --git a/include/linux/libata.h b/include/linux/libata.h index ac2d2cc78b10..8154b366bbd1 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -518,8 +518,7 @@ extern void ata_std_probeinit(struct ata_port *ap); extern int ata_std_softreset(struct ata_port *ap, unsigned int *classes); extern int sata_std_hardreset(struct ata_port *ap, unsigned int *class); extern void ata_std_postreset(struct ata_port *ap, unsigned int *classes); -extern int ata_dev_revalidate(struct ata_port *ap, struct ata_device *dev, - int post_reset); +extern int ata_dev_revalidate(struct ata_device *dev, int post_reset); extern void ata_port_disable(struct ata_port *); extern void ata_std_ports(struct ata_ioports *ioaddr); #ifdef CONFIG_PCI @@ -545,8 +544,8 @@ extern int ata_port_online(struct ata_port *ap); extern int ata_port_offline(struct ata_port *ap); extern int ata_scsi_device_resume(struct scsi_device *); extern int ata_scsi_device_suspend(struct scsi_device *, pm_message_t state); -extern int ata_device_resume(struct ata_port *, struct ata_device *); -extern int ata_device_suspend(struct ata_port *, struct ata_device *, pm_message_t state); +extern int ata_device_resume(struct ata_device *); +extern int ata_device_suspend(struct ata_device *, pm_message_t state); extern int ata_ratelimit(void); extern unsigned int ata_busy_sleep(struct ata_port *ap, unsigned long timeout_pat, @@ -592,15 +591,13 @@ extern void ata_bmdma_stop(struct ata_queued_cmd *qc); extern u8 ata_bmdma_status(struct ata_port *ap); extern void ata_bmdma_irq_clear(struct ata_port *ap); extern void __ata_qc_complete(struct ata_queued_cmd *qc); -extern void ata_scsi_simulate(struct ata_port *ap, struct ata_device *dev, - struct scsi_cmnd *cmd, +extern void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)); extern int ata_std_bios_param(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int geom[]); extern int ata_scsi_slave_config(struct scsi_device *sdev); -extern struct ata_device *ata_dev_pair(struct ata_port *ap, - struct ata_device *adev); +extern struct ata_device *ata_dev_pair(struct ata_device *adev); /* * Timing helpers @@ -812,12 +809,12 @@ static inline struct ata_queued_cmd *ata_qc_from_tag (struct ata_port *ap, return NULL; } -static inline void ata_tf_init(struct ata_port *ap, struct ata_taskfile *tf, unsigned int device) +static inline void ata_tf_init(struct ata_device *dev, struct ata_taskfile *tf) { memset(tf, 0, sizeof(*tf)); - tf->ctl = ap->ctl; - if (device == 0) + tf->ctl = dev->ap->ctl; + if (dev->devno == 0) tf->device = ATA_DEVICE_OBS; else tf->device = ATA_DEVICE_OBS | ATA_DEV1; @@ -832,7 +829,7 @@ static inline void ata_qc_reinit(struct ata_queued_cmd *qc) qc->nbytes = qc->curbytes = 0; qc->err_mask = 0; - ata_tf_init(qc->ap, &qc->tf, qc->dev->devno); + ata_tf_init(qc->dev, &qc->tf); /* init result_tf such that it indicates normal completion */ qc->result_tf.command = ATA_DRDY; -- cgit v1.2.3 From 61440db61fe4945ad9f7b32b4d6a22b17174aa1f Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:57:55 +0900 Subject: [PATCH] libata: implement ATA printk helpers Implement ata_{port|dev}_printk() which prefixes the message with proper identification string. This change is necessary for later PM support because devices and links should be identified differently depending on how they are attached. This also helps unifying device id strings. Currently, there are two forms in use (P is the port number D device number) - 'ataP(D):', and 'ataP: dev D '. These macros also make it harder to forget proper ID string (e.g. printing only port number when a device is in question). Debug message handling can be integrated into these printk macros by passing debug type and level via @lv. Signed-off-by: Tejun Heo --- include/linux/libata.h | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'include') diff --git a/include/linux/libata.h b/include/linux/libata.h index 8154b366bbd1..91e10e6b7565 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -650,7 +650,18 @@ extern void ata_eng_timeout(struct ata_port *ap); extern void ata_eh_qc_complete(struct ata_queued_cmd *qc); extern void ata_eh_qc_retry(struct ata_queued_cmd *qc); +/* + * printk helpers + */ +#define ata_port_printk(ap, lv, fmt, args...) \ + printk(lv"ata%u: "fmt, (ap)->id , ##args) + +#define ata_dev_printk(dev, lv, fmt, args...) \ + printk(lv"ata%u.%02u: "fmt, (dev)->ap->id, (dev)->devno , ##args) +/* + * qc helpers + */ static inline int ata_sg_is_last(struct scatterlist *sg, struct ata_queued_cmd *qc) { -- cgit v1.2.3 From 9ec957f2002bd2994be659bbc0ec28397fa251ee Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:57:58 +0900 Subject: [PATCH] libata-eh-fw: add flags and operations for new EH Add ATA_FLAG_EH_{PENDING|FROZEN}, ATA_ATA_QCFLAG_{FAILED|SENSE_VALID} and ops->freeze, thaw, error_handler, post_internal_cmd() for new EH. Signed-off-by: Tejun Heo --- include/linux/libata.h | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/include/linux/libata.h b/include/linux/libata.h index 91e10e6b7565..e5d6d7f8e6dc 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -146,13 +146,16 @@ enum { ATA_FLAG_PIO_LBA48 = (1 << 8), /* Host DMA engine is LBA28 only */ ATA_FLAG_IRQ_MASK = (1 << 9), /* Mask IRQ in PIO xfers */ - ATA_FLAG_NOINTR = (1 << 16), /* FIXME: Remove this once + ATA_FLAG_NOINTR = (1 << 13), /* FIXME: Remove this once * proper HSM is in place. */ - ATA_FLAG_DEBUGMSG = (1 << 17), - ATA_FLAG_FLUSH_PORT_TASK = (1 << 18), /* flush port task */ + ATA_FLAG_DEBUGMSG = (1 << 14), + ATA_FLAG_FLUSH_PORT_TASK = (1 << 15), /* flush port task */ - ATA_FLAG_DISABLED = (1 << 19), /* port is disabled, ignore it */ - ATA_FLAG_SUSPENDED = (1 << 20), /* port is suspended */ + ATA_FLAG_EH_PENDING = (1 << 16), /* EH pending */ + ATA_FLAG_FROZEN = (1 << 17), /* port is frozen */ + + ATA_FLAG_DISABLED = (1 << 22), /* port is disabled, ignore it */ + ATA_FLAG_SUSPENDED = (1 << 23), /* port is suspended (power) */ /* bits 24:31 of ap->flags are reserved for LLDD specific flags */ @@ -164,7 +167,9 @@ enum { ATA_QCFLAG_IO = (1 << 3), /* standard IO command */ ATA_QCFLAG_RESULT_TF = (1 << 4), /* result TF requested */ - ATA_QCFLAG_EH_SCHEDULED = (1 << 16), /* EH scheduled */ + ATA_QCFLAG_FAILED = (1 << 16), /* cmd failed and is owned by EH */ + ATA_QCFLAG_SENSE_VALID = (1 << 17), /* sense data valid */ + ATA_QCFLAG_EH_SCHEDULED = (1 << 18), /* EH scheduled (obsolete) */ /* host set flags */ ATA_HOST_SIMPLEX = (1 << 0), /* Host is simplex, one DMA channel per host_set only */ @@ -463,7 +468,15 @@ struct ata_port_operations { void (*qc_prep) (struct ata_queued_cmd *qc); unsigned int (*qc_issue) (struct ata_queued_cmd *qc); - void (*eng_timeout) (struct ata_port *ap); + /* Error handlers. ->error_handler overrides ->eng_timeout and + * indicates that new-style EH is in place. + */ + void (*eng_timeout) (struct ata_port *ap); /* obsolete */ + + void (*freeze) (struct ata_port *ap); + void (*thaw) (struct ata_port *ap); + void (*error_handler) (struct ata_port *ap); + void (*post_internal_cmd) (struct ata_queued_cmd *qc); irqreturn_t (*irq_handler)(int, void *, struct pt_regs *); void (*irq_clear) (struct ata_port *); -- cgit v1.2.3 From 2ab7db1ff1d64a2ba389d0692d532f42a15f1f72 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:58:02 +0900 Subject: [PATCH] libata-eh-fw: use special reserved tag and qc for internal commands New EH may issue internal commands to recover from error while failed qc's are still hanging around. To allow such usage, reserve tag ATA_MAX_QUEUE-1 for internal command. This also makes it easy to tell whether a qc is for internal command or not. ata_tag_internal() test implements this test. To avoid breaking existing drivers, ata_exec_internal() uses ATA_TAG_INTERNAL only for drivers which implement ->error_handler. For drivers using old EH, tag 0 is used. Note that this makes ata_tag_internal() test valid only when ->error_handler is implemented. This is okay as drivers on old EH should not and does not have any reason to use ata_tag_internal(). Signed-off-by: Tejun Heo --- drivers/scsi/libata-core.c | 32 +++++++++++++++++++++++++++++--- include/linux/libata.h | 9 ++++++++- 2 files changed, 37 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index de2cd61a264d..966abb5f423e 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -980,15 +980,39 @@ unsigned ata_exec_internal(struct ata_device *dev, struct ata_port *ap = dev->ap; u8 command = tf->command; struct ata_queued_cmd *qc; + unsigned int tag, preempted_tag; DECLARE_COMPLETION(wait); unsigned long flags; unsigned int err_mask; spin_lock_irqsave(&ap->host_set->lock, flags); - qc = ata_qc_new_init(dev); - BUG_ON(qc == NULL); + /* initialize internal qc */ + /* XXX: Tag 0 is used for drivers with legacy EH as some + * drivers choke if any other tag is given. This breaks + * ata_tag_internal() test for those drivers. Don't use new + * EH stuff without converting to it. + */ + if (ap->ops->error_handler) + tag = ATA_TAG_INTERNAL; + else + tag = 0; + + if (test_and_set_bit(tag, &ap->qactive)) + BUG(); + qc = ata_qc_from_tag(ap, tag); + + qc->tag = tag; + qc->scsicmd = NULL; + qc->ap = ap; + qc->dev = dev; + ata_qc_reinit(qc); + + preempted_tag = ap->active_tag; + ap->active_tag = ATA_TAG_POISON; + + /* prepare & issue qc */ qc->tf = *tf; if (cdb) memcpy(qc->cdb, cdb, ATAPI_CDB_LEN); @@ -1035,6 +1059,7 @@ unsigned ata_exec_internal(struct ata_device *dev, err_mask = qc->err_mask; ata_qc_free(qc); + ap->active_tag = preempted_tag; /* XXX - Some LLDDs (sata_mv) disable port on command failure. * Until those drivers are fixed, we detect the condition @@ -4014,7 +4039,8 @@ static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap) struct ata_queued_cmd *qc = NULL; unsigned int i; - for (i = 0; i < ATA_MAX_QUEUE; i++) + /* the last tag is reserved for internal command. */ + for (i = 0; i < ATA_MAX_QUEUE - 1; i++) if (!test_and_set_bit(i, &ap->qactive)) { qc = ata_qc_from_tag(ap, i); break; diff --git a/include/linux/libata.h b/include/linux/libata.h index e5d6d7f8e6dc..5a403e434ff8 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -108,7 +108,9 @@ enum { LIBATA_MAX_PRD = ATA_MAX_PRD / 2, ATA_MAX_PORTS = 8, ATA_DEF_QUEUE = 1, - ATA_MAX_QUEUE = 1, + /* tag ATA_MAX_QUEUE - 1 is reserved for internal commands */ + ATA_MAX_QUEUE = 2, + ATA_TAG_INTERNAL = ATA_MAX_QUEUE - 1, ATA_MAX_SECTORS = 200, /* FIXME */ ATA_MAX_BUS = 2, ATA_DEF_BUSY_WAIT = 10000, @@ -717,6 +719,11 @@ static inline unsigned int ata_tag_valid(unsigned int tag) return (tag < ATA_MAX_QUEUE) ? 1 : 0; } +static inline unsigned int ata_tag_internal(unsigned int tag) +{ + return tag == ATA_MAX_QUEUE - 1; +} + static inline unsigned int ata_class_enabled(unsigned int class) { return class == ATA_DEV_ATA || class == ATA_DEV_ATAPI; -- cgit v1.2.3 From f69499f42caf74194df678c9c293f2ee0fe90bc3 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:58:03 +0900 Subject: [PATCH] libata-eh-fw: update ata_qc_from_tag() to enforce normal/EH qc ownership New EH framework has clear distinction about who owns a qc. Every qc starts owned by normal execution path - PIO, interrupt or whatever. When an exception condition occurs which affects the qc, the qc gets scheduled for EH. Note that some events (say, link lost and regained, command timeout) may schedule qc's which are not directly related but could have been affected for EH too. Scheduling for EH is atomic w.r.t. ap->host_set->lock and once schedule for EH, normal execution path is not allowed to access the qc in whatever way. (PIO synchronization acts a bit different and will be dealt with later) This patch make ata_qc_from_tag() check whether a qc is active and owned by normal path before returning it. If conditions don't match, NULL is returned and thus access to the qc is denied. __ata_qc_from_tag() is the original ata_qc_from_tag() and is used by libata core/EH layers to access inactive/failed qc's. This change is applied only if the associated LLDD implements new EH as indicated by non-NULL ->error_handler Signed-off-by: Tejun Heo --- drivers/scsi/libata-core.c | 4 ++-- include/linux/libata.h | 19 +++++++++++++++++-- 2 files changed, 19 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 966abb5f423e..1c34c1427aa3 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -1001,7 +1001,7 @@ unsigned ata_exec_internal(struct ata_device *dev, if (test_and_set_bit(tag, &ap->qactive)) BUG(); - qc = ata_qc_from_tag(ap, tag); + qc = __ata_qc_from_tag(ap, tag); qc->tag = tag; qc->scsicmd = NULL; @@ -4042,7 +4042,7 @@ static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap) /* the last tag is reserved for internal command. */ for (i = 0; i < ATA_MAX_QUEUE - 1; i++) if (!test_and_set_bit(i, &ap->qactive)) { - qc = ata_qc_from_tag(ap, i); + qc = __ata_qc_from_tag(ap, i); break; } diff --git a/include/linux/libata.h b/include/linux/libata.h index 5a403e434ff8..bfcefdca0616 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -832,14 +832,29 @@ static inline void ata_qc_set_polling(struct ata_queued_cmd *qc) qc->tf.ctl |= ATA_NIEN; } -static inline struct ata_queued_cmd *ata_qc_from_tag (struct ata_port *ap, - unsigned int tag) +static inline struct ata_queued_cmd *__ata_qc_from_tag(struct ata_port *ap, + unsigned int tag) { if (likely(ata_tag_valid(tag))) return &ap->qcmd[tag]; return NULL; } +static inline struct ata_queued_cmd *ata_qc_from_tag(struct ata_port *ap, + unsigned int tag) +{ + struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag); + + if (unlikely(!qc) || !ap->ops->error_handler) + return qc; + + if ((qc->flags & (ATA_QCFLAG_ACTIVE | + ATA_QCFLAG_FAILED)) == ATA_QCFLAG_ACTIVE) + return qc; + + return NULL; +} + static inline void ata_tf_init(struct ata_device *dev, struct ata_taskfile *tf) { memset(tf, 0, sizeof(*tf)); -- cgit v1.2.3 From f686bcb8078ac7505ec88818886c2c72639f4fc5 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:58:05 +0900 Subject: [PATCH] libata-eh-fw: implement new EH scheduling via error completion There are several ways a qc can get schedule for EH in new EH. This patch implements one of them - completing a qc with ATA_QCFLAG_FAILED set or with non-zero qc->err_mask. ALL such qc's are examined by EH. New EH schedules a qc for EH from completion iff ->error_handler is implemented, qc is marked as failed or qc->err_mask is non-zero and the command is not an internal command (internal cmd is handled via ->post_internal_cmd). The EH scheduling itself is performed by asking SCSI midlayer to schedule EH for the specified scmd. For drivers implementing old-EH, nothing changes. As this change makes ata_qc_complete() rather large, it's not inlined anymore and __ata_qc_complete() is exported to other parts of libata for later use. Signed-off-by: Tejun Heo --- drivers/scsi/libata-core.c | 62 +++++++++++++++++++++++++++++++++++++++++++++- drivers/scsi/libata-eh.c | 27 ++++++++++++++++++++ drivers/scsi/libata.h | 2 ++ include/linux/libata.h | 27 +------------------- 4 files changed, 91 insertions(+), 27 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 1c34c1427aa3..1f5c3270992a 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -4123,6 +4123,66 @@ void __ata_qc_complete(struct ata_queued_cmd *qc) qc->complete_fn(qc); } +/** + * ata_qc_complete - Complete an active ATA command + * @qc: Command to complete + * @err_mask: ATA Status register contents + * + * Indicate to the mid and upper layers that an ATA + * command has completed, with either an ok or not-ok status. + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + */ +void ata_qc_complete(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + + /* XXX: New EH and old EH use different mechanisms to + * synchronize EH with regular execution path. + * + * In new EH, a failed qc is marked with ATA_QCFLAG_FAILED. + * Normal execution path is responsible for not accessing a + * failed qc. libata core enforces the rule by returning NULL + * from ata_qc_from_tag() for failed qcs. + * + * Old EH depends on ata_qc_complete() nullifying completion + * requests if ATA_QCFLAG_EH_SCHEDULED is set. Old EH does + * not synchronize with interrupt handler. Only PIO task is + * taken care of. + */ + if (ap->ops->error_handler) { + WARN_ON(ap->flags & ATA_FLAG_FROZEN); + + if (unlikely(qc->err_mask)) + qc->flags |= ATA_QCFLAG_FAILED; + + if (unlikely(qc->flags & ATA_QCFLAG_FAILED)) { + if (!ata_tag_internal(qc->tag)) { + /* always fill result TF for failed qc */ + ap->ops->tf_read(ap, &qc->result_tf); + ata_qc_schedule_eh(qc); + return; + } + } + + /* read result TF if requested */ + if (qc->flags & ATA_QCFLAG_RESULT_TF) + ap->ops->tf_read(ap, &qc->result_tf); + + __ata_qc_complete(qc); + } else { + if (qc->flags & ATA_QCFLAG_EH_SCHEDULED) + return; + + /* read result TF if failed or requested */ + if (qc->err_mask || qc->flags & ATA_QCFLAG_RESULT_TF) + ap->ops->tf_read(ap, &qc->result_tf); + + __ata_qc_complete(qc); + } +} + static inline int ata_should_dma_map(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; @@ -5245,7 +5305,7 @@ EXPORT_SYMBOL_GPL(ata_device_add); EXPORT_SYMBOL_GPL(ata_host_set_remove); EXPORT_SYMBOL_GPL(ata_sg_init); EXPORT_SYMBOL_GPL(ata_sg_init_one); -EXPORT_SYMBOL_GPL(__ata_qc_complete); +EXPORT_SYMBOL_GPL(ata_qc_complete); EXPORT_SYMBOL_GPL(ata_qc_issue_prot); EXPORT_SYMBOL_GPL(ata_tf_load); EXPORT_SYMBOL_GPL(ata_tf_read); diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index 959a1cdffac2..471846fe4b73 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c @@ -210,6 +210,33 @@ void ata_eng_timeout(struct ata_port *ap) DPRINTK("EXIT\n"); } +/** + * ata_qc_schedule_eh - schedule qc for error handling + * @qc: command to schedule error handling for + * + * Schedule error handling for @qc. EH will kick in as soon as + * other commands are drained. + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + */ +void ata_qc_schedule_eh(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + + WARN_ON(!ap->ops->error_handler); + + qc->flags |= ATA_QCFLAG_FAILED; + qc->ap->flags |= ATA_FLAG_EH_PENDING; + + /* The following will fail if timeout has already expired. + * ata_scsi_error() takes care of such scmds on EH entry. + * Note that ATA_QCFLAG_FAILED is unconditionally set after + * this function completes. + */ + scsi_req_abort_cmd(qc->scsicmd); +} + static void ata_eh_scsidone(struct scsi_cmnd *scmd) { /* nada */ diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h index c9ff83bbcfae..52622b7f8a9e 100644 --- a/drivers/scsi/libata.h +++ b/drivers/scsi/libata.h @@ -57,6 +57,7 @@ extern int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset, unsigned int *classes); extern void ata_qc_free(struct ata_queued_cmd *qc); extern void ata_qc_issue(struct ata_queued_cmd *qc); +extern void __ata_qc_complete(struct ata_queued_cmd *qc); extern int ata_check_atapi_dma(struct ata_queued_cmd *qc); extern void ata_dev_select(struct ata_port *ap, unsigned int device, unsigned int wait, unsigned int can_sleep); @@ -101,5 +102,6 @@ extern void ata_scsi_rbuf_fill(struct ata_scsi_args *args, /* libata-eh.c */ extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd); extern void ata_scsi_error(struct Scsi_Host *host); +extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc); #endif /* __LIBATA_H__ */ diff --git a/include/linux/libata.h b/include/linux/libata.h index bfcefdca0616..6023f324e68e 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -605,7 +605,7 @@ extern void ata_bmdma_start (struct ata_queued_cmd *qc); extern void ata_bmdma_stop(struct ata_queued_cmd *qc); extern u8 ata_bmdma_status(struct ata_port *ap); extern void ata_bmdma_irq_clear(struct ata_port *ap); -extern void __ata_qc_complete(struct ata_queued_cmd *qc); +extern void ata_qc_complete(struct ata_queued_cmd *qc); extern void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)); extern int ata_std_bios_param(struct scsi_device *sdev, @@ -882,31 +882,6 @@ static inline void ata_qc_reinit(struct ata_queued_cmd *qc) qc->result_tf.feature = 0; } -/** - * ata_qc_complete - Complete an active ATA command - * @qc: Command to complete - * @err_mask: ATA Status register contents - * - * Indicate to the mid and upper layers that an ATA - * command has completed, with either an ok or not-ok status. - * - * LOCKING: - * spin_lock_irqsave(host_set lock) - */ -static inline void ata_qc_complete(struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - - if (unlikely(qc->flags & ATA_QCFLAG_EH_SCHEDULED)) - return; - - /* read result TF if failed or requested */ - if (qc->err_mask || qc->flags & ATA_QCFLAG_RESULT_TF) - ap->ops->tf_read(ap, &qc->result_tf); - - __ata_qc_complete(qc); -} - /** * ata_irq_on - Enable interrupts on a port. * @ap: Port on which interrupts are enabled. -- cgit v1.2.3 From 7b70fc039824bc7303e4007a5f758f832de56611 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:58:07 +0900 Subject: [PATCH] libata-eh-fw: implement ata_port_schedule_eh() and ata_port_abort() ata_port_schedule_eh() directly schedules EH for @ap without associated qc. Once EH scheduled, no further qc is allowed and EH kicks in as soon as all currently active qc's are drained. ata_port_abort() schedules all currently active commands for EH by qc_completing them with ATA_QCFLAG_FAILED set. If ata_port_abort() doesn't find any qc to abort, it directly schedule EH using ata_port_schedule_eh(). These two functions provide ways to invoke EH for conditions which aren't directly related to any specfic qc. Signed-off-by: Tejun Heo --- drivers/scsi/libata-core.c | 2 ++ drivers/scsi/libata-eh.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/scsi/libata-scsi.c | 23 ++++++++++++++++++++ drivers/scsi/libata.h | 1 + include/linux/libata.h | 4 ++++ 5 files changed, 84 insertions(+) (limited to 'include') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 1f5c3270992a..9c97783462d6 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -5383,5 +5383,7 @@ EXPORT_SYMBOL_GPL(ata_scsi_device_suspend); EXPORT_SYMBOL_GPL(ata_scsi_device_resume); EXPORT_SYMBOL_GPL(ata_eng_timeout); +EXPORT_SYMBOL_GPL(ata_port_schedule_eh); +EXPORT_SYMBOL_GPL(ata_port_abort); EXPORT_SYMBOL_GPL(ata_eh_qc_complete); EXPORT_SYMBOL_GPL(ata_eh_qc_retry); diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index 471846fe4b73..037a561809f5 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c @@ -237,6 +237,60 @@ void ata_qc_schedule_eh(struct ata_queued_cmd *qc) scsi_req_abort_cmd(qc->scsicmd); } +/** + * ata_port_schedule_eh - schedule error handling without a qc + * @ap: ATA port to schedule EH for + * + * Schedule error handling for @ap. EH will kick in as soon as + * all commands are drained. + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + */ +void ata_port_schedule_eh(struct ata_port *ap) +{ + WARN_ON(!ap->ops->error_handler); + + ap->flags |= ATA_FLAG_EH_PENDING; + ata_schedule_scsi_eh(ap->host); + + DPRINTK("port EH scheduled\n"); +} + +/** + * ata_port_abort - abort all qc's on the port + * @ap: ATA port to abort qc's for + * + * Abort all active qc's of @ap and schedule EH. + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + * + * RETURNS: + * Number of aborted qc's. + */ +int ata_port_abort(struct ata_port *ap) +{ + int tag, nr_aborted = 0; + + WARN_ON(!ap->ops->error_handler); + + for (tag = 0; tag < ATA_MAX_QUEUE; tag++) { + struct ata_queued_cmd *qc = ata_qc_from_tag(ap, tag); + + if (qc) { + qc->flags |= ATA_QCFLAG_FAILED; + ata_qc_complete(qc); + nr_aborted++; + } + } + + if (!nr_aborted) + ata_port_schedule_eh(ap); + + return nr_aborted; +} + static void ata_eh_scsidone(struct scsi_cmnd *scmd) { /* nada */ diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index a9b4083a4f67..fd7064b9697d 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -2596,3 +2596,26 @@ void ata_scsi_scan_host(struct ata_port *ap) } } +/** + * ata_schedule_scsi_eh - schedule EH for SCSI host + * @shost: SCSI host to invoke error handling on. + * + * Schedule SCSI EH without scmd. This is a hack. + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + **/ +void ata_schedule_scsi_eh(struct Scsi_Host *shost) +{ + unsigned long flags; + + spin_lock_irqsave(shost->host_lock, flags); + + if (scsi_host_set_state(shost, SHOST_RECOVERY) == 0 || + scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY) == 0) { + shost->host_eh_scheduled++; + scsi_eh_wakeup(shost); + } + + spin_unlock_irqrestore(shost->host_lock, flags); +} diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h index 52622b7f8a9e..b76ad7d7062a 100644 --- a/drivers/scsi/libata.h +++ b/drivers/scsi/libata.h @@ -98,6 +98,7 @@ extern void ata_scsi_set_sense(struct scsi_cmnd *cmd, extern void ata_scsi_rbuf_fill(struct ata_scsi_args *args, unsigned int (*actor) (struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen)); +extern void ata_schedule_scsi_eh(struct Scsi_Host *shost); /* libata-eh.c */ extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd); diff --git a/include/linux/libata.h b/include/linux/libata.h index 6023f324e68e..086e14690954 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -662,6 +662,10 @@ extern unsigned long ata_pci_default_filter(const struct ata_port *, struct ata_ * EH */ extern void ata_eng_timeout(struct ata_port *ap); + +extern void ata_port_schedule_eh(struct ata_port *ap); +extern int ata_port_abort(struct ata_port *ap); + extern void ata_eh_qc_complete(struct ata_queued_cmd *qc); extern void ata_eh_qc_retry(struct ata_queued_cmd *qc); -- cgit v1.2.3 From e318049949b07152d851dbfebbd93e560af45ebe Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:58:09 +0900 Subject: [PATCH] libata-eh-fw: implement freeze/thaw Freezing is performed atomic w.r.t. host_set->lock and once frozen LLDD is not allowed to access the port or any qc on it. Also, libata makes sure that no new qc gets issued to a frozen port. A frozen port is thawed after a reset operation completes successfully, so reset methods must do its job while the port is frozen. During initialization all ports get frozen before requesting IRQ, so reset methods are always invoked on a frozen port. Optional ->freeze and ->thaw operations notify LLDD that the port is being frozen and thawed, respectively. LLDD can disable/enable hardware interrupt in these callbacks if the controller's IRQ mask can be changed dynamically. If the controller doesn't allow such operation, LLDD can check for frozen state in the interrupt handler and ack/clear interrupts unconditionally while frozen. Signed-off-by: Tejun Heo --- drivers/scsi/libata-core.c | 26 +++++++++++- drivers/scsi/libata-eh.c | 103 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/libata.h | 4 ++ 3 files changed, 131 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 9c97783462d6..63857a90ac28 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -987,6 +987,12 @@ unsigned ata_exec_internal(struct ata_device *dev, spin_lock_irqsave(&ap->host_set->lock, flags); + /* no internal command while frozen */ + if (ap->flags & ATA_FLAG_FROZEN) { + spin_unlock_irqrestore(&ap->host_set->lock, flags); + return AC_ERR_SYSTEM; + } + /* initialize internal qc */ /* XXX: Tag 0 is used for drivers with legacy EH as some @@ -2565,8 +2571,11 @@ void ata_std_postreset(struct ata_port *ap, unsigned int *classes) sata_scr_write(ap, SCR_ERROR, serror); /* re-enable interrupts */ - if (ap->ioaddr.ctl_addr) /* FIXME: hack. create a hook instead */ - ata_irq_on(ap); + if (!ap->ops->error_handler) { + /* FIXME: hack. create a hook instead */ + if (ap->ioaddr.ctl_addr) + ata_irq_on(ap); + } /* is double-select really necessary? */ if (classes[0] != ATA_DEV_NONE) @@ -2681,6 +2690,8 @@ int ata_drive_probe_reset(struct ata_port *ap, ata_probeinit_fn_t probeinit, { int rc = -EINVAL; + ata_eh_freeze_port(ap); + if (probeinit) probeinit(ap); @@ -2725,6 +2736,9 @@ int ata_drive_probe_reset(struct ata_port *ap, ata_probeinit_fn_t probeinit, if (rc == 0) { if (postreset) postreset(ap, classes); + + ata_eh_thaw_port(ap); + if (classes[0] == ATA_DEV_UNKNOWN) rc = -ENODEV; } @@ -4039,6 +4053,10 @@ static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap) struct ata_queued_cmd *qc = NULL; unsigned int i; + /* no command while frozen */ + if (unlikely(ap->flags & ATA_FLAG_FROZEN)) + return NULL; + /* the last tag is reserved for internal command. */ for (i = 0; i < ATA_MAX_QUEUE - 1; i++) if (!test_and_set_bit(i, &ap->qactive)) { @@ -4953,6 +4971,7 @@ int ata_device_add(const struct ata_probe_ent *ent) ata_chk_status(ap); host_set->ops->irq_clear(ap); + ata_eh_freeze_port(ap); /* freeze port before requesting IRQ */ count++; } @@ -5385,5 +5404,8 @@ EXPORT_SYMBOL_GPL(ata_scsi_device_resume); EXPORT_SYMBOL_GPL(ata_eng_timeout); EXPORT_SYMBOL_GPL(ata_port_schedule_eh); EXPORT_SYMBOL_GPL(ata_port_abort); +EXPORT_SYMBOL_GPL(ata_port_freeze); +EXPORT_SYMBOL_GPL(ata_eh_freeze_port); +EXPORT_SYMBOL_GPL(ata_eh_thaw_port); EXPORT_SYMBOL_GPL(ata_eh_qc_complete); EXPORT_SYMBOL_GPL(ata_eh_qc_retry); diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index 037a561809f5..cb4e2b8d32d9 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c @@ -291,6 +291,109 @@ int ata_port_abort(struct ata_port *ap) return nr_aborted; } +/** + * __ata_port_freeze - freeze port + * @ap: ATA port to freeze + * + * This function is called when HSM violation or some other + * condition disrupts normal operation of the port. Frozen port + * is not allowed to perform any operation until the port is + * thawed, which usually follows a successful reset. + * + * ap->ops->freeze() callback can be used for freezing the port + * hardware-wise (e.g. mask interrupt and stop DMA engine). If a + * port cannot be frozen hardware-wise, the interrupt handler + * must ack and clear interrupts unconditionally while the port + * is frozen. + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + */ +static void __ata_port_freeze(struct ata_port *ap) +{ + WARN_ON(!ap->ops->error_handler); + + if (ap->ops->freeze) + ap->ops->freeze(ap); + + ap->flags |= ATA_FLAG_FROZEN; + + DPRINTK("ata%u port frozen\n", ap->id); +} + +/** + * ata_port_freeze - abort & freeze port + * @ap: ATA port to freeze + * + * Abort and freeze @ap. + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + * + * RETURNS: + * Number of aborted commands. + */ +int ata_port_freeze(struct ata_port *ap) +{ + int nr_aborted; + + WARN_ON(!ap->ops->error_handler); + + nr_aborted = ata_port_abort(ap); + __ata_port_freeze(ap); + + return nr_aborted; +} + +/** + * ata_eh_freeze_port - EH helper to freeze port + * @ap: ATA port to freeze + * + * Freeze @ap. + * + * LOCKING: + * None. + */ +void ata_eh_freeze_port(struct ata_port *ap) +{ + unsigned long flags; + + if (!ap->ops->error_handler) + return; + + spin_lock_irqsave(&ap->host_set->lock, flags); + __ata_port_freeze(ap); + spin_unlock_irqrestore(&ap->host_set->lock, flags); +} + +/** + * ata_port_thaw_port - EH helper to thaw port + * @ap: ATA port to thaw + * + * Thaw frozen port @ap. + * + * LOCKING: + * None. + */ +void ata_eh_thaw_port(struct ata_port *ap) +{ + unsigned long flags; + + if (!ap->ops->error_handler) + return; + + spin_lock_irqsave(&ap->host_set->lock, flags); + + ap->flags &= ~ATA_FLAG_FROZEN; + + if (ap->ops->thaw) + ap->ops->thaw(ap); + + spin_unlock_irqrestore(&ap->host_set->lock, flags); + + DPRINTK("ata%u port thawed\n", ap->id); +} + static void ata_eh_scsidone(struct scsi_cmnd *scmd) { /* nada */ diff --git a/include/linux/libata.h b/include/linux/libata.h index 086e14690954..6758b4d374a0 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -665,6 +665,10 @@ extern void ata_eng_timeout(struct ata_port *ap); extern void ata_port_schedule_eh(struct ata_port *ap); extern int ata_port_abort(struct ata_port *ap); +extern int ata_port_freeze(struct ata_port *ap); + +extern void ata_eh_freeze_port(struct ata_port *ap); +extern void ata_eh_thaw_port(struct ata_port *ap); extern void ata_eh_qc_complete(struct ata_queued_cmd *qc); extern void ata_eh_qc_retry(struct ata_queued_cmd *qc); -- cgit v1.2.3 From ad9e27624479bd167dd7eac0cea4bb3ad13bc926 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:58:12 +0900 Subject: [PATCH] libata-eh-fw: update ata_scsi_error() for new EH Update ata_scsi_error() for new EH. ata_scsi_error() is responsible for claiming timed out qcs and invoking ->error_handler in safe and synchronized manner. As the state of the controller is unknown if a qc has timed out, the port is frozen in such cases. Note that ata_scsi_timed_out() isn't used for new EH. This is because a timed out qc cannot be claimed by EH without freezing the port and freezing the port in ata_scsi_timed_out() results in unnecessary abortion of other active qcs. ata_scsi_timed_out() can be removed once all drivers are converted to new EH. While at it, add 'TODO: kill' comments to old EH functions. Signed-off-by: Tejun Heo --- drivers/scsi/libata-eh.c | 136 +++++++++++++++++++++++++++++++++++++++++++++-- include/linux/libata.h | 3 ++ 2 files changed, 134 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index cb4e2b8d32d9..0803231f6577 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c @@ -44,6 +44,8 @@ #include "libata.h" +static void __ata_port_freeze(struct ata_port *ap); + /** * ata_scsi_timed_out - SCSI layer time out callback * @cmd: timed out SCSI command @@ -55,6 +57,8 @@ * from finishing it by setting EH_SCHEDULED and return * EH_NOT_HANDLED. * + * TODO: kill this function once old EH is gone. + * * LOCKING: * Called from timer context * @@ -67,10 +71,16 @@ enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd) struct ata_port *ap = ata_shost_to_port(host); unsigned long flags; struct ata_queued_cmd *qc; - enum scsi_eh_timer_return ret = EH_HANDLED; + enum scsi_eh_timer_return ret; DPRINTK("ENTER\n"); + if (ap->ops->error_handler) { + ret = EH_NOT_HANDLED; + goto out; + } + + ret = EH_HANDLED; spin_lock_irqsave(&ap->host_set->lock, flags); qc = ata_qc_from_tag(ap, ap->active_tag); if (qc) { @@ -81,6 +91,7 @@ enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd) } spin_unlock_irqrestore(&ap->host_set->lock, flags); + out: DPRINTK("EXIT, ret=%d\n", ret); return ret; } @@ -100,21 +111,132 @@ enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd) void ata_scsi_error(struct Scsi_Host *host) { struct ata_port *ap = ata_shost_to_port(host); + spinlock_t *hs_lock = &ap->host_set->lock; + int i, repeat_cnt = ATA_EH_MAX_REPEAT; + unsigned long flags; DPRINTK("ENTER\n"); - /* synchronize with IRQ handler and port task */ - spin_unlock_wait(&ap->host_set->lock); + /* synchronize with port task */ ata_port_flush_task(ap); - WARN_ON(ata_qc_from_tag(ap, ap->active_tag) == NULL); + /* synchronize with host_set lock and sort out timeouts */ + + /* For new EH, all qcs are finished in one of three ways - + * normal completion, error completion, and SCSI timeout. + * Both cmpletions can race against SCSI timeout. When normal + * completion wins, the qc never reaches EH. When error + * completion wins, the qc has ATA_QCFLAG_FAILED set. + * + * When SCSI timeout wins, things are a bit more complex. + * Normal or error completion can occur after the timeout but + * before this point. In such cases, both types of + * completions are honored. A scmd is determined to have + * timed out iff its associated qc is active and not failed. + */ + if (ap->ops->error_handler) { + struct scsi_cmnd *scmd, *tmp; + int nr_timedout = 0; + + spin_lock_irqsave(hs_lock, flags); + + list_for_each_entry_safe(scmd, tmp, &host->eh_cmd_q, eh_entry) { + struct ata_queued_cmd *qc; + + for (i = 0; i < ATA_MAX_QUEUE; i++) { + qc = __ata_qc_from_tag(ap, i); + if (qc->flags & ATA_QCFLAG_ACTIVE && + qc->scsicmd == scmd) + break; + } + + if (i < ATA_MAX_QUEUE) { + /* the scmd has an associated qc */ + if (!(qc->flags & ATA_QCFLAG_FAILED)) { + /* which hasn't failed yet, timeout */ + qc->err_mask |= AC_ERR_TIMEOUT; + qc->flags |= ATA_QCFLAG_FAILED; + nr_timedout++; + } + } else { + /* Normal completion occurred after + * SCSI timeout but before this point. + * Successfully complete it. + */ + scmd->retries = scmd->allowed; + scsi_eh_finish_cmd(scmd, &ap->eh_done_q); + } + } + + /* If we have timed out qcs. They belong to EH from + * this point but the state of the controller is + * unknown. Freeze the port to make sure the IRQ + * handler doesn't diddle with those qcs. This must + * be done atomically w.r.t. setting QCFLAG_FAILED. + */ + if (nr_timedout) + __ata_port_freeze(ap); + + spin_unlock_irqrestore(hs_lock, flags); + } else + spin_unlock_wait(hs_lock); + + repeat: + /* invoke error handler */ + if (ap->ops->error_handler) { + /* clear EH pending */ + spin_lock_irqsave(hs_lock, flags); + ap->flags &= ~ATA_FLAG_EH_PENDING; + spin_unlock_irqrestore(hs_lock, flags); + + /* invoke EH */ + ap->ops->error_handler(ap); + + /* Exception might have happend after ->error_handler + * recovered the port but before this point. Repeat + * EH in such case. + */ + spin_lock_irqsave(hs_lock, flags); + + if (ap->flags & ATA_FLAG_EH_PENDING) { + if (--repeat_cnt) { + ata_port_printk(ap, KERN_INFO, + "EH pending after completion, " + "repeating EH (cnt=%d)\n", repeat_cnt); + spin_unlock_irqrestore(hs_lock, flags); + goto repeat; + } + ata_port_printk(ap, KERN_ERR, "EH pending after %d " + "tries, giving up\n", ATA_EH_MAX_REPEAT); + } - ap->ops->eng_timeout(ap); + /* Clear host_eh_scheduled while holding hs_lock such + * that if exception occurs after this point but + * before EH completion, SCSI midlayer will + * re-initiate EH. + */ + host->host_eh_scheduled = 0; + + spin_unlock_irqrestore(hs_lock, flags); + } else { + WARN_ON(ata_qc_from_tag(ap, ap->active_tag) == NULL); + ap->ops->eng_timeout(ap); + } + /* finish or retry handled scmd's and clean up */ WARN_ON(host->host_failed || !list_empty(&host->eh_cmd_q)); scsi_eh_flush_done_q(&ap->eh_done_q); + /* clean up */ + spin_lock_irqsave(hs_lock, flags); + + if (ap->flags & ATA_FLAG_RECOVERED) + ata_port_printk(ap, KERN_INFO, "EH complete\n"); + ap->flags &= ~ATA_FLAG_RECOVERED; + + spin_unlock_irqrestore(hs_lock, flags); + DPRINTK("EXIT\n"); } @@ -133,6 +255,8 @@ void ata_scsi_error(struct Scsi_Host *host) * an interrupt was not delivered to the driver, even though the * transaction completed successfully. * + * TODO: kill this function once old EH is gone. + * * LOCKING: * Inherited from SCSI layer (none, can sleep) */ @@ -198,6 +322,8 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc) * an interrupt was not delivered to the driver, even though the * transaction completed successfully. * + * TODO: kill this function once old EH is gone. + * * LOCKING: * Inherited from SCSI layer (none, can sleep) */ diff --git a/include/linux/libata.h b/include/linux/libata.h index 6758b4d374a0..5ad50163c8ef 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -225,6 +225,9 @@ enum { ATA_PORT_PRIMARY = (1 << 0), ATA_PORT_SECONDARY = (1 << 1), + /* max repeat if error condition is still set after ->error_handler */ + ATA_EH_MAX_REPEAT = 5, + /* how hard are we gonna try to probe/recover devices */ ATA_PROBE_MAX_TRIES = 3, }; -- cgit v1.2.3 From 9be1e979f2e1e57a091a658fa88dac266f9fd6fe Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:58:17 +0900 Subject: [PATCH] libata-eh: add ATA and libata flags for new EH Add ATA and libata flags to be used by new EH. Signed-off-by: Tejun Heo --- include/linux/ata.h | 13 +++++++++++++ include/linux/libata.h | 8 ++++++++ 2 files changed, 21 insertions(+) (limited to 'include') diff --git a/include/linux/ata.h b/include/linux/ata.h index 312a2c0c64e6..a7c41f3df8f4 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -97,6 +97,9 @@ enum { ATA_DRQ = (1 << 3), /* data request i/o */ ATA_ERR = (1 << 0), /* have an error */ ATA_SRST = (1 << 2), /* software reset */ + ATA_ICRC = (1 << 7), /* interface CRC error */ + ATA_UNC = (1 << 6), /* uncorrectable media error */ + ATA_IDNF = (1 << 4), /* ID not found */ ATA_ABORTED = (1 << 2), /* command aborted */ /* ATA command block registers */ @@ -192,6 +195,16 @@ enum { SCR_ACTIVE = 3, SCR_NOTIFICATION = 4, + /* SError bits */ + SERR_DATA_RECOVERED = (1 << 0), /* recovered data error */ + SERR_COMM_RECOVERED = (1 << 1), /* recovered comm failure */ + SERR_DATA = (1 << 8), /* unrecovered data error */ + SERR_PERSISTENT = (1 << 9), /* persistent data/comm error */ + SERR_PROTOCOL = (1 << 10), /* protocol violation */ + SERR_INTERNAL = (1 << 11), /* host internal error */ + SERR_PHYRDY_CHG = (1 << 16), /* PHY RDY changed */ + SERR_DEV_XCHG = (1 << 26), /* device exchanged */ + /* struct ata_taskfile flags */ ATA_TFLAG_LBA48 = (1 << 0), /* enable 48-bit LBA and "HOB" */ ATA_TFLAG_ISADDR = (1 << 1), /* enable r/w to nsect/lba regs */ diff --git a/include/linux/libata.h b/include/linux/libata.h index 5ad50163c8ef..6fe5ed8eabf5 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -155,6 +155,7 @@ enum { ATA_FLAG_EH_PENDING = (1 << 16), /* EH pending */ ATA_FLAG_FROZEN = (1 << 17), /* port is frozen */ + ATA_FLAG_RECOVERED = (1 << 18), /* recovery action performed */ ATA_FLAG_DISABLED = (1 << 22), /* port is disabled, ignore it */ ATA_FLAG_SUSPENDED = (1 << 23), /* port is suspended (power) */ @@ -225,6 +226,13 @@ enum { ATA_PORT_PRIMARY = (1 << 0), ATA_PORT_SECONDARY = (1 << 1), + /* reset / recovery action types */ + ATA_EH_REVALIDATE = (1 << 0), + ATA_EH_SOFTRESET = (1 << 1), + ATA_EH_HARDRESET = (1 << 2), + + ATA_EH_RESET_MASK = ATA_EH_SOFTRESET | ATA_EH_HARDRESET, + /* max repeat if error condition is still set after ->error_handler */ ATA_EH_MAX_REPEAT = 5, -- cgit v1.2.3 From 0c247c559cd70f85ba9f0764ce13ae00e20fcad8 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:58:19 +0900 Subject: [PATCH] libata-eh: implement dev->ering This patch implements ata_ering and uses it to define dev->ering. ata_ering is a ring buffer which records libata errors - whether a command was for normar IO request, err_mask and timestamp. Errors are recorded per-device in dev->ering. This will be used by EH to determine recovery actions. Signed-off-by: Tejun Heo --- drivers/scsi/libata-eh.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/libata.h | 17 +++++++++++++++++ 2 files changed, 62 insertions(+) (limited to 'include') diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index 0803231f6577..71ad18b7cff6 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c @@ -46,6 +46,51 @@ static void __ata_port_freeze(struct ata_port *ap); +static void ata_ering_record(struct ata_ering *ering, int is_io, + unsigned int err_mask) +{ + struct ata_ering_entry *ent; + + WARN_ON(!err_mask); + + ering->cursor++; + ering->cursor %= ATA_ERING_SIZE; + + ent = &ering->ring[ering->cursor]; + ent->is_io = is_io; + ent->err_mask = err_mask; + ent->timestamp = get_jiffies_64(); +} + +static struct ata_ering_entry * ata_ering_top(struct ata_ering *ering) +{ + struct ata_ering_entry *ent = &ering->ring[ering->cursor]; + if (!ent->err_mask) + return NULL; + return ent; +} + +static int ata_ering_map(struct ata_ering *ering, + int (*map_fn)(struct ata_ering_entry *, void *), + void *arg) +{ + int idx, rc = 0; + struct ata_ering_entry *ent; + + idx = ering->cursor; + do { + ent = &ering->ring[idx]; + if (!ent->err_mask) + break; + rc = map_fn(ent, arg); + if (rc) + break; + idx = (idx - 1 + ATA_ERING_SIZE) % ATA_ERING_SIZE; + } while (idx != ering->cursor); + + return rc; +} + /** * ata_scsi_timed_out - SCSI layer time out callback * @cmd: timed out SCSI command diff --git a/include/linux/libata.h b/include/linux/libata.h index 6fe5ed8eabf5..f5cea13599c3 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -226,6 +226,9 @@ enum { ATA_PORT_PRIMARY = (1 << 0), ATA_PORT_SECONDARY = (1 << 1), + /* ering size */ + ATA_ERING_SIZE = 32, + /* reset / recovery action types */ ATA_EH_REVALIDATE = (1 << 0), ATA_EH_SOFTRESET = (1 << 1), @@ -375,6 +378,17 @@ struct ata_host_stats { unsigned long rw_reqbuf; }; +struct ata_ering_entry { + int is_io; + unsigned int err_mask; + u64 timestamp; +}; + +struct ata_ering { + int cursor; + struct ata_ering_entry ring[ATA_ERING_SIZE]; +}; + struct ata_device { struct ata_port *ap; u64 n_sectors; /* size of device, if ATA */ @@ -401,6 +415,9 @@ struct ata_device { u16 cylinders; /* Number of cylinders */ u16 heads; /* Number of heads */ u16 sectors; /* Number of sectors per track */ + + /* error history */ + struct ata_ering ering; }; struct ata_port { -- cgit v1.2.3 From f3e81b19aac23c0e8c55d5961324ef7de44c23bb Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:58:21 +0900 Subject: [PATCH] libata-eh: implement ata_eh_info and ata_eh_context struct ata_eh_info serves as the communication channel between execution path and EH. Execution path describes detected error condition in ap->eh_info and EH recovers the port using it. To avoid missing error conditions detected during EH, EH makes its own copy of eh_info and clears it on entry allowing error info to accumulate during EH. Most EH states including EH's copy of eh_info are stored in ap->eh_context (struct ata_eh_context) which is owned by EH and thus doesn't require any synchronization to access and alter. This standardized context makes it easy to integrate various parts of EH and extend EH to handle multiple links (for PM). Signed-off-by: Tejun Heo --- drivers/scsi/libata-eh.c | 11 ++++++++++- include/linux/libata.h | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index 71ad18b7cff6..1968f2d140f3 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c @@ -229,9 +229,15 @@ void ata_scsi_error(struct Scsi_Host *host) repeat: /* invoke error handler */ if (ap->ops->error_handler) { - /* clear EH pending */ + /* fetch & clear EH info */ spin_lock_irqsave(hs_lock, flags); + + memset(&ap->eh_context, 0, sizeof(ap->eh_context)); + ap->eh_context.i = ap->eh_info; + memset(&ap->eh_info, 0, sizeof(ap->eh_info)); + ap->flags &= ~ATA_FLAG_EH_PENDING; + spin_unlock_irqrestore(hs_lock, flags); /* invoke EH */ @@ -255,6 +261,9 @@ void ata_scsi_error(struct Scsi_Host *host) "tries, giving up\n", ATA_EH_MAX_REPEAT); } + /* this run is complete, make sure EH info is clear */ + memset(&ap->eh_info, 0, sizeof(ap->eh_info)); + /* Clear host_eh_scheduled while holding hs_lock such * that if exception occurs after this point but * before EH completion, SCSI midlayer will diff --git a/include/linux/libata.h b/include/linux/libata.h index f5cea13599c3..298f9918e375 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -229,6 +229,9 @@ enum { /* ering size */ ATA_ERING_SIZE = 32, + /* desc_len for ata_eh_info and context */ + ATA_EH_DESC_LEN = 80, + /* reset / recovery action types */ ATA_EH_REVALIDATE = (1 << 0), ATA_EH_SOFTRESET = (1 << 1), @@ -236,6 +239,9 @@ enum { ATA_EH_RESET_MASK = ATA_EH_SOFTRESET | ATA_EH_HARDRESET, + /* ata_eh_info->flags */ + ATA_EHI_DID_RESET = (1 << 0), /* already reset this port */ + /* max repeat if error condition is still set after ->error_handler */ ATA_EH_MAX_REPEAT = 5, @@ -420,6 +426,21 @@ struct ata_device { struct ata_ering ering; }; +struct ata_eh_info { + struct ata_device *dev; /* offending device */ + u32 serror; /* SError from LLDD */ + unsigned int err_mask; /* port-wide err_mask */ + unsigned int action; /* ATA_EH_* action mask */ + unsigned int flags; /* ATA_EHI_* flags */ + char desc[ATA_EH_DESC_LEN]; + int desc_len; +}; + +struct ata_eh_context { + struct ata_eh_info i; + int tries[ATA_MAX_DEVICES]; +}; + struct ata_port { struct Scsi_Host *host; /* our co-allocated scsi host */ const struct ata_port_operations *ops; @@ -444,6 +465,11 @@ struct ata_port { unsigned int cbl; /* cable type; ATA_CBL_xxx */ unsigned int sata_spd_limit; /* SATA PHY speed limit */ + /* record runtime error info, protected by host_set lock */ + struct ata_eh_info eh_info; + /* EH context owned by EH */ + struct ata_eh_context eh_context; + struct ata_device device[ATA_MAX_DEVICES]; struct ata_queued_cmd qcmd[ATA_MAX_QUEUE]; @@ -710,6 +736,20 @@ extern void ata_eh_qc_retry(struct ata_queued_cmd *qc); #define ata_dev_printk(dev, lv, fmt, args...) \ printk(lv"ata%u.%02u: "fmt, (dev)->ap->id, (dev)->devno , ##args) +/* + * ata_eh_info helpers + */ +#define ata_ehi_push_desc(ehi, fmt, args...) do { \ + (ehi)->desc_len += scnprintf((ehi)->desc + (ehi)->desc_len, \ + ATA_EH_DESC_LEN - (ehi)->desc_len, \ + fmt , ##args); \ +} while (0) + +#define ata_ehi_clear_desc(ehi) do { \ + (ehi)->desc[0] = '\0'; \ + (ehi)->desc_len = 0; \ +} while (0) + /* * qc helpers */ -- cgit v1.2.3 From 022bdb075b9e1f224088a0b268de56268d7bc5b6 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:58:22 +0900 Subject: [PATCH] libata-eh: implement new EH Implement new EH. The exported interface is ata_do_eh() which is to be called from ->error_handler and performs the following steps to recover the failed port. ata_eh_autopsy() : analyze SError/TF, determine the cause of failure and required recovery actions and record it in ap->eh_context ata_eh_report() : report the failure to user ata_eh_recover() : perform recovery actions described in ap->eh_context ata_eh_finish() : finish failed qcs LLDDs can customize error handling by modifying eh_context before calling ata_do_eh() or, if necessary, doing so inbetween each major steps by calling each step explicitly. Signed-off-by: Tejun Heo --- drivers/scsi/libata-core.c | 1 + drivers/scsi/libata-eh.c | 775 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/libata.h | 5 + 3 files changed, 781 insertions(+) (limited to 'include') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 4def48ed6f46..ddc47097d37e 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -5440,3 +5440,4 @@ EXPORT_SYMBOL_GPL(ata_eh_freeze_port); EXPORT_SYMBOL_GPL(ata_eh_thaw_port); EXPORT_SYMBOL_GPL(ata_eh_qc_complete); EXPORT_SYMBOL_GPL(ata_eh_qc_retry); +EXPORT_SYMBOL_GPL(ata_do_eh); diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index 1968f2d140f3..cd133f83e595 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c @@ -626,3 +626,778 @@ void ata_eh_qc_retry(struct ata_queued_cmd *qc) scmd->retries--; __ata_eh_qc_complete(qc); } + +/** + * ata_eh_about_to_do - about to perform eh_action + * @ap: target ATA port + * @action: action about to be performed + * + * Called just before performing EH actions to clear related bits + * in @ap->eh_info such that eh actions are not unnecessarily + * repeated. + * + * LOCKING: + * None. + */ +static void ata_eh_about_to_do(struct ata_port *ap, unsigned int action) +{ + unsigned long flags; + + spin_lock_irqsave(&ap->host_set->lock, flags); + ap->eh_info.action &= ~action; + ap->flags |= ATA_FLAG_RECOVERED; + spin_unlock_irqrestore(&ap->host_set->lock, flags); +} + +/** + * ata_err_string - convert err_mask to descriptive string + * @err_mask: error mask to convert to string + * + * Convert @err_mask to descriptive string. Errors are + * prioritized according to severity and only the most severe + * error is reported. + * + * LOCKING: + * None. + * + * RETURNS: + * Descriptive string for @err_mask + */ +static const char * ata_err_string(unsigned int err_mask) +{ + if (err_mask & AC_ERR_HOST_BUS) + return "host bus error"; + if (err_mask & AC_ERR_ATA_BUS) + return "ATA bus error"; + if (err_mask & AC_ERR_TIMEOUT) + return "timeout"; + if (err_mask & AC_ERR_HSM) + return "HSM violation"; + if (err_mask & AC_ERR_SYSTEM) + return "internal error"; + if (err_mask & AC_ERR_MEDIA) + return "media error"; + if (err_mask & AC_ERR_INVALID) + return "invalid argument"; + if (err_mask & AC_ERR_DEV) + return "device error"; + return "unknown error"; +} + +/** + * atapi_eh_request_sense - perform ATAPI REQUEST_SENSE + * @dev: device to perform REQUEST_SENSE to + * @sense_buf: result sense data buffer (SCSI_SENSE_BUFFERSIZE bytes long) + * + * Perform ATAPI REQUEST_SENSE after the device reported CHECK + * SENSE. This function is EH helper. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, AC_ERR_* mask on failure + */ +static unsigned int atapi_eh_request_sense(struct ata_device *dev, + unsigned char *sense_buf) +{ + struct ata_port *ap = dev->ap; + struct ata_taskfile tf; + u8 cdb[ATAPI_CDB_LEN]; + + DPRINTK("ATAPI request sense\n"); + + ata_tf_init(dev, &tf); + + /* FIXME: is this needed? */ + memset(sense_buf, 0, SCSI_SENSE_BUFFERSIZE); + + /* XXX: why tf_read here? */ + ap->ops->tf_read(ap, &tf); + + /* fill these in, for the case where they are -not- overwritten */ + sense_buf[0] = 0x70; + sense_buf[2] = tf.feature >> 4; + + memset(cdb, 0, ATAPI_CDB_LEN); + cdb[0] = REQUEST_SENSE; + cdb[4] = SCSI_SENSE_BUFFERSIZE; + + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.command = ATA_CMD_PACKET; + + /* is it pointless to prefer PIO for "safety reasons"? */ + if (ap->flags & ATA_FLAG_PIO_DMA) { + tf.protocol = ATA_PROT_ATAPI_DMA; + tf.feature |= ATAPI_PKT_DMA; + } else { + tf.protocol = ATA_PROT_ATAPI; + tf.lbam = (8 * 1024) & 0xff; + tf.lbah = (8 * 1024) >> 8; + } + + return ata_exec_internal(dev, &tf, cdb, DMA_FROM_DEVICE, + sense_buf, SCSI_SENSE_BUFFERSIZE); +} + +/** + * ata_eh_analyze_serror - analyze SError for a failed port + * @ap: ATA port to analyze SError for + * + * Analyze SError if available and further determine cause of + * failure. + * + * LOCKING: + * None. + */ +static void ata_eh_analyze_serror(struct ata_port *ap) +{ + struct ata_eh_context *ehc = &ap->eh_context; + u32 serror = ehc->i.serror; + unsigned int err_mask = 0, action = 0; + + if (serror & SERR_PERSISTENT) { + err_mask |= AC_ERR_ATA_BUS; + action |= ATA_EH_HARDRESET; + } + if (serror & + (SERR_DATA_RECOVERED | SERR_COMM_RECOVERED | SERR_DATA)) { + err_mask |= AC_ERR_ATA_BUS; + action |= ATA_EH_SOFTRESET; + } + if (serror & SERR_PROTOCOL) { + err_mask |= AC_ERR_HSM; + action |= ATA_EH_SOFTRESET; + } + if (serror & SERR_INTERNAL) { + err_mask |= AC_ERR_SYSTEM; + action |= ATA_EH_SOFTRESET; + } + if (serror & (SERR_PHYRDY_CHG | SERR_DEV_XCHG)) { + err_mask |= AC_ERR_ATA_BUS; + action |= ATA_EH_HARDRESET; + } + + ehc->i.err_mask |= err_mask; + ehc->i.action |= action; +} + +/** + * ata_eh_analyze_tf - analyze taskfile of a failed qc + * @qc: qc to analyze + * @tf: Taskfile registers to analyze + * + * Analyze taskfile of @qc and further determine cause of + * failure. This function also requests ATAPI sense data if + * avaliable. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * Determined recovery action + */ +static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc, + const struct ata_taskfile *tf) +{ + unsigned int tmp, action = 0; + u8 stat = tf->command, err = tf->feature; + + if ((stat & (ATA_BUSY | ATA_DRQ | ATA_DRDY)) != ATA_DRDY) { + qc->err_mask |= AC_ERR_HSM; + return ATA_EH_SOFTRESET; + } + + if (!(qc->err_mask & AC_ERR_DEV)) + return 0; + + switch (qc->dev->class) { + case ATA_DEV_ATA: + if (err & ATA_ICRC) + qc->err_mask |= AC_ERR_ATA_BUS; + if (err & ATA_UNC) + qc->err_mask |= AC_ERR_MEDIA; + if (err & ATA_IDNF) + qc->err_mask |= AC_ERR_INVALID; + break; + + case ATA_DEV_ATAPI: + tmp = atapi_eh_request_sense(qc->dev, + qc->scsicmd->sense_buffer); + if (!tmp) { + /* ATA_QCFLAG_SENSE_VALID is used to tell + * atapi_qc_complete() that sense data is + * already valid. + * + * TODO: interpret sense data and set + * appropriate err_mask. + */ + qc->flags |= ATA_QCFLAG_SENSE_VALID; + } else + qc->err_mask |= tmp; + } + + if (qc->err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT | AC_ERR_ATA_BUS)) + action |= ATA_EH_SOFTRESET; + + return action; +} + +static int ata_eh_categorize_ering_entry(struct ata_ering_entry *ent) +{ + if (ent->err_mask & (AC_ERR_ATA_BUS | AC_ERR_TIMEOUT)) + return 1; + + if (ent->is_io) { + if (ent->err_mask & AC_ERR_HSM) + return 1; + if ((ent->err_mask & + (AC_ERR_DEV|AC_ERR_MEDIA|AC_ERR_INVALID)) == AC_ERR_DEV) + return 2; + } + + return 0; +} + +struct speed_down_needed_arg { + u64 since; + int nr_errors[3]; +}; + +static int speed_down_needed_cb(struct ata_ering_entry *ent, void *void_arg) +{ + struct speed_down_needed_arg *arg = void_arg; + + if (ent->timestamp < arg->since) + return -1; + + arg->nr_errors[ata_eh_categorize_ering_entry(ent)]++; + return 0; +} + +/** + * ata_eh_speed_down_needed - Determine wheter speed down is necessary + * @dev: Device of interest + * + * This function examines error ring of @dev and determines + * whether speed down is necessary. Speed down is necessary if + * there have been more than 3 of Cat-1 errors or 10 of Cat-2 + * errors during last 15 minutes. + * + * Cat-1 errors are ATA_BUS, TIMEOUT for any command and HSM + * violation for known supported commands. + * + * Cat-2 errors are unclassified DEV error for known supported + * command. + * + * LOCKING: + * Inherited from caller. + * + * RETURNS: + * 1 if speed down is necessary, 0 otherwise + */ +static int ata_eh_speed_down_needed(struct ata_device *dev) +{ + const u64 interval = 15LLU * 60 * HZ; + static const int err_limits[3] = { -1, 3, 10 }; + struct speed_down_needed_arg arg; + struct ata_ering_entry *ent; + int err_cat; + u64 j64; + + ent = ata_ering_top(&dev->ering); + if (!ent) + return 0; + + err_cat = ata_eh_categorize_ering_entry(ent); + if (err_cat == 0) + return 0; + + memset(&arg, 0, sizeof(arg)); + + j64 = get_jiffies_64(); + if (j64 >= interval) + arg.since = j64 - interval; + else + arg.since = 0; + + ata_ering_map(&dev->ering, speed_down_needed_cb, &arg); + + return arg.nr_errors[err_cat] > err_limits[err_cat]; +} + +/** + * ata_eh_speed_down - record error and speed down if necessary + * @dev: Failed device + * @is_io: Did the device fail during normal IO? + * @err_mask: err_mask of the error + * + * Record error and examine error history to determine whether + * adjusting transmission speed is necessary. It also sets + * transmission limits appropriately if such adjustment is + * necessary. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno otherwise + */ +static int ata_eh_speed_down(struct ata_device *dev, int is_io, + unsigned int err_mask) +{ + if (!err_mask) + return 0; + + /* record error and determine whether speed down is necessary */ + ata_ering_record(&dev->ering, is_io, err_mask); + + if (!ata_eh_speed_down_needed(dev)) + return 0; + + /* speed down SATA link speed if possible */ + if (sata_down_spd_limit(dev->ap) == 0) + return ATA_EH_HARDRESET; + + /* lower transfer mode */ + if (ata_down_xfermask_limit(dev, 0) == 0) + return ATA_EH_SOFTRESET; + + ata_dev_printk(dev, KERN_ERR, + "speed down requested but no transfer mode left\n"); + return 0; +} + +/** + * ata_eh_autopsy - analyze error and determine recovery action + * @ap: ATA port to perform autopsy on + * + * Analyze why @ap failed and determine which recovery action is + * needed. This function also sets more detailed AC_ERR_* values + * and fills sense data for ATAPI CHECK SENSE. + * + * LOCKING: + * Kernel thread context (may sleep). + */ +static void ata_eh_autopsy(struct ata_port *ap) +{ + struct ata_eh_context *ehc = &ap->eh_context; + unsigned int action = ehc->i.action; + struct ata_device *failed_dev = NULL; + unsigned int all_err_mask = 0; + int tag, is_io = 0; + u32 serror; + int rc; + + DPRINTK("ENTER\n"); + + /* obtain and analyze SError */ + rc = sata_scr_read(ap, SCR_ERROR, &serror); + if (rc == 0) { + ehc->i.serror |= serror; + ata_eh_analyze_serror(ap); + } else if (rc != -EOPNOTSUPP) + action |= ATA_EH_HARDRESET; + + /* any real error trumps AC_ERR_OTHER */ + if (ehc->i.err_mask & ~AC_ERR_OTHER) + ehc->i.err_mask &= ~AC_ERR_OTHER; + + all_err_mask |= ehc->i.err_mask; + + for (tag = 0; tag < ATA_MAX_QUEUE; tag++) { + struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag); + + if (!(qc->flags & ATA_QCFLAG_FAILED)) + continue; + + /* inherit upper level err_mask */ + qc->err_mask |= ehc->i.err_mask; + + if (qc->err_mask & AC_ERR_TIMEOUT) + action |= ATA_EH_SOFTRESET; + + /* analyze TF */ + action |= ata_eh_analyze_tf(qc, &qc->result_tf); + + /* DEV errors are probably spurious in case of ATA_BUS error */ + if (qc->err_mask & AC_ERR_ATA_BUS) + qc->err_mask &= ~(AC_ERR_DEV | AC_ERR_MEDIA | + AC_ERR_INVALID); + + /* any real error trumps unknown error */ + if (qc->err_mask & ~AC_ERR_OTHER) + qc->err_mask &= ~AC_ERR_OTHER; + + /* SENSE_VALID trumps dev/unknown error and revalidation */ + if (qc->flags & ATA_QCFLAG_SENSE_VALID) { + qc->err_mask &= ~(AC_ERR_DEV | AC_ERR_OTHER); + action &= ~ATA_EH_REVALIDATE; + } + + /* accumulate error info */ + failed_dev = qc->dev; + all_err_mask |= qc->err_mask; + if (qc->flags & ATA_QCFLAG_IO) + is_io = 1; + } + + /* speed down iff command was in progress */ + if (failed_dev) + action |= ata_eh_speed_down(failed_dev, is_io, all_err_mask); + + if (all_err_mask) + action |= ATA_EH_REVALIDATE; + + ehc->i.dev = failed_dev; + ehc->i.action = action; + + DPRINTK("EXIT\n"); +} + +/** + * ata_eh_report - report error handling to user + * @ap: ATA port EH is going on + * + * Report EH to user. + * + * LOCKING: + * None. + */ +static void ata_eh_report(struct ata_port *ap) +{ + struct ata_eh_context *ehc = &ap->eh_context; + const char *frozen, *desc; + int tag, nr_failed = 0; + + desc = NULL; + if (ehc->i.desc[0] != '\0') + desc = ehc->i.desc; + + for (tag = 0; tag < ATA_MAX_QUEUE; tag++) { + struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag); + + if (!(qc->flags & ATA_QCFLAG_FAILED)) + continue; + if (qc->flags & ATA_QCFLAG_SENSE_VALID && !qc->err_mask) + continue; + + nr_failed++; + } + + if (!nr_failed && !ehc->i.err_mask) + return; + + frozen = ""; + if (ap->flags & ATA_FLAG_FROZEN) + frozen = " frozen"; + + if (ehc->i.dev) { + ata_dev_printk(ehc->i.dev, KERN_ERR, + "exception Emask 0x%x SErr 0x%x action 0x%x%s\n", + ehc->i.err_mask, ehc->i.serror, ehc->i.action, + frozen); + if (desc) + ata_dev_printk(ehc->i.dev, KERN_ERR, "(%s)\n", desc); + } else { + ata_port_printk(ap, KERN_ERR, + "exception Emask 0x%x SErr 0x%x action 0x%x%s\n", + ehc->i.err_mask, ehc->i.serror, ehc->i.action, + frozen); + if (desc) + ata_port_printk(ap, KERN_ERR, "(%s)\n", desc); + } + + for (tag = 0; tag < ATA_MAX_QUEUE; tag++) { + struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag); + + if (!(qc->flags & ATA_QCFLAG_FAILED) || !qc->err_mask) + continue; + + ata_dev_printk(qc->dev, KERN_ERR, "tag %d cmd 0x%x " + "Emask 0x%x stat 0x%x err 0x%x (%s)\n", + qc->tag, qc->tf.command, qc->err_mask, + qc->result_tf.command, qc->result_tf.feature, + ata_err_string(qc->err_mask)); + } +} + +static int ata_eh_reset(struct ata_port *ap, ata_reset_fn_t softreset, + ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) +{ + struct ata_eh_context *ehc = &ap->eh_context; + unsigned int classes[ATA_MAX_DEVICES]; + int tries = ATA_EH_RESET_TRIES; + ata_reset_fn_t reset; + int rc; + + if (softreset && (!hardreset || (!sata_set_spd_needed(ap) && + !(ehc->i.action & ATA_EH_HARDRESET)))) + reset = softreset; + else + reset = hardreset; + + retry: + ata_port_printk(ap, KERN_INFO, "%s resetting port\n", + reset == softreset ? "soft" : "hard"); + + /* reset */ + ata_eh_about_to_do(ap, ATA_EH_RESET_MASK); + ehc->i.flags |= ATA_EHI_DID_RESET; + + rc = ata_do_reset(ap, reset, classes); + + if (rc && --tries) { + ata_port_printk(ap, KERN_WARNING, + "%sreset failed, retrying in 5 secs\n", + reset == softreset ? "soft" : "hard"); + ssleep(5); + + if (reset == hardreset) + sata_down_spd_limit(ap); + if (hardreset) + reset = hardreset; + goto retry; + } + + if (rc == 0) { + if (postreset) + postreset(ap, classes); + + /* reset successful, schedule revalidation */ + ehc->i.dev = NULL; + ehc->i.action &= ~ATA_EH_RESET_MASK; + ehc->i.action |= ATA_EH_REVALIDATE; + } + + return rc; +} + +static int ata_eh_revalidate(struct ata_port *ap, + struct ata_device **r_failed_dev) +{ + struct ata_eh_context *ehc = &ap->eh_context; + struct ata_device *dev; + int i, rc = 0; + + DPRINTK("ENTER\n"); + + for (i = 0; i < ATA_MAX_DEVICES; i++) { + dev = &ap->device[i]; + + if (ehc->i.action & ATA_EH_REVALIDATE && ata_dev_enabled(dev) && + (!ehc->i.dev || ehc->i.dev == dev)) { + if (ata_port_offline(ap)) { + rc = -EIO; + break; + } + + ata_eh_about_to_do(ap, ATA_EH_REVALIDATE); + rc = ata_dev_revalidate(dev, + ehc->i.flags & ATA_EHI_DID_RESET); + if (rc) + break; + + ehc->i.action &= ~ATA_EH_REVALIDATE; + } + } + + if (rc) + *r_failed_dev = dev; + + DPRINTK("EXIT\n"); + return rc; +} + +static int ata_port_nr_enabled(struct ata_port *ap) +{ + int i, cnt = 0; + + for (i = 0; i < ATA_MAX_DEVICES; i++) + if (ata_dev_enabled(&ap->device[i])) + cnt++; + return cnt; +} + +/** + * ata_eh_recover - recover host port after error + * @ap: host port to recover + * @softreset: softreset method (can be NULL) + * @hardreset: hardreset method (can be NULL) + * @postreset: postreset method (can be NULL) + * + * This is the alpha and omega, eum and yang, heart and soul of + * libata exception handling. On entry, actions required to + * recover each devices are recorded in eh_context. This + * function executes all the operations with appropriate retrials + * and fallbacks to resurrect failed devices. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno on failure. + */ +static int ata_eh_recover(struct ata_port *ap, ata_reset_fn_t softreset, + ata_reset_fn_t hardreset, + ata_postreset_fn_t postreset) +{ + struct ata_eh_context *ehc = &ap->eh_context; + struct ata_device *dev; + int down_xfermask, i, rc; + + DPRINTK("ENTER\n"); + + /* prep for recovery */ + for (i = 0; i < ATA_MAX_DEVICES; i++) { + dev = &ap->device[i]; + + ehc->tries[dev->devno] = ATA_EH_DEV_TRIES; + } + + retry: + down_xfermask = 0; + rc = 0; + + /* skip EH if possible. */ + if (!ata_port_nr_enabled(ap) && !(ap->flags & ATA_FLAG_FROZEN)) + ehc->i.action = 0; + + /* reset */ + if (ehc->i.action & ATA_EH_RESET_MASK) { + ata_eh_freeze_port(ap); + + rc = ata_eh_reset(ap, softreset, hardreset, postreset); + if (rc) { + ata_port_printk(ap, KERN_ERR, + "reset failed, giving up\n"); + goto out; + } + + ata_eh_thaw_port(ap); + } + + /* revalidate existing devices */ + rc = ata_eh_revalidate(ap, &dev); + if (rc) + goto dev_fail; + + /* configure transfer mode if the port has been reset */ + if (ehc->i.flags & ATA_EHI_DID_RESET) { + rc = ata_set_mode(ap, &dev); + if (rc) { + down_xfermask = 1; + goto dev_fail; + } + } + + goto out; + + dev_fail: + switch (rc) { + case -ENODEV: + case -EINVAL: + ehc->tries[dev->devno] = 0; + break; + case -EIO: + sata_down_spd_limit(ap); + default: + ehc->tries[dev->devno]--; + if (down_xfermask && + ata_down_xfermask_limit(dev, ehc->tries[dev->devno] == 1)) + ehc->tries[dev->devno] = 0; + } + + /* disable device if it has used up all its chances */ + if (ata_dev_enabled(dev) && !ehc->tries[dev->devno]) + ata_dev_disable(dev); + + /* soft didn't work? be haaaaard */ + if (ehc->i.flags & ATA_EHI_DID_RESET) + ehc->i.action |= ATA_EH_HARDRESET; + else + ehc->i.action |= ATA_EH_SOFTRESET; + + if (ata_port_nr_enabled(ap)) { + ata_port_printk(ap, KERN_WARNING, "failed to recover some " + "devices, retrying in 5 secs\n"); + ssleep(5); + } else { + /* no device left, repeat fast */ + msleep(500); + } + + goto retry; + + out: + if (rc) { + for (i = 0; i < ATA_MAX_DEVICES; i++) + ata_dev_disable(&ap->device[i]); + } + + DPRINTK("EXIT, rc=%d\n", rc); + return rc; +} + +/** + * ata_eh_finish - finish up EH + * @ap: host port to finish EH for + * + * Recovery is complete. Clean up EH states and retry or finish + * failed qcs. + * + * LOCKING: + * None. + */ +static void ata_eh_finish(struct ata_port *ap) +{ + int tag; + + /* retry or finish qcs */ + for (tag = 0; tag < ATA_MAX_QUEUE; tag++) { + struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag); + + if (!(qc->flags & ATA_QCFLAG_FAILED)) + continue; + + if (qc->err_mask) { + /* FIXME: Once EH migration is complete, + * generate sense data in this function, + * considering both err_mask and tf. + */ + if (qc->err_mask & AC_ERR_INVALID) + ata_eh_qc_complete(qc); + else + ata_eh_qc_retry(qc); + } else { + if (qc->flags & ATA_QCFLAG_SENSE_VALID) { + ata_eh_qc_complete(qc); + } else { + /* feed zero TF to sense generation */ + memset(&qc->result_tf, 0, sizeof(qc->result_tf)); + ata_eh_qc_retry(qc); + } + } + } +} + +/** + * ata_do_eh - do standard error handling + * @ap: host port to handle error for + * @softreset: softreset method (can be NULL) + * @hardreset: hardreset method (can be NULL) + * @postreset: postreset method (can be NULL) + * + * Perform standard error handling sequence. + * + * LOCKING: + * Kernel thread context (may sleep). + */ +void ata_do_eh(struct ata_port *ap, ata_reset_fn_t softreset, + ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) +{ + ata_eh_autopsy(ap); + ata_eh_report(ap); + ata_eh_recover(ap, softreset, hardreset, postreset); + ata_eh_finish(ap); +} diff --git a/include/linux/libata.h b/include/linux/libata.h index 298f9918e375..9fe46073cf8c 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -247,6 +247,8 @@ enum { /* how hard are we gonna try to probe/recover devices */ ATA_PROBE_MAX_TRIES = 3, + ATA_EH_RESET_TRIES = 3, + ATA_EH_DEV_TRIES = 3, }; enum hsm_task_states { @@ -727,6 +729,9 @@ extern void ata_eh_thaw_port(struct ata_port *ap); extern void ata_eh_qc_complete(struct ata_queued_cmd *qc); extern void ata_eh_qc_retry(struct ata_queued_cmd *qc); +extern void ata_do_eh(struct ata_port *ap, ata_reset_fn_t softreset, + ata_reset_fn_t hardreset, ata_postreset_fn_t postreset); + /* * printk helpers */ -- cgit v1.2.3 From 6d97dbd72da31a0e334f251fa9df4be9fab6fde2 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 20:58:24 +0900 Subject: [PATCH] libata-eh: implement BMDMA EH Implement stock BMDMA error handling methods. Signed-off-by: Tejun Heo --- drivers/scsi/libata-bmdma.c | 144 ++++++++++++++++++++++++++++++++++++++++++++ drivers/scsi/libata-core.c | 5 ++ include/linux/libata.h | 8 +++ 3 files changed, 157 insertions(+) (limited to 'include') diff --git a/drivers/scsi/libata-bmdma.c b/drivers/scsi/libata-bmdma.c index 835dff0bafdc..49eff18a67e3 100644 --- a/drivers/scsi/libata-bmdma.c +++ b/drivers/scsi/libata-bmdma.c @@ -652,6 +652,150 @@ void ata_bmdma_stop(struct ata_queued_cmd *qc) ata_altstatus(ap); /* dummy read */ } +/** + * ata_bmdma_freeze - Freeze BMDMA controller port + * @ap: port to freeze + * + * Freeze BMDMA controller port. + * + * LOCKING: + * Inherited from caller. + */ +void ata_bmdma_freeze(struct ata_port *ap) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + + ap->ctl |= ATA_NIEN; + ap->last_ctl = ap->ctl; + + if (ap->flags & ATA_FLAG_MMIO) + writeb(ap->ctl, (void __iomem *)ioaddr->ctl_addr); + else + outb(ap->ctl, ioaddr->ctl_addr); +} + +/** + * ata_bmdma_thaw - Thaw BMDMA controller port + * @ap: port to thaw + * + * Thaw BMDMA controller port. + * + * LOCKING: + * Inherited from caller. + */ +void ata_bmdma_thaw(struct ata_port *ap) +{ + /* clear & re-enable interrupts */ + ata_chk_status(ap); + ap->ops->irq_clear(ap); + if (ap->ioaddr.ctl_addr) /* FIXME: hack. create a hook instead */ + ata_irq_on(ap); +} + +/** + * ata_bmdma_drive_eh - Perform EH with given methods for BMDMA controller + * @ap: port to handle error for + * @softreset: softreset method (can be NULL) + * @hardreset: hardreset method (can be NULL) + * @postreset: postreset method (can be NULL) + * + * Handle error for ATA BMDMA controller. It can handle both + * PATA and SATA controllers. Many controllers should be able to + * use this EH as-is or with some added handling before and + * after. + * + * This function is intended to be used for constructing + * ->error_handler callback by low level drivers. + * + * LOCKING: + * Kernel thread context (may sleep) + */ +void ata_bmdma_drive_eh(struct ata_port *ap, ata_reset_fn_t softreset, + ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) +{ + struct ata_host_set *host_set = ap->host_set; + struct ata_eh_context *ehc = &ap->eh_context; + struct ata_queued_cmd *qc; + unsigned long flags; + int thaw = 0; + + qc = __ata_qc_from_tag(ap, ap->active_tag); + if (qc && !(qc->flags & ATA_QCFLAG_FAILED)) + qc = NULL; + + /* reset PIO HSM and stop DMA engine */ + spin_lock_irqsave(&host_set->lock, flags); + + ap->flags &= ~ATA_FLAG_NOINTR; + ap->hsm_task_state = HSM_ST_IDLE; + + if (qc && (qc->tf.protocol == ATA_PROT_DMA || + qc->tf.protocol == ATA_PROT_ATAPI_DMA)) { + u8 host_stat; + + host_stat = ata_bmdma_status(ap); + + ata_ehi_push_desc(&ehc->i, "BMDMA stat 0x%x", host_stat); + + /* BMDMA controllers indicate host bus error by + * setting DMA_ERR bit and timing out. As it wasn't + * really a timeout event, adjust error mask and + * cancel frozen state. + */ + if (qc->err_mask == AC_ERR_TIMEOUT && host_stat & ATA_DMA_ERR) { + qc->err_mask = AC_ERR_HOST_BUS; + thaw = 1; + } + + ap->ops->bmdma_stop(qc); + } + + ata_altstatus(ap); + ata_chk_status(ap); + ap->ops->irq_clear(ap); + + spin_unlock_irqrestore(&host_set->lock, flags); + + if (thaw) + ata_eh_thaw_port(ap); + + /* PIO and DMA engines have been stopped, perform recovery */ + ata_do_eh(ap, softreset, hardreset, postreset); +} + +/** + * ata_bmdma_error_handler - Stock error handler for BMDMA controller + * @ap: port to handle error for + * + * Stock error handler for BMDMA controller. + * + * LOCKING: + * Kernel thread context (may sleep) + */ +void ata_bmdma_error_handler(struct ata_port *ap) +{ + ata_reset_fn_t hardreset; + + hardreset = NULL; + if (sata_scr_valid(ap)) + hardreset = sata_std_hardreset; + + ata_bmdma_drive_eh(ap, ata_std_softreset, hardreset, ata_std_postreset); +} + +/** + * ata_bmdma_post_internal_cmd - Stock post_internal_cmd for + * BMDMA controller + * @qc: internal command to clean up + * + * LOCKING: + * Kernel thread context (may sleep) + */ +void ata_bmdma_post_internal_cmd(struct ata_queued_cmd *qc) +{ + ata_bmdma_stop(qc); +} + #ifdef CONFIG_PCI static struct ata_probe_ent * ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port) diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index ddc47097d37e..2969599ec0b9 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -5377,6 +5377,11 @@ EXPORT_SYMBOL_GPL(ata_bmdma_start); EXPORT_SYMBOL_GPL(ata_bmdma_irq_clear); EXPORT_SYMBOL_GPL(ata_bmdma_status); EXPORT_SYMBOL_GPL(ata_bmdma_stop); +EXPORT_SYMBOL_GPL(ata_bmdma_freeze); +EXPORT_SYMBOL_GPL(ata_bmdma_thaw); +EXPORT_SYMBOL_GPL(ata_bmdma_drive_eh); +EXPORT_SYMBOL_GPL(ata_bmdma_error_handler); +EXPORT_SYMBOL_GPL(ata_bmdma_post_internal_cmd); EXPORT_SYMBOL_GPL(ata_port_probe); EXPORT_SYMBOL_GPL(sata_set_spd); EXPORT_SYMBOL_GPL(sata_phy_reset); diff --git a/include/linux/libata.h b/include/linux/libata.h index 9fe46073cf8c..6ccacbf889e3 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -661,6 +661,14 @@ extern void ata_bmdma_start (struct ata_queued_cmd *qc); extern void ata_bmdma_stop(struct ata_queued_cmd *qc); extern u8 ata_bmdma_status(struct ata_port *ap); extern void ata_bmdma_irq_clear(struct ata_port *ap); +extern void ata_bmdma_freeze(struct ata_port *ap); +extern void ata_bmdma_thaw(struct ata_port *ap); +extern void ata_bmdma_drive_eh(struct ata_port *ap, + ata_reset_fn_t softreset, + ata_reset_fn_t hardreset, + ata_postreset_fn_t postreset); +extern void ata_bmdma_error_handler(struct ata_port *ap); +extern void ata_bmdma_post_internal_cmd(struct ata_queued_cmd *qc); extern void ata_qc_complete(struct ata_queued_cmd *qc); extern void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)); -- cgit v1.2.3 From 88e490340ea4c3a2ebc0187a4339912e2fc1a081 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 21:03:38 +0900 Subject: [PATCH] libata-ncq: add NCQ related ATA/libata constants and macros Add NCQ related ATA/libata constants and macros. Signed-off-by: Tejun Heo --- include/linux/ata.h | 9 +++++++++ include/linux/libata.h | 2 ++ 2 files changed, 11 insertions(+) (limited to 'include') diff --git a/include/linux/ata.h b/include/linux/ata.h index 1cbeb434af9a..c494e1c0531e 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -133,6 +133,8 @@ enum { ATA_CMD_WRITE = 0xCA, ATA_CMD_WRITE_EXT = 0x35, ATA_CMD_WRITE_FUA_EXT = 0x3D, + ATA_CMD_FPDMA_READ = 0x60, + ATA_CMD_FPDMA_WRITE = 0x61, ATA_CMD_PIO_READ = 0x20, ATA_CMD_PIO_READ_EXT = 0x24, ATA_CMD_PIO_WRITE = 0x30, @@ -151,6 +153,10 @@ enum { ATA_CMD_INIT_DEV_PARAMS = 0x91, ATA_CMD_READ_NATIVE_MAX = 0xF8, ATA_CMD_READ_NATIVE_MAX_EXT = 0x27, + ATA_CMD_READ_LOG_EXT = 0x2f, + + /* READ_LOG_EXT pages */ + ATA_LOG_SATA_NCQ = 0x10, /* SETFEATURES stuff */ SETFEATURES_XFER = 0x03, @@ -221,6 +227,7 @@ enum ata_tf_protocols { ATA_PROT_NODATA, /* no data */ ATA_PROT_PIO, /* PIO single sector */ ATA_PROT_DMA, /* DMA */ + ATA_PROT_NCQ, /* NCQ */ ATA_PROT_ATAPI, /* packet command, PIO data xfer*/ ATA_PROT_ATAPI_NODATA, /* packet command, no data */ ATA_PROT_ATAPI_DMA, /* packet command with special DMA sauce */ @@ -276,6 +283,8 @@ struct ata_taskfile { #define ata_id_has_pm(id) ((id)[82] & (1 << 3)) #define ata_id_has_lba(id) ((id)[49] & (1 << 9)) #define ata_id_has_dma(id) ((id)[49] & (1 << 8)) +#define ata_id_has_ncq(id) ((id)[76] & (1 << 8)) +#define ata_id_queue_depth(id) (((id)[75] & 0x1f) + 1) #define ata_id_removeable(id) ((id)[0] & (1 << 7)) #define ata_id_has_dword_io(id) ((id)[50] & (1 << 0)) #define ata_id_u32(id,n) \ diff --git a/include/linux/libata.h b/include/linux/libata.h index db17723e23fb..7c9e280a4829 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -125,6 +125,7 @@ enum { ATA_DFLAG_LBA = (1 << 0), /* device supports LBA */ ATA_DFLAG_LBA48 = (1 << 1), /* device supports LBA48 */ ATA_DFLAG_CDB_INTR = (1 << 2), /* device asserts INTRQ when ready for CDB */ + ATA_DFLAG_NCQ = (1 << 3), /* device supports NCQ */ ATA_DFLAG_CFG_MASK = (1 << 8) - 1, ATA_DFLAG_PIO = (1 << 8), /* device currently in PIO mode */ @@ -150,6 +151,7 @@ enum { ATA_FLAG_IRQ_MASK = (1 << 9), /* Mask IRQ in PIO xfers */ ATA_FLAG_PIO_POLLING = (1 << 10), /* use polling PIO if LLD * doesn't handle PIO interrupts */ + ATA_FLAG_NCQ = (1 << 11), /* host supports NCQ */ ATA_FLAG_DEBUGMSG = (1 << 14), ATA_FLAG_FLUSH_PORT_TASK = (1 << 15), /* flush port task */ -- cgit v1.2.3 From 6cec4a3943bdfe46e2952bc246f17670f747be8d Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 21:03:41 +0900 Subject: [PATCH] libata-ncq: rename ap->qactive to ap->qc_allocated Rename ap->qactive to ap->qc_allocated. This is to accomodate addition of ap->qc_active, mask of active qcs. Signed-off-by: Tejun Heo --- drivers/scsi/libata-core.c | 6 +++--- include/linux/libata.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 487b8f22981f..f8401800dc1a 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -1006,7 +1006,7 @@ unsigned ata_exec_internal(struct ata_device *dev, else tag = 0; - if (test_and_set_bit(tag, &ap->qactive)) + if (test_and_set_bit(tag, &ap->qc_allocated)) BUG(); qc = __ata_qc_from_tag(ap, tag); @@ -4207,7 +4207,7 @@ static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap) /* the last tag is reserved for internal command. */ for (i = 0; i < ATA_MAX_QUEUE - 1; i++) - if (!test_and_set_bit(i, &ap->qactive)) { + if (!test_and_set_bit(i, &ap->qc_allocated)) { qc = __ata_qc_from_tag(ap, i); break; } @@ -4264,7 +4264,7 @@ void ata_qc_free(struct ata_queued_cmd *qc) tag = qc->tag; if (likely(ata_tag_valid(tag))) { qc->tag = ATA_TAG_POISON; - clear_bit(tag, &ap->qactive); + clear_bit(tag, &ap->qc_allocated); } } diff --git a/include/linux/libata.h b/include/linux/libata.h index 7c9e280a4829..b3a4f8bea828 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -474,7 +474,7 @@ struct ata_port { struct ata_device device[ATA_MAX_DEVICES]; struct ata_queued_cmd qcmd[ATA_MAX_QUEUE]; - unsigned long qactive; + unsigned long qc_allocated; unsigned int active_tag; struct ata_host_stats stats; -- cgit v1.2.3 From dedaf2b0365ccec50714fbde0b3215e7e94fa47c Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 21:03:43 +0900 Subject: [PATCH] libata-ncq: implement ap->qc_active, ap->sactive and complete helper Add ap->qc_active and ap->sactive, mask of all active qcs and libata's view of the SActive register, respectively. Also, implement ata_qc_complete_multiple() which takes new qc_active mask and complete multiple qcs according to the mask. These will be used to track NCQ commands and complete them. The distinction between ap->qc_active and ap->sactive is also useful for later PM implementation. Signed-off-by: Tejun Heo --- drivers/scsi/libata-core.c | 81 ++++++++++++++++++++++++++++++++++++++++++++-- include/linux/libata.h | 5 +++ 2 files changed, 84 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index f8401800dc1a..eea1fe9c8b79 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -981,6 +981,7 @@ unsigned ata_exec_internal(struct ata_device *dev, u8 command = tf->command; struct ata_queued_cmd *qc; unsigned int tag, preempted_tag; + u32 preempted_sactive, preempted_qc_active; DECLARE_COMPLETION(wait); unsigned long flags; unsigned int err_mask; @@ -1017,7 +1018,11 @@ unsigned ata_exec_internal(struct ata_device *dev, ata_qc_reinit(qc); preempted_tag = ap->active_tag; + preempted_sactive = ap->sactive; + preempted_qc_active = ap->qc_active; ap->active_tag = ATA_TAG_POISON; + ap->sactive = 0; + ap->qc_active = 0; /* prepare & issue qc */ qc->tf = *tf; @@ -1082,6 +1087,8 @@ unsigned ata_exec_internal(struct ata_device *dev, ata_qc_free(qc); ap->active_tag = preempted_tag; + ap->sactive = preempted_sactive; + ap->qc_active = preempted_qc_active; /* XXX - Some LLDDs (sata_mv) disable port on command failure. * Until those drivers are fixed, we detect the condition @@ -4270,6 +4277,8 @@ void ata_qc_free(struct ata_queued_cmd *qc) void __ata_qc_complete(struct ata_queued_cmd *qc) { + struct ata_port *ap = qc->ap; + WARN_ON(qc == NULL); /* ata_qc_from_tag _might_ return NULL */ WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE)); @@ -4277,13 +4286,17 @@ void __ata_qc_complete(struct ata_queued_cmd *qc) ata_sg_clean(qc); /* command should be marked inactive atomically with qc completion */ - qc->ap->active_tag = ATA_TAG_POISON; + if (qc->tf.protocol == ATA_PROT_NCQ) + ap->sactive &= ~(1 << qc->tag); + else + ap->active_tag = ATA_TAG_POISON; /* atapi: mark qc as inactive to prevent the interrupt handler * from completing the command twice later, before the error handler * is called. (when rc != 0 and atapi request sense is needed) */ qc->flags &= ~ATA_QCFLAG_ACTIVE; + ap->qc_active &= ~(1 << qc->tag); /* call completion callback */ qc->complete_fn(qc); @@ -4349,6 +4362,55 @@ void ata_qc_complete(struct ata_queued_cmd *qc) } } +/** + * ata_qc_complete_multiple - Complete multiple qcs successfully + * @ap: port in question + * @qc_active: new qc_active mask + * @finish_qc: LLDD callback invoked before completing a qc + * + * Complete in-flight commands. This functions is meant to be + * called from low-level driver's interrupt routine to complete + * requests normally. ap->qc_active and @qc_active is compared + * and commands are completed accordingly. + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + * + * RETURNS: + * Number of completed commands on success, -errno otherwise. + */ +int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active, + void (*finish_qc)(struct ata_queued_cmd *)) +{ + int nr_done = 0; + u32 done_mask; + int i; + + done_mask = ap->qc_active ^ qc_active; + + if (unlikely(done_mask & qc_active)) { + ata_port_printk(ap, KERN_ERR, "illegal qc_active transition " + "(%08x->%08x)\n", ap->qc_active, qc_active); + return -EINVAL; + } + + for (i = 0; i < ATA_MAX_QUEUE; i++) { + struct ata_queued_cmd *qc; + + if (!(done_mask & (1 << i))) + continue; + + if ((qc = ata_qc_from_tag(ap, i))) { + if (finish_qc) + finish_qc(qc); + ata_qc_complete(qc); + nr_done++; + } + } + + return nr_done; +} + static inline int ata_should_dma_map(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; @@ -4388,8 +4450,22 @@ void ata_qc_issue(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; - qc->ap->active_tag = qc->tag; + /* Make sure only one non-NCQ command is outstanding. The + * check is skipped for old EH because it reuses active qc to + * request ATAPI sense. + */ + WARN_ON(ap->ops->error_handler && ata_tag_valid(ap->active_tag)); + + if (qc->tf.protocol == ATA_PROT_NCQ) { + WARN_ON(ap->sactive & (1 << qc->tag)); + ap->sactive |= 1 << qc->tag; + } else { + WARN_ON(ap->sactive); + ap->active_tag = qc->tag; + } + qc->flags |= ATA_QCFLAG_ACTIVE; + ap->qc_active |= 1 << qc->tag; if (ata_should_dma_map(qc)) { if (qc->flags & ATA_QCFLAG_SG) { @@ -5549,6 +5625,7 @@ EXPORT_SYMBOL_GPL(ata_host_set_remove); EXPORT_SYMBOL_GPL(ata_sg_init); EXPORT_SYMBOL_GPL(ata_sg_init_one); EXPORT_SYMBOL_GPL(ata_qc_complete); +EXPORT_SYMBOL_GPL(ata_qc_complete_multiple); EXPORT_SYMBOL_GPL(ata_qc_issue_prot); EXPORT_SYMBOL_GPL(ata_tf_load); EXPORT_SYMBOL_GPL(ata_tf_read); diff --git a/include/linux/libata.h b/include/linux/libata.h index b3a4f8bea828..dd0db2d21bc5 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -475,7 +475,10 @@ struct ata_port { struct ata_queued_cmd qcmd[ATA_MAX_QUEUE]; unsigned long qc_allocated; + unsigned int qc_active; + unsigned int active_tag; + u32 sactive; struct ata_host_stats stats; struct ata_host_set *host_set; @@ -668,6 +671,8 @@ extern void ata_bmdma_drive_eh(struct ata_port *ap, extern void ata_bmdma_error_handler(struct ata_port *ap); extern void ata_bmdma_post_internal_cmd(struct ata_queued_cmd *qc); extern void ata_qc_complete(struct ata_queued_cmd *qc); +extern int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active, + void (*finish_qc)(struct ata_queued_cmd *)); extern void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)); extern int ata_std_bios_param(struct scsi_device *sdev, -- cgit v1.2.3 From a6e6ce8e8dc907a2cf2b994b0ea4099423f046bf Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 15 May 2006 21:03:48 +0900 Subject: [PATCH] libata-ncq: implement NCQ device configuration Now that all NCQ related stuff are in place, implement NCQ device configuration and bump ATA_MAX_QUEUE to 32 thus activating NCQ support. Original implementation is from Jens Axboe. Signed-off-by: Tejun Heo --- drivers/scsi/libata-core.c | 31 +++++++++++++++++++++++++++++-- drivers/scsi/libata-scsi.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/libata.h | 4 +++- 3 files changed, 78 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 14ffb5264b65..9051b6821c1c 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -1251,6 +1251,28 @@ static inline u8 ata_dev_knobble(struct ata_device *dev) return ((dev->ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(dev->id))); } +static void ata_dev_config_ncq(struct ata_device *dev, + char *desc, size_t desc_sz) +{ + struct ata_port *ap = dev->ap; + int hdepth = 0, ddepth = ata_id_queue_depth(dev->id); + + if (!ata_id_has_ncq(dev->id)) { + desc[0] = '\0'; + return; + } + + if (ap->flags & ATA_FLAG_NCQ) { + hdepth = min(ap->host->can_queue, ATA_MAX_QUEUE - 1); + dev->flags |= ATA_DFLAG_NCQ; + } + + if (hdepth >= ddepth) + snprintf(desc, desc_sz, "NCQ (depth %d)", ddepth); + else + snprintf(desc, desc_sz, "NCQ (depth %d/%d)", hdepth, ddepth); +} + /** * ata_dev_configure - Configure the specified ATA/ATAPI device * @dev: Target device to configure @@ -1311,6 +1333,7 @@ static int ata_dev_configure(struct ata_device *dev, int print_info) if (ata_id_has_lba(id)) { const char *lba_desc; + char ncq_desc[20]; lba_desc = "LBA"; dev->flags |= ATA_DFLAG_LBA; @@ -1319,14 +1342,17 @@ static int ata_dev_configure(struct ata_device *dev, int print_info) lba_desc = "LBA48"; } + /* config NCQ */ + ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc)); + /* print device info to dmesg */ if (print_info) ata_dev_printk(dev, KERN_INFO, "ATA-%d, " - "max %s, %Lu sectors: %s\n", + "max %s, %Lu sectors: %s %s\n", ata_id_major_version(id), ata_mode_string(xfer_mask), (unsigned long long)dev->n_sectors, - lba_desc); + lba_desc, ncq_desc); } else { /* CHS */ @@ -5675,6 +5701,7 @@ EXPORT_SYMBOL_GPL(ata_port_queue_task); EXPORT_SYMBOL_GPL(ata_scsi_ioctl); EXPORT_SYMBOL_GPL(ata_scsi_queuecmd); EXPORT_SYMBOL_GPL(ata_scsi_slave_config); +EXPORT_SYMBOL_GPL(ata_scsi_change_queue_depth); EXPORT_SYMBOL_GPL(ata_scsi_release); EXPORT_SYMBOL_GPL(ata_host_intr); EXPORT_SYMBOL_GPL(sata_scr_valid); diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 9bef68c7c1de..996058af1bcd 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -684,6 +685,14 @@ static void ata_scsi_dev_config(struct scsi_device *sdev, request_queue_t *q = sdev->request_queue; blk_queue_max_hw_segments(q, q->max_hw_segments - 1); } + + if (dev->flags & ATA_DFLAG_NCQ) { + int depth; + + depth = min(sdev->host->can_queue, ata_id_queue_depth(dev->id)); + depth = min(ATA_MAX_QUEUE - 1, depth); + scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, depth); + } } /** @@ -717,6 +726,43 @@ int ata_scsi_slave_config(struct scsi_device *sdev) return 0; /* scsi layer doesn't check return value, sigh */ } +/** + * ata_scsi_change_queue_depth - SCSI callback for queue depth config + * @sdev: SCSI device to configure queue depth for + * @queue_depth: new queue depth + * + * This is libata standard hostt->change_queue_depth callback. + * SCSI will call into this callback when user tries to set queue + * depth via sysfs. + * + * LOCKING: + * SCSI layer (we don't care) + * + * RETURNS: + * Newly configured queue depth. + */ +int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth) +{ + struct ata_port *ap = ata_shost_to_port(sdev->host); + struct ata_device *dev; + int max_depth; + + if (queue_depth < 1) + return sdev->queue_depth; + + dev = ata_scsi_find_dev(ap, sdev); + if (!dev || !ata_dev_enabled(dev)) + return sdev->queue_depth; + + max_depth = min(sdev->host->can_queue, ata_id_queue_depth(dev->id)); + max_depth = min(ATA_MAX_QUEUE - 1, max_depth); + if (queue_depth > max_depth) + queue_depth = max_depth; + + scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, queue_depth); + return queue_depth; +} + /** * ata_scsi_start_stop_xlat - Translate SCSI START STOP UNIT command * @qc: Storage for translated ATA taskfile diff --git a/include/linux/libata.h b/include/linux/libata.h index dd0db2d21bc5..fcdd798bb086 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -109,7 +109,7 @@ enum { ATA_MAX_PORTS = 8, ATA_DEF_QUEUE = 1, /* tag ATA_MAX_QUEUE - 1 is reserved for internal commands */ - ATA_MAX_QUEUE = 2, + ATA_MAX_QUEUE = 32, ATA_TAG_INTERNAL = ATA_MAX_QUEUE - 1, ATA_MAX_SECTORS = 200, /* FIXME */ ATA_MAX_BUS = 2, @@ -679,6 +679,8 @@ extern int ata_std_bios_param(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int geom[]); extern int ata_scsi_slave_config(struct scsi_device *sdev); +extern int ata_scsi_change_queue_depth(struct scsi_device *sdev, + int queue_depth); extern struct ata_device *ata_dev_pair(struct ata_device *adev); /* -- cgit v1.2.3 From d6b89a196dfb03fdfbe3d574ab6773fe14a1d2c6 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Tue, 9 May 2006 11:33:38 -0500 Subject: [PATCH] powerpc: whitespace cleanup in reg.h In reg.h we mostly have #define but there are a few #define around. Clean these up so we use space exclusively. Signed-off-by: Michael Neuling Signed-off-by: Paul Mackerras --- include/asm-powerpc/reg.h | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) (limited to 'include') diff --git a/include/asm-powerpc/reg.h b/include/asm-powerpc/reg.h index bd467bf5cf5a..0257189d5017 100644 --- a/include/asm-powerpc/reg.h +++ b/include/asm-powerpc/reg.h @@ -153,7 +153,7 @@ #define SPRN_DABR 0x3F5 /* Data Address Breakpoint Register */ #define DABR_TRANSLATION (1UL << 2) #define SPRN_DAR 0x013 /* Data Address Register */ -#define SPRN_DSISR 0x012 /* Data Storage Interrupt Status Register */ +#define SPRN_DSISR 0x012 /* Data Storage Interrupt Status Register */ #define DSISR_NOHPTE 0x40000000 /* no translation found */ #define DSISR_PROTFAULT 0x08000000 /* protection fault */ #define DSISR_ISSTORE 0x02000000 /* access was a store */ @@ -258,16 +258,16 @@ #define SPRN_IABR 0x3F2 /* Instruction Address Breakpoint Register */ #define SPRN_HID4 0x3F4 /* 970 HID4 */ #define SPRN_HID5 0x3F6 /* 970 HID5 */ -#define SPRN_HID6 0x3F9 /* BE HID 6 */ -#define HID6_LB (0x0F<<12) /* Concurrent Large Page Modes */ -#define HID6_DLP (1<<20) /* Disable all large page modes (4K only) */ -#define SPRN_TSC_CELL 0x399 /* Thread switch control on Cell */ -#define TSC_CELL_DEC_ENABLE_0 0x400000 /* Decrementer Interrupt */ -#define TSC_CELL_DEC_ENABLE_1 0x200000 /* Decrementer Interrupt */ -#define TSC_CELL_EE_ENABLE 0x100000 /* External Interrupt */ -#define TSC_CELL_EE_BOOST 0x080000 /* External Interrupt Boost */ -#define SPRN_TSC 0x3FD /* Thread switch control on others */ -#define SPRN_TST 0x3FC /* Thread switch timeout on others */ +#define SPRN_HID6 0x3F9 /* BE HID 6 */ +#define HID6_LB (0x0F<<12) /* Concurrent Large Page Modes */ +#define HID6_DLP (1<<20) /* Disable all large page modes (4K only) */ +#define SPRN_TSC_CELL 0x399 /* Thread switch control on Cell */ +#define TSC_CELL_DEC_ENABLE_0 0x400000 /* Decrementer Interrupt */ +#define TSC_CELL_DEC_ENABLE_1 0x200000 /* Decrementer Interrupt */ +#define TSC_CELL_EE_ENABLE 0x100000 /* External Interrupt */ +#define TSC_CELL_EE_BOOST 0x080000 /* External Interrupt Boost */ +#define SPRN_TSC 0x3FD /* Thread switch control on others */ +#define SPRN_TST 0x3FC /* Thread switch timeout on others */ #if !defined(SPRN_IAC1) && !defined(SPRN_IAC2) #define SPRN_IAC1 0x3F4 /* Instruction Address Compare 1 */ #define SPRN_IAC2 0x3F5 /* Instruction Address Compare 2 */ @@ -362,7 +362,7 @@ #endif #define SPRN_PTEHI 0x3D5 /* 981 7450 PTE HI word (S/W TLB load) */ #define SPRN_PTELO 0x3D6 /* 982 7450 PTE LO word (S/W TLB load) */ -#define SPRN_PURR 0x135 /* Processor Utilization of Resources Reg */ +#define SPRN_PURR 0x135 /* Processor Utilization of Resources Reg */ #define SPRN_PVR 0x11F /* Processor Version Register */ #define SPRN_RPA 0x3D6 /* Required Physical Address Register */ #define SPRN_SDA 0x3BF /* Sampled Data Address Register */ @@ -559,20 +559,20 @@ /* 64-bit processors */ /* XXX the prefix should be PVR_, we'll do a global sweep to fix it one day */ -#define PV_NORTHSTAR 0x0033 -#define PV_PULSAR 0x0034 -#define PV_POWER4 0x0035 -#define PV_ICESTAR 0x0036 -#define PV_SSTAR 0x0037 -#define PV_POWER4p 0x0038 +#define PV_NORTHSTAR 0x0033 +#define PV_PULSAR 0x0034 +#define PV_POWER4 0x0035 +#define PV_ICESTAR 0x0036 +#define PV_SSTAR 0x0037 +#define PV_POWER4p 0x0038 #define PV_970 0x0039 -#define PV_POWER5 0x003A +#define PV_POWER5 0x003A #define PV_POWER5p 0x003B #define PV_970FX 0x003C -#define PV_630 0x0040 -#define PV_630p 0x0041 -#define PV_970MP 0x0044 -#define PV_BE 0x0070 +#define PV_630 0x0040 +#define PV_630p 0x0041 +#define PV_970MP 0x0044 +#define PV_BE 0x0070 /* * Number of entries in the SLB. If this ever changes we should handle -- cgit v1.2.3 From 2babf5c2ec2f2d5de3e38d20f7df7fd815fd10c9 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 17 May 2006 18:00:46 +1000 Subject: [PATCH] powerpc: Unify mem= handling We currently do mem= handling in three seperate places. And as benh pointed out I wrote two of them. Now that we parse command line parameters earlier we can clean this mess up. Moving the parsing out of prom_init means the device tree might be allocated above the memory limit. If that happens we'd have to move it. As it happens we already have logic to do that for kdump, so just genericise it. This also means we might have reserved regions above the memory limit, if we do the bootmem allocator will blow up, so we have to modify lmb_enforce_memory_limit() to truncate the reserves as well. Tested on P5 LPAR, iSeries, F50, 44p. Tested moving device tree on P5 and 44p and F50. Signed-off-by: Michael Ellerman Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/machine_kexec_64.c | 5 ++ arch/powerpc/kernel/prom.c | 89 ++++++++++++++++++---------------- arch/powerpc/kernel/prom_init.c | 55 ++------------------- arch/powerpc/kernel/setup_64.c | 3 -- arch/powerpc/mm/lmb.c | 43 +++++++++++----- arch/powerpc/platforms/iseries/setup.c | 22 --------- include/asm-powerpc/kexec.h | 13 ++++- 7 files changed, 100 insertions(+), 130 deletions(-) (limited to 'include') diff --git a/arch/powerpc/kernel/machine_kexec_64.c b/arch/powerpc/kernel/machine_kexec_64.c index ee166c586642..1ccb188ba40d 100644 --- a/arch/powerpc/kernel/machine_kexec_64.c +++ b/arch/powerpc/kernel/machine_kexec_64.c @@ -339,3 +339,8 @@ void __init kexec_setup(void) { export_htab_values(); } + +int overlaps_crashkernel(unsigned long start, unsigned long size) +{ + return (start + size) > crashk_res.start && start <= crashk_res.end; +} diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 4ca608c9cd72..a04f726d3bab 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -50,6 +50,7 @@ #include #include #include +#include #ifdef DEBUG #define DBG(fmt...) printk(KERN_ERR fmt) @@ -836,6 +837,42 @@ static unsigned long __init unflatten_dt_node(unsigned long mem, return mem; } +static int __init early_parse_mem(char *p) +{ + if (!p) + return 1; + + memory_limit = PAGE_ALIGN(memparse(p, &p)); + DBG("memory limit = 0x%lx\n", memory_limit); + + return 0; +} +early_param("mem", early_parse_mem); + +/* + * The device tree may be allocated below our memory limit, or inside the + * crash kernel region for kdump. If so, move it out now. + */ +static void move_device_tree(void) +{ + unsigned long start, size; + void *p; + + DBG("-> move_device_tree\n"); + + start = __pa(initial_boot_params); + size = initial_boot_params->totalsize; + + if ((memory_limit && (start + size) > memory_limit) || + overlaps_crashkernel(start, size)) { + p = __va(lmb_alloc_base(size, PAGE_SIZE, lmb.rmo_size)); + memcpy(p, initial_boot_params, size); + initial_boot_params = (struct boot_param_header *)p; + DBG("Moved device tree to 0x%p\n", p); + } + + DBG("<- move_device_tree\n"); +} /** * unflattens the device-tree passed by the firmware, creating the @@ -1070,6 +1107,7 @@ static int __init early_init_dt_scan_chosen(unsigned long node, iommu_force_on = 1; #endif + /* mem=x on the command line is the preferred mechanism */ lprop = of_get_flat_dt_prop(node, "linux,memory-limit", NULL); if (lprop) memory_limit = *lprop; @@ -1123,17 +1161,6 @@ static int __init early_init_dt_scan_chosen(unsigned long node, DBG("Command line is: %s\n", cmd_line); - if (strstr(cmd_line, "mem=")) { - char *p, *q; - - for (q = cmd_line; (p = strstr(q, "mem=")) != 0; ) { - q = p + 4; - if (p > cmd_line && p[-1] != ' ') - continue; - memory_limit = memparse(q, &q); - } - } - /* break now */ return 1; } @@ -1297,11 +1324,6 @@ void __init early_init_devtree(void *params) strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE); parse_early_param(); - lmb_enforce_memory_limit(memory_limit); - lmb_analyze(); - - DBG("Phys. mem: %lx\n", lmb_phys_mem_size()); - /* Reserve LMB regions used by kernel, initrd, dt, etc... */ lmb_reserve(PHYSICAL_START, __pa(klimit) - PHYSICAL_START); #ifdef CONFIG_CRASH_DUMP @@ -1309,6 +1331,15 @@ void __init early_init_devtree(void *params) #endif early_reserve_mem(); + lmb_enforce_memory_limit(memory_limit); + lmb_analyze(); + + DBG("Phys. mem: %lx\n", lmb_phys_mem_size()); + + /* We may need to relocate the flat tree, do it now. + * FIXME .. and the initrd too? */ + move_device_tree(); + DBG("Scanning CPUs ...\n"); /* Retreive CPU related informations from the flat tree @@ -2058,29 +2089,3 @@ int prom_update_property(struct device_node *np, return 0; } -#ifdef CONFIG_KEXEC -/* We may have allocated the flat device tree inside the crash kernel region - * in prom_init. If so we need to move it out into regular memory. */ -void kdump_move_device_tree(void) -{ - unsigned long start, end; - struct boot_param_header *new; - - start = __pa((unsigned long)initial_boot_params); - end = start + initial_boot_params->totalsize; - - if (end < crashk_res.start || start > crashk_res.end) - return; - - new = (struct boot_param_header*) - __va(lmb_alloc(initial_boot_params->totalsize, PAGE_SIZE)); - - memcpy(new, initial_boot_params, initial_boot_params->totalsize); - - initial_boot_params = new; - - DBG("Flat device tree blob moved to %p\n", initial_boot_params); - - /* XXX should we unreserve the old DT? */ -} -#endif /* CONFIG_KEXEC */ diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 078fb5533541..a52377c68fc6 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -194,8 +194,6 @@ static int __initdata of_platform; static char __initdata prom_cmd_line[COMMAND_LINE_SIZE]; -static unsigned long __initdata prom_memory_limit; - static unsigned long __initdata alloc_top; static unsigned long __initdata alloc_top_high; static unsigned long __initdata alloc_bottom; @@ -594,16 +592,6 @@ static void __init early_cmdline_parse(void) } #endif - opt = strstr(RELOC(prom_cmd_line), RELOC("mem=")); - if (opt) { - opt += 4; - RELOC(prom_memory_limit) = prom_memparse(opt, (const char **)&opt); -#ifdef CONFIG_PPC64 - /* Align to 16 MB == size of ppc64 large page */ - RELOC(prom_memory_limit) = ALIGN(RELOC(prom_memory_limit), 0x1000000); -#endif - } - #ifdef CONFIG_KEXEC /* * crashkernel=size@addr specifies the location to reserve for @@ -1114,29 +1102,6 @@ static void __init prom_init_mem(void) RELOC(alloc_bottom) = PAGE_ALIGN(RELOC(prom_initrd_end)); } - /* - * If prom_memory_limit is set we reduce the upper limits *except* for - * alloc_top_high. This must be the real top of RAM so we can put - * TCE's up there. - */ - - RELOC(alloc_top_high) = RELOC(ram_top); - - if (RELOC(prom_memory_limit)) { - if (RELOC(prom_memory_limit) <= RELOC(alloc_bottom)) { - prom_printf("Ignoring mem=%x <= alloc_bottom.\n", - RELOC(prom_memory_limit)); - RELOC(prom_memory_limit) = 0; - } else if (RELOC(prom_memory_limit) >= RELOC(ram_top)) { - prom_printf("Ignoring mem=%x >= ram_top.\n", - RELOC(prom_memory_limit)); - RELOC(prom_memory_limit) = 0; - } else { - RELOC(ram_top) = RELOC(prom_memory_limit); - RELOC(rmo_top) = min(RELOC(rmo_top), RELOC(prom_memory_limit)); - } - } - /* * Setup our top alloc point, that is top of RMO or top of * segment 0 when running non-LPAR. @@ -1149,9 +1114,9 @@ static void __init prom_init_mem(void) RELOC(rmo_top) = RELOC(ram_top); RELOC(rmo_top) = min(0x30000000ul, RELOC(rmo_top)); RELOC(alloc_top) = RELOC(rmo_top); + RELOC(alloc_top_high) = RELOC(ram_top); prom_printf("memory layout at init:\n"); - prom_printf(" memory_limit : %x (16 MB aligned)\n", RELOC(prom_memory_limit)); prom_printf(" alloc_bottom : %x\n", RELOC(alloc_bottom)); prom_printf(" alloc_top : %x\n", RELOC(alloc_top)); prom_printf(" alloc_top_hi : %x\n", RELOC(alloc_top_high)); @@ -1348,16 +1313,10 @@ static void __init prom_initialize_tce_table(void) reserve_mem(local_alloc_bottom, local_alloc_top - local_alloc_bottom); - if (RELOC(prom_memory_limit)) { - /* - * We align the start to a 16MB boundary so we can map - * the TCE area using large pages if possible. - * The end should be the top of RAM so no need to align it. - */ - RELOC(prom_tce_alloc_start) = _ALIGN_DOWN(local_alloc_bottom, - 0x1000000); - RELOC(prom_tce_alloc_end) = local_alloc_top; - } + /* These are only really needed if there is a memory limit in + * effect, but we don't know so export them always. */ + RELOC(prom_tce_alloc_start) = local_alloc_bottom; + RELOC(prom_tce_alloc_end) = local_alloc_top; /* Flag the first invalid entry */ prom_debug("ending prom_initialize_tce_table\n"); @@ -2265,10 +2224,6 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, /* * Fill in some infos for use by the kernel later on */ - if (RELOC(prom_memory_limit)) - prom_setprop(_prom->chosen, "/chosen", "linux,memory-limit", - &RELOC(prom_memory_limit), - sizeof(prom_memory_limit)); #ifdef CONFIG_PPC64 if (RELOC(ppc64_iommu_off)) prom_setprop(_prom->chosen, "/chosen", "linux,iommu-off", diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 6224624c3d38..59773d9044ba 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -347,9 +347,6 @@ void __init setup_system(void) { DBG(" -> setup_system()\n"); -#ifdef CONFIG_KEXEC - kdump_move_device_tree(); -#endif /* * Unflatten the device-tree passed by prom_init or kexec */ diff --git a/arch/powerpc/mm/lmb.c b/arch/powerpc/mm/lmb.c index 417d58518558..8b6f522655a6 100644 --- a/arch/powerpc/mm/lmb.c +++ b/arch/powerpc/mm/lmb.c @@ -89,20 +89,25 @@ static long __init lmb_regions_adjacent(struct lmb_region *rgn, return lmb_addrs_adjacent(base1, size1, base2, size2); } -/* Assumption: base addr of region 1 < base addr of region 2 */ -static void __init lmb_coalesce_regions(struct lmb_region *rgn, - unsigned long r1, unsigned long r2) +static void __init lmb_remove_region(struct lmb_region *rgn, unsigned long r) { unsigned long i; - rgn->region[r1].size += rgn->region[r2].size; - for (i=r2; i < rgn->cnt-1; i++) { - rgn->region[i].base = rgn->region[i+1].base; - rgn->region[i].size = rgn->region[i+1].size; + for (i = r; i < rgn->cnt - 1; i++) { + rgn->region[i].base = rgn->region[i + 1].base; + rgn->region[i].size = rgn->region[i + 1].size; } rgn->cnt--; } +/* Assumption: base addr of region 1 < base addr of region 2 */ +static void __init lmb_coalesce_regions(struct lmb_region *rgn, + unsigned long r1, unsigned long r2) +{ + rgn->region[r1].size += rgn->region[r2].size; + lmb_remove_region(rgn, r2); +} + /* This routine called with relocation disabled. */ void __init lmb_init(void) { @@ -294,17 +299,16 @@ unsigned long __init lmb_end_of_DRAM(void) return (lmb.memory.region[idx].base + lmb.memory.region[idx].size); } -/* - * Truncate the lmb list to memory_limit if it's set - * You must call lmb_analyze() after this. - */ +/* You must call lmb_analyze() after this. */ void __init lmb_enforce_memory_limit(unsigned long memory_limit) { unsigned long i, limit; + struct lmb_property *p; if (! memory_limit) return; + /* Truncate the lmb regions to satisfy the memory limit. */ limit = memory_limit; for (i = 0; i < lmb.memory.cnt; i++) { if (limit > lmb.memory.region[i].size) { @@ -316,4 +320,21 @@ void __init lmb_enforce_memory_limit(unsigned long memory_limit) lmb.memory.cnt = i + 1; break; } + + lmb.rmo_size = lmb.memory.region[0].size; + + /* And truncate any reserves above the limit also. */ + for (i = 0; i < lmb.reserved.cnt; i++) { + p = &lmb.reserved.region[i]; + + if (p->base > memory_limit) + p->size = 0; + else if ((p->base + p->size) > memory_limit) + p->size = memory_limit - p->base; + + if (p->size == 0) { + lmb_remove_region(&lmb.reserved, i); + i--; + } + } } diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c index 074d1d949708..fd6d0ebe8ddd 100644 --- a/arch/powerpc/platforms/iseries/setup.c +++ b/arch/powerpc/platforms/iseries/setup.c @@ -90,8 +90,6 @@ extern unsigned long embedded_sysmap_end; extern unsigned long iSeries_recal_tb; extern unsigned long iSeries_recal_titan; -static unsigned long cmd_mem_limit; - struct MemoryBlock { unsigned long absStart; unsigned long absEnd; @@ -1026,8 +1024,6 @@ void build_flat_dt(struct iseries_flat_dt *dt, unsigned long phys_mem_size) /* /chosen */ dt_start_node(dt, "chosen"); dt_prop_str(dt, "bootargs", cmd_line); - if (cmd_mem_limit) - dt_prop_u64(dt, "linux,memory-limit", cmd_mem_limit); dt_end_node(dt); dt_cpus(dt); @@ -1053,29 +1049,11 @@ void * __init iSeries_early_setup(void) iSeries_get_cmdline(); - /* Save unparsed command line copy for /proc/cmdline */ - strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE); - - /* Parse early parameters, in particular mem=x */ - parse_early_param(); - build_flat_dt(&iseries_dt, phys_mem_size); return (void *) __pa(&iseries_dt); } -/* - * On iSeries we just parse the mem=X option from the command line. - * On pSeries it's a bit more complicated, see prom_init_mem() - */ -static int __init early_parsemem(char *p) -{ - if (p) - cmd_mem_limit = ALIGN(memparse(p, &p), PAGE_SIZE); - return 0; -} -early_param("mem", early_parsemem); - static void hvputc(char c) { if (c == '\n') diff --git a/include/asm-powerpc/kexec.h b/include/asm-powerpc/kexec.h index 6a2af2f6853b..0a1afced173f 100644 --- a/include/asm-powerpc/kexec.h +++ b/include/asm-powerpc/kexec.h @@ -31,9 +31,10 @@ #define KEXEC_ARCH KEXEC_ARCH_PPC #endif +#ifndef __ASSEMBLY__ + #ifdef CONFIG_KEXEC -#ifndef __ASSEMBLY__ #ifdef __powerpc64__ /* * This function is responsible for capturing register states if coming @@ -123,8 +124,16 @@ extern int default_machine_kexec_prepare(struct kimage *image); extern void default_machine_crash_shutdown(struct pt_regs *regs); extern void machine_kexec_simple(struct kimage *image); +extern int overlaps_crashkernel(unsigned long start, unsigned long size); + +#else /* !CONFIG_KEXEC */ + +static inline int overlaps_crashkernel(unsigned long start, unsigned long size) +{ + return 0; +} -#endif /* ! __ASSEMBLY__ */ #endif /* CONFIG_KEXEC */ +#endif /* ! __ASSEMBLY__ */ #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_KEXEC_H */ -- cgit v1.2.3 From 473104134b35ce1c3ca77b738c561d6c215adc1b Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 17 May 2006 18:00:49 +1000 Subject: [PATCH] powerpc: Kdump header cleanup We need to know the base address of the kdump kernel even when we're not a kdump kernel, so add a #define for it. Move the logic that sets the kdump kernelbase into kdump.h instead of page.h. Rename kdump_setup() to setup_kdump_trampoline() to make it clearer what it's doing, and add an empty definition for the !CRASH_DUMP case to avoid a Signed-off-by: Michael Ellerman Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/crash_dump.c | 11 ++++++++--- arch/powerpc/kernel/prom.c | 4 +--- arch/powerpc/kernel/setup_64.c | 4 +--- include/asm-powerpc/kdump.h | 29 +++++++++++++++++++++++++++-- include/asm-powerpc/page.h | 8 +------- 5 files changed, 38 insertions(+), 18 deletions(-) (limited to 'include') diff --git a/arch/powerpc/kernel/crash_dump.c b/arch/powerpc/kernel/crash_dump.c index 764d07329716..371973be8d71 100644 --- a/arch/powerpc/kernel/crash_dump.c +++ b/arch/powerpc/kernel/crash_dump.c @@ -25,6 +25,11 @@ #define DBG(fmt...) #endif +void reserve_kdump_trampoline(void) +{ + lmb_reserve(0, KDUMP_RESERVE_LIMIT); +} + static void __init create_trampoline(unsigned long addr) { /* The maximum range of a single instruction branch, is the current @@ -39,11 +44,11 @@ static void __init create_trampoline(unsigned long addr) create_branch(addr + 4, addr + PHYSICAL_START, 0); } -void __init kdump_setup(void) +void __init setup_kdump_trampoline(void) { unsigned long i; - DBG(" -> kdump_setup()\n"); + DBG(" -> setup_kdump_trampoline()\n"); for (i = KDUMP_TRAMPOLINE_START; i < KDUMP_TRAMPOLINE_END; i += 8) { create_trampoline(i); @@ -52,7 +57,7 @@ void __init kdump_setup(void) create_trampoline(__pa(system_reset_fwnmi) - PHYSICAL_START); create_trampoline(__pa(machine_check_fwnmi) - PHYSICAL_START); - DBG(" <- kdump_setup()\n"); + DBG(" <- setup_kdump_trampoline()\n"); } #ifdef CONFIG_PROC_VMCORE diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index a04f726d3bab..2498afeef291 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -1326,9 +1326,7 @@ void __init early_init_devtree(void *params) /* Reserve LMB regions used by kernel, initrd, dt, etc... */ lmb_reserve(PHYSICAL_START, __pa(klimit) - PHYSICAL_START); -#ifdef CONFIG_CRASH_DUMP - lmb_reserve(0, KDUMP_RESERVE_LIMIT); -#endif + reserve_kdump_trampoline(); early_reserve_mem(); lmb_enforce_memory_limit(memory_limit); diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 59773d9044ba..78f3a5fd43f6 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -193,9 +193,7 @@ void __init early_setup(unsigned long dt_ptr) /* Probe the machine type */ probe_machine(); -#ifdef CONFIG_CRASH_DUMP - kdump_setup(); -#endif + setup_kdump_trampoline(); DBG("Found, Initializing memory management...\n"); diff --git a/include/asm-powerpc/kdump.h b/include/asm-powerpc/kdump.h index a87aed00d61f..5a5c3b5ab1e0 100644 --- a/include/asm-powerpc/kdump.h +++ b/include/asm-powerpc/kdump.h @@ -1,13 +1,38 @@ #ifndef _PPC64_KDUMP_H #define _PPC64_KDUMP_H +/* Kdump kernel runs at 32 MB, change at your peril. */ +#define KDUMP_KERNELBASE 0x2000000 + /* How many bytes to reserve at zero for kdump. The reserve limit should - * be greater or equal to the trampoline's end address. */ + * be greater or equal to the trampoline's end address. + * Reserve to the end of the FWNMI area, see head_64.S */ #define KDUMP_RESERVE_LIMIT 0x8000 +#ifdef CONFIG_CRASH_DUMP + +#define PHYSICAL_START KDUMP_KERNELBASE #define KDUMP_TRAMPOLINE_START 0x0100 #define KDUMP_TRAMPOLINE_END 0x3000 -extern void kdump_setup(void); +#else /* !CONFIG_CRASH_DUMP */ + +#define PHYSICAL_START 0x0 + +#endif /* CONFIG_CRASH_DUMP */ + +#ifndef __ASSEMBLY__ +#ifdef CONFIG_CRASH_DUMP + +extern void reserve_kdump_trampoline(void); +extern void setup_kdump_trampoline(void); + +#else /* !CONFIG_CRASH_DUMP */ + +static inline void reserve_kdump_trampoline(void) { ; } +static inline void setup_kdump_trampoline(void) { ; } + +#endif /* CONFIG_CRASH_DUMP */ +#endif /* __ASSEMBLY__ */ #endif /* __PPC64_KDUMP_H */ diff --git a/include/asm-powerpc/page.h b/include/asm-powerpc/page.h index 2fbecebe1c92..ae610b620487 100644 --- a/include/asm-powerpc/page.h +++ b/include/asm-powerpc/page.h @@ -13,6 +13,7 @@ #ifdef __KERNEL__ #include #include +#include /* * On PPC32 page size is 4K. For PPC64 we support either 4K or 64K software @@ -52,13 +53,6 @@ * If you want to test if something's a kernel address, use is_kernel_addr(). */ -#ifdef CONFIG_CRASH_DUMP -/* Kdump kernel runs at 32 MB, change at your peril. */ -#define PHYSICAL_START 0x2000000 -#else -#define PHYSICAL_START 0x0 -#endif - #define PAGE_OFFSET ASM_CONST(CONFIG_KERNEL_START) #define KERNELBASE (PAGE_OFFSET + PHYSICAL_START) -- cgit v1.2.3 From 35dd54326e857f1648c7cc1028e8d5e1dbe04992 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Thu, 18 May 2006 11:16:11 +1000 Subject: [PATCH] powerpc: Move crashkernel= handling into the kernel. This was missing a quilt ref. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/machine_kexec_64.c | 94 ++++++++++++++++++++++++++++++++++ arch/powerpc/kernel/prom.c | 1 + arch/powerpc/kernel/prom_init.c | 54 ------------------- include/asm-powerpc/kexec.h | 3 ++ 4 files changed, 98 insertions(+), 54 deletions(-) (limited to 'include') diff --git a/arch/powerpc/kernel/machine_kexec_64.c b/arch/powerpc/kernel/machine_kexec_64.c index 1ccb188ba40d..a8fa04ef27cd 100644 --- a/arch/powerpc/kernel/machine_kexec_64.c +++ b/arch/powerpc/kernel/machine_kexec_64.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include /* _end */ #include @@ -335,9 +336,102 @@ static void __init export_htab_values(void) of_node_put(node); } +static struct property crashk_base_prop = { + .name = "linux,crashkernel-base", + .length = sizeof(unsigned long), + .value = (unsigned char *)&crashk_res.start, +}; + +static unsigned long crashk_size; + +static struct property crashk_size_prop = { + .name = "linux,crashkernel-size", + .length = sizeof(unsigned long), + .value = (unsigned char *)&crashk_size, +}; + +static void __init export_crashk_values(void) +{ + struct device_node *node; + struct property *prop; + + node = of_find_node_by_path("/chosen"); + if (!node) + return; + + /* There might be existing crash kernel properties, but we can't + * be sure what's in them, so remove them. */ + prop = of_find_property(node, "linux,crashkernel-base", NULL); + if (prop) + prom_remove_property(node, prop); + + prop = of_find_property(node, "linux,crashkernel-size", NULL); + if (prop) + prom_remove_property(node, prop); + + if (crashk_res.start != 0) { + prom_add_property(node, &crashk_base_prop); + crashk_size = crashk_res.end - crashk_res.start + 1; + prom_add_property(node, &crashk_size_prop); + } + + of_node_put(node); +} + void __init kexec_setup(void) { export_htab_values(); + export_crashk_values(); +} + +static int __init early_parse_crashk(char *p) +{ + unsigned long size; + + if (!p) + return 1; + + size = memparse(p, &p); + + if (*p == '@') + crashk_res.start = memparse(p + 1, &p); + else + crashk_res.start = KDUMP_KERNELBASE; + + crashk_res.end = crashk_res.start + size - 1; + + return 0; +} +early_param("crashkernel", early_parse_crashk); + +void __init reserve_crashkernel(void) +{ + unsigned long size; + + if (crashk_res.start == 0) + return; + + /* We might have got these values via the command line or the + * device tree, either way sanitise them now. */ + + size = crashk_res.end - crashk_res.start + 1; + + if (crashk_res.start != KDUMP_KERNELBASE) + printk("Crash kernel location must be 0x%x\n", + KDUMP_KERNELBASE); + + crashk_res.start = KDUMP_KERNELBASE; + size = PAGE_ALIGN(size); + crashk_res.end = crashk_res.start + size - 1; + + /* Crash kernel trumps memory limit */ + if (memory_limit && memory_limit <= crashk_res.end) { + memory_limit = crashk_res.end + 1; + printk("Adjusted memory limit for crashkernel, now 0x%lx\n", + memory_limit); + } + + lmb_reserve(crashk_res.start, size); } int overlaps_crashkernel(unsigned long start, unsigned long size) diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 2498afeef291..8d0415b080bb 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -1327,6 +1327,7 @@ void __init early_init_devtree(void *params) /* Reserve LMB regions used by kernel, initrd, dt, etc... */ lmb_reserve(PHYSICAL_START, __pa(klimit) - PHYSICAL_START); reserve_kdump_trampoline(); + reserve_crashkernel(); early_reserve_mem(); lmb_enforce_memory_limit(memory_limit); diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index a52377c68fc6..2442361772e2 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -200,11 +200,6 @@ static unsigned long __initdata alloc_bottom; static unsigned long __initdata rmo_top; static unsigned long __initdata ram_top; -#ifdef CONFIG_KEXEC -static unsigned long __initdata prom_crashk_base; -static unsigned long __initdata prom_crashk_size; -#endif - static struct mem_map_entry __initdata mem_reserve_map[MEM_RESERVE_MAP_SIZE]; static int __initdata mem_reserve_cnt; @@ -591,35 +586,6 @@ static void __init early_cmdline_parse(void) RELOC(iommu_force_on) = 1; } #endif - -#ifdef CONFIG_KEXEC - /* - * crashkernel=size@addr specifies the location to reserve for - * crash kernel. - */ - opt = strstr(RELOC(prom_cmd_line), RELOC("crashkernel=")); - if (opt) { - opt += 12; - RELOC(prom_crashk_size) = - prom_memparse(opt, (const char **)&opt); - - if (ALIGN(RELOC(prom_crashk_size), 0x1000000) != - RELOC(prom_crashk_size)) { - prom_printf("Warning: crashkernel size is not " - "aligned to 16MB\n"); - } - - /* - * At present, the crash kernel always run at 32MB. - * Just ignore whatever user passed. - */ - RELOC(prom_crashk_base) = 0x2000000; - if (*opt == '@') { - prom_printf("Warning: PPC64 kdump kernel always runs " - "at 32 MB\n"); - } - } -#endif } #ifdef CONFIG_PPC_PSERIES @@ -1122,12 +1088,6 @@ static void __init prom_init_mem(void) prom_printf(" alloc_top_hi : %x\n", RELOC(alloc_top_high)); prom_printf(" rmo_top : %x\n", RELOC(rmo_top)); prom_printf(" ram_top : %x\n", RELOC(ram_top)); -#ifdef CONFIG_KEXEC - if (RELOC(prom_crashk_base)) { - prom_printf(" crashk_base : %x\n", RELOC(prom_crashk_base)); - prom_printf(" crashk_size : %x\n", RELOC(prom_crashk_size)); - } -#endif } @@ -2187,10 +2147,6 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, */ prom_init_mem(); -#ifdef CONFIG_KEXEC - if (RELOC(prom_crashk_base)) - reserve_mem(RELOC(prom_crashk_base), RELOC(prom_crashk_size)); -#endif /* * Determine which cpu is actually running right _now_ */ @@ -2243,16 +2199,6 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, } #endif -#ifdef CONFIG_KEXEC - if (RELOC(prom_crashk_base)) { - prom_setprop(_prom->chosen, "/chosen", "linux,crashkernel-base", - PTRRELOC(&prom_crashk_base), - sizeof(RELOC(prom_crashk_base))); - prom_setprop(_prom->chosen, "/chosen", "linux,crashkernel-size", - PTRRELOC(&prom_crashk_size), - sizeof(RELOC(prom_crashk_size))); - } -#endif /* * Fixup any known bugs in the device-tree */ diff --git a/include/asm-powerpc/kexec.h b/include/asm-powerpc/kexec.h index 0a1afced173f..efe8872ec583 100644 --- a/include/asm-powerpc/kexec.h +++ b/include/asm-powerpc/kexec.h @@ -125,6 +125,7 @@ extern void default_machine_crash_shutdown(struct pt_regs *regs); extern void machine_kexec_simple(struct kimage *image); extern int overlaps_crashkernel(unsigned long start, unsigned long size); +extern void reserve_crashkernel(void); #else /* !CONFIG_KEXEC */ @@ -133,6 +134,8 @@ static inline int overlaps_crashkernel(unsigned long start, unsigned long size) return 0; } +static inline void reserve_crashkernel(void) { ; } + #endif /* CONFIG_KEXEC */ #endif /* ! __ASSEMBLY__ */ #endif /* __KERNEL__ */ -- cgit v1.2.3 From 8ae5b2801a0beb10a55a7ebd5140482e2f84c3fa Mon Sep 17 00:00:00 2001 From: "jimix@watson.ibm.com" Date: Wed, 17 May 2006 12:00:35 -0400 Subject: [PATCH] powerpc: udbg_printf() formatting attribute This patch allows the compiler to catch any printf-like mismatches for udbg_printf(). After some brute force building I've only found issues with my own code and lparcfg.c It could break some developers, but IMHO that would be goodness. Signed-off-by: Jimi Xenidis Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/lparcfg.c | 4 ++-- include/asm-powerpc/udbg.h | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/arch/powerpc/kernel/lparcfg.c b/arch/powerpc/kernel/lparcfg.c index 2cbde865d4f5..c02deaab26c7 100644 --- a/arch/powerpc/kernel/lparcfg.c +++ b/arch/powerpc/kernel/lparcfg.c @@ -521,10 +521,10 @@ static ssize_t lparcfg_write(struct file *file, const char __user * buf, current_weight = (resource >> 5 * 8) & 0xFF; - pr_debug("%s: current_entitled = %lu, current_weight = %lu\n", + pr_debug("%s: current_entitled = %lu, current_weight = %u\n", __FUNCTION__, current_entitled, current_weight); - pr_debug("%s: new_entitled = %lu, new_weight = %lu\n", + pr_debug("%s: new_entitled = %lu, new_weight = %u\n", __FUNCTION__, *new_entitled_ptr, *new_weight_ptr); retval = plpar_hcall_norets(H_SET_PPP, *new_entitled_ptr, diff --git a/include/asm-powerpc/udbg.h b/include/asm-powerpc/udbg.h index 5c4236c342bb..19a1517ac43b 100644 --- a/include/asm-powerpc/udbg.h +++ b/include/asm-powerpc/udbg.h @@ -23,7 +23,8 @@ extern int udbg_write(const char *s, int n); extern int udbg_read(char *buf, int buflen); extern void register_early_udbg_console(void); -extern void udbg_printf(const char *fmt, ...); +extern void udbg_printf(const char *fmt, ...) + __attribute__ ((format (printf, 1, 2))); extern void udbg_progress(char *s, unsigned short hex); extern void udbg_init_uart(void __iomem *comport, unsigned int speed, -- cgit v1.2.3 From d4ad66faecc4dd9f3db14e0b013741a6f867b089 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Thu, 18 May 2006 18:05:15 +1000 Subject: [PATCH] powerpc: Add of_parse_dma_window() Add a function for generic parsing of dma-window properties (ie, ibm,dma-window and ibm,my-dma-window) of pci and virtual device nodes. This function will also be used by cell. Signed-off-by: Jeremy Kerr Acked-by: Olof Johansson Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/prom_parse.c | 22 ++++++++++++++++++++++ include/asm-powerpc/prom.h | 6 ++++++ 2 files changed, 28 insertions(+) (limited to 'include') diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c index 3934c227549b..23bb060330ef 100644 --- a/arch/powerpc/kernel/prom_parse.c +++ b/arch/powerpc/kernel/prom_parse.c @@ -548,3 +548,25 @@ int of_pci_address_to_resource(struct device_node *dev, int bar, return __of_address_to_resource(dev, addrp, size, flags, r); } EXPORT_SYMBOL_GPL(of_pci_address_to_resource); + +void of_parse_dma_window(struct device_node *dn, unsigned char *dma_window_prop, + unsigned long *busno, unsigned long *phys, unsigned long *size) +{ + u32 *dma_window, cells; + unsigned char *prop; + + dma_window = (u32 *)dma_window_prop; + + /* busno is always one cell */ + *busno = *(dma_window++); + + prop = get_property(dn, "ibm,#dma-address-cells", NULL); + cells = prop ? *(u32 *)prop : prom_n_addr_cells(dn); + *phys = of_read_addr(dma_window, cells); + + dma_window += cells; + + prop = get_property(dn, "ibm,#dma-size-cells", NULL); + cells = prop ? *(u32 *)prop : prom_n_size_cells(dn); + *size = of_read_addr(dma_window, cells); +} diff --git a/include/asm-powerpc/prom.h b/include/asm-powerpc/prom.h index 97ef1cd71a4d..c79d58ab7441 100644 --- a/include/asm-powerpc/prom.h +++ b/include/asm-powerpc/prom.h @@ -230,6 +230,12 @@ extern int of_address_to_resource(struct device_node *dev, int index, extern int of_pci_address_to_resource(struct device_node *dev, int bar, struct resource *r); +/* Parse the ibm,dma-window property of an OF node into the busno, phys and + * size parameters. + */ +void of_parse_dma_window(struct device_node *dn, unsigned char *dma_window_prop, + unsigned long *busno, unsigned long *phys, unsigned long *size); + extern void kdump_move_device_tree(void); #endif /* __KERNEL__ */ -- cgit v1.2.3 From 3655d1d323386e001c786af10f0a3f39f438f03b Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Fri, 19 May 2006 11:43:04 +0800 Subject: [PATCH] libata: Fix the HSM error_mask mapping (was: Re: libata-tj and SMART) Fix the HSM error_mask mapping. Changes: - Better mapping in ac_err_mask() - In HSM_ST_FIRST ans HSM_ST state, check ATA_ERR|ATA_DF and map it to AC_ERR_DEV instead of AC_ERR_HSM. - In HSM_ST_FIRST and HSM_ST state, map DRQ=1 ERR=1 to AC_ERR_HSM. - For PIO data in and DRQ=1 ERR=1, add check after the junk data block is read. Signed-off-by: Albert Lee Signed-off-by: Jeff Garzik --- drivers/scsi/libata-core.c | 31 ++++++++++++++++++++++++------- include/linux/libata.h | 2 +- 2 files changed, 25 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 00881226f8dd..aa38ed3e59a8 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -4009,9 +4009,15 @@ fsm_start: poll_next = (qc->tf.flags & ATA_TFLAG_POLLING); /* check device status */ - if (unlikely((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ)) { - /* Wrong status. Let EH handle this */ - qc->err_mask |= AC_ERR_HSM; + if (unlikely((status & ATA_DRQ) == 0)) { + /* handle BSY=0, DRQ=0 as error */ + if (likely(status & (ATA_ERR | ATA_DF))) + /* device stops HSM for abort/error */ + qc->err_mask |= AC_ERR_DEV; + else + /* HSM violation. Let EH handle this */ + qc->err_mask |= AC_ERR_HSM; + ap->hsm_task_state = HSM_ST_ERR; goto fsm_start; } @@ -4025,7 +4031,7 @@ fsm_start: if (unlikely(status & (ATA_ERR | ATA_DF))) { printk(KERN_WARNING "ata%d: DRQ=1 with device error, dev_stat 0x%X\n", ap->id, status); - qc->err_mask |= AC_ERR_DEV; + qc->err_mask |= AC_ERR_HSM; ap->hsm_task_state = HSM_ST_ERR; goto fsm_start; } @@ -4067,7 +4073,9 @@ fsm_start: if (qc->tf.protocol == ATA_PROT_ATAPI) { /* ATAPI PIO protocol */ if ((status & ATA_DRQ) == 0) { - /* no more data to transfer */ + /* No more data to transfer or device error. + * Device error will be tagged in HSM_ST_LAST. + */ ap->hsm_task_state = HSM_ST_LAST; goto fsm_start; } @@ -4081,7 +4089,7 @@ fsm_start: if (unlikely(status & (ATA_ERR | ATA_DF))) { printk(KERN_WARNING "ata%d: DRQ=1 with device error, dev_stat 0x%X\n", ap->id, status); - qc->err_mask |= AC_ERR_DEV; + qc->err_mask |= AC_ERR_HSM; ap->hsm_task_state = HSM_ST_ERR; goto fsm_start; } @@ -4096,7 +4104,13 @@ fsm_start: /* ATA PIO protocol */ if (unlikely((status & ATA_DRQ) == 0)) { /* handle BSY=0, DRQ=0 as error */ - qc->err_mask |= AC_ERR_HSM; + if (likely(status & (ATA_ERR | ATA_DF))) + /* device stops HSM for abort/error */ + qc->err_mask |= AC_ERR_DEV; + else + /* HSM violation. Let EH handle this */ + qc->err_mask |= AC_ERR_HSM; + ap->hsm_task_state = HSM_ST_ERR; goto fsm_start; } @@ -4121,6 +4135,9 @@ fsm_start: status = ata_wait_idle(ap); } + if (status & (ATA_BUSY | ATA_DRQ)) + qc->err_mask |= AC_ERR_HSM; + /* ata_pio_sectors() might change the * state to HSM_ST_LAST. so, the state * is changed after ata_pio_sectors(). diff --git a/include/linux/libata.h b/include/linux/libata.h index 2803ab8e9243..c51502c047a4 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -1062,7 +1062,7 @@ static inline int ata_try_flush_cache(const struct ata_device *dev) static inline unsigned int ac_err_mask(u8 status) { - if (status & ATA_BUSY) + if (status & (ATA_BUSY | ATA_DRQ)) return AC_ERR_HSM; if (status & (ATA_ERR | ATA_DF)) return AC_ERR_DEV; -- cgit v1.2.3 From f8bbfc247efb0e5fa69094614380768ce79afe17 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 19 May 2006 21:07:05 +0900 Subject: [PATCH] SCSI: make scsi_implement_eh() generic API for SCSI transports libata implemented a feature to schedule EH without an associated EH by manipulating shost->host_eh_scheduled in ata_scsi_schedule_eh() directly. Move this function to scsi_error.c and rename it to scsi_schedule_eh(). It is now an exported API for SCSI transports and exported via new header file drivers/scsi/scsi_transport_api.h This patch also de-export scsi_eh_wakeup() which was exported specifically for ata_scsi_schedule_eh(). Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/scsi/libata-eh.c | 3 ++- drivers/scsi/libata-scsi.c | 24 ------------------------ drivers/scsi/scsi_error.c | 23 ++++++++++++++++++++++- drivers/scsi/scsi_priv.h | 1 + drivers/scsi/scsi_transport_api.h | 6 ++++++ include/scsi/scsi_eh.h | 1 - 6 files changed, 31 insertions(+), 27 deletions(-) create mode 100644 drivers/scsi/scsi_transport_api.h (limited to 'include') diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index 750e734d1c09..71b45ad2c124 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c @@ -39,6 +39,7 @@ #include #include #include +#include "scsi_transport_api.h" #include @@ -432,7 +433,7 @@ void ata_port_schedule_eh(struct ata_port *ap) WARN_ON(!ap->ops->error_handler); ap->flags |= ATA_FLAG_EH_PENDING; - ata_schedule_scsi_eh(ap->host); + scsi_schedule_eh(ap->host); DPRINTK("port EH scheduled\n"); } diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index f036ae4b8afb..2007b4b6e1b4 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -2745,27 +2745,3 @@ void ata_scsi_scan_host(struct ata_port *ap) scsi_scan_target(&ap->host->shost_gendev, 0, i, 0, 0); } } - -/** - * ata_schedule_scsi_eh - schedule EH for SCSI host - * @shost: SCSI host to invoke error handling on. - * - * Schedule SCSI EH without scmd. This is a hack. - * - * LOCKING: - * spin_lock_irqsave(host_set lock) - **/ -void ata_schedule_scsi_eh(struct Scsi_Host *shost) -{ - unsigned long flags; - - spin_lock_irqsave(shost->host_lock, flags); - - if (scsi_host_set_state(shost, SHOST_RECOVERY) == 0 || - scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY) == 0) { - shost->host_eh_scheduled++; - scsi_eh_wakeup(shost); - } - - spin_unlock_irqrestore(shost->host_lock, flags); -} diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 9ca71cbefce0..346ab72ebf86 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -56,7 +56,28 @@ void scsi_eh_wakeup(struct Scsi_Host *shost) printk("Waking error handler thread\n")); } } -EXPORT_SYMBOL_GPL(scsi_eh_wakeup); + +/** + * scsi_schedule_eh - schedule EH for SCSI host + * @shost: SCSI host to invoke error handling on. + * + * Schedule SCSI EH without scmd. + **/ +void scsi_schedule_eh(struct Scsi_Host *shost) +{ + unsigned long flags; + + spin_lock_irqsave(shost->host_lock, flags); + + if (scsi_host_set_state(shost, SHOST_RECOVERY) == 0 || + scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY) == 0) { + shost->host_eh_scheduled++; + scsi_eh_wakeup(shost); + } + + spin_unlock_irqrestore(shost->host_lock, flags); +} +EXPORT_SYMBOL_GPL(scsi_schedule_eh); /** * scsi_eh_scmd_add - add scsi cmd to error handling. diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index 0b39081113be..27c48274e8cb 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -63,6 +63,7 @@ extern int scsi_delete_timer(struct scsi_cmnd *); extern void scsi_times_out(struct scsi_cmnd *cmd); extern int scsi_error_handler(void *host); extern int scsi_decide_disposition(struct scsi_cmnd *cmd); +extern void scsi_eh_wakeup(struct Scsi_Host *shost); extern int scsi_eh_scmd_add(struct scsi_cmnd *, int); /* scsi_lib.c */ diff --git a/drivers/scsi/scsi_transport_api.h b/drivers/scsi/scsi_transport_api.h new file mode 100644 index 000000000000..934f0e62bb5c --- /dev/null +++ b/drivers/scsi/scsi_transport_api.h @@ -0,0 +1,6 @@ +#ifndef _SCSI_TRANSPORT_API_H +#define _SCSI_TRANSPORT_API_H + +void scsi_schedule_eh(struct Scsi_Host *shost); + +#endif /* _SCSI_TRANSPORT_API_H */ diff --git a/include/scsi/scsi_eh.h b/include/scsi/scsi_eh.h index 212c983a6a18..d160880b2a87 100644 --- a/include/scsi/scsi_eh.h +++ b/include/scsi/scsi_eh.h @@ -35,7 +35,6 @@ static inline int scsi_sense_valid(struct scsi_sense_hdr *sshdr) } -extern void scsi_eh_wakeup(struct Scsi_Host *shost); extern void scsi_eh_finish_cmd(struct scsi_cmnd *scmd, struct list_head *done_q); extern void scsi_eh_flush_done_q(struct list_head *done_q); -- cgit v1.2.3 From 656cffc95f0cb8211aa75eaca249e6ff4f59ec83 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Thu, 18 May 2006 20:31:42 -0500 Subject: [SCSI] iscsi: fix command requeues during iscsi recovery Do not flush queues then block session. This will cause commands to needlessly swing around on us and remove goofy recovery_failed field and replace with state value. And do not start recovery from within the host reset function. This causeis too many problems becuase open-iscsi was desinged to call out to userspace then have userpscae decide if we should go into recovery or kill the session. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/libiscsi.c | 87 ++++++++++++++++++++----------------- include/scsi/libiscsi.h | 3 -- include/scsi/scsi_transport_iscsi.h | 2 + 3 files changed, 50 insertions(+), 42 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 580c0505603c..d810acae45f7 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -487,6 +487,11 @@ void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err) unsigned long flags; spin_lock_irqsave(&session->lock, flags); + if (session->state == ISCSI_STATE_FAILED) { + spin_unlock_irqrestore(&session->lock, flags); + return; + } + if (session->conn_cnt == 1 || session->leadconn == conn) session->state = ISCSI_STATE_FAILED; spin_unlock_irqrestore(&session->lock, flags); @@ -612,6 +617,7 @@ enum { FAILURE_SESSION_FREED, FAILURE_WINDOW_CLOSED, FAILURE_SESSION_TERMINATE, + FAILURE_SESSION_IN_RECOVERY, FAILURE_SESSION_RECOVERY_TIMEOUT, }; @@ -631,18 +637,30 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) spin_lock(&session->lock); - if (session->state != ISCSI_STATE_LOGGED_IN) { - if (session->recovery_failed) { - reason = FAILURE_SESSION_RECOVERY_TIMEOUT; - goto fault; - } else if (session->state == ISCSI_STATE_FAILED) { - reason = FAILURE_SESSION_FAILED; - goto reject; - } else if (session->state == ISCSI_STATE_TERMINATE) { - reason = FAILURE_SESSION_TERMINATE; + /* + * ISCSI_STATE_FAILED is a temp. state. The recovery + * code will decide what is best to do with command queued + * during this time + */ + if (session->state != ISCSI_STATE_LOGGED_IN && + session->state != ISCSI_STATE_FAILED) { + /* + * to handle the race between when we set the recovery state + * and block the session we requeue here (commands could + * be entering our queuecommand while a block is starting + * up because the block code is not locked) + */ + if (session->state == ISCSI_STATE_IN_RECOVERY) { + reason = FAILURE_SESSION_IN_RECOVERY; goto fault; } - reason = FAILURE_SESSION_FREED; + + if (session->state == ISCSI_STATE_RECOVERY_FAILED) + reason = FAILURE_SESSION_RECOVERY_TIMEOUT; + else if (session->state == ISCSI_STATE_TERMINATE) + reason = FAILURE_SESSION_TERMINATE; + else + reason = FAILURE_SESSION_FREED; goto fault; } @@ -728,8 +746,8 @@ iscsi_conn_send_generic(struct iscsi_conn *conn, struct iscsi_hdr *hdr, */ mtask = conn->login_mtask; else { - BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE); - BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED); + BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE); + BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED); nop->exp_statsn = cpu_to_be32(conn->exp_statsn); if (!__kfifo_get(session->mgmtpool.queue, @@ -803,7 +821,7 @@ void iscsi_session_recovery_timedout(struct iscsi_cls_session *cls_session) spin_lock_bh(&session->lock); if (session->state != ISCSI_STATE_LOGGED_IN) { - session->recovery_failed = 1; + session->state = ISCSI_STATE_RECOVERY_FAILED; if (conn) wake_up(&conn->ehwait); } @@ -838,20 +856,14 @@ failed: * we drop the lock here but the leadconn cannot be destoyed while * we are in the scsi eh */ - if (fail_session) { + if (fail_session) iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); - /* - * if userspace cannot respond then we must kick this off - * here for it - */ - iscsi_start_session_recovery(session, conn, STOP_CONN_RECOVER); - } debug_scsi("iscsi_eh_host_reset wait for relogin\n"); wait_event_interruptible(conn->ehwait, session->state == ISCSI_STATE_TERMINATE || session->state == ISCSI_STATE_LOGGED_IN || - session->recovery_failed); + session->state == ISCSI_STATE_RECOVERY_FAILED); if (signal_pending(current)) flush_signals(current); @@ -940,8 +952,7 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc, wait_event_interruptible(conn->ehwait, sc->SCp.phase != session->age || session->state != ISCSI_STATE_LOGGED_IN || - conn->tmabort_state != TMABORT_INITIAL || - session->recovery_failed); + conn->tmabort_state != TMABORT_INITIAL); if (signal_pending(current)) flush_signals(current); del_timer_sync(&conn->tmabort_timer); @@ -1491,7 +1502,6 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn) conn->stop_stage = 0; conn->tmabort_state = TMABORT_INITIAL; session->age++; - session->recovery_failed = 0; spin_unlock_bh(&session->lock); iscsi_unblock_session(session_to_cls(session)); @@ -1566,8 +1576,8 @@ static void fail_all_commands(struct iscsi_conn *conn) conn->ctask = NULL; } -void iscsi_start_session_recovery(struct iscsi_session *session, - struct iscsi_conn *conn, int flag) +static void iscsi_start_session_recovery(struct iscsi_session *session, + struct iscsi_conn *conn, int flag) { int old_stop_stage; @@ -1597,19 +1607,10 @@ void iscsi_start_session_recovery(struct iscsi_session *session, set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); if (session->conn_cnt == 0 || session->leadconn == conn) - session->state = ISCSI_STATE_FAILED; + session->state = ISCSI_STATE_IN_RECOVERY; spin_unlock_bh(&session->lock); - session->tt->terminate_conn(conn); - /* - * flush queues. - */ - spin_lock_bh(&session->lock); - fail_all_commands(conn); - flush_control_queues(session, conn); - spin_unlock_bh(&session->lock); - /* * for connection level recovery we should not calculate * header digest. conn->hdr_size used for optimization @@ -1619,18 +1620,26 @@ void iscsi_start_session_recovery(struct iscsi_session *session, if (flag == STOP_CONN_RECOVER) { conn->hdrdgst_en = 0; conn->datadgst_en = 0; - /* * if this is called from the eh and and from userspace * then we only need to block once. */ - if (session->state == ISCSI_STATE_FAILED && + if (session->state == ISCSI_STATE_IN_RECOVERY && old_stop_stage != STOP_CONN_RECOVER) iscsi_block_session(session_to_cls(session)); } + + session->tt->terminate_conn(conn); + /* + * flush queues. + */ + spin_lock_bh(&session->lock); + fail_all_commands(conn); + flush_control_queues(session, conn); + spin_unlock_bh(&session->lock); + mutex_unlock(&conn->xmitmutex); } -EXPORT_SYMBOL_GPL(iscsi_start_session_recovery); void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) { diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h index 2dba929a2a05..17b28f08b692 100644 --- a/include/scsi/libiscsi.h +++ b/include/scsi/libiscsi.h @@ -210,7 +210,6 @@ struct iscsi_session { * - mgmtpool, * * - r2tpool */ int state; /* session state */ - int recovery_failed; struct list_head item; int conn_cnt; int age; /* counts session re-opens */ @@ -241,8 +240,6 @@ iscsi_session_setup(struct iscsi_transport *, struct scsi_transport_template *, int, int, uint32_t, uint32_t *); extern void iscsi_session_teardown(struct iscsi_cls_session *); extern struct iscsi_session *class_to_transport_session(struct iscsi_cls_session *); -extern void iscsi_start_session_recovery(struct iscsi_session *, - struct iscsi_conn *, int); extern void iscsi_session_recovery_timedout(struct iscsi_cls_session *); #define session_to_cls(_sess) \ diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h index c9e9475c6dff..92129b97d31e 100644 --- a/include/scsi/scsi_transport_iscsi.h +++ b/include/scsi/scsi_transport_iscsi.h @@ -173,6 +173,8 @@ struct iscsi_cls_conn { #define ISCSI_STATE_LOGGED_IN 2 #define ISCSI_STATE_FAILED 3 #define ISCSI_STATE_TERMINATE 4 +#define ISCSI_STATE_IN_RECOVERY 5 +#define ISCSI_STATE_RECOVERY_FAILED 6 struct iscsi_cls_session { struct list_head sess_list; /* item in session_list */ -- cgit v1.2.3 From e0ecae8da26d94dd878ff1d939c5aa4224df18a4 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Thu, 18 May 2006 20:31:43 -0500 Subject: [SCSI] iscsi: update version update version Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/iscsi_tcp.c | 8 +++++--- include/scsi/iscsi_proto.h | 2 -- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 08357a6c7e09..c66faee07ca5 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -43,11 +43,13 @@ #include "iscsi_tcp.h" +#define ISCSI_TCP_VERSION "1.0-574" + MODULE_AUTHOR("Dmitry Yusupov , " "Alex Aizman "); MODULE_DESCRIPTION("iSCSI/TCP data-path"); MODULE_LICENSE("GPL"); -MODULE_VERSION("0:4.445"); +MODULE_VERSION(ISCSI_TCP_VERSION); /* #define DEBUG_TCP */ #define DEBUG_ASSERT @@ -2448,8 +2450,8 @@ static void iscsi_tcp_session_destroy(struct iscsi_cls_session *cls_session) } static struct scsi_host_template iscsi_sht = { - .name = "iSCSI Initiator over TCP/IP, v." - ISCSI_VERSION_STR, + .name = "iSCSI Initiator over TCP/IP, v" + ISCSI_TCP_VERSION, .queuecommand = iscsi_queuecommand, .change_queue_depth = iscsi_change_queue_depth, .can_queue = ISCSI_XMIT_CMDS_MAX - 1, diff --git a/include/scsi/iscsi_proto.h b/include/scsi/iscsi_proto.h index 4feda05fdf25..02f6e4b9e693 100644 --- a/include/scsi/iscsi_proto.h +++ b/include/scsi/iscsi_proto.h @@ -21,8 +21,6 @@ #ifndef ISCSI_PROTO_H #define ISCSI_PROTO_H -#define ISCSI_VERSION_STR "0.3" -#define ISCSI_DATE_STR "22-Apr-2005" #define ISCSI_DRAFT20_VERSION 0x00 /* default iSCSI listen port for incoming connections */ -- cgit v1.2.3 From 4c5c81613b0eb0dba97a8f312a2f1162f39fd47b Mon Sep 17 00:00:00 2001 From: Andrew Chew Date: Thu, 20 Apr 2006 15:54:26 -0700 Subject: [PATCH] sata_nv: Add MCP61 support Added MCP61 SATA support to sata_nv. Signed-off-by: Jeff Garzik --- drivers/ide/pci/amd74xx.c | 7 +++++-- drivers/scsi/sata_nv.c | 6 ++++++ include/linux/pci_ids.h | 4 ++++ 3 files changed, 15 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c index b22ee5462318..6e9dbf4d8077 100644 --- a/drivers/ide/pci/amd74xx.c +++ b/drivers/ide/pci/amd74xx.c @@ -74,6 +74,7 @@ static struct amd_ide_chip { { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, 0x50, AMD_UDMA_133 }, { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE, 0x50, AMD_UDMA_133 }, { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE, 0x50, AMD_UDMA_133 }, + { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE, 0x50, AMD_UDMA_133 }, { PCI_DEVICE_ID_AMD_CS5536_IDE, 0x40, AMD_UDMA_100 }, { 0 } }; @@ -488,7 +489,8 @@ static ide_pci_device_t amd74xx_chipsets[] __devinitdata = { /* 14 */ DECLARE_NV_DEV("NFORCE-MCP04"), /* 15 */ DECLARE_NV_DEV("NFORCE-MCP51"), /* 16 */ DECLARE_NV_DEV("NFORCE-MCP55"), - /* 17 */ DECLARE_AMD_DEV("AMD5536"), + /* 17 */ DECLARE_NV_DEV("NFORCE-MCP61"), + /* 18 */ DECLARE_AMD_DEV("AMD5536"), }; static int __devinit amd74xx_probe(struct pci_dev *dev, const struct pci_device_id *id) @@ -525,7 +527,8 @@ static struct pci_device_id amd74xx_pci_tbl[] = { { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 16 }, - { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 17 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 17 }, + { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 18 }, { 0, }, }; MODULE_DEVICE_TABLE(pci, amd74xx_pci_tbl); diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c index 70c51088d371..043ff4fd9ba7 100644 --- a/drivers/scsi/sata_nv.c +++ b/drivers/scsi/sata_nv.c @@ -140,6 +140,12 @@ static const struct pci_device_id nv_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC }, { PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE<<8, 0xffff00, GENERIC }, diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index d6fe048376ab..233f60741c82 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1182,6 +1182,10 @@ #define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_1100 0x034E #define PCI_DEVICE_ID_NVIDIA_NVENET_14 0x0372 #define PCI_DEVICE_ID_NVIDIA_NVENET_15 0x0373 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA 0x03E7 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE 0x03EC +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2 0x03F6 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3 0x03F7 #define PCI_VENDOR_ID_IMS 0x10e0 #define PCI_DEVICE_ID_IMS_TT128 0x9128 -- cgit v1.2.3 From a6b2c5d4754dc539a560fdf0d3fb78a14174394a Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 22 May 2006 16:59:59 +0100 Subject: [PATCH] PATCH: libata. Add ->data_xfer method We need to pass the device in order to do per device checks such as 32bit I/O enables. With the changes to include dev->ap we now don't have to add parameters however just clean them up. Also add data_xfer methods to the existing drivers except ata_piix (which is in the other block of patches). If you reject the piix one just add a data_xfer to it... Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/scsi/libata-core.c | 63 +++++++++++++-------------------------------- drivers/scsi/sata_mv.c | 2 ++ drivers/scsi/sata_nv.c | 1 + drivers/scsi/sata_promise.c | 2 ++ drivers/scsi/sata_qstor.c | 1 + drivers/scsi/sata_sil.c | 1 + drivers/scsi/sata_sis.c | 1 + drivers/scsi/sata_svw.c | 1 + drivers/scsi/sata_sx4.c | 1 + drivers/scsi/sata_uli.c | 1 + drivers/scsi/sata_via.c | 1 + drivers/scsi/sata_vsc.c | 1 + include/linux/libata.h | 6 +++++ 13 files changed, 37 insertions(+), 45 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 45b6b29bc10f..074a46e5bbdd 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -3527,7 +3527,7 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words) /** * ata_mmio_data_xfer - Transfer data by MMIO - * @ap: port to read/write + * @dev: device for this I/O * @buf: data buffer * @buflen: buffer length * @write_data: read/write @@ -3538,9 +3538,10 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words) * Inherited from caller. */ -static void ata_mmio_data_xfer(struct ata_port *ap, unsigned char *buf, - unsigned int buflen, int write_data) +void ata_mmio_data_xfer(struct ata_device *adev, unsigned char *buf, + unsigned int buflen, int write_data) { + struct ata_port *ap = adev->ap; unsigned int i; unsigned int words = buflen >> 1; u16 *buf16 = (u16 *) buf; @@ -3572,7 +3573,7 @@ static void ata_mmio_data_xfer(struct ata_port *ap, unsigned char *buf, /** * ata_pio_data_xfer - Transfer data by PIO - * @ap: port to read/write + * @adev: device to target * @buf: data buffer * @buflen: buffer length * @write_data: read/write @@ -3583,9 +3584,10 @@ static void ata_mmio_data_xfer(struct ata_port *ap, unsigned char *buf, * Inherited from caller. */ -static void ata_pio_data_xfer(struct ata_port *ap, unsigned char *buf, - unsigned int buflen, int write_data) +void ata_pio_data_xfer(struct ata_device *adev, unsigned char *buf, + unsigned int buflen, int write_data) { + struct ata_port *ap = adev->ap; unsigned int words = buflen >> 1; /* Transfer multiple of 2 bytes */ @@ -3609,39 +3611,6 @@ static void ata_pio_data_xfer(struct ata_port *ap, unsigned char *buf, } } -/** - * ata_data_xfer - Transfer data from/to the data register. - * @ap: port to read/write - * @buf: data buffer - * @buflen: buffer length - * @do_write: read/write - * - * Transfer data from/to the device data register. - * - * LOCKING: - * Inherited from caller. - */ - -static void ata_data_xfer(struct ata_port *ap, unsigned char *buf, - unsigned int buflen, int do_write) -{ - /* Make the crap hardware pay the costs not the good stuff */ - if (unlikely(ap->flags & ATA_FLAG_IRQ_MASK)) { - unsigned long flags; - local_irq_save(flags); - if (ap->flags & ATA_FLAG_MMIO) - ata_mmio_data_xfer(ap, buf, buflen, do_write); - else - ata_pio_data_xfer(ap, buf, buflen, do_write); - local_irq_restore(flags); - } else { - if (ap->flags & ATA_FLAG_MMIO) - ata_mmio_data_xfer(ap, buf, buflen, do_write); - else - ata_pio_data_xfer(ap, buf, buflen, do_write); - } -} - /** * ata_pio_sector - Transfer ATA_SECT_SIZE (512 bytes) of data. * @qc: Command on going @@ -3676,17 +3645,18 @@ static void ata_pio_sector(struct ata_queued_cmd *qc) if (PageHighMem(page)) { unsigned long flags; + /* FIXME: use a bounce buffer */ local_irq_save(flags); buf = kmap_atomic(page, KM_IRQ0); /* do the actual data transfer */ - ata_data_xfer(ap, buf + offset, ATA_SECT_SIZE, do_write); + ap->ops->data_xfer(qc->dev, buf + offset, ATA_SECT_SIZE, do_write); kunmap_atomic(buf, KM_IRQ0); local_irq_restore(flags); } else { buf = page_address(page); - ata_data_xfer(ap, buf + offset, ATA_SECT_SIZE, do_write); + ap->ops->data_xfer(qc->dev, buf + offset, ATA_SECT_SIZE, do_write); } qc->cursect++; @@ -3742,7 +3712,7 @@ static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc) DPRINTK("send cdb\n"); WARN_ON(qc->dev->cdb_len < 12); - ata_data_xfer(ap, qc->cdb, qc->dev->cdb_len, 1); + ap->ops->data_xfer(qc->dev, qc->cdb, qc->dev->cdb_len, 1); ata_altstatus(ap); /* flush */ switch (qc->tf.protocol) { @@ -3802,7 +3772,7 @@ next_sg: "%u bytes trailing data\n", bytes); for (i = 0; i < words; i++) - ata_data_xfer(ap, (unsigned char*)pad_buf, 2, do_write); + ap->ops->data_xfer(qc->dev, (unsigned char*)pad_buf, 2, do_write); ap->hsm_task_state = HSM_ST_LAST; return; @@ -3828,17 +3798,18 @@ next_sg: if (PageHighMem(page)) { unsigned long flags; + /* FIXME: use bounce buffer */ local_irq_save(flags); buf = kmap_atomic(page, KM_IRQ0); /* do the actual data transfer */ - ata_data_xfer(ap, buf + offset, count, do_write); + ap->ops->data_xfer(qc->dev, buf + offset, count, do_write); kunmap_atomic(buf, KM_IRQ0); local_irq_restore(flags); } else { buf = page_address(page); - ata_data_xfer(ap, buf + offset, count, do_write); + ap->ops->data_xfer(qc->dev, buf + offset, count, do_write); } bytes -= count; @@ -5702,6 +5673,8 @@ EXPORT_SYMBOL_GPL(ata_port_start); EXPORT_SYMBOL_GPL(ata_port_stop); EXPORT_SYMBOL_GPL(ata_host_stop); EXPORT_SYMBOL_GPL(ata_interrupt); +EXPORT_SYMBOL_GPL(ata_mmio_data_xfer); +EXPORT_SYMBOL_GPL(ata_pio_data_xfer); EXPORT_SYMBOL_GPL(ata_qc_prep); EXPORT_SYMBOL_GPL(ata_noop_qc_prep); EXPORT_SYMBOL_GPL(ata_bmdma_setup); diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c index 691c115ac8e1..bf3529fdea9c 100644 --- a/drivers/scsi/sata_mv.c +++ b/drivers/scsi/sata_mv.c @@ -406,6 +406,7 @@ static const struct ata_port_operations mv5_ops = { .qc_prep = mv_qc_prep, .qc_issue = mv_qc_issue, + .data_xfer = ata_mmio_data_xfer, .eng_timeout = mv_eng_timeout, @@ -433,6 +434,7 @@ static const struct ata_port_operations mv6_ops = { .qc_prep = mv_qc_prep, .qc_issue = mv_qc_issue, + .data_xfer = ata_mmio_data_xfer, .eng_timeout = mv_eng_timeout, diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c index 043ff4fd9ba7..d93513ef7412 100644 --- a/drivers/scsi/sata_nv.c +++ b/drivers/scsi/sata_nv.c @@ -234,6 +234,7 @@ static const struct ata_port_operations nv_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, .eng_timeout = ata_eng_timeout, + .data_xfer = ata_pio_data_xfer, .irq_handler = nv_interrupt, .irq_clear = ata_bmdma_irq_clear, .scr_read = nv_scr_read, diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c index 285ab0263d91..01111594d09c 100644 --- a/drivers/scsi/sata_promise.c +++ b/drivers/scsi/sata_promise.c @@ -137,6 +137,7 @@ static const struct ata_port_operations pdc_sata_ops = { .qc_prep = pdc_qc_prep, .qc_issue = pdc_qc_issue_prot, .eng_timeout = pdc_eng_timeout, + .data_xfer = ata_mmio_data_xfer, .irq_handler = pdc_interrupt, .irq_clear = pdc_irq_clear, @@ -159,6 +160,7 @@ static const struct ata_port_operations pdc_pata_ops = { .qc_prep = pdc_qc_prep, .qc_issue = pdc_qc_issue_prot, + .data_xfer = ata_mmio_data_xfer, .eng_timeout = pdc_eng_timeout, .irq_handler = pdc_interrupt, .irq_clear = pdc_irq_clear, diff --git a/drivers/scsi/sata_qstor.c b/drivers/scsi/sata_qstor.c index 54283e06070e..68737cadd2d4 100644 --- a/drivers/scsi/sata_qstor.c +++ b/drivers/scsi/sata_qstor.c @@ -156,6 +156,7 @@ static const struct ata_port_operations qs_ata_ops = { .phy_reset = qs_phy_reset, .qc_prep = qs_qc_prep, .qc_issue = qs_qc_issue, + .data_xfer = ata_mmio_data_xfer, .eng_timeout = qs_eng_timeout, .irq_handler = qs_intr, .irq_clear = qs_irq_clear, diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c index aa63044eed2e..3bd807738698 100644 --- a/drivers/scsi/sata_sil.c +++ b/drivers/scsi/sata_sil.c @@ -176,6 +176,7 @@ static const struct ata_port_operations sil_ops = { .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, + .data_xfer = ata_mmio_data_xfer, .freeze = sil_freeze, .thaw = sil_thaw, .error_handler = ata_bmdma_error_handler, diff --git a/drivers/scsi/sata_sis.c b/drivers/scsi/sata_sis.c index 3097821688dc..82a07bff7e91 100644 --- a/drivers/scsi/sata_sis.c +++ b/drivers/scsi/sata_sis.c @@ -113,6 +113,7 @@ static const struct ata_port_operations sis_ops = { .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, + .data_xfer = ata_pio_data_xfer, .eng_timeout = ata_eng_timeout, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, diff --git a/drivers/scsi/sata_svw.c b/drivers/scsi/sata_svw.c index d5eb5375e265..7a4703bfa12a 100644 --- a/drivers/scsi/sata_svw.c +++ b/drivers/scsi/sata_svw.c @@ -320,6 +320,7 @@ static const struct ata_port_operations k2_sata_ops = { .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, + .data_xfer = ata_mmio_data_xfer, .eng_timeout = ata_eng_timeout, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, diff --git a/drivers/scsi/sata_sx4.c b/drivers/scsi/sata_sx4.c index e799ef35e9db..c4db6bf14a25 100644 --- a/drivers/scsi/sata_sx4.c +++ b/drivers/scsi/sata_sx4.c @@ -204,6 +204,7 @@ static const struct ata_port_operations pdc_20621_ops = { .phy_reset = pdc_20621_phy_reset, .qc_prep = pdc20621_qc_prep, .qc_issue = pdc20621_qc_issue_prot, + .data_xfer = ata_mmio_data_xfer, .eng_timeout = pdc_eng_timeout, .irq_handler = pdc20621_interrupt, .irq_clear = pdc20621_irq_clear, diff --git a/drivers/scsi/sata_uli.c b/drivers/scsi/sata_uli.c index 15f81bfc30f0..7fae3e06e461 100644 --- a/drivers/scsi/sata_uli.c +++ b/drivers/scsi/sata_uli.c @@ -110,6 +110,7 @@ static const struct ata_port_operations uli_ops = { .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, + .data_xfer = ata_pio_data_xfer, .eng_timeout = ata_eng_timeout, diff --git a/drivers/scsi/sata_via.c b/drivers/scsi/sata_via.c index 17aefab5f42f..1c9e2f36805a 100644 --- a/drivers/scsi/sata_via.c +++ b/drivers/scsi/sata_via.c @@ -124,6 +124,7 @@ static const struct ata_port_operations svia_sata_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, + .data_xfer = ata_pio_data_xfer, .eng_timeout = ata_eng_timeout, diff --git a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c index 0372be7ff1c9..438e7c6a0f8f 100644 --- a/drivers/scsi/sata_vsc.c +++ b/drivers/scsi/sata_vsc.c @@ -297,6 +297,7 @@ static const struct ata_port_operations vsc_sata_ops = { .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, + .data_xfer = ata_pio_data_xfer, .eng_timeout = ata_eng_timeout, .irq_handler = vsc_sata_interrupt, .irq_clear = ata_bmdma_irq_clear, diff --git a/include/linux/libata.h b/include/linux/libata.h index c51502c047a4..25a6bf181599 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -525,6 +525,8 @@ struct ata_port_operations { void (*bmdma_setup) (struct ata_queued_cmd *qc); void (*bmdma_start) (struct ata_queued_cmd *qc); + void (*data_xfer) (struct ata_device *, unsigned char *, unsigned int, int); + void (*qc_prep) (struct ata_queued_cmd *qc); unsigned int (*qc_issue) (struct ata_queued_cmd *qc); @@ -646,6 +648,10 @@ extern int ata_port_start (struct ata_port *ap); extern void ata_port_stop (struct ata_port *ap); extern void ata_host_stop (struct ata_host_set *host_set); extern irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs); +extern void ata_mmio_data_xfer(struct ata_device *adev, unsigned char *buf, + unsigned int buflen, int write_data); +extern void ata_pio_data_xfer(struct ata_device *adev, unsigned char *buf, + unsigned int buflen, int write_data); extern void ata_qc_prep(struct ata_queued_cmd *qc); extern void ata_noop_qc_prep(struct ata_queued_cmd *qc); extern unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc); -- cgit v1.2.3 From 96ff6afaf1c2fdd118139095dea66c0910379780 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Fri, 19 May 2006 16:48:47 +1000 Subject: [PATCH] powerpc: remove iSeries_Global_Device_List We can now scan the list of device nodes instead. This also allows us to remove the Device_list member of struct pci_dn. Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/iseries/iommu.c | 15 +++++++++------ arch/powerpc/platforms/iseries/pci.c | 14 ++++++-------- include/asm-powerpc/pci-bridge.h | 1 - 3 files changed, 15 insertions(+), 15 deletions(-) (limited to 'include') diff --git a/arch/powerpc/platforms/iseries/iommu.c b/arch/powerpc/platforms/iseries/iommu.c index 3ac22065c424..75a5a1e8abb8 100644 --- a/arch/powerpc/platforms/iseries/iommu.c +++ b/arch/powerpc/platforms/iseries/iommu.c @@ -32,13 +32,11 @@ #include #include #include +#include #include #include #include -extern struct list_head iSeries_Global_Device_List; - - static void tce_build_iSeries(struct iommu_table *tbl, long index, long npages, unsigned long uaddr, enum dma_data_direction direction) { @@ -140,10 +138,15 @@ void iommu_table_getparms_iSeries(unsigned long busno, */ static struct iommu_table *iommu_table_find(struct iommu_table * tbl) { - struct pci_dn *pdn; + struct device_node *node; + + for (node = NULL; (node = of_find_all_nodes(node)); ) { + struct pci_dn *pdn = PCI_DN(node); + struct iommu_table *it; - list_for_each_entry(pdn, &iSeries_Global_Device_List, Device_List) { - struct iommu_table *it = pdn->iommu_table; + if (pdn == NULL) + continue; + it = pdn->iommu_table; if ((it != NULL) && (it->it_type == TCE_PCI) && (it->it_offset == tbl->it_offset) && diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c index 9d571e749098..5bc08d4eef49 100644 --- a/arch/powerpc/platforms/iseries/pci.c +++ b/arch/powerpc/platforms/iseries/pci.c @@ -50,8 +50,6 @@ */ static struct device_node *find_Device_Node(int bus, int devfn); -LIST_HEAD(iSeries_Global_Device_List); - static int Pci_Retry_Max = 3; /* Only retry 3 times */ static int Pci_Error_Flag = 1; /* Set Retry Error on. */ @@ -245,8 +243,6 @@ void iSeries_pcibios_init(void) pdn->bussubno = *busp; pdn->Irq = irq; pdn->LogicalSlot = *lsn; - list_add_tail(&pdn->Device_List, - &iSeries_Global_Device_List); } } } @@ -338,11 +334,13 @@ EXPORT_SYMBOL(iSeries_memcpy_fromio); */ static struct device_node *find_Device_Node(int bus, int devfn) { - struct pci_dn *pdn; + struct device_node *node; + + for (node = NULL; (node = of_find_all_nodes(node)); ) { + struct pci_dn *pdn = PCI_DN(node); - list_for_each_entry(pdn, &iSeries_Global_Device_List, Device_List) { - if ((bus == pdn->busno) && (devfn == pdn->devfn)) - return pdn->node; + if (pdn && (bus == pdn->busno) && (devfn == pdn->devfn)) + return node; } return NULL; } diff --git a/include/asm-powerpc/pci-bridge.h b/include/asm-powerpc/pci-bridge.h index 38de92d41a14..59794b466efc 100644 --- a/include/asm-powerpc/pci-bridge.h +++ b/include/asm-powerpc/pci-bridge.h @@ -79,7 +79,6 @@ struct pci_dn { struct pci_dev *pcidev; /* back-pointer to the pci device */ struct device_node *node; /* back-pointer to the device_node */ #ifdef CONFIG_PPC_ISERIES - struct list_head Device_List; int Irq; /* Assigned IRQ */ int Flags; /* Possible flags(disable/bist)*/ u8 LogicalSlot; /* Hv Slot Index for Tces */ -- cgit v1.2.3 From b02527931672749d404b5f640b7e086afc37f4e0 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Fri, 19 May 2006 16:50:39 +1000 Subject: [PATCH] powerpc: remove Irq from pci_dn As we now store enough information in the device_node to allocate the irq number in pcibios_final_fixup. Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/iseries/pci.c | 53 +++++++++++++++++++----------------- include/asm-powerpc/pci-bridge.h | 1 - 2 files changed, 28 insertions(+), 26 deletions(-) (limited to 'include') diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c index 5bc08d4eef49..edaafbb817b7 100644 --- a/arch/powerpc/platforms/iseries/pci.c +++ b/arch/powerpc/platforms/iseries/pci.c @@ -190,9 +190,6 @@ void iSeries_pcibios_init(void) /* Find and connect the devices. */ for (dn = NULL; (dn = of_get_next_child(node, dn)) != NULL;) { struct pci_dn *pdn; - u8 irq; - int err; - u32 *agent; u32 *reg; u32 *lsn; @@ -206,11 +203,6 @@ void iSeries_pcibios_init(void) printk(KERN_DEBUG "no subbus property!\n"); continue; } - agent = (u32 *)get_property(dn, "linux,agent-id", NULL); - if (agent == NULL) { - printk(KERN_DEBUG "no agent-id\n"); - continue; - } lsn = (u32 *)get_property(dn, "linux,logical-slot-number", NULL); if (lsn == NULL) { @@ -218,21 +210,6 @@ void iSeries_pcibios_init(void) continue; } - irq = iSeries_allocate_IRQ(bus, 0, *busp); - err = HvCallXm_connectBusUnit(bus, *busp, *agent, irq); - if (err) { - pci_Log_Error("Connect Bus Unit", - bus, *busp, *agent, err); - continue; - } - err = HvCallPci_configStore8(bus, *busp, *agent, - PCI_INTERRUPT_LINE, irq); - if (err) { - pci_Log_Error("PciCfgStore Irq Failed!", - bus, *busp, *agent, err); - continue; - } - pdn = kzalloc(sizeof(*pdn), GFP_KERNEL); if (pdn == NULL) return; @@ -241,7 +218,6 @@ void iSeries_pcibios_init(void) pdn->busno = bus; pdn->devfn = (reg[0] >> 8) & 0xff; pdn->bussubno = *busp; - pdn->Irq = irq; pdn->LogicalSlot = *lsn; } } @@ -266,6 +242,34 @@ void __init iSeries_pci_final_fixup(void) pdev->bus->number, pdev->devfn, node); if (node != NULL) { + struct pci_dn *pdn = PCI_DN(node); + u32 *agent; + + agent = (u32 *)get_property(node, "linux,agent-id", + NULL); + if ((pdn != NULL) && (agent != NULL)) { + u8 irq = iSeries_allocate_IRQ(pdn->busno, 0, + pdn->bussubno); + int err; + + err = HvCallXm_connectBusUnit(pdn->busno, pdn->bussubno, + *agent, irq); + if (err) + pci_Log_Error("Connect Bus Unit", + pdn->busno, pdn->bussubno, *agent, err); + else { + err = HvCallPci_configStore8(pdn->busno, pdn->bussubno, + *agent, + PCI_INTERRUPT_LINE, + irq); + if (err) + pci_Log_Error("PciCfgStore Irq Failed!", + pdn->busno, pdn->bussubno, *agent, err); + } + if (!err) + pdev->irq = irq; + } + ++DeviceCount; pdev->sysdata = (void *)node; PCI_DN(node)->pcidev = pdev; @@ -275,7 +279,6 @@ void __init iSeries_pci_final_fixup(void) } else printk("PCI: Device Tree not found for 0x%016lX\n", (unsigned long)pdev); - pdev->irq = PCI_DN(node)->Irq; } iSeries_activate_IRQs(); mf_display_src(0xC9000200); diff --git a/include/asm-powerpc/pci-bridge.h b/include/asm-powerpc/pci-bridge.h index 59794b466efc..09079e400d2b 100644 --- a/include/asm-powerpc/pci-bridge.h +++ b/include/asm-powerpc/pci-bridge.h @@ -79,7 +79,6 @@ struct pci_dn { struct pci_dev *pcidev; /* back-pointer to the pci device */ struct device_node *node; /* back-pointer to the device_node */ #ifdef CONFIG_PPC_ISERIES - int Irq; /* Assigned IRQ */ int Flags; /* Possible flags(disable/bist)*/ u8 LogicalSlot; /* Hv Slot Index for Tces */ #endif -- cgit v1.2.3 From 403fac4f83bd8e089a192c542511fbeb2729a6c5 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Fri, 19 May 2006 16:51:57 +1000 Subject: [PATCH] powerpc: remove LogicalSlot from pci_dn As we now store enough information in the device_node. Also the Flags field was not used either, do remove that. Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/iseries/iommu.c | 5 ++++- arch/powerpc/platforms/iseries/pci.c | 8 -------- include/asm-powerpc/pci-bridge.h | 4 ---- 3 files changed, 4 insertions(+), 13 deletions(-) (limited to 'include') diff --git a/arch/powerpc/platforms/iseries/iommu.c b/arch/powerpc/platforms/iseries/iommu.c index 75a5a1e8abb8..a992f6af249f 100644 --- a/arch/powerpc/platforms/iseries/iommu.c +++ b/arch/powerpc/platforms/iseries/iommu.c @@ -162,10 +162,13 @@ void iommu_devnode_init_iSeries(struct device_node *dn) { struct iommu_table *tbl; struct pci_dn *pdn = PCI_DN(dn); + u32 *lsn = (u32 *)get_property(dn, "linux,logical-slot-number", NULL); + + BUG_ON(lsn == NULL); tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL); - iommu_table_getparms_iSeries(pdn->busno, pdn->LogicalSlot, 0, tbl); + iommu_table_getparms_iSeries(pdn->busno, *lsn, 0, tbl); /* Look for existing tce table */ pdn->iommu_table = iommu_table_find(tbl); diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c index edaafbb817b7..86a869839d34 100644 --- a/arch/powerpc/platforms/iseries/pci.c +++ b/arch/powerpc/platforms/iseries/pci.c @@ -191,7 +191,6 @@ void iSeries_pcibios_init(void) for (dn = NULL; (dn = of_get_next_child(node, dn)) != NULL;) { struct pci_dn *pdn; u32 *reg; - u32 *lsn; reg = (u32 *)get_property(dn, "reg", NULL); if (reg == NULL) { @@ -203,12 +202,6 @@ void iSeries_pcibios_init(void) printk(KERN_DEBUG "no subbus property!\n"); continue; } - lsn = (u32 *)get_property(dn, - "linux,logical-slot-number", NULL); - if (lsn == NULL) { - printk(KERN_DEBUG "no logical-slot-number\n"); - continue; - } pdn = kzalloc(sizeof(*pdn), GFP_KERNEL); if (pdn == NULL) @@ -218,7 +211,6 @@ void iSeries_pcibios_init(void) pdn->busno = bus; pdn->devfn = (reg[0] >> 8) & 0xff; pdn->bussubno = *busp; - pdn->LogicalSlot = *lsn; } } } diff --git a/include/asm-powerpc/pci-bridge.h b/include/asm-powerpc/pci-bridge.h index 09079e400d2b..84a3075db524 100644 --- a/include/asm-powerpc/pci-bridge.h +++ b/include/asm-powerpc/pci-bridge.h @@ -78,10 +78,6 @@ struct pci_dn { struct iommu_table *iommu_table; /* for phb's or bridges */ struct pci_dev *pcidev; /* back-pointer to the pci device */ struct device_node *node; /* back-pointer to the device_node */ -#ifdef CONFIG_PPC_ISERIES - int Flags; /* Possible flags(disable/bist)*/ - u8 LogicalSlot; /* Hv Slot Index for Tces */ -#endif u32 config_space[16]; /* saved PCI config space */ }; -- cgit v1.2.3 From 0a9cb46a73abd6c45e7c986bec984eed60c417b6 Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Fri, 19 May 2006 15:35:32 -0500 Subject: [PATCH] remove powerpc bitops in favor of existing generic bitops There already exists a big endian safe bitops implementation in lib/find_next_bit.c. The code in it is 90%+ common with the powerpc specific version, so the powerpc version is redundant. This patch makes the necessary changes to use the generic bitops in powerpc, and removes the powerpc specific version. Signed-off-by: Jon Mason Signed-off-by: Paul Mackerras --- arch/powerpc/Kconfig | 4 ++ arch/powerpc/lib/Makefile | 1 - arch/powerpc/lib/bitops.c | 150 ------------------------------------------- arch/ppc/Kconfig | 4 ++ include/asm-powerpc/bitops.h | 6 +- 5 files changed, 11 insertions(+), 154 deletions(-) delete mode 100644 arch/powerpc/lib/bitops.c (limited to 'include') diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 6729c98b66f9..75ba0ec49e54 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -45,6 +45,10 @@ config GENERIC_CALIBRATE_DELAY bool default y +config GENERIC_FIND_NEXT_BIT + bool + default y + config PPC bool default y diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile index 34f5c2e074c9..ae354d65b82c 100644 --- a/arch/powerpc/lib/Makefile +++ b/arch/powerpc/lib/Makefile @@ -7,7 +7,6 @@ obj-y := string.o strcase.o obj-$(CONFIG_PPC32) += div64.o copy_32.o checksum_32.o endif -obj-y += bitops.o obj-$(CONFIG_PPC64) += checksum_64.o copypage_64.o copyuser_64.o \ memcpy_64.o usercopy_64.o mem_64.o string.o \ strcase.o diff --git a/arch/powerpc/lib/bitops.c b/arch/powerpc/lib/bitops.c deleted file mode 100644 index f68ad71a0187..000000000000 --- a/arch/powerpc/lib/bitops.c +++ /dev/null @@ -1,150 +0,0 @@ -#include -#include -#include -#include - -/** - * find_next_bit - find the next set bit in a memory region - * @addr: The address to base the search on - * @offset: The bitnumber to start searching at - * @size: The maximum size to search - */ -unsigned long find_next_bit(const unsigned long *addr, unsigned long size, - unsigned long offset) -{ - const unsigned long *p = addr + BITOP_WORD(offset); - unsigned long result = offset & ~(BITS_PER_LONG-1); - unsigned long tmp; - - if (offset >= size) - return size; - size -= result; - offset %= BITS_PER_LONG; - if (offset) { - tmp = *(p++); - tmp &= (~0UL << offset); - if (size < BITS_PER_LONG) - goto found_first; - if (tmp) - goto found_middle; - size -= BITS_PER_LONG; - result += BITS_PER_LONG; - } - while (size & ~(BITS_PER_LONG-1)) { - if ((tmp = *(p++))) - goto found_middle; - result += BITS_PER_LONG; - size -= BITS_PER_LONG; - } - if (!size) - return result; - tmp = *p; - -found_first: - tmp &= (~0UL >> (BITS_PER_LONG - size)); - if (tmp == 0UL) /* Are any bits set? */ - return result + size; /* Nope. */ -found_middle: - return result + __ffs(tmp); -} -EXPORT_SYMBOL(find_next_bit); - -/* - * This implementation of find_{first,next}_zero_bit was stolen from - * Linus' asm-alpha/bitops.h. - */ -unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size, - unsigned long offset) -{ - const unsigned long *p = addr + BITOP_WORD(offset); - unsigned long result = offset & ~(BITS_PER_LONG-1); - unsigned long tmp; - - if (offset >= size) - return size; - size -= result; - offset %= BITS_PER_LONG; - if (offset) { - tmp = *(p++); - tmp |= ~0UL >> (BITS_PER_LONG - offset); - if (size < BITS_PER_LONG) - goto found_first; - if (~tmp) - goto found_middle; - size -= BITS_PER_LONG; - result += BITS_PER_LONG; - } - while (size & ~(BITS_PER_LONG-1)) { - if (~(tmp = *(p++))) - goto found_middle; - result += BITS_PER_LONG; - size -= BITS_PER_LONG; - } - if (!size) - return result; - tmp = *p; - -found_first: - tmp |= ~0UL << size; - if (tmp == ~0UL) /* Are any bits zero? */ - return result + size; /* Nope. */ -found_middle: - return result + ffz(tmp); -} -EXPORT_SYMBOL(find_next_zero_bit); - -static inline unsigned int ext2_ilog2(unsigned int x) -{ - int lz; - - asm("cntlzw %0,%1": "=r"(lz):"r"(x)); - return 31 - lz; -} - -static inline unsigned int ext2_ffz(unsigned int x) -{ - u32 rc; - if ((x = ~x) == 0) - return 32; - rc = ext2_ilog2(x & -x); - return rc; -} - -unsigned long find_next_zero_le_bit(const unsigned long *addr, - unsigned long size, unsigned long offset) -{ - const unsigned int *p = ((const unsigned int *)addr) + (offset >> 5); - unsigned int result = offset & ~31; - unsigned int tmp; - - if (offset >= size) - return size; - size -= result; - offset &= 31; - if (offset) { - tmp = cpu_to_le32p(p++); - tmp |= ~0U >> (32 - offset); /* bug or feature ? */ - if (size < 32) - goto found_first; - if (tmp != ~0) - goto found_middle; - size -= 32; - result += 32; - } - while (size >= 32) { - if ((tmp = cpu_to_le32p(p++)) != ~0) - goto found_middle; - result += 32; - size -= 32; - } - if (!size) - return result; - tmp = cpu_to_le32p(p); -found_first: - tmp |= ~0 << size; - if (tmp == ~0) /* Are any bits zero? */ - return result + size; /* Nope. */ -found_middle: - return result + ext2_ffz(tmp); -} -EXPORT_SYMBOL(find_next_zero_le_bit); diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig index e9a8f5d1dfcd..b55de4f42aec 100644 --- a/arch/ppc/Kconfig +++ b/arch/ppc/Kconfig @@ -40,6 +40,10 @@ config GENERIC_NVRAM bool default y +config GENERIC_FIND_NEXT_BIT + bool + default y + config SCHED_NO_NO_OMIT_FRAME_POINTER bool default y diff --git a/include/asm-powerpc/bitops.h b/include/asm-powerpc/bitops.h index d1c2a4405660..76e2f08c3c83 100644 --- a/include/asm-powerpc/bitops.h +++ b/include/asm-powerpc/bitops.h @@ -288,8 +288,8 @@ static __inline__ int test_le_bit(unsigned long nr, #define __test_and_clear_le_bit(nr, addr) \ __test_and_clear_bit((nr) ^ BITOP_LE_SWIZZLE, (addr)) -#define find_first_zero_le_bit(addr, size) find_next_zero_le_bit((addr), (size), 0) -unsigned long find_next_zero_le_bit(const unsigned long *addr, +#define find_first_zero_le_bit(addr, size) generic_find_next_zero_le_bit((addr), (size), 0) +unsigned long generic_find_next_zero_le_bit(const unsigned long *addr, unsigned long size, unsigned long offset); /* Bitmap functions for the ext2 filesystem */ @@ -309,7 +309,7 @@ unsigned long find_next_zero_le_bit(const unsigned long *addr, #define ext2_find_first_zero_bit(addr, size) \ find_first_zero_le_bit((unsigned long*)addr, size) #define ext2_find_next_zero_bit(addr, size, off) \ - find_next_zero_le_bit((unsigned long*)addr, size, off) + generic_find_next_zero_le_bit((unsigned long*)addr, size, off) /* Bitmap functions for the minix filesystem. */ -- cgit v1.2.3 From 957d2df1801865eb1e63864bc63b970aa9c460ba Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 23 May 2006 13:18:57 +0100 Subject: [PATCH] libata: Remove obsolete flag ATA_FLAG_IRQ_MASK was added when I did the original data transfer with IRQ masked bits for PIO. It has since been replaced by ->pio_data_xfer methods so should be removed so nobody uses it by mistake thinking it still works. Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- include/linux/libata.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include') diff --git a/include/linux/libata.h b/include/linux/libata.h index 25a6bf181599..9c60b4a4e2fd 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -149,7 +149,6 @@ enum { ATA_FLAG_NO_ATAPI = (1 << 6), /* No ATAPI support */ ATA_FLAG_PIO_DMA = (1 << 7), /* PIO cmds via DMA */ ATA_FLAG_PIO_LBA48 = (1 << 8), /* Host DMA engine is LBA28 only */ - ATA_FLAG_IRQ_MASK = (1 << 9), /* Mask IRQ in PIO xfers */ ATA_FLAG_PIO_POLLING = (1 << 10), /* use polling PIO if LLD * doesn't handle PIO interrupts */ ATA_FLAG_NCQ = (1 << 11), /* host supports NCQ */ -- cgit v1.2.3 From 622b20fcb8b42aa4c3c87c0a036f2ad0927b64bc Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 24 May 2006 14:06:11 +0100 Subject: [PATCH] PCI identifiers for the pata_via update These IDs are also used by the drivers/ide/pci changes submitted by VIA. Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- include/linux/pci_ids.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 233f60741c82..e75727954a12 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1238,6 +1238,7 @@ #define PCI_DEVICE_ID_VIA_PX8X0_0 0x0259 #define PCI_DEVICE_ID_VIA_3269_0 0x0269 #define PCI_DEVICE_ID_VIA_K8T800PRO_0 0x0282 +#define PCI_DEVICE_ID_VIA_3296_0 0x0296 #define PCI_DEVICE_ID_VIA_8363_0 0x0305 #define PCI_DEVICE_ID_VIA_P4M800CE 0x0314 #define PCI_DEVICE_ID_VIA_8371_0 0x0391 @@ -1245,6 +1246,7 @@ #define PCI_DEVICE_ID_VIA_82C561 0x0561 #define PCI_DEVICE_ID_VIA_82C586_1 0x0571 #define PCI_DEVICE_ID_VIA_82C576 0x0576 +#define PCI_DEVICE_ID_VIA_SATA_EIDE 0x0581 #define PCI_DEVICE_ID_VIA_82C586_0 0x0586 #define PCI_DEVICE_ID_VIA_82C596 0x0596 #define PCI_DEVICE_ID_VIA_82C597_0 0x0597 @@ -1285,10 +1287,11 @@ #define PCI_DEVICE_ID_VIA_8783_0 0x3208 #define PCI_DEVICE_ID_VIA_8237 0x3227 #define PCI_DEVICE_ID_VIA_8251 0x3287 -#define PCI_DEVICE_ID_VIA_3296_0 0x0296 +#define PCI_DEVICE_ID_VIA_8237A 0x3337 #define PCI_DEVICE_ID_VIA_8231 0x8231 #define PCI_DEVICE_ID_VIA_8231_4 0x8235 #define PCI_DEVICE_ID_VIA_8365_1 0x8305 +#define PCI_DEVICE_ID_VIA_CX700 0x8324 #define PCI_DEVICE_ID_VIA_8371_1 0x8391 #define PCI_DEVICE_ID_VIA_82C598_1 0x8598 #define PCI_DEVICE_ID_VIA_838X_1 0xB188 -- cgit v1.2.3 From 75e995855f45a83afdae34d50c0b3ee14fb23b7a Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 24 May 2006 14:14:41 +0100 Subject: [PATCH] libata: add pio_data_xfer_noirq Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/scsi/libata-core.c | 25 +++++++++++++++++++++++++ include/linux/libata.h | 2 ++ 2 files changed, 27 insertions(+) (limited to 'include') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 074a46e5bbdd..f19fe662f0ca 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -3611,6 +3611,30 @@ void ata_pio_data_xfer(struct ata_device *adev, unsigned char *buf, } } +/** + * ata_pio_data_xfer_noirq - Transfer data by PIO + * @adev: device to target + * @buf: data buffer + * @buflen: buffer length + * @write_data: read/write + * + * Transfer data from/to the device data register by PIO. Do the + * transfer with interrupts disabled. + * + * LOCKING: + * Inherited from caller. + */ + +void ata_pio_data_xfer_noirq(struct ata_device *adev, unsigned char *buf, + unsigned int buflen, int write_data) +{ + unsigned long flags; + local_irq_save(flags); + ata_pio_data_xfer(adev, buf, buflen, write_data); + local_irq_restore(flags); +} + + /** * ata_pio_sector - Transfer ATA_SECT_SIZE (512 bytes) of data. * @qc: Command on going @@ -5675,6 +5699,7 @@ EXPORT_SYMBOL_GPL(ata_host_stop); EXPORT_SYMBOL_GPL(ata_interrupt); EXPORT_SYMBOL_GPL(ata_mmio_data_xfer); EXPORT_SYMBOL_GPL(ata_pio_data_xfer); +EXPORT_SYMBOL_GPL(ata_pio_data_xfer_noirq); EXPORT_SYMBOL_GPL(ata_qc_prep); EXPORT_SYMBOL_GPL(ata_noop_qc_prep); EXPORT_SYMBOL_GPL(ata_bmdma_setup); diff --git a/include/linux/libata.h b/include/linux/libata.h index 9c60b4a4e2fd..b0ee1c1437d6 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -651,6 +651,8 @@ extern void ata_mmio_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data); extern void ata_pio_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data); +extern void ata_pio_data_xfer_noirq(struct ata_device *adev, unsigned char *buf, + unsigned int buflen, int write_data); extern void ata_qc_prep(struct ata_queued_cmd *qc); extern void ata_noop_qc_prep(struct ata_queued_cmd *qc); extern unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc); -- cgit v1.2.3 From 7395acb2c840fd4d0cacc91d6fb71440057141ab Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 31 May 2006 18:27:25 +0900 Subject: [PATCH] libata: shift host flag constants Nudge host flag constants to make a room after ATA_FLAG_EH_PENDING. New EH flag will be added. Signed-off-by: Tejun Heo --- include/linux/libata.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/linux/libata.h b/include/linux/libata.h index b0ee1c1437d6..3f9c65f1aafa 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -149,14 +149,14 @@ enum { ATA_FLAG_NO_ATAPI = (1 << 6), /* No ATAPI support */ ATA_FLAG_PIO_DMA = (1 << 7), /* PIO cmds via DMA */ ATA_FLAG_PIO_LBA48 = (1 << 8), /* Host DMA engine is LBA28 only */ - ATA_FLAG_PIO_POLLING = (1 << 10), /* use polling PIO if LLD - * doesn't handle PIO interrupts */ - ATA_FLAG_NCQ = (1 << 11), /* host supports NCQ */ + ATA_FLAG_PIO_POLLING = (1 << 9), /* use polling PIO if LLD + * doesn't handle PIO interrupts */ + ATA_FLAG_NCQ = (1 << 10), /* host supports NCQ */ - ATA_FLAG_DEBUGMSG = (1 << 14), - ATA_FLAG_FLUSH_PORT_TASK = (1 << 15), /* flush port task */ + ATA_FLAG_DEBUGMSG = (1 << 13), + ATA_FLAG_FLUSH_PORT_TASK = (1 << 14), /* flush port task */ - ATA_FLAG_EH_PENDING = (1 << 16), /* EH pending */ + ATA_FLAG_EH_PENDING = (1 << 15), /* EH pending */ ATA_FLAG_FROZEN = (1 << 17), /* port is frozen */ ATA_FLAG_RECOVERED = (1 << 18), /* recovery action performed */ -- cgit v1.2.3 From c6cf9e99d1de5ca6a08fb639bb73031ffe50d802 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 31 May 2006 18:27:27 +0900 Subject: [PATCH] libata: implement ata_eh_wait() Implement ata_eh_wait(). On return from this function, it's guaranteed that the EH which was pending or in progress when the function was called is complete - including the tailing part of SCSI EH. This will be used by hotplug and others to synchronize with EH. Signed-off-by: Tejun Heo --- drivers/scsi/libata-core.c | 1 + drivers/scsi/libata-eh.c | 38 ++++++++++++++++++++++++++++++++++++++ drivers/scsi/libata.h | 1 + include/linux/libata.h | 2 ++ 4 files changed, 42 insertions(+) (limited to 'include') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 11df827e166f..66df895c9617 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -5189,6 +5189,7 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host, INIT_WORK(&ap->port_task, NULL, NULL); INIT_LIST_HEAD(&ap->eh_done_q); + init_waitqueue_head(&ap->eh_wait_q); /* set cable type */ ap->cbl = ATA_CBL_NONE; diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index b88f492eab12..9173d8f2ce5d 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c @@ -237,6 +237,7 @@ void ata_scsi_error(struct Scsi_Host *host) ap->eh_context.i = ap->eh_info; memset(&ap->eh_info, 0, sizeof(ap->eh_info)); + ap->flags |= ATA_FLAG_EH_IN_PROGRESS; ap->flags &= ~ATA_FLAG_EH_PENDING; spin_unlock_irqrestore(hs_lock, flags); @@ -290,11 +291,48 @@ void ata_scsi_error(struct Scsi_Host *host) ata_port_printk(ap, KERN_INFO, "EH complete\n"); ap->flags &= ~ATA_FLAG_RECOVERED; + /* tell wait_eh that we're done */ + ap->flags &= ~ATA_FLAG_EH_IN_PROGRESS; + wake_up_all(&ap->eh_wait_q); + spin_unlock_irqrestore(hs_lock, flags); DPRINTK("EXIT\n"); } +/** + * ata_port_wait_eh - Wait for the currently pending EH to complete + * @ap: Port to wait EH for + * + * Wait until the currently pending EH is complete. + * + * LOCKING: + * Kernel thread context (may sleep). + */ +void ata_port_wait_eh(struct ata_port *ap) +{ + unsigned long flags; + DEFINE_WAIT(wait); + + retry: + spin_lock_irqsave(&ap->host_set->lock, flags); + + while (ap->flags & (ATA_FLAG_EH_PENDING | ATA_FLAG_EH_IN_PROGRESS)) { + prepare_to_wait(&ap->eh_wait_q, &wait, TASK_UNINTERRUPTIBLE); + spin_unlock_irqrestore(&ap->host_set->lock, flags); + schedule(); + spin_lock_irqsave(&ap->host_set->lock, flags); + } + + spin_unlock_irqrestore(&ap->host_set->lock, flags); + + /* make sure SCSI EH is complete */ + if (scsi_host_in_recovery(ap->host)) { + msleep(10); + goto retry; + } +} + /** * ata_qc_timeout - Handle timeout of queued command * @qc: Command that timed out diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h index b76ad7d7062a..d56d9e1d73dc 100644 --- a/drivers/scsi/libata.h +++ b/drivers/scsi/libata.h @@ -103,6 +103,7 @@ extern void ata_schedule_scsi_eh(struct Scsi_Host *shost); /* libata-eh.c */ extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd); extern void ata_scsi_error(struct Scsi_Host *host); +extern void ata_port_wait_eh(struct ata_port *ap); extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc); #endif /* __LIBATA_H__ */ diff --git a/include/linux/libata.h b/include/linux/libata.h index 3f9c65f1aafa..2eb5828839e4 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -157,6 +157,7 @@ enum { ATA_FLAG_FLUSH_PORT_TASK = (1 << 14), /* flush port task */ ATA_FLAG_EH_PENDING = (1 << 15), /* EH pending */ + ATA_FLAG_EH_IN_PROGRESS = (1 << 16), /* EH in progress */ ATA_FLAG_FROZEN = (1 << 17), /* port is frozen */ ATA_FLAG_RECOVERED = (1 << 18), /* recovery action performed */ @@ -490,6 +491,7 @@ struct ata_port { u32 msg_enable; struct list_head eh_done_q; + wait_queue_head_t eh_wait_q; void *private_data; -- cgit v1.2.3 From abdda7331d469fa965167365f011d05e226008fb Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 31 May 2006 18:27:29 +0900 Subject: [PATCH] libata-hp-prep: add flags and eh_info/context fields for hotplug Add hotplug related flags and eh_info/context fields. Signed-off-by: Tejun Heo --- include/linux/libata.h | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/libata.h b/include/linux/libata.h index 2eb5828839e4..d4a668cf143b 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -131,6 +131,9 @@ enum { ATA_DFLAG_PIO = (1 << 8), /* device currently in PIO mode */ + ATA_DFLAG_DETACH = (1 << 16), + ATA_DFLAG_DETACHED = (1 << 17), + ATA_DEV_UNKNOWN = 0, /* unknown device */ ATA_DEV_ATA = 1, /* ATA device */ ATA_DEV_ATA_UNSUP = 2, /* ATA device (unsupported) */ @@ -152,6 +155,9 @@ enum { ATA_FLAG_PIO_POLLING = (1 << 9), /* use polling PIO if LLD * doesn't handle PIO interrupts */ ATA_FLAG_NCQ = (1 << 10), /* host supports NCQ */ + ATA_FLAG_HRST_TO_RESUME = (1 << 11), /* hardreset to resume phy */ + ATA_FLAG_SKIP_D2H_BSY = (1 << 12), /* can't wait for the first D2H + * Register FIS clearing BSY */ ATA_FLAG_DEBUGMSG = (1 << 13), ATA_FLAG_FLUSH_PORT_TASK = (1 << 14), /* flush port task */ @@ -160,6 +166,9 @@ enum { ATA_FLAG_EH_IN_PROGRESS = (1 << 16), /* EH in progress */ ATA_FLAG_FROZEN = (1 << 17), /* port is frozen */ ATA_FLAG_RECOVERED = (1 << 18), /* recovery action performed */ + ATA_FLAG_LOADING = (1 << 19), /* boot/loading probe */ + ATA_FLAG_UNLOADING = (1 << 20), /* module is unloading */ + ATA_FLAG_SCSI_HOTPLUG = (1 << 21), /* SCSI hotplug scheduled */ ATA_FLAG_DISABLED = (1 << 22), /* port is disabled, ignore it */ ATA_FLAG_SUSPENDED = (1 << 23), /* port is suspended (power) */ @@ -241,7 +250,9 @@ enum { ATA_EH_RESET_MASK = ATA_EH_SOFTRESET | ATA_EH_HARDRESET, /* ata_eh_info->flags */ - ATA_EHI_DID_RESET = (1 << 0), /* already reset this port */ + ATA_EHI_HOTPLUGGED = (1 << 0), /* could have been hotplugged */ + + ATA_EHI_DID_RESET = (1 << 16), /* already reset this port */ /* max repeat if error condition is still set after ->error_handler */ ATA_EH_MAX_REPEAT = 5, @@ -434,6 +445,10 @@ struct ata_eh_info { unsigned int err_mask; /* port-wide err_mask */ unsigned int action; /* ATA_EH_* action mask */ unsigned int flags; /* ATA_EHI_* flags */ + + unsigned long hotplug_timestamp; + unsigned int probe_mask; + char desc[ATA_EH_DESC_LEN]; int desc_len; }; @@ -441,6 +456,8 @@ struct ata_eh_info { struct ata_eh_context { struct ata_eh_info i; int tries[ATA_MAX_DEVICES]; + unsigned int classes[ATA_MAX_DEVICES]; + unsigned int did_probe_mask; }; struct ata_port { -- cgit v1.2.3 From 72fa4b742b327bd1b07985d79a61c61dbd9fd4e6 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 31 May 2006 18:27:32 +0900 Subject: [PATCH] libata-hp-prep: make some ata_device fields persistent Lifetimes of some fields span over device plugging/unplugging. This patch moves such persistent fields to the top of ata_device and separate them with ATA_DEVICE_CLEAR_OFFSET. Fields above the offset are initialized once during host initializatino while all other fields are cleared before hotplugging. Currently ->ap, devno and part of flags are persistent. Note that flags is partially cleared while holding host_set lock. This is to synchronize with later warm plug implementation which will record hotplug request in dev->flags. Signed-off-by: Tejun Heo --- drivers/scsi/libata-core.c | 14 ++++++++++++-- include/linux/libata.h | 11 +++++++++-- 2 files changed, 21 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 8fda8228159c..a07ab77d32d6 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -5153,9 +5153,18 @@ static void ata_host_remove(struct ata_port *ap, unsigned int do_unregister) void ata_dev_init(struct ata_device *dev) { struct ata_port *ap = dev->ap; + unsigned long flags; + + /* High bits of dev->flags are used to record warm plug + * requests which occur asynchronously. Synchronize using + * host_set lock. + */ + spin_lock_irqsave(&ap->host_set->lock, flags); + dev->flags &= ~ATA_DFLAG_INIT_MASK; + spin_unlock_irqrestore(&ap->host_set->lock, flags); - memset((void *)dev, 0, sizeof(*dev)); - dev->devno = dev - ap->device; + memset((void *)dev + ATA_DEVICE_CLEAR_OFFSET, 0, + sizeof(*dev) - ATA_DEVICE_CLEAR_OFFSET); dev->pio_mask = UINT_MAX; dev->mwdma_mask = UINT_MAX; dev->udma_mask = UINT_MAX; @@ -5218,6 +5227,7 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host, for (i = 0; i < ATA_MAX_DEVICES; i++) { struct ata_device *dev = &ap->device[i]; dev->ap = ap; + dev->devno = i; ata_dev_init(dev); } diff --git a/include/linux/libata.h b/include/linux/libata.h index d4a668cf143b..aa14eda0656c 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -130,6 +130,7 @@ enum { ATA_DFLAG_CFG_MASK = (1 << 8) - 1, ATA_DFLAG_PIO = (1 << 8), /* device currently in PIO mode */ + ATA_DFLAG_INIT_MASK = (1 << 16) - 1, ATA_DFLAG_DETACH = (1 << 16), ATA_DFLAG_DETACHED = (1 << 17), @@ -410,10 +411,11 @@ struct ata_ering { struct ata_device { struct ata_port *ap; - u64 n_sectors; /* size of device, if ATA */ + unsigned int devno; /* 0 or 1 */ unsigned long flags; /* ATA_DFLAG_xxx */ + /* n_sector is used as CLEAR_OFFSET, read comment above CLEAR_OFFSET */ + u64 n_sectors; /* size of device, if ATA */ unsigned int class; /* ATA_DEV_xxx */ - unsigned int devno; /* 0 or 1 */ u16 id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */ u8 pio_mode; u8 dma_mode; @@ -439,6 +441,11 @@ struct ata_device { struct ata_ering ering; }; +/* Offset into struct ata_device. Fields above it are maintained + * acress device init. Fields below are zeroed. + */ +#define ATA_DEVICE_CLEAR_OFFSET offsetof(struct ata_device, n_sectors) + struct ata_eh_info { struct ata_device *dev; /* offending device */ u32 serror; /* SError from LLDD */ -- cgit v1.2.3 From 5a04bf4befa8bffa012eedc3a0903c158b9131a9 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 31 May 2006 18:27:38 +0900 Subject: [PATCH] libata-hp-prep: implement ap->hw_sata_spd_limit Add ap->hw_sata_spd_limit and initialize it once during the boot initialization (or driver load initialization). ap->sata_spd_limit is reset to ap->hw_sata_spd_limit on hotplug. This prevents spd limits introduced by earlier devices from affecting new devices. Signed-off-by: Tejun Heo --- drivers/scsi/libata-core.c | 21 ++++++++++++--------- include/linux/libata.h | 1 + 2 files changed, 13 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index a07ab77d32d6..b1a02fdbb0a5 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -2466,17 +2466,9 @@ static int sata_phy_resume(struct ata_port *ap) */ void ata_std_probeinit(struct ata_port *ap) { - u32 scontrol; - /* resume link */ sata_phy_resume(ap); - /* init sata_spd_limit to the current value */ - if (sata_scr_read(ap, SCR_CONTROL, &scontrol) == 0) { - int spd = (scontrol >> 4) & 0xf; - ap->sata_spd_limit &= (1 << spd) - 1; - } - /* wait for device */ if (ata_port_online(ap)) ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT); @@ -5155,6 +5147,9 @@ void ata_dev_init(struct ata_device *dev) struct ata_port *ap = dev->ap; unsigned long flags; + /* SATA spd limit is bound to the first device */ + ap->sata_spd_limit = ap->hw_sata_spd_limit; + /* High bits of dev->flags are used to record warm plug * requests which occur asynchronously. Synchronize using * host_set lock. @@ -5210,7 +5205,7 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host, ap->udma_mask = ent->udma_mask; ap->flags |= ent->host_flags; ap->ops = ent->port_ops; - ap->sata_spd_limit = UINT_MAX; + ap->hw_sata_spd_limit = UINT_MAX; ap->active_tag = ATA_TAG_POISON; ap->last_ctl = 0xFF; ap->msg_enable = ATA_MSG_DRV; @@ -5375,10 +5370,18 @@ int ata_device_add(const struct ata_probe_ent *ent) DPRINTK("probe begin\n"); for (i = 0; i < count; i++) { struct ata_port *ap; + u32 scontrol; int rc; ap = host_set->ports[i]; + /* init sata_spd_limit to the current value */ + if (sata_scr_read(ap, SCR_CONTROL, &scontrol) == 0) { + int spd = (scontrol >> 4) & 0xf; + ap->hw_sata_spd_limit &= (1 << spd) - 1; + } + ap->sata_spd_limit = ap->hw_sata_spd_limit; + DPRINTK("ata%u: bus probe begin\n", ap->id); rc = ata_bus_probe(ap); DPRINTK("ata%u: bus probe end\n", ap->id); diff --git a/include/linux/libata.h b/include/linux/libata.h index aa14eda0656c..10dc235ad8bc 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -489,6 +489,7 @@ struct ata_port { unsigned int mwdma_mask; unsigned int udma_mask; unsigned int cbl; /* cable type; ATA_CBL_xxx */ + unsigned int hw_sata_spd_limit; unsigned int sata_spd_limit; /* SATA PHY speed limit */ /* record runtime error info, protected by host_set lock */ -- cgit v1.2.3 From 3edebac41bab7e146578ad9e723ee7fff71c99c0 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 31 May 2006 18:27:40 +0900 Subject: [PATCH] libata-hp-prep: store attached SCSI device Add device persistent field dev->sdev and store the attached SCSI device. With hotplug, libata needs to know the attached SCSI device to offline and detach it, but scsi_device_lookup() cannot be used because libata will reuse SCSI ID numbers - dead but not gone devices (due to zombie opens, etc...) interfere with the lookup. dev->sdev doesn't hold reference to the SCSI device. It's cleared when the SCSI device goes away. Signed-off-by: Tejun Heo --- drivers/scsi/libata-scsi.c | 14 ++++++++++---- include/linux/libata.h | 1 + 2 files changed, 11 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 05090768d9a8..da9689b70826 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -2743,16 +2743,22 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd, void ata_scsi_scan_host(struct ata_port *ap) { - struct ata_device *dev; unsigned int i; if (ap->flags & ATA_FLAG_DISABLED) return; for (i = 0; i < ATA_MAX_DEVICES; i++) { - dev = &ap->device[i]; + struct ata_device *dev = &ap->device[i]; + struct scsi_device *sdev; + + if (!ata_dev_enabled(dev) || dev->sdev) + continue; - if (ata_dev_enabled(dev)) - scsi_scan_target(&ap->host->shost_gendev, 0, i, 0, 0); + sdev = __scsi_add_device(ap->host, 0, i, 0, NULL); + if (!IS_ERR(sdev)) { + dev->sdev = sdev; + scsi_device_put(sdev); + } } } diff --git a/include/linux/libata.h b/include/linux/libata.h index 10dc235ad8bc..c0513c752751 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -413,6 +413,7 @@ struct ata_device { struct ata_port *ap; unsigned int devno; /* 0 or 1 */ unsigned long flags; /* ATA_DFLAG_xxx */ + struct scsi_device *sdev; /* attached SCSI device */ /* n_sector is used as CLEAR_OFFSET, read comment above CLEAR_OFFSET */ u64 n_sectors; /* size of device, if ATA */ unsigned int class; /* ATA_DEV_xxx */ -- cgit v1.2.3 From d7bb4cc7575929a60b0a718daa1bce87bea9a9cc Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 31 May 2006 18:27:46 +0900 Subject: [PATCH] libata-hp-prep: implement sata_phy_debounce() With hotplug, PHY always needs to be debounced before a reset as any reset might find new devices. Extract PHY waiting code from sata_phy_resume() and extend it to include SStatus debouncing. Note that sata_phy_debounce() is superset of what used to be done inside sata_phy_resume(). Three default debounce timing parameters are defined to be used by hot/boot plug. As resume failure during probing will be properly handled as errors, timeout doesn't have to be long as before. probeinit() uses the same timeout to retain the original behavior. Signed-off-by: Tejun Heo --- drivers/scsi/libata-core.c | 107 +++++++++++++++++++++++++++++++++++++++------ include/linux/libata.h | 6 +++ 2 files changed, 99 insertions(+), 14 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index a9f79b47b4c3..4823ecefb8a1 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -61,6 +61,11 @@ #include "libata.h" +/* debounce timing parameters in msecs { interval, duration, timeout } */ +const unsigned long sata_deb_timing_boot[] = { 5, 100, 2000 }; +const unsigned long sata_deb_timing_eh[] = { 25, 500, 2000 }; +const unsigned long sata_deb_timing_before_fsrst[] = { 100, 2000, 5000 }; + static unsigned int ata_dev_init_params(struct ata_device *dev, u16 heads, u16 sectors); static unsigned int ata_dev_set_xfermode(struct ata_device *dev); @@ -2427,10 +2432,81 @@ err_out: DPRINTK("EXIT\n"); } -static int sata_phy_resume(struct ata_port *ap) +/** + * sata_phy_debounce - debounce SATA phy status + * @ap: ATA port to debounce SATA phy status for + * @params: timing parameters { interval, duratinon, timeout } in msec + * + * Make sure SStatus of @ap reaches stable state, determined by + * holding the same value where DET is not 1 for @duration polled + * every @interval, before @timeout. Timeout constraints the + * beginning of the stable state. Because, after hot unplugging, + * DET gets stuck at 1 on some controllers, this functions waits + * until timeout then returns 0 if DET is stable at 1. + * + * LOCKING: + * Kernel thread context (may sleep) + * + * RETURNS: + * 0 on success, -errno on failure. + */ +int sata_phy_debounce(struct ata_port *ap, const unsigned long *params) { - unsigned long timeout = jiffies + (HZ * 5); - u32 scontrol, sstatus; + unsigned long interval_msec = params[0]; + unsigned long duration = params[1] * HZ / 1000; + unsigned long timeout = jiffies + params[2] * HZ / 1000; + unsigned long last_jiffies; + u32 last, cur; + int rc; + + if ((rc = sata_scr_read(ap, SCR_STATUS, &cur))) + return rc; + cur &= 0xf; + + last = cur; + last_jiffies = jiffies; + + while (1) { + msleep(interval_msec); + if ((rc = sata_scr_read(ap, SCR_STATUS, &cur))) + return rc; + cur &= 0xf; + + /* DET stable? */ + if (cur == last) { + if (cur == 1 && time_before(jiffies, timeout)) + continue; + if (time_after(jiffies, last_jiffies + duration)) + return 0; + continue; + } + + /* unstable, start over */ + last = cur; + last_jiffies = jiffies; + + /* check timeout */ + if (time_after(jiffies, timeout)) + return -EBUSY; + } +} + +/** + * sata_phy_resume - resume SATA phy + * @ap: ATA port to resume SATA phy for + * @params: timing parameters { interval, duratinon, timeout } in msec + * + * Resume SATA phy of @ap and debounce it. + * + * LOCKING: + * Kernel thread context (may sleep) + * + * RETURNS: + * 0 on success, -errno on failure. + */ +int sata_phy_resume(struct ata_port *ap, const unsigned long *params) +{ + u32 scontrol; int rc; if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol))) @@ -2441,16 +2517,12 @@ static int sata_phy_resume(struct ata_port *ap) if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol))) return rc; - /* Wait for phy to become ready, if necessary. */ - do { - msleep(200); - if ((rc = sata_scr_read(ap, SCR_STATUS, &sstatus))) - return rc; - if ((sstatus & 0xf) != 1) - return 0; - } while (time_before(jiffies, timeout)); + /* Some PHYs react badly if SStatus is pounded immediately + * after resuming. Delay 200ms before debouncing. + */ + msleep(200); - return -EBUSY; + return sata_phy_debounce(ap, params); } /** @@ -2468,8 +2540,10 @@ static int sata_phy_resume(struct ata_port *ap) */ void ata_std_probeinit(struct ata_port *ap) { + static const unsigned long deb_timing[] = { 5, 100, 5000 }; + /* resume link */ - sata_phy_resume(ap); + sata_phy_resume(ap, deb_timing); /* wait for device */ if (ata_port_online(ap)) @@ -2585,7 +2659,7 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class) msleep(1); /* bring phy back */ - sata_phy_resume(ap); + sata_phy_resume(ap, sata_deb_timing_eh); /* TODO: phy layer with polling, timeouts, etc. */ if (ata_port_offline(ap)) { @@ -5718,6 +5792,9 @@ u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val, * Do not depend on ABI/API stability. */ +EXPORT_SYMBOL_GPL(sata_deb_timing_boot); +EXPORT_SYMBOL_GPL(sata_deb_timing_eh); +EXPORT_SYMBOL_GPL(sata_deb_timing_before_fsrst); EXPORT_SYMBOL_GPL(ata_std_bios_param); EXPORT_SYMBOL_GPL(ata_std_ports); EXPORT_SYMBOL_GPL(ata_device_add); @@ -5757,6 +5834,8 @@ EXPORT_SYMBOL_GPL(ata_bmdma_error_handler); EXPORT_SYMBOL_GPL(ata_bmdma_post_internal_cmd); EXPORT_SYMBOL_GPL(ata_port_probe); EXPORT_SYMBOL_GPL(sata_set_spd); +EXPORT_SYMBOL_GPL(sata_phy_debounce); +EXPORT_SYMBOL_GPL(sata_phy_resume); EXPORT_SYMBOL_GPL(sata_phy_reset); EXPORT_SYMBOL_GPL(__sata_phy_reset); EXPORT_SYMBOL_GPL(ata_bus_reset); diff --git a/include/linux/libata.h b/include/linux/libata.h index c0513c752751..1c167f728fb4 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -607,11 +607,17 @@ struct ata_timing { #define FIT(v,vmin,vmax) max_t(short,min_t(short,v,vmax),vmin) +extern const unsigned long sata_deb_timing_boot[]; +extern const unsigned long sata_deb_timing_eh[]; +extern const unsigned long sata_deb_timing_before_fsrst[]; + extern void ata_port_probe(struct ata_port *); extern void __sata_phy_reset(struct ata_port *ap); extern void sata_phy_reset(struct ata_port *ap); extern void ata_bus_reset(struct ata_port *ap); extern int sata_set_spd(struct ata_port *ap); +extern int sata_phy_debounce(struct ata_port *ap, const unsigned long *param); +extern int sata_phy_resume(struct ata_port *ap, const unsigned long *param); extern int ata_drive_probe_reset(struct ata_port *ap, ata_probeinit_fn_t probeinit, ata_reset_fn_t softreset, ata_reset_fn_t hardreset, -- cgit v1.2.3 From f5914a461eb9703773226a0813f6ffcae10c0861 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 31 May 2006 18:27:48 +0900 Subject: [PATCH] libata-hp-prep: add prereset() method and implement ata_std_prereset() With hotplug, every reset might be a probing reset and thus something similar to probe_init() is needed. prereset() method is called before a series of resets to a port and is the counterpart of postreset(). prereset() can tell EH to use different type of reset or skip reset by modifying ehc->i.action. This patch also implements ata_std_prereset(). Most controllers should be able to use this function directly or with some wrapping. After hotplug, different controllers need different actions to resume the PHY and detect the newly attached device. Controllers can be categorized as follows. * Controllers which can wait for the first D2H FIS after hotplug. Note that if the waiting is implemented by polling TF status, there needs to be a way to set BSY on PHY status change. It can be implemented by hardware or with the help of the driver. * Controllers which can wait for the first D2H FIS after sending COMRESET. These controllers need to issue COMRESET to wait for the first FIS. Note that the received D2H FIS could be the first D2H FIS after POR (power-on-reset) or D2H FIS in response to the COMRESET. Some controllers use COMRESET as TF status synchronization point and clear TF automatically (sata_sil). * Controllers which cannot wait for the first D2H FIS reliably. Blindly issuing SRST to spinning-up device often results in command issue failure or timeout, causing extended delay. For these controllers, ata_std_prereset() explicitly waits ATA_SPINUP_WAIT (currently 8s) to give newly attached device time to spin up, then issues reset. Note that failing to getting ready in ATA_SPINUP_WAIT is not critical. libata will retry. So, the timeout needs to be long enough to spin up most devices. LLDDs can tell ata_std_prereset() which of above action is needed with ATA_FLAG_HRST_TO_RESUME and ATA_FLAG_SKIP_D2H_BSY flags. These flags are PHY-specific property and will be moved to ata_link later. While at it, this patch unifies function typedef's such that they all have named arguments. Signed-off-by: Tejun Heo --- drivers/scsi/ahci.c | 3 +- drivers/scsi/libata-bmdma.c | 11 +++--- drivers/scsi/libata-core.c | 85 +++++++++++++++++++++++++++++++++++++++++++++ drivers/scsi/libata-eh.c | 60 +++++++++++++++++++++++++++----- drivers/scsi/sata_sil24.c | 3 +- include/linux/libata.h | 24 +++++++++---- 6 files changed, 165 insertions(+), 21 deletions(-) (limited to 'include') diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index 45fd71d80128..8493b021cc07 100644 --- a/drivers/scsi/ahci.c +++ b/drivers/scsi/ahci.c @@ -1026,7 +1026,8 @@ static void ahci_error_handler(struct ata_port *ap) } /* perform recovery */ - ata_do_eh(ap, ahci_softreset, ahci_hardreset, ahci_postreset); + ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_hardreset, + ahci_postreset); } static void ahci_post_internal_cmd(struct ata_queued_cmd *qc) diff --git a/drivers/scsi/libata-bmdma.c b/drivers/scsi/libata-bmdma.c index 6d30d2c52960..4bc05371737c 100644 --- a/drivers/scsi/libata-bmdma.c +++ b/drivers/scsi/libata-bmdma.c @@ -695,6 +695,7 @@ void ata_bmdma_thaw(struct ata_port *ap) /** * ata_bmdma_drive_eh - Perform EH with given methods for BMDMA controller * @ap: port to handle error for + * @prereset: prereset method (can be NULL) * @softreset: softreset method (can be NULL) * @hardreset: hardreset method (can be NULL) * @postreset: postreset method (can be NULL) @@ -710,8 +711,9 @@ void ata_bmdma_thaw(struct ata_port *ap) * LOCKING: * Kernel thread context (may sleep) */ -void ata_bmdma_drive_eh(struct ata_port *ap, ata_reset_fn_t softreset, - ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) +void ata_bmdma_drive_eh(struct ata_port *ap, ata_prereset_fn_t prereset, + ata_reset_fn_t softreset, ata_reset_fn_t hardreset, + ata_postreset_fn_t postreset) { struct ata_host_set *host_set = ap->host_set; struct ata_eh_context *ehc = &ap->eh_context; @@ -759,7 +761,7 @@ void ata_bmdma_drive_eh(struct ata_port *ap, ata_reset_fn_t softreset, ata_eh_thaw_port(ap); /* PIO and DMA engines have been stopped, perform recovery */ - ata_do_eh(ap, softreset, hardreset, postreset); + ata_do_eh(ap, prereset, softreset, hardreset, postreset); } /** @@ -779,7 +781,8 @@ void ata_bmdma_error_handler(struct ata_port *ap) if (sata_scr_valid(ap)) hardreset = sata_std_hardreset; - ata_bmdma_drive_eh(ap, ata_std_softreset, hardreset, ata_std_postreset); + ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, hardreset, + ata_std_postreset); } /** diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 4823ecefb8a1..2531a701d6e9 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -2525,6 +2525,90 @@ int sata_phy_resume(struct ata_port *ap, const unsigned long *params) return sata_phy_debounce(ap, params); } +static void ata_wait_spinup(struct ata_port *ap) +{ + struct ata_eh_context *ehc = &ap->eh_context; + unsigned long end, secs; + int rc; + + /* first, debounce phy if SATA */ + if (ap->cbl == ATA_CBL_SATA) { + rc = sata_phy_debounce(ap, sata_deb_timing_eh); + + /* if debounced successfully and offline, no need to wait */ + if ((rc == 0 || rc == -EOPNOTSUPP) && ata_port_offline(ap)) + return; + } + + /* okay, let's give the drive time to spin up */ + end = ehc->i.hotplug_timestamp + ATA_SPINUP_WAIT * HZ / 1000; + secs = ((end - jiffies) + HZ - 1) / HZ; + + if (time_after(jiffies, end)) + return; + + if (secs > 5) + ata_port_printk(ap, KERN_INFO, "waiting for device to spin up " + "(%lu secs)\n", secs); + + schedule_timeout_uninterruptible(end - jiffies); +} + +/** + * ata_std_prereset - prepare for reset + * @ap: ATA port to be reset + * + * @ap is about to be reset. Initialize it. + * + * LOCKING: + * Kernel thread context (may sleep) + * + * RETURNS: + * 0 on success, -errno otherwise. + */ +int ata_std_prereset(struct ata_port *ap) +{ + struct ata_eh_context *ehc = &ap->eh_context; + const unsigned long *timing; + int rc; + + /* hotplug? */ + if (ehc->i.flags & ATA_EHI_HOTPLUGGED) { + if (ap->flags & ATA_FLAG_HRST_TO_RESUME) + ehc->i.action |= ATA_EH_HARDRESET; + if (ap->flags & ATA_FLAG_SKIP_D2H_BSY) + ata_wait_spinup(ap); + } + + /* if we're about to do hardreset, nothing more to do */ + if (ehc->i.action & ATA_EH_HARDRESET) + return 0; + + /* if SATA, resume phy */ + if (ap->cbl == ATA_CBL_SATA) { + if (ap->flags & ATA_FLAG_LOADING) + timing = sata_deb_timing_boot; + else + timing = sata_deb_timing_eh; + + rc = sata_phy_resume(ap, timing); + if (rc && rc != -EOPNOTSUPP) { + /* phy resume failed */ + ata_port_printk(ap, KERN_WARNING, "failed to resume " + "link for reset (errno=%d)\n", rc); + return rc; + } + } + + /* Wait for !BSY if the controller can wait for the first D2H + * Reg FIS and we don't know that no device is attached. + */ + if (!(ap->flags & ATA_FLAG_SKIP_D2H_BSY) && !ata_port_offline(ap)) + ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT); + + return 0; +} + /** * ata_std_probeinit - initialize probing * @ap: port to be probed @@ -5840,6 +5924,7 @@ EXPORT_SYMBOL_GPL(sata_phy_reset); EXPORT_SYMBOL_GPL(__sata_phy_reset); EXPORT_SYMBOL_GPL(ata_bus_reset); EXPORT_SYMBOL_GPL(ata_std_probeinit); +EXPORT_SYMBOL_GPL(ata_std_prereset); EXPORT_SYMBOL_GPL(ata_std_softreset); EXPORT_SYMBOL_GPL(sata_std_hardreset); EXPORT_SYMBOL_GPL(ata_std_postreset); diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index 9173d8f2ce5d..0e66f140e53b 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c @@ -1318,20 +1318,58 @@ static void ata_eh_report(struct ata_port *ap) } } -static int ata_eh_reset(struct ata_port *ap, ata_reset_fn_t softreset, +static int ata_eh_reset(struct ata_port *ap, + ata_prereset_fn_t prereset, ata_reset_fn_t softreset, ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) { struct ata_eh_context *ehc = &ap->eh_context; unsigned int classes[ATA_MAX_DEVICES]; int tries = ATA_EH_RESET_TRIES; + unsigned int action; ata_reset_fn_t reset; int i, rc; + /* Determine which reset to use and record in ehc->i.action. + * prereset() may examine and modify it. + */ + action = ehc->i.action; + ehc->i.action &= ~ATA_EH_RESET_MASK; if (softreset && (!hardreset || (!sata_set_spd_needed(ap) && - !(ehc->i.action & ATA_EH_HARDRESET)))) - reset = softreset; + !(action & ATA_EH_HARDRESET)))) + ehc->i.action |= ATA_EH_SOFTRESET; else + ehc->i.action |= ATA_EH_HARDRESET; + + if (prereset) { + rc = prereset(ap); + if (rc) { + ata_port_printk(ap, KERN_ERR, + "prereset failed (errno=%d)\n", rc); + return rc; + } + } + + /* prereset() might have modified ehc->i.action */ + if (ehc->i.action & ATA_EH_HARDRESET) reset = hardreset; + else if (ehc->i.action & ATA_EH_SOFTRESET) + reset = softreset; + else { + /* prereset told us not to reset, bang classes and return */ + for (i = 0; i < ATA_MAX_DEVICES; i++) + classes[i] = ATA_DEV_NONE; + return 0; + } + + /* did prereset() screw up? if so, fix up to avoid oopsing */ + if (!reset) { + ata_port_printk(ap, KERN_ERR, "BUG: prereset() requested " + "invalid reset type\n"); + if (softreset) + reset = softreset; + else + reset = hardreset; + } retry: ata_port_printk(ap, KERN_INFO, "%s resetting port\n", @@ -1424,6 +1462,7 @@ static int ata_port_nr_enabled(struct ata_port *ap) /** * ata_eh_recover - recover host port after error * @ap: host port to recover + * @prereset: prereset method (can be NULL) * @softreset: softreset method (can be NULL) * @hardreset: hardreset method (can be NULL) * @postreset: postreset method (can be NULL) @@ -1440,8 +1479,8 @@ static int ata_port_nr_enabled(struct ata_port *ap) * RETURNS: * 0 on success, -errno on failure. */ -static int ata_eh_recover(struct ata_port *ap, ata_reset_fn_t softreset, - ata_reset_fn_t hardreset, +static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, + ata_reset_fn_t softreset, ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) { struct ata_eh_context *ehc = &ap->eh_context; @@ -1469,7 +1508,8 @@ static int ata_eh_recover(struct ata_port *ap, ata_reset_fn_t softreset, if (ehc->i.action & ATA_EH_RESET_MASK) { ata_eh_freeze_port(ap); - rc = ata_eh_reset(ap, softreset, hardreset, postreset); + rc = ata_eh_reset(ap, prereset, softreset, hardreset, + postreset); if (rc) { ata_port_printk(ap, KERN_ERR, "reset failed, giving up\n"); @@ -1586,6 +1626,7 @@ static void ata_eh_finish(struct ata_port *ap) /** * ata_do_eh - do standard error handling * @ap: host port to handle error for + * @prereset: prereset method (can be NULL) * @softreset: softreset method (can be NULL) * @hardreset: hardreset method (can be NULL) * @postreset: postreset method (can be NULL) @@ -1595,11 +1636,12 @@ static void ata_eh_finish(struct ata_port *ap) * LOCKING: * Kernel thread context (may sleep). */ -void ata_do_eh(struct ata_port *ap, ata_reset_fn_t softreset, - ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) +void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset, + ata_reset_fn_t softreset, ata_reset_fn_t hardreset, + ata_postreset_fn_t postreset) { ata_eh_autopsy(ap); ata_eh_report(ap); - ata_eh_recover(ap, softreset, hardreset, postreset); + ata_eh_recover(ap, prereset, softreset, hardreset, postreset); ata_eh_finish(ap); } diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c index 4c76f05d9b65..26d7c54c175e 100644 --- a/drivers/scsi/sata_sil24.c +++ b/drivers/scsi/sata_sil24.c @@ -912,7 +912,8 @@ static void sil24_error_handler(struct ata_port *ap) } /* perform recovery */ - ata_do_eh(ap, sil24_softreset, sil24_hardreset, ata_std_postreset); + ata_do_eh(ap, ata_std_prereset, sil24_softreset, sil24_hardreset, + ata_std_postreset); } static void sil24_post_internal_cmd(struct ata_queued_cmd *qc) diff --git a/include/linux/libata.h b/include/linux/libata.h index 1c167f728fb4..fe5f53943c44 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -262,6 +262,15 @@ enum { ATA_PROBE_MAX_TRIES = 3, ATA_EH_RESET_TRIES = 3, ATA_EH_DEV_TRIES = 3, + + /* Drive spinup time (time from power-on to the first D2H FIS) + * in msecs - 8s currently. Failing to get ready in this time + * isn't critical. It will result in reset failure for + * controllers which can't wait for the first D2H FIS. libata + * will retry, so it just has to be long enough to spin up + * most devices. + */ + ATA_SPINUP_WAIT = 8000, }; enum hsm_task_states { @@ -294,9 +303,10 @@ struct ata_queued_cmd; /* typedefs */ typedef void (*ata_qc_cb_t) (struct ata_queued_cmd *qc); -typedef void (*ata_probeinit_fn_t)(struct ata_port *); -typedef int (*ata_reset_fn_t)(struct ata_port *, unsigned int *); -typedef void (*ata_postreset_fn_t)(struct ata_port *ap, unsigned int *); +typedef void (*ata_probeinit_fn_t)(struct ata_port *ap); +typedef int (*ata_prereset_fn_t)(struct ata_port *ap); +typedef int (*ata_reset_fn_t)(struct ata_port *ap, unsigned int *classes); +typedef void (*ata_postreset_fn_t)(struct ata_port *ap, unsigned int *classes); struct ata_ioports { unsigned long cmd_addr; @@ -623,6 +633,7 @@ extern int ata_drive_probe_reset(struct ata_port *ap, ata_reset_fn_t softreset, ata_reset_fn_t hardreset, ata_postreset_fn_t postreset, unsigned int *classes); extern void ata_std_probeinit(struct ata_port *ap); +extern int ata_std_prereset(struct ata_port *ap); extern int ata_std_softreset(struct ata_port *ap, unsigned int *classes); extern int sata_std_hardreset(struct ata_port *ap, unsigned int *class); extern void ata_std_postreset(struct ata_port *ap, unsigned int *classes); @@ -706,7 +717,7 @@ extern u8 ata_bmdma_status(struct ata_port *ap); extern void ata_bmdma_irq_clear(struct ata_port *ap); extern void ata_bmdma_freeze(struct ata_port *ap); extern void ata_bmdma_thaw(struct ata_port *ap); -extern void ata_bmdma_drive_eh(struct ata_port *ap, +extern void ata_bmdma_drive_eh(struct ata_port *ap, ata_prereset_fn_t prereset, ata_reset_fn_t softreset, ata_reset_fn_t hardreset, ata_postreset_fn_t postreset); @@ -784,8 +795,9 @@ extern void ata_eh_thaw_port(struct ata_port *ap); extern void ata_eh_qc_complete(struct ata_queued_cmd *qc); extern void ata_eh_qc_retry(struct ata_queued_cmd *qc); -extern void ata_do_eh(struct ata_port *ap, ata_reset_fn_t softreset, - ata_reset_fn_t hardreset, ata_postreset_fn_t postreset); +extern void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset, + ata_reset_fn_t softreset, ata_reset_fn_t hardreset, + ata_postreset_fn_t postreset); /* * printk helpers -- cgit v1.2.3 From 9a1004d0c11be41c83d06a67dfe74567a41ae582 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 31 May 2006 18:27:52 +0900 Subject: [PATCH] libata: export ata_hsm_move() ata_hsm_move() will be used by LLDDs which depend on standard PIO HSM but implement their own interrupt handlers. Signed-off-by: Tejun Heo --- drivers/scsi/libata-core.c | 6 +++--- include/linux/libata.h | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 2531a701d6e9..c965eea3b3d4 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -4140,9 +4140,8 @@ static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq) * RETURNS: * 1 when poll next status needed, 0 otherwise. */ - -static int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, - u8 status, int in_wq) +int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, + u8 status, int in_wq) { unsigned long flags = 0; int poll_next; @@ -5885,6 +5884,7 @@ EXPORT_SYMBOL_GPL(ata_device_add); EXPORT_SYMBOL_GPL(ata_host_set_remove); EXPORT_SYMBOL_GPL(ata_sg_init); EXPORT_SYMBOL_GPL(ata_sg_init_one); +EXPORT_SYMBOL_GPL(ata_hsm_move); EXPORT_SYMBOL_GPL(ata_qc_complete); EXPORT_SYMBOL_GPL(ata_qc_complete_multiple); EXPORT_SYMBOL_GPL(ata_qc_issue_prot); diff --git a/include/linux/libata.h b/include/linux/libata.h index fe5f53943c44..a1ceb5b67b97 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -723,6 +723,8 @@ extern void ata_bmdma_drive_eh(struct ata_port *ap, ata_prereset_fn_t prereset, ata_postreset_fn_t postreset); extern void ata_bmdma_error_handler(struct ata_port *ap); extern void ata_bmdma_post_internal_cmd(struct ata_queued_cmd *qc); +extern int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, + u8 status, int in_wq); extern void ata_qc_complete(struct ata_queued_cmd *qc); extern int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active, void (*finish_qc)(struct ata_queued_cmd *)); -- cgit v1.2.3 From 084fe639b81c4d418a2cf714acb0475e3713cb73 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 31 May 2006 18:28:03 +0900 Subject: [PATCH] libata-hp: implement hotplug Implement ATA part of hotplug. To avoid probing broken devices over and over again, disabled devices are not automatically detached. They are detached only if probing is requested for the device or the associated port is offline. Also, to avoid infinite probing loop, Each device is probed only once per EH run. As SATA PHY status is fragile, devices are detached only after it has used up its recovery chances unless explicitly requested by LLDD or user (LLDD may request direct detach if, for example, it supports cold presence detection). Signed-off-by: Tejun Heo --- drivers/scsi/libata-eh.c | 123 +++++++++++++++++++++++++++++++++++++++-------- include/linux/libata.h | 13 +++++ 2 files changed, 115 insertions(+), 21 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index a049bffdf770..b53e2e7db498 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c @@ -932,10 +932,8 @@ static void ata_eh_analyze_serror(struct ata_port *ap) err_mask |= AC_ERR_SYSTEM; action |= ATA_EH_SOFTRESET; } - if (serror & (SERR_PHYRDY_CHG | SERR_DEV_XCHG)) { - err_mask |= AC_ERR_ATA_BUS; - action |= ATA_EH_HARDRESET; - } + if (serror & (SERR_PHYRDY_CHG | SERR_DEV_XCHG)) + ata_ehi_hotplugged(&ehc->i); ehc->i.err_mask |= err_mask; ehc->i.action |= action; @@ -1487,11 +1485,12 @@ static int ata_eh_reset(struct ata_port *ap, int classify, return rc; } -static int ata_eh_revalidate(struct ata_port *ap, - struct ata_device **r_failed_dev) +static int ata_eh_revalidate_and_attach(struct ata_port *ap, + struct ata_device **r_failed_dev) { struct ata_eh_context *ehc = &ap->eh_context; struct ata_device *dev; + unsigned long flags; int i, rc = 0; DPRINTK("ENTER\n"); @@ -1513,6 +1512,23 @@ static int ata_eh_revalidate(struct ata_port *ap, break; ehc->i.action &= ~ATA_EH_REVALIDATE; + } else if (dev->class == ATA_DEV_UNKNOWN && + ehc->tries[dev->devno] && + ata_class_enabled(ehc->classes[dev->devno])) { + dev->class = ehc->classes[dev->devno]; + + rc = ata_dev_read_id(dev, &dev->class, 1, dev->id); + if (rc == 0) + rc = ata_dev_configure(dev, 1); + + if (rc) { + dev->class = ATA_DEV_UNKNOWN; + break; + } + + spin_lock_irqsave(&ap->host_set->lock, flags); + ap->flags |= ATA_FLAG_SCSI_HOTPLUG; + spin_unlock_irqrestore(&ap->host_set->lock, flags); } } @@ -1533,6 +1549,36 @@ static int ata_port_nr_enabled(struct ata_port *ap) return cnt; } +static int ata_port_nr_vacant(struct ata_port *ap) +{ + int i, cnt = 0; + + for (i = 0; i < ATA_MAX_DEVICES; i++) + if (ap->device[i].class == ATA_DEV_UNKNOWN) + cnt++; + return cnt; +} + +static int ata_eh_skip_recovery(struct ata_port *ap) +{ + struct ata_eh_context *ehc = &ap->eh_context; + int i; + + if (ap->flags & ATA_FLAG_FROZEN || ata_port_nr_enabled(ap)) + return 0; + + /* skip if class codes for all vacant slots are ATA_DEV_NONE */ + for (i = 0; i < ATA_MAX_DEVICES; i++) { + struct ata_device *dev = &ap->device[i]; + + if (dev->class == ATA_DEV_UNKNOWN && + ehc->classes[dev->devno] != ATA_DEV_NONE) + return 0; + } + + return 1; +} + /** * ata_eh_recover - recover host port after error * @ap: host port to recover @@ -1543,9 +1589,10 @@ static int ata_port_nr_enabled(struct ata_port *ap) * * This is the alpha and omega, eum and yang, heart and soul of * libata exception handling. On entry, actions required to - * recover each devices are recorded in eh_context. This - * function executes all the operations with appropriate retrials - * and fallbacks to resurrect failed devices. + * recover the port and hotplug requests are recorded in + * eh_context. This function executes all the operations with + * appropriate retrials and fallbacks to resurrect failed + * devices, detach goners and greet newcomers. * * LOCKING: * Kernel thread context (may sleep). @@ -1568,6 +1615,19 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, dev = &ap->device[i]; ehc->tries[dev->devno] = ATA_EH_DEV_TRIES; + + /* process hotplug request */ + if (dev->flags & ATA_DFLAG_DETACH) + ata_eh_detach_dev(dev); + + if (!ata_dev_enabled(dev) && + ((ehc->i.probe_mask & (1 << dev->devno)) && + !(ehc->did_probe_mask & (1 << dev->devno)))) { + ata_eh_detach_dev(dev); + ata_dev_init(dev); + ehc->did_probe_mask |= (1 << dev->devno); + ehc->i.action |= ATA_EH_SOFTRESET; + } } retry: @@ -1575,15 +1635,18 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, rc = 0; /* skip EH if possible. */ - if (!ata_port_nr_enabled(ap) && !(ap->flags & ATA_FLAG_FROZEN)) + if (ata_eh_skip_recovery(ap)) ehc->i.action = 0; + for (i = 0; i < ATA_MAX_DEVICES; i++) + ehc->classes[i] = ATA_DEV_UNKNOWN; + /* reset */ if (ehc->i.action & ATA_EH_RESET_MASK) { ata_eh_freeze_port(ap); - rc = ata_eh_reset(ap, 0, prereset, softreset, hardreset, - postreset); + rc = ata_eh_reset(ap, ata_port_nr_vacant(ap), prereset, + softreset, hardreset, postreset); if (rc) { ata_port_printk(ap, KERN_ERR, "reset failed, giving up\n"); @@ -1593,8 +1656,8 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, ata_eh_thaw_port(ap); } - /* revalidate existing devices */ - rc = ata_eh_revalidate(ap, &dev); + /* revalidate existing devices and attach new ones */ + rc = ata_eh_revalidate_and_attach(ap, &dev); if (rc) goto dev_fail; @@ -1612,6 +1675,8 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, dev_fail: switch (rc) { case -ENODEV: + /* device missing, schedule probing */ + ehc->i.probe_mask |= (1 << dev->devno); case -EINVAL: ehc->tries[dev->devno] = 0; break; @@ -1624,15 +1689,31 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, ehc->tries[dev->devno] = 0; } - /* disable device if it has used up all its chances */ - if (ata_dev_enabled(dev) && !ehc->tries[dev->devno]) + if (ata_dev_enabled(dev) && !ehc->tries[dev->devno]) { + /* disable device if it has used up all its chances */ ata_dev_disable(dev); - /* soft didn't work? be haaaaard */ - if (ehc->i.flags & ATA_EHI_DID_RESET) - ehc->i.action |= ATA_EH_HARDRESET; - else - ehc->i.action |= ATA_EH_SOFTRESET; + /* detach if offline */ + if (ata_port_offline(ap)) + ata_eh_detach_dev(dev); + + /* probe if requested */ + if ((ehc->i.probe_mask & (1 << dev->devno)) && + !(ehc->did_probe_mask & (1 << dev->devno))) { + ata_eh_detach_dev(dev); + ata_dev_init(dev); + + ehc->tries[dev->devno] = ATA_EH_DEV_TRIES; + ehc->did_probe_mask |= (1 << dev->devno); + ehc->i.action |= ATA_EH_SOFTRESET; + } + } else { + /* soft didn't work? be haaaaard */ + if (ehc->i.flags & ATA_EHI_DID_RESET) + ehc->i.action |= ATA_EH_HARDRESET; + else + ehc->i.action |= ATA_EH_SOFTRESET; + } if (ata_port_nr_enabled(ap)) { ata_port_printk(ap, KERN_WARNING, "failed to recover some " diff --git a/include/linux/libata.h b/include/linux/libata.h index a1ceb5b67b97..56971943d261 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -824,6 +824,19 @@ extern void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset, (ehi)->desc_len = 0; \ } while (0) +static inline void ata_ehi_hotplugged(struct ata_eh_info *ehi) +{ + if (ehi->flags & ATA_EHI_HOTPLUGGED) + return; + + ehi->flags |= ATA_EHI_HOTPLUGGED; + ehi->hotplug_timestamp = jiffies; + + ehi->err_mask |= AC_ERR_ATA_BUS; + ehi->action |= ATA_EH_SOFTRESET; + ehi->probe_mask |= (1 << ATA_MAX_DEVICES) - 1; +} + /* * qc helpers */ -- cgit v1.2.3 From 580b2102327ab8444af5bde4e70b50d268a1d558 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 31 May 2006 18:28:05 +0900 Subject: [PATCH] libata-hp: implement SCSI part of hotplug Implement SCSI part of hotplug. This must be done in a separate context as SCSI makes use of EH during probing. SCSI scan fails silently if EH is in progress. In such cases, libata pauses briefly and retries until every device is attached. Signed-off-by: Tejun Heo --- drivers/scsi/libata-core.c | 1 + drivers/scsi/libata-eh.c | 6 ++- drivers/scsi/libata-scsi.c | 116 +++++++++++++++++++++++++++++++++++++++++++++ drivers/scsi/libata.h | 1 + include/linux/libata.h | 2 +- 5 files changed, 124 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index c965eea3b3d4..8df8ecc51a78 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -5370,6 +5370,7 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host, ap->msg_enable = ATA_MSG_DRV; INIT_WORK(&ap->port_task, NULL, NULL); + INIT_WORK(&ap->hotplug_task, ata_scsi_hotplug, ap); INIT_LIST_HEAD(&ap->eh_done_q); init_waitqueue_head(&ap->eh_wait_q); diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index b53e2e7db498..733dfa532977 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c @@ -287,9 +287,13 @@ void ata_scsi_error(struct Scsi_Host *host) /* clean up */ spin_lock_irqsave(hs_lock, flags); + if (ap->flags & ATA_FLAG_SCSI_HOTPLUG) + queue_work(ata_aux_wq, &ap->hotplug_task); + if (ap->flags & ATA_FLAG_RECOVERED) ata_port_printk(ap, KERN_INFO, "EH complete\n"); - ap->flags &= ~ATA_FLAG_RECOVERED; + + ap->flags &= ~(ATA_FLAG_SCSI_HOTPLUG | ATA_FLAG_RECOVERED); /* tell wait_eh that we're done */ ap->flags &= ~ATA_FLAG_EH_IN_PROGRESS; diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 3dc6188af0e8..12563998d97c 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -2786,3 +2786,119 @@ int ata_scsi_offline_dev(struct ata_device *dev) } return 0; } + +/** + * ata_scsi_remove_dev - remove attached SCSI device + * @dev: ATA device to remove attached SCSI device for + * + * This function is called from ata_eh_scsi_hotplug() and + * responsible for removing the SCSI device attached to @dev. + * + * LOCKING: + * Kernel thread context (may sleep). + */ +static void ata_scsi_remove_dev(struct ata_device *dev) +{ + struct ata_port *ap = dev->ap; + struct scsi_device *sdev; + unsigned long flags; + + /* Alas, we need to grab scan_mutex to ensure SCSI device + * state doesn't change underneath us and thus + * scsi_device_get() always succeeds. The mutex locking can + * be removed if there is __scsi_device_get() interface which + * increments reference counts regardless of device state. + */ + mutex_lock(&ap->host->scan_mutex); + spin_lock_irqsave(&ap->host_set->lock, flags); + + /* clearing dev->sdev is protected by host_set lock */ + sdev = dev->sdev; + dev->sdev = NULL; + + if (sdev) { + /* If user initiated unplug races with us, sdev can go + * away underneath us after the host_set lock and + * scan_mutex are released. Hold onto it. + */ + if (scsi_device_get(sdev) == 0) { + /* The following ensures the attached sdev is + * offline on return from ata_scsi_offline_dev() + * regardless it wins or loses the race + * against this function. + */ + scsi_device_set_state(sdev, SDEV_OFFLINE); + } else { + WARN_ON(1); + sdev = NULL; + } + } + + spin_unlock_irqrestore(&ap->host_set->lock, flags); + mutex_unlock(&ap->host->scan_mutex); + + if (sdev) { + ata_dev_printk(dev, KERN_INFO, "detaching (SCSI %s)\n", + sdev->sdev_gendev.bus_id); + + scsi_remove_device(sdev); + scsi_device_put(sdev); + } +} + +/** + * ata_scsi_hotplug - SCSI part of hotplug + * @data: Pointer to ATA port to perform SCSI hotplug on + * + * Perform SCSI part of hotplug. It's executed from a separate + * workqueue after EH completes. This is necessary because SCSI + * hot plugging requires working EH and hot unplugging is + * synchronized with hot plugging with a mutex. + * + * LOCKING: + * Kernel thread context (may sleep). + */ +void ata_scsi_hotplug(void *data) +{ + struct ata_port *ap = data; + int i; + + if (ap->flags & ATA_FLAG_UNLOADING) { + DPRINTK("ENTER/EXIT - unloading\n"); + return; + } + + DPRINTK("ENTER\n"); + + /* unplug detached devices */ + for (i = 0; i < ATA_MAX_DEVICES; i++) { + struct ata_device *dev = &ap->device[i]; + unsigned long flags; + + if (!(dev->flags & ATA_DFLAG_DETACHED)) + continue; + + spin_lock_irqsave(&ap->host_set->lock, flags); + dev->flags &= ~ATA_DFLAG_DETACHED; + spin_unlock_irqrestore(&ap->host_set->lock, flags); + + ata_scsi_remove_dev(dev); + } + + /* scan for new ones */ + ata_scsi_scan_host(ap); + + /* If we scanned while EH was in progress, scan would have + * failed silently. Requeue if there are enabled but + * unattached devices. + */ + for (i = 0; i < ATA_MAX_DEVICES; i++) { + struct ata_device *dev = &ap->device[i]; + if (ata_dev_enabled(dev) && !dev->sdev) { + queue_delayed_work(ata_aux_wq, &ap->hotplug_task, HZ); + break; + } + } + + DPRINTK("EXIT\n"); +} diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h index e38759fdc183..0586b0cd73fd 100644 --- a/drivers/scsi/libata.h +++ b/drivers/scsi/libata.h @@ -76,6 +76,7 @@ extern struct scsi_transport_template ata_scsi_transport_template; extern void ata_scsi_scan_host(struct ata_port *ap); extern int ata_scsi_offline_dev(struct ata_device *dev); +extern void ata_scsi_hotplug(void *data); extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen); diff --git a/include/linux/libata.h b/include/linux/libata.h index 56971943d261..407115624d9f 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -521,7 +521,7 @@ struct ata_port { struct ata_host_set *host_set; struct device *dev; - struct work_struct port_task; + struct work_struct port_task, hotplug_task; unsigned int hsm_task_state; -- cgit v1.2.3 From 83c47bcb3c533180a6dda78152334de50065358a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 31 May 2006 18:28:07 +0900 Subject: [PATCH] libata-hp: implement warmplug Implement warmplug. User-initiated unplug can be detected by hostt->slave_destroy() and plug by transportt->user_scan(). This patch only implements the two callbacks. The next function will hook them. Signed-off-by: Tejun Heo --- drivers/scsi/libata-core.c | 1 + drivers/scsi/libata-scsi.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/libata.h | 1 + 3 files changed, 91 insertions(+) (limited to 'include') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 8df8ecc51a78..c61cfc742388 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -5942,6 +5942,7 @@ EXPORT_SYMBOL_GPL(ata_port_queue_task); EXPORT_SYMBOL_GPL(ata_scsi_ioctl); EXPORT_SYMBOL_GPL(ata_scsi_queuecmd); EXPORT_SYMBOL_GPL(ata_scsi_slave_config); +EXPORT_SYMBOL_GPL(ata_scsi_slave_destroy); EXPORT_SYMBOL_GPL(ata_scsi_change_queue_depth); EXPORT_SYMBOL_GPL(ata_scsi_release); EXPORT_SYMBOL_GPL(ata_host_intr); diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 12563998d97c..7c1ac58c430a 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -57,6 +57,8 @@ static struct ata_device * __ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev); static struct ata_device * ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev); +static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, + unsigned int id, unsigned int lun); #define RW_RECOVERY_MPAGE 0x1 @@ -726,6 +728,40 @@ int ata_scsi_slave_config(struct scsi_device *sdev) return 0; /* scsi layer doesn't check return value, sigh */ } +/** + * ata_scsi_slave_destroy - SCSI device is about to be destroyed + * @sdev: SCSI device to be destroyed + * + * @sdev is about to be destroyed for hot/warm unplugging. If + * this unplugging was initiated by libata as indicated by NULL + * dev->sdev, this function doesn't have to do anything. + * Otherwise, SCSI layer initiated warm-unplug is in progress. + * Clear dev->sdev, schedule the device for ATA detach and invoke + * EH. + * + * LOCKING: + * Defined by SCSI layer. We don't really care. + */ +void ata_scsi_slave_destroy(struct scsi_device *sdev) +{ + struct ata_port *ap = ata_shost_to_port(sdev->host); + unsigned long flags; + struct ata_device *dev; + + if (!ap->ops->error_handler) + return; + + spin_lock_irqsave(&ap->host_set->lock, flags); + dev = __ata_scsi_find_dev(ap, sdev); + if (dev && dev->sdev) { + /* SCSI device already in CANCEL state, no need to offline it */ + dev->sdev = NULL; + dev->flags |= ATA_DFLAG_DETACH; + ata_port_schedule_eh(ap); + } + spin_unlock_irqrestore(&ap->host_set->lock, flags); +} + /** * ata_scsi_change_queue_depth - SCSI callback for queue depth config * @sdev: SCSI device to configure queue depth for @@ -2902,3 +2938,56 @@ void ata_scsi_hotplug(void *data) DPRINTK("EXIT\n"); } + +/** + * ata_scsi_user_scan - indication for user-initiated bus scan + * @shost: SCSI host to scan + * @channel: Channel to scan + * @id: ID to scan + * @lun: LUN to scan + * + * This function is called when user explicitly requests bus + * scan. Set probe pending flag and invoke EH. + * + * LOCKING: + * SCSI layer (we don't care) + * + * RETURNS: + * Zero. + */ +static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, + unsigned int id, unsigned int lun) +{ + struct ata_port *ap = ata_shost_to_port(shost); + unsigned long flags; + int rc = 0; + + if (!ap->ops->error_handler) + return -EOPNOTSUPP; + + if ((channel != SCAN_WILD_CARD && channel != 0) || + (lun != SCAN_WILD_CARD && lun != 0)) + return -EINVAL; + + spin_lock_irqsave(&ap->host_set->lock, flags); + + if (id == SCAN_WILD_CARD) { + ap->eh_info.probe_mask |= (1 << ATA_MAX_DEVICES) - 1; + ap->eh_info.action |= ATA_EH_SOFTRESET; + } else { + struct ata_device *dev = ata_find_dev(ap, id); + + if (dev) { + ap->eh_info.probe_mask |= 1 << dev->devno; + ap->eh_info.action |= ATA_EH_SOFTRESET; + } else + rc = -EINVAL; + } + + if (rc == 0) + ata_port_schedule_eh(ap); + + spin_unlock_irqrestore(&ap->host_set->lock, flags); + + return rc; +} diff --git a/include/linux/libata.h b/include/linux/libata.h index 407115624d9f..74786c33c526 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -734,6 +734,7 @@ extern int ata_std_bios_param(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int geom[]); extern int ata_scsi_slave_config(struct scsi_device *sdev); +extern void ata_scsi_slave_destroy(struct scsi_device *sdev); extern int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth); extern struct ata_device *ata_dev_pair(struct ata_device *adev); -- cgit v1.2.3 From 720ba12620ee09dce269adf4ad50958adac7bb54 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 31 May 2006 18:28:13 +0900 Subject: [PATCH] libata-hp: update unload-unplug Update unload unplug - driver unloading / PCI removal. This is done by ata_port_detach() which short-circuits EH, disables all devices and freezes the port. With this patch, EH and unloading/unplugging are properly synchronized. Signed-off-by: Tejun Heo --- drivers/scsi/ahci.c | 10 +++---- drivers/scsi/libata-core.c | 67 +++++++++++++++++++++++++++++++++++++++++----- drivers/scsi/libata-eh.c | 8 ++++-- include/linux/libata.h | 1 + 4 files changed, 71 insertions(+), 15 deletions(-) (limited to 'include') diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index afb3805f9e95..60f455bf3696 100644 --- a/drivers/scsi/ahci.c +++ b/drivers/scsi/ahci.c @@ -1389,21 +1389,17 @@ static void ahci_remove_one (struct pci_dev *pdev) struct device *dev = pci_dev_to_dev(pdev); struct ata_host_set *host_set = dev_get_drvdata(dev); struct ahci_host_priv *hpriv = host_set->private_data; - struct ata_port *ap; unsigned int i; int have_msi; - for (i = 0; i < host_set->n_ports; i++) { - ap = host_set->ports[i]; - - scsi_remove_host(ap->host); - } + for (i = 0; i < host_set->n_ports; i++) + ata_port_detach(host_set->ports[i]); have_msi = hpriv->flags & AHCI_FLAG_MSI; free_irq(host_set->irq, host_set); for (i = 0; i < host_set->n_ports; i++) { - ap = host_set->ports[i]; + struct ata_port *ap = host_set->ports[i]; ata_scsi_release(ap->host); scsi_host_put(ap->host); diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index a42877e6b865..01f2c59536bc 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -5609,6 +5609,63 @@ err_free_ret: return 0; } +/** + * ata_port_detach - Detach ATA port in prepration of device removal + * @ap: ATA port to be detached + * + * Detach all ATA devices and the associated SCSI devices of @ap; + * then, remove the associated SCSI host. @ap is guaranteed to + * be quiescent on return from this function. + * + * LOCKING: + * Kernel thread context (may sleep). + */ +void ata_port_detach(struct ata_port *ap) +{ + unsigned long flags; + int i; + + if (!ap->ops->error_handler) + return; + + /* tell EH we're leaving & flush EH */ + spin_lock_irqsave(&ap->host_set->lock, flags); + ap->flags |= ATA_FLAG_UNLOADING; + spin_unlock_irqrestore(&ap->host_set->lock, flags); + + ata_port_wait_eh(ap); + + /* EH is now guaranteed to see UNLOADING, so no new device + * will be attached. Disable all existing devices. + */ + spin_lock_irqsave(&ap->host_set->lock, flags); + + for (i = 0; i < ATA_MAX_DEVICES; i++) + ata_dev_disable(&ap->device[i]); + + spin_unlock_irqrestore(&ap->host_set->lock, flags); + + /* Final freeze & EH. All in-flight commands are aborted. EH + * will be skipped and retrials will be terminated with bad + * target. + */ + spin_lock_irqsave(&ap->host_set->lock, flags); + ata_port_freeze(ap); /* won't be thawed */ + spin_unlock_irqrestore(&ap->host_set->lock, flags); + + ata_port_wait_eh(ap); + + /* Flush hotplug task. The sequence is similar to + * ata_port_flush_task(). + */ + flush_workqueue(ata_aux_wq); + cancel_delayed_work(&ap->hotplug_task); + flush_workqueue(ata_aux_wq); + + /* remove the associated SCSI host */ + scsi_remove_host(ap->host); +} + /** * ata_host_set_remove - PCI layer callback for device removal * @host_set: ATA host set that was removed @@ -5622,18 +5679,15 @@ err_free_ret: void ata_host_set_remove(struct ata_host_set *host_set) { - struct ata_port *ap; unsigned int i; - for (i = 0; i < host_set->n_ports; i++) { - ap = host_set->ports[i]; - scsi_remove_host(ap->host); - } + for (i = 0; i < host_set->n_ports; i++) + ata_port_detach(host_set->ports[i]); free_irq(host_set->irq, host_set); for (i = 0; i < host_set->n_ports; i++) { - ap = host_set->ports[i]; + struct ata_port *ap = host_set->ports[i]; ata_scsi_release(ap->host); @@ -5901,6 +5955,7 @@ EXPORT_SYMBOL_GPL(sata_deb_timing_before_fsrst); EXPORT_SYMBOL_GPL(ata_std_bios_param); EXPORT_SYMBOL_GPL(ata_std_ports); EXPORT_SYMBOL_GPL(ata_device_add); +EXPORT_SYMBOL_GPL(ata_port_detach); EXPORT_SYMBOL_GPL(ata_host_set_remove); EXPORT_SYMBOL_GPL(ata_sg_init); EXPORT_SYMBOL_GPL(ata_sg_init_one); diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index 70c132bef68e..30a83a57a12f 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c @@ -46,6 +46,7 @@ #include "libata.h" static void __ata_port_freeze(struct ata_port *ap); +static void ata_eh_finish(struct ata_port *ap); static void ata_ering_record(struct ata_ering *ering, int is_io, unsigned int err_mask) @@ -242,8 +243,11 @@ void ata_scsi_error(struct Scsi_Host *host) spin_unlock_irqrestore(hs_lock, flags); - /* invoke EH */ - ap->ops->error_handler(ap); + /* invoke EH. if unloading, just finish failed qcs */ + if (!(ap->flags & ATA_FLAG_UNLOADING)) + ap->ops->error_handler(ap); + else + ata_eh_finish(ap); /* Exception might have happend after ->error_handler * recovered the port but before this point. Repeat diff --git a/include/linux/libata.h b/include/linux/libata.h index 74786c33c526..f11ba2715bef 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -649,6 +649,7 @@ extern int ata_pci_device_resume(struct pci_dev *pdev); extern int ata_pci_clear_simplex(struct pci_dev *pdev); #endif /* CONFIG_PCI */ extern int ata_device_add(const struct ata_probe_ent *ent); +extern void ata_port_detach(struct ata_port *ap); extern void ata_host_set_remove(struct ata_host_set *host_set); extern int ata_scsi_detect(struct scsi_host_template *sht); extern int ata_scsi_ioctl(struct scsi_device *dev, int cmd, void __user *arg); -- cgit v1.2.3 From 52783c5dcc8d317bc8c3e2692d366e8a305abada Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 31 May 2006 18:28:22 +0900 Subject: [PATCH] libata-hp: killl ops->probe_reset Now that all drivers implementing new EH are converted to new probing mechanism, ops->probe_reset doesn't have any user. Kill it. Signed-off-by: Tejun Heo --- drivers/scsi/libata-core.c | 187 ++++----------------------------------------- include/linux/libata.h | 8 -- 2 files changed, 13 insertions(+), 182 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 01f2c59536bc..30a6020c5121 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -1479,31 +1479,21 @@ static int ata_bus_probe(struct ata_port *ap) down_xfermask = 0; /* reset and determine device classes */ - for (i = 0; i < ATA_MAX_DEVICES; i++) - classes[i] = ATA_DEV_UNKNOWN; + ap->ops->phy_reset(ap); - if (ap->ops->probe_reset) { - rc = ap->ops->probe_reset(ap, classes); - if (rc) { - ata_port_printk(ap, KERN_ERR, - "reset failed (errno=%d)\n", rc); - return rc; - } - } else { - ap->ops->phy_reset(ap); + for (i = 0; i < ATA_MAX_DEVICES; i++) { + dev = &ap->device[i]; - for (i = 0; i < ATA_MAX_DEVICES; i++) { - if (!(ap->flags & ATA_FLAG_DISABLED)) - classes[i] = ap->device[i].class; - ap->device[i].class = ATA_DEV_UNKNOWN; - } + if (!(ap->flags & ATA_FLAG_DISABLED) && + dev->class != ATA_DEV_UNKNOWN) + classes[dev->devno] = dev->class; + else + classes[dev->devno] = ATA_DEV_NONE; - ata_port_probe(ap); + dev->class = ATA_DEV_UNKNOWN; } - for (i = 0; i < ATA_MAX_DEVICES; i++) - if (classes[i] == ATA_DEV_UNKNOWN) - classes[i] = ATA_DEV_NONE; + ata_port_probe(ap); /* after the reset the device state is PIO 0 and the controller state is undefined. Record the mode */ @@ -2609,38 +2599,12 @@ int ata_std_prereset(struct ata_port *ap) return 0; } -/** - * ata_std_probeinit - initialize probing - * @ap: port to be probed - * - * @ap is about to be probed. Initialize it. This function is - * to be used as standard callback for ata_drive_probe_reset(). - * - * NOTE!!! Do not use this function as probeinit if a low level - * driver implements only hardreset. Just pass NULL as probeinit - * in that case. Using this function is probably okay but doing - * so makes reset sequence different from the original - * ->phy_reset implementation and Jeff nervous. :-P - */ -void ata_std_probeinit(struct ata_port *ap) -{ - static const unsigned long deb_timing[] = { 5, 100, 5000 }; - - /* resume link */ - sata_phy_resume(ap, deb_timing); - - /* wait for device */ - if (ata_port_online(ap)) - ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT); -} - /** * ata_std_softreset - reset host port via ATA SRST * @ap: port to reset * @classes: resulting classes of attached devices * - * Reset host port using ATA SRST. This function is to be used - * as standard callback for ata_drive_*_reset() functions. + * Reset host port using ATA SRST. * * LOCKING: * Kernel thread context (may sleep) @@ -2695,8 +2659,6 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes) * @class: resulting class of attached device * * SATA phy-reset host port using DET bits of SControl register. - * This function is to be used as standard callback for - * ata_drive_*_reset(). * * LOCKING: * Kernel thread context (may sleep) @@ -2775,9 +2737,6 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class) * the device might have been reset more than once using * different reset methods before postreset is invoked. * - * This function is to be used as standard callback for - * ata_drive_*_reset(). - * * LOCKING: * Kernel thread context (may sleep) */ @@ -2824,32 +2783,6 @@ void ata_std_postreset(struct ata_port *ap, unsigned int *classes) DPRINTK("EXIT\n"); } -/** - * ata_std_probe_reset - standard probe reset method - * @ap: prot to perform probe-reset - * @classes: resulting classes of attached devices - * - * The stock off-the-shelf ->probe_reset method. - * - * LOCKING: - * Kernel thread context (may sleep) - * - * RETURNS: - * 0 on success, -errno otherwise. - */ -int ata_std_probe_reset(struct ata_port *ap, unsigned int *classes) -{ - ata_reset_fn_t hardreset; - - hardreset = NULL; - if (sata_scr_valid(ap)) - hardreset = sata_std_hardreset; - - return ata_drive_probe_reset(ap, ata_std_probeinit, - ata_std_softreset, hardreset, - ata_std_postreset, classes); -} - int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset, unsigned int *classes) { @@ -2878,97 +2811,6 @@ int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset, return 0; } -/** - * ata_drive_probe_reset - Perform probe reset with given methods - * @ap: port to reset - * @probeinit: probeinit method (can be NULL) - * @softreset: softreset method (can be NULL) - * @hardreset: hardreset method (can be NULL) - * @postreset: postreset method (can be NULL) - * @classes: resulting classes of attached devices - * - * Reset the specified port and classify attached devices using - * given methods. This function prefers softreset but tries all - * possible reset sequences to reset and classify devices. This - * function is intended to be used for constructing ->probe_reset - * callback by low level drivers. - * - * Reset methods should follow the following rules. - * - * - Return 0 on sucess, -errno on failure. - * - If classification is supported, fill classes[] with - * recognized class codes. - * - If classification is not supported, leave classes[] alone. - * - * LOCKING: - * Kernel thread context (may sleep) - * - * RETURNS: - * 0 on success, -EINVAL if no reset method is avaliable, -ENODEV - * if classification fails, and any error code from reset - * methods. - */ -int ata_drive_probe_reset(struct ata_port *ap, ata_probeinit_fn_t probeinit, - ata_reset_fn_t softreset, ata_reset_fn_t hardreset, - ata_postreset_fn_t postreset, unsigned int *classes) -{ - int rc = -EINVAL; - - ata_eh_freeze_port(ap); - - if (probeinit) - probeinit(ap); - - if (softreset && !sata_set_spd_needed(ap)) { - rc = ata_do_reset(ap, softreset, classes); - if (rc == 0 && classes[0] != ATA_DEV_UNKNOWN) - goto done; - ata_port_printk(ap, KERN_INFO, "softreset failed, " - "will try hardreset in 5 secs\n"); - ssleep(5); - } - - if (!hardreset) - goto done; - - while (1) { - rc = ata_do_reset(ap, hardreset, classes); - if (rc == 0) { - if (classes[0] != ATA_DEV_UNKNOWN) - goto done; - break; - } - - if (sata_down_spd_limit(ap)) - goto done; - - ata_port_printk(ap, KERN_INFO, "hardreset failed, " - "will retry in 5 secs\n"); - ssleep(5); - } - - if (softreset) { - ata_port_printk(ap, KERN_INFO, - "hardreset succeeded without classification, " - "will retry softreset in 5 secs\n"); - ssleep(5); - - rc = ata_do_reset(ap, softreset, classes); - } - - done: - if (rc == 0) { - if (postreset) - postreset(ap, classes); - - ata_eh_thaw_port(ap); - - if (classes[0] == ATA_DEV_UNKNOWN) - rc = -ENODEV; - } - return rc; -} - /** * ata_dev_same_device - Determine whether new ID matches configured device * @dev: device to compare against @@ -5419,7 +5261,7 @@ static struct ata_port * ata_host_add(const struct ata_probe_ent *ent, DPRINTK("ENTER\n"); - if (!ent->port_ops->probe_reset && !ent->port_ops->error_handler && + if (!ent->port_ops->error_handler && !(ent->host_flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST))) { printk(KERN_ERR "ata%u: no reset mechanism available\n", port_no); @@ -5551,7 +5393,7 @@ int ata_device_add(const struct ata_probe_ent *ent) */ } - if (!ap->ops->probe_reset) { + if (ap->ops->error_handler) { unsigned long flags; ata_port_probe(ap); @@ -5998,13 +5840,10 @@ EXPORT_SYMBOL_GPL(sata_phy_resume); EXPORT_SYMBOL_GPL(sata_phy_reset); EXPORT_SYMBOL_GPL(__sata_phy_reset); EXPORT_SYMBOL_GPL(ata_bus_reset); -EXPORT_SYMBOL_GPL(ata_std_probeinit); EXPORT_SYMBOL_GPL(ata_std_prereset); EXPORT_SYMBOL_GPL(ata_std_softreset); EXPORT_SYMBOL_GPL(sata_std_hardreset); EXPORT_SYMBOL_GPL(ata_std_postreset); -EXPORT_SYMBOL_GPL(ata_std_probe_reset); -EXPORT_SYMBOL_GPL(ata_drive_probe_reset); EXPORT_SYMBOL_GPL(ata_dev_revalidate); EXPORT_SYMBOL_GPL(ata_dev_classify); EXPORT_SYMBOL_GPL(ata_dev_pair); diff --git a/include/linux/libata.h b/include/linux/libata.h index f11ba2715bef..a2a33a902917 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -303,7 +303,6 @@ struct ata_queued_cmd; /* typedefs */ typedef void (*ata_qc_cb_t) (struct ata_queued_cmd *qc); -typedef void (*ata_probeinit_fn_t)(struct ata_port *ap); typedef int (*ata_prereset_fn_t)(struct ata_port *ap); typedef int (*ata_reset_fn_t)(struct ata_port *ap, unsigned int *classes); typedef void (*ata_postreset_fn_t)(struct ata_port *ap, unsigned int *classes); @@ -553,7 +552,6 @@ struct ata_port_operations { void (*phy_reset) (struct ata_port *ap); /* obsolete */ void (*set_mode) (struct ata_port *ap); - int (*probe_reset) (struct ata_port *ap, unsigned int *classes); void (*post_set_mode) (struct ata_port *ap); @@ -628,11 +626,6 @@ extern void ata_bus_reset(struct ata_port *ap); extern int sata_set_spd(struct ata_port *ap); extern int sata_phy_debounce(struct ata_port *ap, const unsigned long *param); extern int sata_phy_resume(struct ata_port *ap, const unsigned long *param); -extern int ata_drive_probe_reset(struct ata_port *ap, - ata_probeinit_fn_t probeinit, - ata_reset_fn_t softreset, ata_reset_fn_t hardreset, - ata_postreset_fn_t postreset, unsigned int *classes); -extern void ata_std_probeinit(struct ata_port *ap); extern int ata_std_prereset(struct ata_port *ap); extern int ata_std_softreset(struct ata_port *ap, unsigned int *classes); extern int sata_std_hardreset(struct ata_port *ap, unsigned int *class); @@ -688,7 +681,6 @@ extern void ata_std_dev_select (struct ata_port *ap, unsigned int device); extern u8 ata_check_status(struct ata_port *ap); extern u8 ata_altstatus(struct ata_port *ap); extern void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf); -extern int ata_std_probe_reset(struct ata_port *ap, unsigned int *classes); extern int ata_port_start (struct ata_port *ap); extern void ata_port_stop (struct ata_port *ap); extern void ata_host_stop (struct ata_host_set *host_set); -- cgit v1.2.3 From 67a611149b2ac5f4af1e36bfffbfe3198cd3712c Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Tue, 30 May 2006 00:37:20 -0500 Subject: [SCSI] iscsi: don't switch states when just cleaning up If recovery failed or we are in recovery only overwrite the state if we are going to terminate the session or if we logged back in. STOP_CONN_SUSPEND and conn_cnt are not used. We only support a single connection session ATM, so cleanup that code while we are working around it. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/iscsi_tcp.c | 40 +++++++++++++++++------------------ drivers/scsi/libiscsi.c | 55 ++++++++++++------------------------------------ include/scsi/libiscsi.h | 1 - 3 files changed, 33 insertions(+), 63 deletions(-) (limited to 'include') diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index c66faee07ca5..2abda804a924 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -1955,30 +1955,28 @@ iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session, if (err) return err; - if (conn->stop_stage != STOP_CONN_SUSPEND) { - /* bind iSCSI connection and socket */ - tcp_conn->sock = sock; + /* bind iSCSI connection and socket */ + tcp_conn->sock = sock; - /* setup Socket parameters */ - sk = sock->sk; - sk->sk_reuse = 1; - sk->sk_sndtimeo = 15 * HZ; /* FIXME: make it configurable */ - sk->sk_allocation = GFP_ATOMIC; + /* setup Socket parameters */ + sk = sock->sk; + sk->sk_reuse = 1; + sk->sk_sndtimeo = 15 * HZ; /* FIXME: make it configurable */ + sk->sk_allocation = GFP_ATOMIC; - /* FIXME: disable Nagle's algorithm */ + /* FIXME: disable Nagle's algorithm */ - /* - * Intercept TCP callbacks for sendfile like receive - * processing. - */ - conn->recv_lock = &sk->sk_callback_lock; - iscsi_conn_set_callbacks(conn); - tcp_conn->sendpage = tcp_conn->sock->ops->sendpage; - /* - * set receive state machine into initial state - */ - tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER; - } + /* + * Intercept TCP callbacks for sendfile like receive + * processing. + */ + conn->recv_lock = &sk->sk_callback_lock; + iscsi_conn_set_callbacks(conn); + tcp_conn->sendpage = tcp_conn->sock->ops->sendpage; + /* + * set receive state machine into initial state + */ + tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER; return 0; } diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index d810acae45f7..963002598995 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -492,7 +492,7 @@ void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err) return; } - if (session->conn_cnt == 1 || session->leadconn == conn) + if (conn->stop_stage == 0) session->state = ISCSI_STATE_FAILED; spin_unlock_irqrestore(&session->lock, flags); set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); @@ -652,7 +652,7 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) */ if (session->state == ISCSI_STATE_IN_RECOVERY) { reason = FAILURE_SESSION_IN_RECOVERY; - goto fault; + goto reject; } if (session->state == ISCSI_STATE_RECOVERY_FAILED) @@ -1411,8 +1411,8 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) struct iscsi_session *session = conn->session; unsigned long flags; - mutex_lock(&conn->xmitmutex); set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); + mutex_lock(&conn->xmitmutex); if (conn->c_stage == ISCSI_CONN_INITIAL_STAGE) { if (session->tt->suspend_conn_recv) session->tt->suspend_conn_recv(conn); @@ -1498,7 +1498,6 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn) * unblock eh_abort() if it is blocked. re-try all * commands after successful recovery */ - session->conn_cnt++; conn->stop_stage = 0; conn->tmabort_state = TMABORT_INITIAL; session->age++; @@ -1508,13 +1507,7 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn) wake_up(&conn->ehwait); return 0; case STOP_CONN_TERM: - session->conn_cnt++; - conn->stop_stage = 0; - break; - case STOP_CONN_SUSPEND: conn->stop_stage = 0; - clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx); - clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); break; default: break; @@ -1589,28 +1582,24 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, /* * When this is called for the in_login state, we only want to clean - * up the login task and connection. + * up the login task and connection. We do not need to block and set + * the recovery state again */ - if (conn->stop_stage != STOP_CONN_RECOVER) - session->conn_cnt--; + if (flag == STOP_CONN_TERM) + session->state = ISCSI_STATE_TERMINATE; + else if (conn->stop_stage != STOP_CONN_RECOVER) + session->state = ISCSI_STATE_IN_RECOVERY; old_stop_stage = conn->stop_stage; conn->stop_stage = flag; + conn->c_stage = ISCSI_CONN_STOPPED; + set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); spin_unlock_bh(&session->lock); if (session->tt->suspend_conn_recv) session->tt->suspend_conn_recv(conn); mutex_lock(&conn->xmitmutex); - spin_lock_bh(&session->lock); - conn->c_stage = ISCSI_CONN_STOPPED; - set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); - - if (session->conn_cnt == 0 || session->leadconn == conn) - session->state = ISCSI_STATE_IN_RECOVERY; - - spin_unlock_bh(&session->lock); - /* * for connection level recovery we should not calculate * header digest. conn->hdr_size used for optimization @@ -1620,13 +1609,11 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, if (flag == STOP_CONN_RECOVER) { conn->hdrdgst_en = 0; conn->datadgst_en = 0; - /* - * if this is called from the eh and and from userspace - * then we only need to block once. - */ if (session->state == ISCSI_STATE_IN_RECOVERY && - old_stop_stage != STOP_CONN_RECOVER) + old_stop_stage != STOP_CONN_RECOVER) { + debug_scsi("blocking session\n"); iscsi_block_session(session_to_cls(session)); + } } session->tt->terminate_conn(conn); @@ -1651,20 +1638,6 @@ void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) case STOP_CONN_TERM: iscsi_start_session_recovery(session, conn, flag); break; - case STOP_CONN_SUSPEND: - if (session->tt->suspend_conn_recv) - session->tt->suspend_conn_recv(conn); - - mutex_lock(&conn->xmitmutex); - spin_lock_bh(&session->lock); - - conn->stop_stage = flag; - conn->c_stage = ISCSI_CONN_STOPPED; - set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); - - spin_unlock_bh(&session->lock); - mutex_unlock(&conn->xmitmutex); - break; default: printk(KERN_ERR "iscsi: invalid stop flag %d\n", flag); } diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h index 17b28f08b692..cbf7e58bd6f9 100644 --- a/include/scsi/libiscsi.h +++ b/include/scsi/libiscsi.h @@ -211,7 +211,6 @@ struct iscsi_session { * - r2tpool */ int state; /* session state */ struct list_head item; - int conn_cnt; int age; /* counts session re-opens */ struct list_head connections; /* list of connections */ -- cgit v1.2.3 From 3219e5294150aee7d389e19029f49b44fb6b5c9f Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Tue, 30 May 2006 00:37:28 -0500 Subject: [SCSI] iscsi: fix writepsace race We can race and misset the suspend bit if iscsi_write_space is called then iscsi_send returns with a failure indicating there is no space. To handle this this patch returns a error upwards allowing xmitworker to decide if we need to try and transmit again. For the no write space case xmitworker will not retry, and instead let iscsi_write_space queue it back up if needed (this relies on the work queue code to properly requeue us if needed). Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/iscsi_tcp.c | 182 ++++++++++++++++++++---------------- drivers/scsi/libiscsi.c | 31 +++--- include/scsi/scsi_transport_iscsi.h | 8 +- 3 files changed, 126 insertions(+), 95 deletions(-) (limited to 'include') diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 2abda804a924..7fa85937a99f 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -1006,7 +1006,6 @@ iscsi_write_space(struct sock *sk) tcp_conn->old_write_space(sk); debug_tcp("iscsi_write_space: cid %d\n", conn->id); - clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); scsi_queue_work(conn->session->host, &conn->xmitwork); } @@ -1056,7 +1055,7 @@ iscsi_send(struct iscsi_conn *conn, struct iscsi_buf *buf, int size, int flags) { struct iscsi_tcp_conn *tcp_conn = conn->dd_data; struct socket *sk = tcp_conn->sock; - int offset = buf->sg.offset + buf->sent; + int offset = buf->sg.offset + buf->sent, res; /* * if we got use_sg=0 or are sending something we kmallocd @@ -1067,10 +1066,22 @@ iscsi_send(struct iscsi_conn *conn, struct iscsi_buf *buf, int size, int flags) * slab case. */ if (buf->use_sendmsg) - return sock_no_sendpage(sk, buf->sg.page, offset, size, flags); + res = sock_no_sendpage(sk, buf->sg.page, offset, size, flags); else - return tcp_conn->sendpage(sk, buf->sg.page, offset, size, - flags); + res = tcp_conn->sendpage(sk, buf->sg.page, offset, size, flags); + + if (res >= 0) { + conn->txdata_octets += res; + buf->sent += res; + return res; + } + + tcp_conn->sendpage_failures_cnt++; + if (res == -EAGAIN) + res = -ENOBUFS; + else + iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); + return res; } /** @@ -1085,7 +1096,6 @@ iscsi_send(struct iscsi_conn *conn, struct iscsi_buf *buf, int size, int flags) static inline int iscsi_sendhdr(struct iscsi_conn *conn, struct iscsi_buf *buf, int datalen) { - struct iscsi_tcp_conn *tcp_conn; int flags = 0; /* MSG_DONTWAIT; */ int res, size; @@ -1097,17 +1107,10 @@ iscsi_sendhdr(struct iscsi_conn *conn, struct iscsi_buf *buf, int datalen) res = iscsi_send(conn, buf, size, flags); debug_tcp("sendhdr %d bytes, sent %d res %d\n", size, buf->sent, res); if (res >= 0) { - conn->txdata_octets += res; - buf->sent += res; if (size != res) return -EAGAIN; return 0; - } else if (res == -EAGAIN) { - tcp_conn = conn->dd_data; - tcp_conn->sendpage_failures_cnt++; - set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); - } else if (res == -EPIPE) - iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); + } return res; } @@ -1126,7 +1129,6 @@ static inline int iscsi_sendpage(struct iscsi_conn *conn, struct iscsi_buf *buf, int *count, int *sent) { - struct iscsi_tcp_conn *tcp_conn; int flags = 0; /* MSG_DONTWAIT; */ int res, size; @@ -1141,19 +1143,12 @@ iscsi_sendpage(struct iscsi_conn *conn, struct iscsi_buf *buf, debug_tcp("sendpage: %d bytes, sent %d left %d sent %d res %d\n", size, buf->sent, *count, *sent, res); if (res >= 0) { - conn->txdata_octets += res; - buf->sent += res; *count -= res; *sent += res; if (size != res) return -EAGAIN; return 0; - } else if (res == -EAGAIN) { - tcp_conn = conn->dd_data; - tcp_conn->sendpage_failures_cnt++; - set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); - } else if (res == -EPIPE) - iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); + } return res; } @@ -1342,6 +1337,7 @@ static int iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask) { struct iscsi_tcp_mgmt_task *tcp_mtask = mtask->dd_data; + int rc; debug_scsi("mtask deq [cid %d state %x itt 0x%x]\n", conn->id, tcp_mtask->xmstate, mtask->itt); @@ -1355,12 +1351,13 @@ iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask) conn->hdrdgst_en) iscsi_hdr_digest(conn, &tcp_mtask->headbuf, (u8*)tcp_mtask->hdrext); - if (iscsi_sendhdr(conn, &tcp_mtask->headbuf, - mtask->data_count)) { + rc = iscsi_sendhdr(conn, &tcp_mtask->headbuf, + mtask->data_count); + if (rc) { tcp_mtask->xmstate |= XMSTATE_IMM_HDR; if (mtask->data_count) tcp_mtask->xmstate &= ~XMSTATE_IMM_DATA; - return -EAGAIN; + return rc; } } @@ -1371,10 +1368,13 @@ iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask) * Virtual buffer could be spreaded across multiple pages... */ do { - if (iscsi_sendpage(conn, &tcp_mtask->sendbuf, - &mtask->data_count, &tcp_mtask->sent)) { + int rc; + + rc = iscsi_sendpage(conn, &tcp_mtask->sendbuf, + &mtask->data_count, &tcp_mtask->sent); + if (rc) { tcp_mtask->xmstate |= XMSTATE_IMM_DATA; - return -EAGAIN; + return rc; } } while (mtask->data_count); } @@ -1396,16 +1396,19 @@ static inline int handle_xmstate_r_hdr(struct iscsi_conn *conn, struct iscsi_tcp_cmd_task *tcp_ctask) { + int rc; + tcp_ctask->xmstate &= ~XMSTATE_R_HDR; if (conn->hdrdgst_en) iscsi_hdr_digest(conn, &tcp_ctask->headbuf, (u8*)tcp_ctask->hdrext); - if (!iscsi_sendhdr(conn, &tcp_ctask->headbuf, 0)) { + rc = iscsi_sendhdr(conn, &tcp_ctask->headbuf, 0); + if (!rc) { BUG_ON(tcp_ctask->xmstate != XMSTATE_IDLE); return 0; /* wait for Data-In */ } tcp_ctask->xmstate |= XMSTATE_R_HDR; - return -EAGAIN; + return rc; } static inline int @@ -1413,16 +1416,16 @@ handle_xmstate_w_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) { struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; + int rc; tcp_ctask->xmstate &= ~XMSTATE_W_HDR; if (conn->hdrdgst_en) iscsi_hdr_digest(conn, &tcp_ctask->headbuf, (u8*)tcp_ctask->hdrext); - if (iscsi_sendhdr(conn, &tcp_ctask->headbuf, ctask->imm_count)) { + rc = iscsi_sendhdr(conn, &tcp_ctask->headbuf, ctask->imm_count); + if (rc) tcp_ctask->xmstate |= XMSTATE_W_HDR; - return -EAGAIN; - } - return 0; + return rc; } static inline int @@ -1430,17 +1433,19 @@ handle_xmstate_data_digest(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) { struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; + int rc; tcp_ctask->xmstate &= ~XMSTATE_DATA_DIGEST; debug_tcp("resent data digest 0x%x\n", tcp_ctask->datadigest); - if (iscsi_digest_final_send(conn, ctask, &tcp_ctask->immbuf, - &tcp_ctask->datadigest, 0)) { + rc = iscsi_digest_final_send(conn, ctask, &tcp_ctask->immbuf, + &tcp_ctask->datadigest, 0); + if (rc) { tcp_ctask->xmstate |= XMSTATE_DATA_DIGEST; debug_tcp("resent data digest 0x%x fail!\n", tcp_ctask->datadigest); - return -EAGAIN; } - return 0; + + return rc; } static inline int @@ -1448,6 +1453,7 @@ handle_xmstate_imm_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) { struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; struct iscsi_tcp_conn *tcp_conn = conn->dd_data; + int rc; BUG_ON(!ctask->imm_count); tcp_ctask->xmstate &= ~XMSTATE_IMM_DATA; @@ -1458,8 +1464,9 @@ handle_xmstate_imm_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) } for (;;) { - if (iscsi_sendpage(conn, &tcp_ctask->sendbuf, &ctask->imm_count, - &tcp_ctask->sent)) { + rc = iscsi_sendpage(conn, &tcp_ctask->sendbuf, + &ctask->imm_count, &tcp_ctask->sent); + if (rc) { tcp_ctask->xmstate |= XMSTATE_IMM_DATA; if (conn->datadgst_en) { crypto_digest_final(tcp_conn->data_tx_tfm, @@ -1467,7 +1474,7 @@ handle_xmstate_imm_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) debug_tcp("tx imm sendpage fail 0x%x\n", tcp_ctask->datadigest); } - return -EAGAIN; + return rc; } if (conn->datadgst_en) crypto_digest_update(tcp_conn->data_tx_tfm, @@ -1480,11 +1487,12 @@ handle_xmstate_imm_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) } if (conn->datadgst_en && !(tcp_ctask->xmstate & XMSTATE_W_PAD)) { - if (iscsi_digest_final_send(conn, ctask, &tcp_ctask->immbuf, - &tcp_ctask->immdigest, 1)) { + rc = iscsi_digest_final_send(conn, ctask, &tcp_ctask->immbuf, + &tcp_ctask->immdigest, 1); + if (rc) { debug_tcp("sending imm digest 0x%x fail!\n", tcp_ctask->immdigest); - return -EAGAIN; + return rc; } debug_tcp("sending imm digest 0x%x\n", tcp_ctask->immdigest); } @@ -1497,6 +1505,7 @@ handle_xmstate_uns_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) { struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; struct iscsi_data_task *dtask; + int rc; tcp_ctask->xmstate |= XMSTATE_UNS_DATA; if (tcp_ctask->xmstate & XMSTATE_UNS_INIT) { @@ -1507,10 +1516,12 @@ handle_xmstate_uns_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) (u8*)dtask->hdrext); tcp_ctask->xmstate &= ~XMSTATE_UNS_INIT; } - if (iscsi_sendhdr(conn, &tcp_ctask->headbuf, ctask->data_count)) { + + rc = iscsi_sendhdr(conn, &tcp_ctask->headbuf, ctask->data_count); + if (rc) { tcp_ctask->xmstate &= ~XMSTATE_UNS_DATA; tcp_ctask->xmstate |= XMSTATE_UNS_HDR; - return -EAGAIN; + return rc; } debug_scsi("uns dout [itt 0x%x dlen %d sent %d]\n", @@ -1524,6 +1535,7 @@ handle_xmstate_uns_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; struct iscsi_data_task *dtask = tcp_ctask->dtask; struct iscsi_tcp_conn *tcp_conn = conn->dd_data; + int rc; BUG_ON(!ctask->data_count); tcp_ctask->xmstate &= ~XMSTATE_UNS_DATA; @@ -1536,8 +1548,9 @@ handle_xmstate_uns_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) for (;;) { int start = tcp_ctask->sent; - if (iscsi_sendpage(conn, &tcp_ctask->sendbuf, - &ctask->data_count, &tcp_ctask->sent)) { + rc = iscsi_sendpage(conn, &tcp_ctask->sendbuf, + &ctask->data_count, &tcp_ctask->sent); + if (rc) { ctask->unsol_count -= tcp_ctask->sent - start; tcp_ctask->xmstate |= XMSTATE_UNS_DATA; /* will continue with this ctask later.. */ @@ -1547,7 +1560,7 @@ handle_xmstate_uns_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) debug_tcp("tx uns data fail 0x%x\n", dtask->digest); } - return -EAGAIN; + return rc; } BUG_ON(tcp_ctask->sent > ctask->total_length); @@ -1574,12 +1587,13 @@ handle_xmstate_uns_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) */ if (ctask->unsol_count) { if (conn->datadgst_en) { - if (iscsi_digest_final_send(conn, ctask, + rc = iscsi_digest_final_send(conn, ctask, &dtask->digestbuf, - &dtask->digest, 1)) { + &dtask->digest, 1); + if (rc) { debug_tcp("send uns digest 0x%x fail\n", dtask->digest); - return -EAGAIN; + return rc; } debug_tcp("sending uns digest 0x%x, more uns\n", dtask->digest); @@ -1589,12 +1603,13 @@ handle_xmstate_uns_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) } if (conn->datadgst_en && !(tcp_ctask->xmstate & XMSTATE_W_PAD)) { - if (iscsi_digest_final_send(conn, ctask, + rc = iscsi_digest_final_send(conn, ctask, &dtask->digestbuf, - &dtask->digest, 1)) { + &dtask->digest, 1); + if (rc) { debug_tcp("send last uns digest 0x%x fail\n", dtask->digest); - return -EAGAIN; + return rc; } debug_tcp("sending uns digest 0x%x\n",dtask->digest); } @@ -1610,7 +1625,7 @@ handle_xmstate_sol_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; struct iscsi_r2t_info *r2t = tcp_ctask->r2t; struct iscsi_data_task *dtask = &r2t->dtask; - int left; + int left, rc; tcp_ctask->xmstate &= ~XMSTATE_SOL_DATA; tcp_ctask->dtask = dtask; @@ -1626,7 +1641,8 @@ solicit_again: if (!r2t->data_count) goto data_out_done; - if (iscsi_sendpage(conn, &r2t->sendbuf, &r2t->data_count, &r2t->sent)) { + rc = iscsi_sendpage(conn, &r2t->sendbuf, &r2t->data_count, &r2t->sent); + if (rc) { tcp_ctask->xmstate |= XMSTATE_SOL_DATA; /* will continue with this ctask later.. */ if (conn->datadgst_en) { @@ -1634,7 +1650,7 @@ solicit_again: (u8 *)&dtask->digest); debug_tcp("r2t data send fail 0x%x\n", dtask->digest); } - return -EAGAIN; + return rc; } BUG_ON(r2t->data_count < 0); @@ -1661,12 +1677,13 @@ data_out_done: left = r2t->data_length - r2t->sent; if (left) { if (conn->datadgst_en) { - if (iscsi_digest_final_send(conn, ctask, + rc = iscsi_digest_final_send(conn, ctask, &dtask->digestbuf, - &dtask->digest, 1)) { + &dtask->digest, 1); + if (rc) { debug_tcp("send r2t data digest 0x%x" "fail\n", dtask->digest); - return -EAGAIN; + return rc; } debug_tcp("r2t data send digest 0x%x\n", dtask->digest); @@ -1683,11 +1700,12 @@ data_out_done: */ BUG_ON(tcp_ctask->r2t_data_count - r2t->data_length < 0); if (conn->datadgst_en) { - if (iscsi_digest_final_send(conn, ctask, &dtask->digestbuf, - &dtask->digest, 1)) { + rc = iscsi_digest_final_send(conn, ctask, &dtask->digestbuf, + &dtask->digest, 1); + if (rc) { debug_tcp("send last r2t data digest 0x%x" "fail\n", dtask->digest); - return -EAGAIN; + return rc; } debug_tcp("r2t done dout digest 0x%x\n", dtask->digest); } @@ -1713,15 +1731,16 @@ handle_xmstate_w_pad(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; struct iscsi_tcp_conn *tcp_conn = conn->dd_data; struct iscsi_data_task *dtask = tcp_ctask->dtask; - int sent; + int sent, rc; tcp_ctask->xmstate &= ~XMSTATE_W_PAD; iscsi_buf_init_iov(&tcp_ctask->sendbuf, (char*)&tcp_ctask->pad, tcp_ctask->pad_count); - if (iscsi_sendpage(conn, &tcp_ctask->sendbuf, &tcp_ctask->pad_count, - &sent)) { + rc = iscsi_sendpage(conn, &tcp_ctask->sendbuf, &tcp_ctask->pad_count, + &sent); + if (rc) { tcp_ctask->xmstate |= XMSTATE_W_PAD; - return -EAGAIN; + return rc; } if (conn->datadgst_en) { @@ -1729,22 +1748,24 @@ handle_xmstate_w_pad(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) &tcp_ctask->sendbuf.sg, 1); /* imm data? */ if (!dtask) { - if (iscsi_digest_final_send(conn, ctask, + rc = iscsi_digest_final_send(conn, ctask, &tcp_ctask->immbuf, - &tcp_ctask->immdigest, 1)) { + &tcp_ctask->immdigest, 1); + if (rc) { debug_tcp("send padding digest 0x%x" "fail!\n", tcp_ctask->immdigest); - return -EAGAIN; + return rc; } debug_tcp("done with padding, digest 0x%x\n", tcp_ctask->datadigest); } else { - if (iscsi_digest_final_send(conn, ctask, + rc = iscsi_digest_final_send(conn, ctask, &dtask->digestbuf, - &dtask->digest, 1)) { + &dtask->digest, 1); + if (rc) { debug_tcp("send padding digest 0x%x" "fail\n", dtask->digest); - return -EAGAIN; + return rc; } debug_tcp("done with padding, digest 0x%x\n", dtask->digest); @@ -1769,10 +1790,8 @@ iscsi_tcp_ctask_xmit(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) if (ctask->mtask) return rc; - if (tcp_ctask->xmstate & XMSTATE_R_HDR) { - rc = handle_xmstate_r_hdr(conn, tcp_ctask); - return rc; - } + if (tcp_ctask->xmstate & XMSTATE_R_HDR) + return handle_xmstate_r_hdr(conn, tcp_ctask); if (tcp_ctask->xmstate & XMSTATE_W_HDR) { rc = handle_xmstate_w_hdr(conn, ctask); @@ -1824,10 +1843,11 @@ solicit_head_again: if (conn->hdrdgst_en) iscsi_hdr_digest(conn, &r2t->headbuf, (u8*)r2t->dtask.hdrext); - if (iscsi_sendhdr(conn, &r2t->headbuf, r2t->data_count)) { + rc = iscsi_sendhdr(conn, &r2t->headbuf, r2t->data_count); + if (rc) { tcp_ctask->xmstate &= ~XMSTATE_SOL_DATA; tcp_ctask->xmstate |= XMSTATE_SOL_HDR; - return -EAGAIN; + return rc; } debug_scsi("sol dout [dsn %d itt 0x%x dlen %d sent %d]\n", diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 256b87a85978..2673a11a9495 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -513,10 +513,11 @@ EXPORT_SYMBOL_GPL(iscsi_conn_failure); static int iscsi_data_xmit(struct iscsi_conn *conn) { struct iscsi_transport *tt; + int rc = 0; if (unlikely(conn->suspend_tx)) { debug_scsi("conn %d Tx suspended!\n", conn->id); - return 0; + return -ENODATA; } tt = conn->session->tt; @@ -536,13 +537,15 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) BUG_ON(conn->ctask && conn->mtask); if (conn->ctask) { - if (tt->xmit_cmd_task(conn, conn->ctask)) + rc = tt->xmit_cmd_task(conn, conn->ctask); + if (rc) goto again; /* done with this in-progress ctask */ conn->ctask = NULL; } if (conn->mtask) { - if (tt->xmit_mgmt_task(conn, conn->mtask)) + rc = tt->xmit_mgmt_task(conn, conn->mtask); + if (rc) goto again; /* done with this in-progress mtask */ conn->mtask = NULL; @@ -556,7 +559,8 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) list_add_tail(&conn->mtask->running, &conn->mgmt_run_list); spin_unlock_bh(&conn->session->lock); - if (tt->xmit_mgmt_task(conn, conn->mtask)) + rc = tt->xmit_mgmt_task(conn, conn->mtask); + if (rc) goto again; } /* done with this mtask */ @@ -574,7 +578,8 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) if (list_empty(&conn->ctask->running)) list_add_tail(&conn->ctask->running, &conn->run_list); spin_unlock_bh(&conn->session->lock); - if (tt->xmit_cmd_task(conn, conn->ctask)) + rc = tt->xmit_cmd_task(conn, conn->ctask); + if (rc) goto again; } /* done with this ctask */ @@ -588,32 +593,34 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) list_add_tail(&conn->mtask->running, &conn->mgmt_run_list); spin_unlock_bh(&conn->session->lock); - if (tt->xmit_mgmt_task(conn, conn->mtask)) + rc = tt->xmit_mgmt_task(conn, conn->mtask); + if (rc) goto again; } /* done with this mtask */ conn->mtask = NULL; } - return 0; + return -ENODATA; again: if (unlikely(conn->suspend_tx)) - return 0; + return -ENODATA; - return -EAGAIN; + return rc; } static void iscsi_xmitworker(void *data) { struct iscsi_conn *conn = data; - + int rc; /* * serialize Xmit worker on a per-connection basis. */ mutex_lock(&conn->xmitmutex); - if (iscsi_data_xmit(conn)) - scsi_queue_work(conn->session->host, &conn->xmitwork); + do { + rc = iscsi_data_xmit(conn); + } while (rc >= 0 || rc == -EAGAIN); mutex_unlock(&conn->xmitmutex); } diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h index 92129b97d31e..b684426a5900 100644 --- a/include/scsi/scsi_transport_iscsi.h +++ b/include/scsi/scsi_transport_iscsi.h @@ -57,8 +57,12 @@ struct iscsi_mgmt_task; * Called from queuecommand with session lock held. * @init_mgmt_task: Initialize a iscsi_mgmt_task and any internal structs. * Called from iscsi_conn_send_generic with xmitmutex. - * @xmit_cmd_task: requests LLD to transfer cmd task - * @xmit_mgmt_task: requests LLD to transfer mgmt task + * @xmit_cmd_task: Requests LLD to transfer cmd task. Returns 0 or the + * the number of bytes transferred on success, and -Exyz + * value on error. + * @xmit_mgmt_task: Requests LLD to transfer mgmt task. Returns 0 or the + * the number of bytes transferred on success, and -Exyz + * value on error. * @cleanup_cmd_task: requests LLD to fail cmd task. Called with xmitmutex * and session->lock after the connection has been * suspended and terminated during recovery. If called -- cgit v1.2.3 From 98a90c02792f22afd8161f96fc9b9f0f0eb0880e Mon Sep 17 00:00:00 2001 From: Renzo Davoli Date: Sun, 21 May 2006 20:06:58 +0200 Subject: [PATCH] powerpc: enable PPC_PTRACE_[GS]ETREGS on ppc32 I have tested PPC_PTRACE_GETREGS and PPC_PTRACE_SETREGS on umview. I do not understand why historically these tags has been defined as PPC_PTRACE_GETREGS and PPC_PTRACE_SETREGS instead of simply PTRACE_[GS]ETREGS. The other "originality" is that the address must be put into the "addr" field instead of the "data" field as stated in the manual. Signed-off-by: renzo davoli Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/ptrace.c | 2 -- include/asm-powerpc/ptrace.h | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'include') diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 4a677d1bd4ef..5563e2e7d89c 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -404,7 +404,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) ret = ptrace_detach(child, data); break; -#ifdef CONFIG_PPC64 case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */ int i; unsigned long *reg = &((unsigned long *)child->thread.regs)[0]; @@ -468,7 +467,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) } break; } -#endif /* CONFIG_PPC64 */ #ifdef CONFIG_ALTIVEC case PTRACE_GETVRREGS: diff --git a/include/asm-powerpc/ptrace.h b/include/asm-powerpc/ptrace.h index 9c550b314823..dc4cb9cc73a1 100644 --- a/include/asm-powerpc/ptrace.h +++ b/include/asm-powerpc/ptrace.h @@ -229,13 +229,13 @@ do { \ #define PTRACE_GET_DEBUGREG 25 #define PTRACE_SET_DEBUGREG 26 -#ifdef __powerpc64__ /* Additional PTRACE requests implemented on PowerPC. */ #define PPC_PTRACE_GETREGS 0x99 /* Get GPRs 0 - 31 */ #define PPC_PTRACE_SETREGS 0x98 /* Set GPRs 0 - 31 */ #define PPC_PTRACE_GETFPREGS 0x97 /* Get FPRs 0 - 31 */ #define PPC_PTRACE_SETFPREGS 0x96 /* Set FPRs 0 - 31 */ +#ifdef __powerpc64__ /* Calls to trace a 64bit program from a 32bit program */ #define PPC_PTRACE_PEEKTEXT_3264 0x95 #define PPC_PTRACE_PEEKDATA_3264 0x94 -- cgit v1.2.3 From a5bba930d802009c259e56c8d53086d96f63813b Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 30 May 2006 13:51:37 +1000 Subject: [PATCH] powerpc vdso updates This patch cleans up some locking & error handling in the ppc vdso and moves the vdso base pointer from the thread struct to the mm context where it more logically belongs. It brings the powerpc implementation closer to Ingo's new x86 one and also adds an arch_vma_name() function allowing to print [vsdo] in /proc//maps if Ingo's x86 vdso patch is also applied. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/signal_32.c | 8 +++--- arch/powerpc/kernel/signal_64.c | 4 +-- arch/powerpc/kernel/vdso.c | 57 ++++++++++++++++++++++++++--------------- include/asm-powerpc/elf.h | 2 +- include/asm-powerpc/mmu.h | 1 + include/asm-powerpc/page.h | 3 +++ include/asm-powerpc/processor.h | 1 - 7 files changed, 47 insertions(+), 29 deletions(-) (limited to 'include') diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index 01e3c08cb550..22f078984845 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c @@ -757,10 +757,10 @@ static int handle_rt_signal(unsigned long sig, struct k_sigaction *ka, /* Save user registers on the stack */ frame = &rt_sf->uc.uc_mcontext; - if (vdso32_rt_sigtramp && current->thread.vdso_base) { + if (vdso32_rt_sigtramp && current->mm->context.vdso_base) { if (save_user_regs(regs, frame, 0)) goto badframe; - regs->link = current->thread.vdso_base + vdso32_rt_sigtramp; + regs->link = current->mm->context.vdso_base + vdso32_rt_sigtramp; } else { if (save_user_regs(regs, frame, __NR_rt_sigreturn)) goto badframe; @@ -1029,10 +1029,10 @@ static int handle_signal(unsigned long sig, struct k_sigaction *ka, || __put_user(sig, &sc->signal)) goto badframe; - if (vdso32_sigtramp && current->thread.vdso_base) { + if (vdso32_sigtramp && current->mm->context.vdso_base) { if (save_user_regs(regs, &frame->mctx, 0)) goto badframe; - regs->link = current->thread.vdso_base + vdso32_sigtramp; + regs->link = current->mm->context.vdso_base + vdso32_sigtramp; } else { if (save_user_regs(regs, &frame->mctx, __NR_sigreturn)) goto badframe; diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c index 27f65b95184d..23ba69c26913 100644 --- a/arch/powerpc/kernel/signal_64.c +++ b/arch/powerpc/kernel/signal_64.c @@ -394,8 +394,8 @@ static int setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info, current->thread.fpscr.val = 0; /* Set up to return from userspace. */ - if (vdso64_rt_sigtramp && current->thread.vdso_base) { - regs->link = current->thread.vdso_base + vdso64_rt_sigtramp; + if (vdso64_rt_sigtramp && current->mm->context.vdso_base) { + regs->link = current->mm->context.vdso_base + vdso64_rt_sigtramp; } else { err |= setup_trampoline(__NR_rt_sigreturn, &frame->tramp[0]); if (err) diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c index 573afb68d69e..bc3e15be3087 100644 --- a/arch/powerpc/kernel/vdso.c +++ b/arch/powerpc/kernel/vdso.c @@ -223,6 +223,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, struct vm_area_struct *vma; unsigned long vdso_pages; unsigned long vdso_base; + int rc; #ifdef CONFIG_PPC64 if (test_thread_flag(TIF_32BIT)) { @@ -237,20 +238,13 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, vdso_base = VDSO32_MBASE; #endif - current->thread.vdso_base = 0; + current->mm->context.vdso_base = 0; /* vDSO has a problem and was disabled, just don't "enable" it for the * process */ if (vdso_pages == 0) return 0; - - vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); - if (vma == NULL) - return -ENOMEM; - - memset(vma, 0, sizeof(*vma)); - /* Add a page to the vdso size for the data page */ vdso_pages ++; @@ -259,17 +253,23 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, * at vdso_base which is the "natural" base for it, but we might fail * and end up putting it elsewhere. */ + down_write(&mm->mmap_sem); vdso_base = get_unmapped_area(NULL, vdso_base, vdso_pages << PAGE_SHIFT, 0, 0); - if (vdso_base & ~PAGE_MASK) { - kmem_cache_free(vm_area_cachep, vma); - return (int)vdso_base; + if (IS_ERR_VALUE(vdso_base)) { + rc = vdso_base; + goto fail_mmapsem; } - current->thread.vdso_base = vdso_base; + /* Allocate a VMA structure and fill it up */ + vma = kmem_cache_zalloc(vm_area_cachep, SLAB_KERNEL); + if (vma == NULL) { + rc = -ENOMEM; + goto fail_mmapsem; + } vma->vm_mm = mm; - vma->vm_start = current->thread.vdso_base; + vma->vm_start = vdso_base; vma->vm_end = vma->vm_start + (vdso_pages << PAGE_SHIFT); /* @@ -282,23 +282,38 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, * It's fine to use that for setting breakpoints in the vDSO code * pages though */ - vma->vm_flags = VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC; + vma->vm_flags = VM_READ|VM_EXEC|VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC; vma->vm_flags |= mm->def_flags; vma->vm_page_prot = protection_map[vma->vm_flags & 0x7]; vma->vm_ops = &vdso_vmops; - down_write(&mm->mmap_sem); - if (insert_vm_struct(mm, vma)) { - up_write(&mm->mmap_sem); - kmem_cache_free(vm_area_cachep, vma); - return -ENOMEM; - } + /* Insert new VMA */ + rc = insert_vm_struct(mm, vma); + if (rc) + goto fail_vma; + + /* Put vDSO base into mm struct and account for memory usage */ + current->mm->context.vdso_base = vdso_base; mm->total_vm += (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; up_write(&mm->mmap_sem); - return 0; + + fail_vma: + kmem_cache_free(vm_area_cachep, vma); + fail_mmapsem: + up_write(&mm->mmap_sem); + return rc; +} + +const char *arch_vma_name(struct vm_area_struct *vma) +{ + if (vma->vm_mm && vma->vm_start == vma->vm_mm->context.vdso_base) + return "[vdso]"; + return NULL; } + + static void * __init find_section32(Elf32_Ehdr *ehdr, const char *secname, unsigned long *size) { diff --git a/include/asm-powerpc/elf.h b/include/asm-powerpc/elf.h index 94d228f9c6ac..319655ce66c0 100644 --- a/include/asm-powerpc/elf.h +++ b/include/asm-powerpc/elf.h @@ -294,7 +294,7 @@ do { \ NEW_AUX_ENT(AT_DCACHEBSIZE, dcache_bsize); \ NEW_AUX_ENT(AT_ICACHEBSIZE, icache_bsize); \ NEW_AUX_ENT(AT_UCACHEBSIZE, ucache_bsize); \ - VDSO_AUX_ENT(AT_SYSINFO_EHDR, current->thread.vdso_base) \ + VDSO_AUX_ENT(AT_SYSINFO_EHDR, current->mm->context.vdso_base) \ } while (0) /* PowerPC64 relocations defined by the ABIs */ diff --git a/include/asm-powerpc/mmu.h b/include/asm-powerpc/mmu.h index 31f721994bd8..96e47d1ce979 100644 --- a/include/asm-powerpc/mmu.h +++ b/include/asm-powerpc/mmu.h @@ -360,6 +360,7 @@ typedef struct { #ifdef CONFIG_HUGETLB_PAGE u16 low_htlb_areas, high_htlb_areas; #endif + unsigned long vdso_base; } mm_context_t; diff --git a/include/asm-powerpc/page.h b/include/asm-powerpc/page.h index ae610b620487..a315d0c0d96a 100644 --- a/include/asm-powerpc/page.h +++ b/include/asm-powerpc/page.h @@ -192,6 +192,9 @@ extern void copy_user_page(void *to, void *from, unsigned long vaddr, struct page *p); extern int page_is_ram(unsigned long pfn); +struct vm_area_struct; +extern const char *arch_vma_name(struct vm_area_struct *vma); + #include #endif /* __ASSEMBLY__ */ diff --git a/include/asm-powerpc/processor.h b/include/asm-powerpc/processor.h index 93f83efeb310..d5c7ef1cca26 100644 --- a/include/asm-powerpc/processor.h +++ b/include/asm-powerpc/processor.h @@ -153,7 +153,6 @@ struct thread_struct { unsigned long start_tb; /* Start purr when proc switched in */ unsigned long accum_tb; /* Total accumilated purr for process */ #endif - unsigned long vdso_base; /* base of the vDSO library */ unsigned long dabr; /* Data address breakpoint register */ #ifdef CONFIG_ALTIVEC /* Complete AltiVec register set */ -- cgit v1.2.3 From c5cf0e30bf3d8cb56758abb612827647c0a821cf Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 30 May 2006 14:14:19 +1000 Subject: [PATCH] powerpc: Fix buglet with MMU hash management Our MMU hash management code would not set the "C" bit (changed bit) in the hardware PTE when updating a RO PTE into a RW PTE. That would cause the hardware to possibly to a write back to the hash table to set it on the first store access, which in addition to being a performance issue, might also hit a bug when running with native hash management (non-HV) as our code is specifically optimized for the case where no write back happens. Thus there is a very small therocial window were a hash PTE can become corrupted if that HPTE has just been upgraded to read write, a store access happens on it, and that races with another processor evicting that same slot. Since eviction (caused by an almost full hash) is extremely rare, the bug is very unlikely to happen fortunately. This fixes by allowing the updating of the protection bits in the native hash handling to also set (but not clear) the "C" bit, and, in order to also improve performances in the general case, by always setting that bit on newly inserted hash PTE so that writeback really never happens. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/mm/hash_low_64.S | 3 +++ arch/powerpc/mm/hash_native_64.c | 2 +- include/asm-powerpc/mmu.h | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/arch/powerpc/mm/hash_low_64.S b/arch/powerpc/mm/hash_low_64.S index e0d02c4a2615..106fba391987 100644 --- a/arch/powerpc/mm/hash_low_64.S +++ b/arch/powerpc/mm/hash_low_64.S @@ -136,6 +136,7 @@ _GLOBAL(__hash_page_4K) and r0,r0,r4 /* _PAGE_RW & _PAGE_DIRTY ->r0 bit 30*/ andc r0,r30,r0 /* r0 = pte & ~r0 */ rlwimi r3,r0,32-1,31,31 /* Insert result into PP lsb */ + ori r3,r3,HPTE_R_C /* Always add "C" bit for perf. */ /* We eventually do the icache sync here (maybe inline that * code rather than call a C function...) @@ -400,6 +401,7 @@ _GLOBAL(__hash_page_4K) and r0,r0,r4 /* _PAGE_RW & _PAGE_DIRTY ->r0 bit 30*/ andc r0,r30,r0 /* r0 = pte & ~r0 */ rlwimi r3,r0,32-1,31,31 /* Insert result into PP lsb */ + ori r3,r3,HPTE_R_C /* Always add "C" bit for perf. */ /* We eventually do the icache sync here (maybe inline that * code rather than call a C function...) @@ -671,6 +673,7 @@ _GLOBAL(__hash_page_64K) and r0,r0,r4 /* _PAGE_RW & _PAGE_DIRTY ->r0 bit 30*/ andc r0,r30,r0 /* r0 = pte & ~r0 */ rlwimi r3,r0,32-1,31,31 /* Insert result into PP lsb */ + ori r3,r3,HPTE_R_C /* Always add "C" bit for perf. */ /* We eventually do the icache sync here (maybe inline that * code rather than call a C function...) diff --git a/arch/powerpc/mm/hash_native_64.c b/arch/powerpc/mm/hash_native_64.c index 33654d1b1b43..3b8205033f15 100644 --- a/arch/powerpc/mm/hash_native_64.c +++ b/arch/powerpc/mm/hash_native_64.c @@ -238,7 +238,7 @@ static long native_hpte_updatepp(unsigned long slot, unsigned long newpp, DBG_LOW(" -> hit\n"); /* Update the HPTE */ hptep->r = (hptep->r & ~(HPTE_R_PP | HPTE_R_N)) | - (newpp & (HPTE_R_PP | HPTE_R_N)); + (newpp & (HPTE_R_PP | HPTE_R_N | HPTE_R_C)); native_unlock_hpte(hptep); } diff --git a/include/asm-powerpc/mmu.h b/include/asm-powerpc/mmu.h index 96e47d1ce979..885397420104 100644 --- a/include/asm-powerpc/mmu.h +++ b/include/asm-powerpc/mmu.h @@ -96,6 +96,8 @@ extern char initial_stab[]; #define HPTE_R_FLAGS ASM_CONST(0x00000000000003ff) #define HPTE_R_PP ASM_CONST(0x0000000000000003) #define HPTE_R_N ASM_CONST(0x0000000000000004) +#define HPTE_R_C ASM_CONST(0x0000000000000080) +#define HPTE_R_R ASM_CONST(0x0000000000000100) /* Values for PP (assumes Ks=0, Kp=1) */ /* pp0 will always be 0 for linux */ -- cgit v1.2.3 From 507279db1819aacf4022e790b3fc8bc8cf56debf Mon Sep 17 00:00:00 2001 From: John Rose Date: Mon, 5 Jun 2006 16:31:48 -0500 Subject: [PATCH] powerpc: reorg RTAS delay code This patch attempts to handle RTAS "busy" return codes in a more simple and consistent manner. Typical callers of RTAS shouldn't have to manage wait times and delay calls. This patch also changes the kernel to use msleep() rather than udelay() when a runtime delay is necessary. This will avoid CPU soft lockups for extended delay conditions. Signed-off-by: John Rose Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/rtas-rtc.c | 30 +++++++------- arch/powerpc/kernel/rtas.c | 85 +++++++++++++++++----------------------- arch/powerpc/kernel/rtas_flash.c | 25 ++---------- include/asm-powerpc/rtas.h | 8 +--- 4 files changed, 57 insertions(+), 91 deletions(-) (limited to 'include') diff --git a/arch/powerpc/kernel/rtas-rtc.c b/arch/powerpc/kernel/rtas-rtc.c index 34d073fb6091..77578c093dda 100644 --- a/arch/powerpc/kernel/rtas-rtc.c +++ b/arch/powerpc/kernel/rtas-rtc.c @@ -14,19 +14,20 @@ unsigned long __init rtas_get_boot_time(void) { int ret[8]; - int error, wait_time; + int error; + unsigned int wait_time; u64 max_wait_tb; max_wait_tb = get_tb() + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT; do { error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret); - if (error == RTAS_CLOCK_BUSY || rtas_is_extended_busy(error)) { - wait_time = rtas_extended_busy_delay_time(error); + + wait_time = rtas_busy_delay_time(error); + if (wait_time) { /* This is boot time so we spin. */ udelay(wait_time*1000); - error = RTAS_CLOCK_BUSY; } - } while (error == RTAS_CLOCK_BUSY && (get_tb() < max_wait_tb)); + } while (wait_time && (get_tb() < max_wait_tb)); if (error != 0 && printk_ratelimit()) { printk(KERN_WARNING "error: reading the clock failed (%d)\n", @@ -44,24 +45,25 @@ unsigned long __init rtas_get_boot_time(void) void rtas_get_rtc_time(struct rtc_time *rtc_tm) { int ret[8]; - int error, wait_time; + int error; + unsigned int wait_time; u64 max_wait_tb; max_wait_tb = get_tb() + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT; do { error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret); - if (error == RTAS_CLOCK_BUSY || rtas_is_extended_busy(error)) { + + wait_time = rtas_busy_delay_time(error); + if (wait_time) { if (in_interrupt() && printk_ratelimit()) { memset(rtc_tm, 0, sizeof(struct rtc_time)); printk(KERN_WARNING "error: reading clock" " would delay interrupt\n"); return; /* delay not allowed */ } - wait_time = rtas_extended_busy_delay_time(error); msleep(wait_time); - error = RTAS_CLOCK_BUSY; } - } while (error == RTAS_CLOCK_BUSY && (get_tb() < max_wait_tb)); + } while (wait_time && (get_tb() < max_wait_tb)); if (error != 0 && printk_ratelimit()) { printk(KERN_WARNING "error: reading the clock failed (%d)\n", @@ -88,14 +90,14 @@ int rtas_set_rtc_time(struct rtc_time *tm) tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, 0); - if (error == RTAS_CLOCK_BUSY || rtas_is_extended_busy(error)) { + + wait_time = rtas_busy_delay_time(error); + if (wait_time) { if (in_interrupt()) return 1; /* probably decrementer */ - wait_time = rtas_extended_busy_delay_time(error); msleep(wait_time); - error = RTAS_CLOCK_BUSY; } - } while (error == RTAS_CLOCK_BUSY && (get_tb() < max_wait_tb)); + } while (wait_time && (get_tb() < max_wait_tb)); if (error != 0 && printk_ratelimit()) printk(KERN_WARNING "error: setting the clock failed (%d)\n", diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c index 0112318213ab..13496f319855 100644 --- a/arch/powerpc/kernel/rtas.c +++ b/arch/powerpc/kernel/rtas.c @@ -370,24 +370,36 @@ int rtas_call(int token, int nargs, int nret, int *outputs, ...) return ret; } -/* Given an RTAS status code of 990n compute the hinted delay of 10^n - * (last digit) milliseconds. For now we bound at n=5 (100 sec). +/* For RTAS_BUSY (-2), delay for 1 millisecond. For an extended busy status + * code of 990n, perform the hinted delay of 10^n (last digit) milliseconds. */ -unsigned int rtas_extended_busy_delay_time(int status) +unsigned int rtas_busy_delay_time(int status) { - int order = status - 9900; - unsigned long ms; + int order; + unsigned int ms = 0; + + if (status == RTAS_BUSY) { + ms = 1; + } else if (status >= 9900 && status <= 9905) { + order = status - 9900; + for (ms = 1; order > 0; order--) + ms *= 10; + } - if (order < 0) - order = 0; /* RTC depends on this for -2 clock busy */ - else if (order > 5) - order = 5; /* bound */ + return ms; +} - /* Use microseconds for reasonable accuracy */ - for (ms = 1; order > 0; order--) - ms *= 10; +/* For an RTAS busy status code, perform the hinted delay. */ +unsigned int rtas_busy_delay(int status) +{ + unsigned int ms; - return ms; + might_sleep(); + ms = rtas_busy_delay_time(status); + if (ms) + msleep(ms); + + return ms; } int rtas_error_rc(int rtas_rc) @@ -438,22 +450,14 @@ int rtas_get_power_level(int powerdomain, int *level) int rtas_set_power_level(int powerdomain, int level, int *setlevel) { int token = rtas_token("set-power-level"); - unsigned int wait_time; int rc; if (token == RTAS_UNKNOWN_SERVICE) return -ENOENT; - while (1) { + do { rc = rtas_call(token, 2, 2, setlevel, powerdomain, level); - if (rc == RTAS_BUSY) - udelay(1); - else if (rtas_is_extended_busy(rc)) { - wait_time = rtas_extended_busy_delay_time(rc); - udelay(wait_time * 1000); - } else - break; - } + } while (rtas_busy_delay(rc)); if (rc < 0) return rtas_error_rc(rc); @@ -463,22 +467,14 @@ int rtas_set_power_level(int powerdomain, int level, int *setlevel) int rtas_get_sensor(int sensor, int index, int *state) { int token = rtas_token("get-sensor-state"); - unsigned int wait_time; int rc; if (token == RTAS_UNKNOWN_SERVICE) return -ENOENT; - while (1) { + do { rc = rtas_call(token, 2, 2, state, sensor, index); - if (rc == RTAS_BUSY) - udelay(1); - else if (rtas_is_extended_busy(rc)) { - wait_time = rtas_extended_busy_delay_time(rc); - udelay(wait_time * 1000); - } else - break; - } + } while (rtas_busy_delay(rc)); if (rc < 0) return rtas_error_rc(rc); @@ -488,23 +484,14 @@ int rtas_get_sensor(int sensor, int index, int *state) int rtas_set_indicator(int indicator, int index, int new_value) { int token = rtas_token("set-indicator"); - unsigned int wait_time; int rc; if (token == RTAS_UNKNOWN_SERVICE) return -ENOENT; - while (1) { + do { rc = rtas_call(token, 3, 1, NULL, indicator, index, new_value); - if (rc == RTAS_BUSY) - udelay(1); - else if (rtas_is_extended_busy(rc)) { - wait_time = rtas_extended_busy_delay_time(rc); - udelay(wait_time * 1000); - } - else - break; - } + } while (rtas_busy_delay(rc)); if (rc < 0) return rtas_error_rc(rc); @@ -555,13 +542,11 @@ void rtas_os_term(char *str) do { status = rtas_call(rtas_token("ibm,os-term"), 1, 1, NULL, __pa(rtas_os_term_buf)); + } while (rtas_busy_delay(status)); - if (status == RTAS_BUSY) - udelay(1); - else if (status != 0) - printk(KERN_EMERG "ibm,os-term call failed %d\n", + if (status != 0) + printk(KERN_EMERG "ibm,os-term call failed %d\n", status); - } while (status == RTAS_BUSY); } static int ibm_suspend_me_token = RTAS_UNKNOWN_SERVICE; @@ -789,7 +774,7 @@ EXPORT_SYMBOL(rtas_token); EXPORT_SYMBOL(rtas_call); EXPORT_SYMBOL(rtas_data_buf); EXPORT_SYMBOL(rtas_data_buf_lock); -EXPORT_SYMBOL(rtas_extended_busy_delay_time); +EXPORT_SYMBOL(rtas_busy_delay_time); EXPORT_SYMBOL(rtas_get_sensor); EXPORT_SYMBOL(rtas_get_power_level); EXPORT_SYMBOL(rtas_set_power_level); diff --git a/arch/powerpc/kernel/rtas_flash.c b/arch/powerpc/kernel/rtas_flash.c index aaf384c3f04a..1442b63a75da 100644 --- a/arch/powerpc/kernel/rtas_flash.c +++ b/arch/powerpc/kernel/rtas_flash.c @@ -365,20 +365,12 @@ static int rtas_excl_release(struct inode *inode, struct file *file) static void manage_flash(struct rtas_manage_flash_t *args_buf) { - unsigned int wait_time; s32 rc; - while (1) { + do { rc = rtas_call(rtas_token("ibm,manage-flash-image"), 1, 1, NULL, args_buf->op); - if (rc == RTAS_RC_BUSY) - udelay(1); - else if (rtas_is_extended_busy(rc)) { - wait_time = rtas_extended_busy_delay_time(rc); - udelay(wait_time * 1000); - } else - break; - } + } while (rtas_busy_delay(rc)); args_buf->status = rc; } @@ -451,27 +443,18 @@ static ssize_t manage_flash_write(struct file *file, const char __user *buf, static void validate_flash(struct rtas_validate_flash_t *args_buf) { int token = rtas_token("ibm,validate-flash-image"); - unsigned int wait_time; int update_results; s32 rc; rc = 0; - while(1) { + do { spin_lock(&rtas_data_buf_lock); memcpy(rtas_data_buf, args_buf->buf, VALIDATE_BUF_SIZE); rc = rtas_call(token, 2, 2, &update_results, (u32) __pa(rtas_data_buf), args_buf->buf_size); memcpy(args_buf->buf, rtas_data_buf, VALIDATE_BUF_SIZE); spin_unlock(&rtas_data_buf_lock); - - if (rc == RTAS_RC_BUSY) - udelay(1); - else if (rtas_is_extended_busy(rc)) { - wait_time = rtas_extended_busy_delay_time(rc); - udelay(wait_time * 1000); - } else - break; - } + } while (rtas_busy_delay(rc)); args_buf->status = rc; args_buf->update_results = update_results; diff --git a/include/asm-powerpc/rtas.h b/include/asm-powerpc/rtas.h index f43c6835e62a..a3b4e55569c7 100644 --- a/include/asm-powerpc/rtas.h +++ b/include/asm-powerpc/rtas.h @@ -177,12 +177,8 @@ extern unsigned long rtas_get_boot_time(void); extern void rtas_get_rtc_time(struct rtc_time *rtc_time); extern int rtas_set_rtc_time(struct rtc_time *rtc_time); -/* Given an RTAS status code of 9900..9905 compute the hinted delay */ -unsigned int rtas_extended_busy_delay_time(int status); -static inline int rtas_is_extended_busy(int status) -{ - return status >= 9900 && status <= 9909; -} +extern unsigned int rtas_busy_delay_time(int status); +extern unsigned int rtas_busy_delay(int status); extern void pSeries_log_error(char *buf, unsigned int err_type, int fatal); -- cgit v1.2.3 From 318facbee05417fb432603a8309a10cdb942a87b Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 6 Jun 2006 16:09:39 +0200 Subject: [PATCH] powerpc: implement pcibus_to_node and pcibus_to_cpumask On 64bit powerpc we can find out what node a pci bus hangs off, so implement the topology.h macros that export this information. For 32bit this seems a little more difficult, but I don't know of 32bit powerpc NUMA machines either, so let's leave it out for now. Signed-off-by: Christoph Hellwig Signed-off-by: Paul Mackerras --- include/asm-powerpc/topology.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'include') diff --git a/include/asm-powerpc/topology.h b/include/asm-powerpc/topology.h index 87362a05542b..b7abd423c570 100644 --- a/include/asm-powerpc/topology.h +++ b/include/asm-powerpc/topology.h @@ -32,8 +32,13 @@ static inline int node_to_first_cpu(int node) int of_node_to_nid(struct device_node *device); +#ifdef CONFIG_PPC64 +#define pcibus_to_node(bus) (of_node_to_nid(bus->sysdata)) +#define pcibus_to_cpumask(bus) (node_to_cpumask(of_node_to_nid(bus->sysdata))) +#else #define pcibus_to_node(node) (-1) #define pcibus_to_cpumask(bus) (cpu_online_map) +#endif /* sched_domains SD_NODE_INIT for PPC64 machines */ #define SD_NODE_INIT (struct sched_domain) { \ -- cgit v1.2.3 From 8eb6c6e3b9c8bfed3d75536ab142d7694627c2e5 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 6 Jun 2006 16:11:35 +0200 Subject: [PATCH] powerpc: node-aware dma allocations Make sure dma_alloc_coherent allocates memory from the local node. This is important on Cell where we avoid going through the slow cpu interconnect. Note: I could only test this patch on Cell, it should be verified on some pseries machine by those that have the hardware. Signed-off-by: Christoph Hellwig Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/iommu.c | 14 ++++++++------ arch/powerpc/kernel/pci_iommu.c | 3 ++- arch/powerpc/kernel/vio.c | 2 +- include/asm-powerpc/iommu.h | 3 ++- 4 files changed, 13 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c index 4eba60a32890..cbb794556d02 100644 --- a/arch/powerpc/kernel/iommu.c +++ b/arch/powerpc/kernel/iommu.c @@ -536,11 +536,12 @@ void iommu_unmap_single(struct iommu_table *tbl, dma_addr_t dma_handle, * to the dma address (mapping) of the first page. */ void *iommu_alloc_coherent(struct iommu_table *tbl, size_t size, - dma_addr_t *dma_handle, unsigned long mask, gfp_t flag) + dma_addr_t *dma_handle, unsigned long mask, gfp_t flag, int node) { void *ret = NULL; dma_addr_t mapping; unsigned int npages, order; + struct page *page; size = PAGE_ALIGN(size); npages = size >> PAGE_SHIFT; @@ -560,9 +561,10 @@ void *iommu_alloc_coherent(struct iommu_table *tbl, size_t size, return NULL; /* Alloc enough pages (and possibly more) */ - ret = (void *)__get_free_pages(flag, order); - if (!ret) + page = alloc_pages_node(flag, order, node); + if (!page) return NULL; + ret = page_address(page); memset(ret, 0, size); /* Set up tces to cover the allocated range */ @@ -570,9 +572,9 @@ void *iommu_alloc_coherent(struct iommu_table *tbl, size_t size, mask >> PAGE_SHIFT, order); if (mapping == DMA_ERROR_CODE) { free_pages((unsigned long)ret, order); - ret = NULL; - } else - *dma_handle = mapping; + return NULL; + } + *dma_handle = mapping; return ret; } diff --git a/arch/powerpc/kernel/pci_iommu.c b/arch/powerpc/kernel/pci_iommu.c index 48aa82d01624..7fb4cca021be 100644 --- a/arch/powerpc/kernel/pci_iommu.c +++ b/arch/powerpc/kernel/pci_iommu.c @@ -86,7 +86,8 @@ static void *pci_iommu_alloc_coherent(struct device *hwdev, size_t size, dma_addr_t *dma_handle, gfp_t flag) { return iommu_alloc_coherent(device_to_table(hwdev), size, dma_handle, - device_to_mask(hwdev), flag); + device_to_mask(hwdev), flag, + pcibus_to_node(to_pci_dev(hwdev)->bus)); } static void pci_iommu_free_coherent(struct device *hwdev, size_t size, diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index fe92727aca30..e746686d48b8 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c @@ -394,7 +394,7 @@ static void *vio_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag) { return iommu_alloc_coherent(to_vio_dev(dev)->iommu_table, size, - dma_handle, ~0ul, flag); + dma_handle, ~0ul, flag, -1); } static void vio_free_coherent(struct device *dev, size_t size, diff --git a/include/asm-powerpc/iommu.h b/include/asm-powerpc/iommu.h index 18ca29e9105a..9065f6c972a4 100644 --- a/include/asm-powerpc/iommu.h +++ b/include/asm-powerpc/iommu.h @@ -76,7 +76,8 @@ extern void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist, int nelems, enum dma_data_direction direction); extern void *iommu_alloc_coherent(struct iommu_table *tbl, size_t size, - dma_addr_t *dma_handle, unsigned long mask, gfp_t flag); + dma_addr_t *dma_handle, unsigned long mask, + gfp_t flag, int node); extern void iommu_free_coherent(struct iommu_table *tbl, size_t size, void *vaddr, dma_addr_t dma_handle); extern dma_addr_t iommu_map_single(struct iommu_table *tbl, void *vaddr, -- cgit v1.2.3 From e78dbc800c37f035d476c4fdebdf43cdecfcb731 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Thu, 8 Jun 2006 14:42:34 +1000 Subject: [PATCH] powerpc: oprofile support for POWER6 POWER6 moves some of the MMCRA bits and also requires some bits to be cleared each PMU interrupt. Signed-off-by: Michael Neuling Acked-by: Anton Blanchard Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/cputable.c | 13 +++++++++++- arch/powerpc/oprofile/op_model_power4.c | 37 +++++++++++++-------------------- include/asm-powerpc/cputable.h | 11 +++++++--- include/asm-powerpc/reg.h | 4 ++++ 4 files changed, 39 insertions(+), 26 deletions(-) (limited to 'include') diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index 7dcc01be4b09..83f9ab139d4c 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -237,6 +237,11 @@ struct cpu_spec cpu_specs[] = { .num_pmcs = 6, .oprofile_cpu_type = "ppc64/power5", .oprofile_type = PPC_OPROFILE_POWER4, + /* SIHV / SIPR bits are implemented on POWER4+ (GQ) + * and above but only works on POWER5 and above + */ + .oprofile_mmcra_sihv = MMCRA_SIHV, + .oprofile_mmcra_sipr = MMCRA_SIPR, .platform = "power5", }, { /* Power5 GS */ @@ -250,6 +255,8 @@ struct cpu_spec cpu_specs[] = { .num_pmcs = 6, .oprofile_cpu_type = "ppc64/power5+", .oprofile_type = PPC_OPROFILE_POWER4, + .oprofile_mmcra_sihv = MMCRA_SIHV, + .oprofile_mmcra_sipr = MMCRA_SIPR, .platform = "power5+", }, { /* Power6 */ @@ -260,9 +267,13 @@ struct cpu_spec cpu_specs[] = { .cpu_user_features = COMMON_USER_POWER6, .icache_bsize = 128, .dcache_bsize = 128, - .num_pmcs = 6, + .num_pmcs = 8, .oprofile_cpu_type = "ppc64/power6", .oprofile_type = PPC_OPROFILE_POWER4, + .oprofile_mmcra_sihv = POWER6_MMCRA_SIHV, + .oprofile_mmcra_sipr = POWER6_MMCRA_SIPR, + .oprofile_mmcra_clear = POWER6_MMCRA_THRM | + POWER6_MMCRA_OTHER, .platform = "power6", }, { /* Cell Broadband Engine */ diff --git a/arch/powerpc/oprofile/op_model_power4.c b/arch/powerpc/oprofile/op_model_power4.c index 4c2beab1fdc1..506f6b79f893 100644 --- a/arch/powerpc/oprofile/op_model_power4.c +++ b/arch/powerpc/oprofile/op_model_power4.c @@ -24,10 +24,6 @@ static unsigned long reset_value[OP_MAX_COUNTER]; static int oprofile_running; -static int mmcra_has_sihv; -/* Unfortunately these bits vary between CPUs */ -static unsigned long mmcra_sihv = MMCRA_SIHV; -static unsigned long mmcra_sipr = MMCRA_SIPR; /* mmcr values are set in power4_reg_setup, used in power4_cpu_setup */ static u32 mmcr0_val; @@ -40,16 +36,6 @@ static void power4_reg_setup(struct op_counter_config *ctr, { int i; - /* - * SIHV / SIPR bits are only implemented on POWER4+ (GQ) and above. - * However we disable it on all POWER4 until we verify it works - * (I was seeing some strange behaviour last time I tried). - * - * It has been verified to work on POWER5 so we enable it there. - */ - if (cpu_has_feature(CPU_FTR_MMCRA_SIHV)) - mmcra_has_sihv = 1; - /* * The performance counter event settings are given in the mmcr0, * mmcr1 and mmcra values passed from the user in the @@ -202,18 +188,19 @@ static unsigned long get_pc(struct pt_regs *regs) unsigned long mmcra; /* Cant do much about it */ - if (!mmcra_has_sihv) + if (!cur_cpu_spec->oprofile_mmcra_sihv) return pc; mmcra = mfspr(SPRN_MMCRA); /* Were we in the hypervisor? */ - if (firmware_has_feature(FW_FEATURE_LPAR) && (mmcra & mmcra_sihv)) + if (firmware_has_feature(FW_FEATURE_LPAR) && + (mmcra & cur_cpu_spec->oprofile_mmcra_sihv)) /* function descriptor madness */ return *((unsigned long *)hypervisor_bucket); /* We were in userspace, nothing to do */ - if (mmcra & mmcra_sipr) + if (mmcra & cur_cpu_spec->oprofile_mmcra_sipr) return pc; #ifdef CONFIG_PPC_RTAS @@ -235,15 +222,14 @@ static unsigned long get_pc(struct pt_regs *regs) return pc; } -static int get_kernel(unsigned long pc) +static int get_kernel(unsigned long pc, unsigned long mmcra) { int is_kernel; - if (!mmcra_has_sihv) { + if (!cur_cpu_spec->oprofile_mmcra_sihv) { is_kernel = is_kernel_addr(pc); } else { - unsigned long mmcra = mfspr(SPRN_MMCRA); - is_kernel = ((mmcra & mmcra_sipr) == 0); + is_kernel = ((mmcra & cur_cpu_spec->oprofile_mmcra_sipr) == 0); } return is_kernel; @@ -257,9 +243,12 @@ static void power4_handle_interrupt(struct pt_regs *regs, int val; int i; unsigned int mmcr0; + unsigned long mmcra; + + mmcra = mfspr(SPRN_MMCRA); pc = get_pc(regs); - is_kernel = get_kernel(pc); + is_kernel = get_kernel(pc, mmcra); /* set the PMM bit (see comment below) */ mtmsrd(mfmsr() | MSR_PMM); @@ -287,6 +276,10 @@ static void power4_handle_interrupt(struct pt_regs *regs, */ mmcr0 &= ~MMCR0_PMAO; + /* Clear the appropriate bits in the MMCRA */ + mmcra &= ~cur_cpu_spec->oprofile_mmcra_clear; + mtspr(SPRN_MMCRA, mmcra); + /* * now clear the freeze bit, counting will not start until we * rfid from this exception, because only at that point will diff --git a/include/asm-powerpc/cputable.h b/include/asm-powerpc/cputable.h index 9fcf0162d859..defc166379d2 100644 --- a/include/asm-powerpc/cputable.h +++ b/include/asm-powerpc/cputable.h @@ -69,6 +69,13 @@ struct cpu_spec { /* Processor specific oprofile operations */ enum powerpc_oprofile_type oprofile_type; + /* Bit locations inside the mmcra change */ + unsigned long oprofile_mmcra_sihv; + unsigned long oprofile_mmcra_sipr; + + /* Bits to clear during an oprofile exception */ + unsigned long oprofile_mmcra_clear; + /* Name of processor class, for the ELF AT_PLATFORM entry */ char *platform; }; @@ -117,7 +124,6 @@ extern void do_cpu_ftr_fixups(unsigned long offset); #define CPU_FTR_SMT ASM_CONST(0x0000010000000000) #define CPU_FTR_COHERENT_ICACHE ASM_CONST(0x0000020000000000) #define CPU_FTR_LOCKLESS_TLBIE ASM_CONST(0x0000040000000000) -#define CPU_FTR_MMCRA_SIHV ASM_CONST(0x0000080000000000) #define CPU_FTR_CI_LARGE_PAGE ASM_CONST(0x0000100000000000) #define CPU_FTR_PAUSE_ZERO ASM_CONST(0x0000200000000000) #define CPU_FTR_PURR ASM_CONST(0x0000400000000000) @@ -134,7 +140,6 @@ extern void do_cpu_ftr_fixups(unsigned long offset); #define CPU_FTR_SMT ASM_CONST(0x0) #define CPU_FTR_COHERENT_ICACHE ASM_CONST(0x0) #define CPU_FTR_LOCKLESS_TLBIE ASM_CONST(0x0) -#define CPU_FTR_MMCRA_SIHV ASM_CONST(0x0) #define CPU_FTR_CI_LARGE_PAGE ASM_CONST(0x0) #define CPU_FTR_PURR ASM_CONST(0x0) #endif @@ -320,7 +325,7 @@ extern void do_cpu_ftr_fixups(unsigned long offset); CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | \ CPU_FTR_MMCRA | CPU_FTR_SMT | \ CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \ - CPU_FTR_MMCRA_SIHV | CPU_FTR_PURR) + CPU_FTR_PURR) #define CPU_FTRS_POWER6 (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \ CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | \ CPU_FTR_MMCRA | CPU_FTR_SMT | \ diff --git a/include/asm-powerpc/reg.h b/include/asm-powerpc/reg.h index 0257189d5017..3779b21a7c71 100644 --- a/include/asm-powerpc/reg.h +++ b/include/asm-powerpc/reg.h @@ -443,6 +443,10 @@ #define MMCRA_SIHV 0x10000000UL /* state of MSR HV when SIAR set */ #define MMCRA_SIPR 0x08000000UL /* state of MSR PR when SIAR set */ #define MMCRA_SAMPLE_ENABLE 0x00000001UL /* enable sampling */ +#define POWER6_MMCRA_SIHV 0x0000040000000000ULL +#define POWER6_MMCRA_SIPR 0x0000020000000000ULL +#define POWER6_MMCRA_THRM 0x00000020UL +#define POWER6_MMCRA_OTHER 0x0000000EUL #define SPRN_PMC1 787 #define SPRN_PMC2 788 #define SPRN_PMC3 789 -- cgit v1.2.3 From 651d765d0b2c72d33430487c8b6ef64c60cd2134 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Wed, 7 Jun 2006 16:10:19 +1000 Subject: [PATCH] Add a prctl to change the endianness of a process. This new prctl is intended for changing the execution mode of the processor, on processors that support both a little-endian mode and a big-endian mode. It is intended for use by programs such as instruction set emulators (for example an x86 emulator on PowerPC), which may find it convenient to use the processor in an alternate endianness mode when executing translated instructions. Note that this does not imply the existence of a fully-fledged ABI for both endiannesses, or of compatibility code for converting system calls done in the non-native endianness mode. The program is expected to arrange for all of its system call arguments to be presented in the native endianness. Switching between big and little-endian mode will require some care in constructing the instruction sequence for the switch. Generally the instructions up to the instruction that invokes the prctl system call will have to be in the old endianness, and subsequent instructions will have to be in the new endianness. Signed-off-by: Anton Blanchard Signed-off-by: Paul Mackerras --- include/linux/prctl.h | 7 +++++++ kernel/sys.c | 13 +++++++++++++ 2 files changed, 20 insertions(+) (limited to 'include') diff --git a/include/linux/prctl.h b/include/linux/prctl.h index bf022c43a18e..52a9be41250d 100644 --- a/include/linux/prctl.h +++ b/include/linux/prctl.h @@ -52,4 +52,11 @@ #define PR_SET_NAME 15 /* Set process name */ #define PR_GET_NAME 16 /* Get process name */ +/* Get/set process endian */ +#define PR_GET_ENDIAN 19 +#define PR_SET_ENDIAN 20 +# define PR_ENDIAN_BIG 0 +# define PR_ENDIAN_LITTLE 1 /* True little endian mode */ +# define PR_ENDIAN_PPC_LITTLE 2 /* "PowerPC" pseudo little endian */ + #endif /* _LINUX_PRCTL_H */ diff --git a/kernel/sys.c b/kernel/sys.c index 0b6ec0e7936f..12d2d753dc3b 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -57,6 +57,12 @@ #ifndef GET_FPEXC_CTL # define GET_FPEXC_CTL(a,b) (-EINVAL) #endif +#ifndef GET_ENDIAN +# define GET_ENDIAN(a,b) (-EINVAL) +#endif +#ifndef SET_ENDIAN +# define SET_ENDIAN(a,b) (-EINVAL) +#endif /* * this is where the system-wide overflow UID and GID are defined, for @@ -2057,6 +2063,13 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3, return -EFAULT; return 0; } + case PR_GET_ENDIAN: + error = GET_ENDIAN(current, arg2); + break; + case PR_SET_ENDIAN: + error = SET_ENDIAN(current, arg2); + break; + default: error = -EINVAL; break; -- cgit v1.2.3 From fab5db97e44f76461f76b24adfa8ccb14d4df498 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 7 Jun 2006 16:14:40 +1000 Subject: [PATCH] powerpc: Implement support for setting little-endian mode via prctl This adds the PowerPC part of the code to allow processes to change their endian mode via prctl. This also extends the alignment exception handler to be able to fix up alignment exceptions that occur in little-endian mode, both for "PowerPC" little-endian and true little-endian. We always enter signal handlers in big-endian mode -- the support for little-endian mode does not amount to the creation of a little-endian user/kernel ABI. If the signal handler returns, the endian mode is restored to what it was when the signal was delivered. We have two new kernel CPU feature bits, one for PPC little-endian and one for true little-endian. Most of the classic 32-bit processors support PPC little-endian, and this is reflected in the CPU feature table. There are two corresponding feature bits reported to userland in the AT_HWCAP aux vector entry. This is based on an earlier patch by Anton Blanchard. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/align.c | 189 +++++++++++++++++++++++++--------------- arch/powerpc/kernel/cputable.c | 84 ++++++++++-------- arch/powerpc/kernel/process.c | 44 ++++++++++ arch/powerpc/kernel/signal_32.c | 15 +++- arch/powerpc/kernel/signal_64.c | 12 ++- arch/powerpc/kernel/traps.c | 2 +- include/asm-powerpc/cputable.h | 52 ++++++----- include/asm-powerpc/processor.h | 6 ++ 8 files changed, 267 insertions(+), 137 deletions(-) (limited to 'include') diff --git a/arch/powerpc/kernel/align.c b/arch/powerpc/kernel/align.c index faaec9c6f78f..4734b5de599d 100644 --- a/arch/powerpc/kernel/align.c +++ b/arch/powerpc/kernel/align.c @@ -35,17 +35,19 @@ struct aligninfo { #define INVALID { 0, 0 } -#define LD 1 /* load */ -#define ST 2 /* store */ -#define SE 4 /* sign-extend value */ -#define F 8 /* to/from fp regs */ -#define U 0x10 /* update index register */ -#define M 0x20 /* multiple load/store */ -#define SW 0x40 /* byte swap int or ... */ -#define S 0x40 /* ... single-precision fp */ -#define SX 0x40 /* byte count in XER */ +/* Bits in the flags field */ +#define LD 0 /* load */ +#define ST 1 /* store */ +#define SE 2 /* sign-extend value */ +#define F 4 /* to/from fp regs */ +#define U 8 /* update index register */ +#define M 0x10 /* multiple load/store */ +#define SW 0x20 /* byte swap */ +#define S 0x40 /* single-precision fp or... */ +#define SX 0x40 /* ... byte count in XER */ #define HARD 0x80 /* string, stwcx. */ +/* DSISR bits reported for a DCBZ instruction: */ #define DCBZ 0x5f /* 8xx/82xx dcbz faults when cache not enabled */ #define SWAP(a, b) (t = (a), (a) = (b), (b) = t) @@ -256,12 +258,16 @@ static int emulate_dcbz(struct pt_regs *regs, unsigned char __user *addr) #define REG_BYTE(rp, i) *((u8 *)(rp) + (i)) #endif +#define SWIZ_PTR(p) ((unsigned char __user *)((p) ^ swiz)) + static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr, unsigned int reg, unsigned int nb, - unsigned int flags, unsigned int instr) + unsigned int flags, unsigned int instr, + unsigned long swiz) { unsigned long *rptr; - unsigned int nb0, i; + unsigned int nb0, i, bswiz; + unsigned long p; /* * We do not try to emulate 8 bytes multiple as they aren't really @@ -280,9 +286,12 @@ static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr, if (nb == 0) return 1; } else { - if (__get_user(instr, - (unsigned int __user *)regs->nip)) + unsigned long pc = regs->nip ^ (swiz & 4); + + if (__get_user(instr, (unsigned int __user *)pc)) return -EFAULT; + if (swiz == 0 && (flags & SW)) + instr = cpu_to_le32(instr); nb = (instr >> 11) & 0x1f; if (nb == 0) nb = 32; @@ -300,7 +309,10 @@ static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr, return -EFAULT; /* bad address */ rptr = ®s->gpr[reg]; - if (flags & LD) { + p = (unsigned long) addr; + bswiz = (flags & SW)? 3: 0; + + if (!(flags & ST)) { /* * This zeroes the top 4 bytes of the affected registers * in 64-bit mode, and also zeroes out any remaining @@ -311,26 +323,28 @@ static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr, memset(®s->gpr[0], 0, ((nb0 + 3) / 4) * sizeof(unsigned long)); - for (i = 0; i < nb; ++i) - if (__get_user(REG_BYTE(rptr, i), addr + i)) + for (i = 0; i < nb; ++i, ++p) + if (__get_user(REG_BYTE(rptr, i ^ bswiz), SWIZ_PTR(p))) return -EFAULT; if (nb0 > 0) { rptr = ®s->gpr[0]; addr += nb; - for (i = 0; i < nb0; ++i) - if (__get_user(REG_BYTE(rptr, i), addr + i)) + for (i = 0; i < nb0; ++i, ++p) + if (__get_user(REG_BYTE(rptr, i ^ bswiz), + SWIZ_PTR(p))) return -EFAULT; } } else { - for (i = 0; i < nb; ++i) - if (__put_user(REG_BYTE(rptr, i), addr + i)) + for (i = 0; i < nb; ++i, ++p) + if (__put_user(REG_BYTE(rptr, i ^ bswiz), SWIZ_PTR(p))) return -EFAULT; if (nb0 > 0) { rptr = ®s->gpr[0]; addr += nb; - for (i = 0; i < nb0; ++i) - if (__put_user(REG_BYTE(rptr, i), addr + i)) + for (i = 0; i < nb0; ++i, ++p) + if (__put_user(REG_BYTE(rptr, i ^ bswiz), + SWIZ_PTR(p))) return -EFAULT; } } @@ -352,7 +366,7 @@ int fix_alignment(struct pt_regs *regs) unsigned int reg, areg; unsigned int dsisr; unsigned char __user *addr; - unsigned char __user *p; + unsigned long p, swiz; int ret, t; union { u64 ll; @@ -380,11 +394,15 @@ int fix_alignment(struct pt_regs *regs) * let's make one up from the instruction */ if (cpu_has_feature(CPU_FTR_NODSISRALIGN)) { - unsigned int real_instr; - if (unlikely(__get_user(real_instr, - (unsigned int __user *)regs->nip))) + unsigned long pc = regs->nip; + + if (cpu_has_feature(CPU_FTR_PPC_LE) && (regs->msr & MSR_LE)) + pc ^= 4; + if (unlikely(__get_user(instr, (unsigned int __user *)pc))) return -EFAULT; - dsisr = make_dsisr(real_instr); + if (cpu_has_feature(CPU_FTR_REAL_LE) && (regs->msr & MSR_LE)) + instr = cpu_to_le32(instr); + dsisr = make_dsisr(instr); } /* extract the operation and registers from the dsisr */ @@ -397,6 +415,24 @@ int fix_alignment(struct pt_regs *regs) nb = aligninfo[instr].len; flags = aligninfo[instr].flags; + /* Byteswap little endian loads and stores */ + swiz = 0; + if (regs->msr & MSR_LE) { + flags ^= SW; + /* + * So-called "PowerPC little endian" mode works by + * swizzling addresses rather than by actually doing + * any byte-swapping. To emulate this, we XOR each + * byte address with 7. We also byte-swap, because + * the processor's address swizzling depends on the + * operand size (it xors the address with 7 for bytes, + * 6 for halfwords, 4 for words, 0 for doublewords) but + * we will xor with 7 and load/store each byte separately. + */ + if (cpu_has_feature(CPU_FTR_PPC_LE)) + swiz = 7; + } + /* DAR has the operand effective address */ addr = (unsigned char __user *)regs->dar; @@ -412,7 +448,8 @@ int fix_alignment(struct pt_regs *regs) * function */ if (flags & M) - return emulate_multiple(regs, addr, reg, nb, flags, instr); + return emulate_multiple(regs, addr, reg, nb, + flags, instr, swiz); /* Verify the address of the operand */ if (unlikely(user_mode(regs) && @@ -431,51 +468,71 @@ int fix_alignment(struct pt_regs *regs) /* If we are loading, get the data from user space, else * get it from register values */ - if (flags & LD) { + if (!(flags & ST)) { data.ll = 0; ret = 0; - p = addr; + p = (unsigned long) addr; switch (nb) { case 8: - ret |= __get_user(data.v[0], p++); - ret |= __get_user(data.v[1], p++); - ret |= __get_user(data.v[2], p++); - ret |= __get_user(data.v[3], p++); + ret |= __get_user(data.v[0], SWIZ_PTR(p++)); + ret |= __get_user(data.v[1], SWIZ_PTR(p++)); + ret |= __get_user(data.v[2], SWIZ_PTR(p++)); + ret |= __get_user(data.v[3], SWIZ_PTR(p++)); case 4: - ret |= __get_user(data.v[4], p++); - ret |= __get_user(data.v[5], p++); + ret |= __get_user(data.v[4], SWIZ_PTR(p++)); + ret |= __get_user(data.v[5], SWIZ_PTR(p++)); case 2: - ret |= __get_user(data.v[6], p++); - ret |= __get_user(data.v[7], p++); + ret |= __get_user(data.v[6], SWIZ_PTR(p++)); + ret |= __get_user(data.v[7], SWIZ_PTR(p++)); if (unlikely(ret)) return -EFAULT; } - } else if (flags & F) + } else if (flags & F) { data.dd = current->thread.fpr[reg]; - else + if (flags & S) { + /* Single-precision FP store requires conversion... */ +#ifdef CONFIG_PPC_FPU + preempt_disable(); + enable_kernel_fp(); + cvt_df(&data.dd, (float *)&data.v[4], ¤t->thread); + preempt_enable(); +#else + return 0; +#endif + } + } else data.ll = regs->gpr[reg]; - /* Perform other misc operations like sign extension, byteswap, + if (flags & SW) { + switch (nb) { + case 8: + SWAP(data.v[0], data.v[7]); + SWAP(data.v[1], data.v[6]); + SWAP(data.v[2], data.v[5]); + SWAP(data.v[3], data.v[4]); + break; + case 4: + SWAP(data.v[4], data.v[7]); + SWAP(data.v[5], data.v[6]); + break; + case 2: + SWAP(data.v[6], data.v[7]); + break; + } + } + + /* Perform other misc operations like sign extension * or floating point single precision conversion */ - switch (flags & ~U) { + switch (flags & ~(U|SW)) { case LD+SE: /* sign extend */ if ( nb == 2 ) data.ll = data.x16.low16; else /* nb must be 4 */ data.ll = data.x32.low32; break; - case LD+S: /* byte-swap */ - case ST+S: - if (nb == 2) { - SWAP(data.v[6], data.v[7]); - } else { - SWAP(data.v[4], data.v[7]); - SWAP(data.v[5], data.v[6]); - } - break; - /* Single-precision FP load and store require conversions... */ + /* Single-precision FP load requires conversion... */ case LD+F+S: #ifdef CONFIG_PPC_FPU preempt_disable(); @@ -484,16 +541,6 @@ int fix_alignment(struct pt_regs *regs) preempt_enable(); #else return 0; -#endif - break; - case ST+F+S: -#ifdef CONFIG_PPC_FPU - preempt_disable(); - enable_kernel_fp(); - cvt_df(&data.dd, (float *)&data.v[4], ¤t->thread); - preempt_enable(); -#else - return 0; #endif break; } @@ -501,19 +548,19 @@ int fix_alignment(struct pt_regs *regs) /* Store result to memory or update registers */ if (flags & ST) { ret = 0; - p = addr; + p = (unsigned long) addr; switch (nb) { case 8: - ret |= __put_user(data.v[0], p++); - ret |= __put_user(data.v[1], p++); - ret |= __put_user(data.v[2], p++); - ret |= __put_user(data.v[3], p++); + ret |= __put_user(data.v[0], SWIZ_PTR(p++)); + ret |= __put_user(data.v[1], SWIZ_PTR(p++)); + ret |= __put_user(data.v[2], SWIZ_PTR(p++)); + ret |= __put_user(data.v[3], SWIZ_PTR(p++)); case 4: - ret |= __put_user(data.v[4], p++); - ret |= __put_user(data.v[5], p++); + ret |= __put_user(data.v[4], SWIZ_PTR(p++)); + ret |= __put_user(data.v[5], SWIZ_PTR(p++)); case 2: - ret |= __put_user(data.v[6], p++); - ret |= __put_user(data.v[7], p++); + ret |= __put_user(data.v[6], SWIZ_PTR(p++)); + ret |= __put_user(data.v[7], SWIZ_PTR(p++)); } if (unlikely(ret)) return -EFAULT; diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index 83f9ab139d4c..dfe2fcfb20a0 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -54,7 +54,8 @@ extern void __setup_cpu_ppc970(unsigned long offset, struct cpu_spec* spec); #define COMMON_USER_POWER5_PLUS (COMMON_USER_PPC64 | PPC_FEATURE_POWER5_PLUS|\ PPC_FEATURE_SMT | PPC_FEATURE_ICACHE_SNOOP) #define COMMON_USER_POWER6 (COMMON_USER_PPC64 | PPC_FEATURE_ARCH_2_05 |\ - PPC_FEATURE_SMT | PPC_FEATURE_ICACHE_SNOOP) + PPC_FEATURE_SMT | PPC_FEATURE_ICACHE_SNOOP | \ + PPC_FEATURE_TRUE_LE) #define COMMON_USER_BOOKE (PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | \ PPC_FEATURE_BOOKE) @@ -74,7 +75,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x00400000, .cpu_name = "POWER3 (630)", .cpu_features = CPU_FTRS_POWER3, - .cpu_user_features = COMMON_USER_PPC64, + .cpu_user_features = COMMON_USER_PPC64|PPC_FEATURE_PPC_LE, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, @@ -87,7 +88,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x00410000, .cpu_name = "POWER3 (630+)", .cpu_features = CPU_FTRS_POWER3, - .cpu_user_features = COMMON_USER_PPC64, + .cpu_user_features = COMMON_USER_PPC64|PPC_FEATURE_PPC_LE, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, @@ -318,7 +319,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x00030000, .cpu_name = "603", .cpu_features = CPU_FTRS_603, - .cpu_user_features = COMMON_USER, + .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE, .icache_bsize = 32, .dcache_bsize = 32, .cpu_setup = __setup_cpu_603, @@ -329,7 +330,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x00060000, .cpu_name = "603e", .cpu_features = CPU_FTRS_603, - .cpu_user_features = COMMON_USER, + .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE, .icache_bsize = 32, .dcache_bsize = 32, .cpu_setup = __setup_cpu_603, @@ -340,7 +341,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x00070000, .cpu_name = "603ev", .cpu_features = CPU_FTRS_603, - .cpu_user_features = COMMON_USER, + .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE, .icache_bsize = 32, .dcache_bsize = 32, .cpu_setup = __setup_cpu_603, @@ -351,7 +352,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x00040000, .cpu_name = "604", .cpu_features = CPU_FTRS_604, - .cpu_user_features = COMMON_USER, + .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 2, @@ -363,7 +364,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x00090000, .cpu_name = "604e", .cpu_features = CPU_FTRS_604, - .cpu_user_features = COMMON_USER, + .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -375,7 +376,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x00090000, .cpu_name = "604r", .cpu_features = CPU_FTRS_604, - .cpu_user_features = COMMON_USER, + .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -387,7 +388,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x000a0000, .cpu_name = "604ev", .cpu_features = CPU_FTRS_604, - .cpu_user_features = COMMON_USER, + .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -399,7 +400,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x00084202, .cpu_name = "740/750", .cpu_features = CPU_FTRS_740_NOTAU, - .cpu_user_features = COMMON_USER, + .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -411,7 +412,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x00080100, .cpu_name = "750CX", .cpu_features = CPU_FTRS_750, - .cpu_user_features = COMMON_USER, + .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -423,7 +424,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x00082200, .cpu_name = "750CX", .cpu_features = CPU_FTRS_750, - .cpu_user_features = COMMON_USER, + .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -435,7 +436,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x00082210, .cpu_name = "750CXe", .cpu_features = CPU_FTRS_750, - .cpu_user_features = COMMON_USER, + .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -447,7 +448,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x00083214, .cpu_name = "750CXe", .cpu_features = CPU_FTRS_750, - .cpu_user_features = COMMON_USER, + .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -459,7 +460,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x00083000, .cpu_name = "745/755", .cpu_features = CPU_FTRS_750, - .cpu_user_features = COMMON_USER, + .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -471,7 +472,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x70000100, .cpu_name = "750FX", .cpu_features = CPU_FTRS_750FX1, - .cpu_user_features = COMMON_USER, + .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -483,7 +484,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x70000200, .cpu_name = "750FX", .cpu_features = CPU_FTRS_750FX2, - .cpu_user_features = COMMON_USER, + .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -495,7 +496,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x70000000, .cpu_name = "750FX", .cpu_features = CPU_FTRS_750FX, - .cpu_user_features = COMMON_USER, + .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -507,7 +508,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x70020000, .cpu_name = "750GX", .cpu_features = CPU_FTRS_750GX, - .cpu_user_features = COMMON_USER, + .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -519,7 +520,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x00080000, .cpu_name = "740/750", .cpu_features = CPU_FTRS_740, - .cpu_user_features = COMMON_USER, + .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -531,7 +532,8 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x000c1101, .cpu_name = "7400 (1.1)", .cpu_features = CPU_FTRS_7400_NOTAU, - .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP, + .cpu_user_features = COMMON_USER | + PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -543,7 +545,8 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x000c0000, .cpu_name = "7400", .cpu_features = CPU_FTRS_7400, - .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP, + .cpu_user_features = COMMON_USER | + PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -555,7 +558,8 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x800c0000, .cpu_name = "7410", .cpu_features = CPU_FTRS_7400, - .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP, + .cpu_user_features = COMMON_USER | + PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, @@ -567,7 +571,8 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x80000200, .cpu_name = "7450", .cpu_features = CPU_FTRS_7450_20, - .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP, + .cpu_user_features = COMMON_USER | + PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, @@ -581,7 +586,8 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x80000201, .cpu_name = "7450", .cpu_features = CPU_FTRS_7450_21, - .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP, + .cpu_user_features = COMMON_USER | + PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, @@ -595,7 +601,8 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x80000000, .cpu_name = "7450", .cpu_features = CPU_FTRS_7450_23, - .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP, + .cpu_user_features = COMMON_USER | + PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, @@ -609,7 +616,8 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x80010100, .cpu_name = "7455", .cpu_features = CPU_FTRS_7455_1, - .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP, + .cpu_user_features = COMMON_USER | + PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, @@ -623,7 +631,8 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x80010200, .cpu_name = "7455", .cpu_features = CPU_FTRS_7455_20, - .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP, + .cpu_user_features = COMMON_USER | + PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, @@ -637,7 +646,8 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x80010000, .cpu_name = "7455", .cpu_features = CPU_FTRS_7455, - .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP, + .cpu_user_features = COMMON_USER | + PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, @@ -651,7 +661,8 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x80020100, .cpu_name = "7447/7457", .cpu_features = CPU_FTRS_7447_10, - .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP, + .cpu_user_features = COMMON_USER | + PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, @@ -665,7 +676,8 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x80020101, .cpu_name = "7447/7457", .cpu_features = CPU_FTRS_7447_10, - .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP, + .cpu_user_features = COMMON_USER | + PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, @@ -679,7 +691,7 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x80020000, .cpu_name = "7447/7457", .cpu_features = CPU_FTRS_7447, - .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP, + .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, @@ -693,7 +705,8 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x80030000, .cpu_name = "7447A", .cpu_features = CPU_FTRS_7447A, - .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP, + .cpu_user_features = COMMON_USER | + PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, @@ -707,7 +720,8 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x80040000, .cpu_name = "7448", .cpu_features = CPU_FTRS_7447A, - .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP, + .cpu_user_features = COMMON_USER | + PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE, .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 2dd47d2dd998..2d35d83961b2 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -708,6 +708,50 @@ int get_fpexc_mode(struct task_struct *tsk, unsigned long adr) return put_user(val, (unsigned int __user *) adr); } +int set_endian(struct task_struct *tsk, unsigned int val) +{ + struct pt_regs *regs = tsk->thread.regs; + + if ((val == PR_ENDIAN_LITTLE && !cpu_has_feature(CPU_FTR_REAL_LE)) || + (val == PR_ENDIAN_PPC_LITTLE && !cpu_has_feature(CPU_FTR_PPC_LE))) + return -EINVAL; + + if (regs == NULL) + return -EINVAL; + + if (val == PR_ENDIAN_BIG) + regs->msr &= ~MSR_LE; + else if (val == PR_ENDIAN_LITTLE || val == PR_ENDIAN_PPC_LITTLE) + regs->msr |= MSR_LE; + else + return -EINVAL; + + return 0; +} + +int get_endian(struct task_struct *tsk, unsigned long adr) +{ + struct pt_regs *regs = tsk->thread.regs; + unsigned int val; + + if (!cpu_has_feature(CPU_FTR_PPC_LE) && + !cpu_has_feature(CPU_FTR_REAL_LE)) + return -EINVAL; + + if (regs == NULL) + return -EINVAL; + + if (regs->msr & MSR_LE) { + if (cpu_has_feature(CPU_FTR_REAL_LE)) + val = PR_ENDIAN_LITTLE; + else + val = PR_ENDIAN_PPC_LITTLE; + } else + val = PR_ENDIAN_BIG; + + return put_user(val, (unsigned int __user *)adr); +} + #define TRUNC_PTR(x) ((typeof(x))(((unsigned long)(x)) & 0xffffffff)) int sys_clone(unsigned long clone_flags, unsigned long usp, diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index 22f078984845..237faeec2ec2 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c @@ -419,9 +419,7 @@ static long restore_user_regs(struct pt_regs *regs, { long err; unsigned int save_r2 = 0; -#if defined(CONFIG_ALTIVEC) || defined(CONFIG_SPE) unsigned long msr; -#endif /* * restore general registers but not including MSR or SOFTE. Also @@ -430,11 +428,16 @@ static long restore_user_regs(struct pt_regs *regs, if (!sig) save_r2 = (unsigned int)regs->gpr[2]; err = restore_general_regs(regs, sr); + err |= __get_user(msr, &sr->mc_gregs[PT_MSR]); if (!sig) regs->gpr[2] = (unsigned long) save_r2; if (err) return 1; + /* if doing signal return, restore the previous little-endian mode */ + if (sig) + regs->msr = (regs->msr & ~MSR_LE) | (msr & MSR_LE); + /* * Do this before updating the thread state in * current->thread.fpr/vr/evr. That way, if we get preempted @@ -455,7 +458,7 @@ static long restore_user_regs(struct pt_regs *regs, /* force the process to reload the altivec registers from current->thread when it next does altivec instructions */ regs->msr &= ~MSR_VEC; - if (!__get_user(msr, &sr->mc_gregs[PT_MSR]) && (msr & MSR_VEC) != 0) { + if (msr & MSR_VEC) { /* restore altivec registers from the stack */ if (__copy_from_user(current->thread.vr, &sr->mc_vregs, sizeof(sr->mc_vregs))) @@ -472,7 +475,7 @@ static long restore_user_regs(struct pt_regs *regs, /* force the process to reload the spe registers from current->thread when it next does spe instructions */ regs->msr &= ~MSR_SPE; - if (!__get_user(msr, &sr->mc_gregs[PT_MSR]) && (msr & MSR_SPE) != 0) { + if (msr & MSR_SPE) { /* restore spe registers from the stack */ if (__copy_from_user(current->thread.evr, &sr->mc_vregs, ELF_NEVRREG * sizeof(u32))) @@ -777,6 +780,8 @@ static int handle_rt_signal(unsigned long sig, struct k_sigaction *ka, regs->gpr[5] = (unsigned long) &rt_sf->uc; regs->gpr[6] = (unsigned long) rt_sf; regs->nip = (unsigned long) ka->sa.sa_handler; + /* enter the signal handler in big-endian mode */ + regs->msr &= ~MSR_LE; regs->trap = 0; return 1; @@ -1047,6 +1052,8 @@ static int handle_signal(unsigned long sig, struct k_sigaction *ka, regs->gpr[3] = sig; regs->gpr[4] = (unsigned long) sc; regs->nip = (unsigned long) ka->sa.sa_handler; + /* enter the signal handler in big-endian mode */ + regs->msr &= ~MSR_LE; regs->trap = 0; return 1; diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c index 23ba69c26913..66a5fbe31989 100644 --- a/arch/powerpc/kernel/signal_64.c +++ b/arch/powerpc/kernel/signal_64.c @@ -141,9 +141,7 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig, unsigned long err = 0; unsigned long save_r13 = 0; elf_greg_t *gregs = (elf_greg_t *)regs; -#ifdef CONFIG_ALTIVEC unsigned long msr; -#endif int i; /* If this is not a signal return, we preserve the TLS in r13 */ @@ -154,7 +152,12 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig, err |= __copy_from_user(regs, &sc->gp_regs, PT_MSR*sizeof(unsigned long)); - /* skip MSR and SOFTE */ + /* get MSR separately, transfer the LE bit if doing signal return */ + err |= __get_user(msr, &sc->gp_regs[PT_MSR]); + if (sig) + regs->msr = (regs->msr & ~MSR_LE) | (msr & MSR_LE); + + /* skip SOFTE */ for (i = PT_MSR+1; i <= PT_RESULT; i++) { if (i == PT_SOFTE) continue; @@ -179,7 +182,6 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig, #ifdef CONFIG_ALTIVEC err |= __get_user(v_regs, &sc->v_regs); - err |= __get_user(msr, &sc->gp_regs[PT_MSR]); if (err) return err; /* Copy 33 vec registers (vr0..31 and vscr) from the stack */ @@ -410,6 +412,8 @@ static int setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info, /* Set up "regs" so we "return" to the signal handler. */ err |= get_user(regs->nip, &funct_desc_ptr->entry); + /* enter the signal handler in big-endian mode */ + regs->msr &= ~MSR_LE; regs->gpr[1] = newsp; err |= get_user(regs->gpr[2], &funct_desc_ptr->toc); regs->gpr[3] = signr; diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 064a52564692..03def5715494 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -658,7 +658,7 @@ static int emulate_instruction(struct pt_regs *regs) u32 instword; u32 rd; - if (!user_mode(regs)) + if (!user_mode(regs) || (regs->msr & MSR_LE)) return -EINVAL; CHECK_FULL_REGS(regs); diff --git a/include/asm-powerpc/cputable.h b/include/asm-powerpc/cputable.h index defc166379d2..69f2c242797f 100644 --- a/include/asm-powerpc/cputable.h +++ b/include/asm-powerpc/cputable.h @@ -24,6 +24,9 @@ #define PPC_FEATURE_ICACHE_SNOOP 0x00002000 #define PPC_FEATURE_ARCH_2_05 0x00001000 +#define PPC_FEATURE_TRUE_LE 0x00000002 +#define PPC_FEATURE_PPC_LE 0x00000001 + #ifdef __KERNEL__ #ifndef __ASSEMBLY__ @@ -111,6 +114,8 @@ extern void do_cpu_ftr_fixups(unsigned long offset); #define CPU_FTR_NO_BTIC ASM_CONST(0x0000000000040000) #define CPU_FTR_BIG_PHYS ASM_CONST(0x0000000000080000) #define CPU_FTR_NODSISRALIGN ASM_CONST(0x0000000000100000) +#define CPU_FTR_PPC_LE ASM_CONST(0x0000000000200000) +#define CPU_FTR_REAL_LE ASM_CONST(0x0000000000400000) #ifdef __powerpc64__ /* Add the 64b processor unique features in the top half of the word */ @@ -197,92 +202,95 @@ extern void do_cpu_ftr_fixups(unsigned long offset); #define CPU_FTRS_PPC601 (CPU_FTR_COMMON | CPU_FTR_601 | CPU_FTR_HPTE_TABLE) #define CPU_FTRS_603 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \ CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | \ - CPU_FTR_MAYBE_CAN_NAP) + CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_PPC_LE) #define CPU_FTRS_604 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \ - CPU_FTR_USE_TB | CPU_FTR_604_PERF_MON | CPU_FTR_HPTE_TABLE) + CPU_FTR_USE_TB | CPU_FTR_604_PERF_MON | CPU_FTR_HPTE_TABLE | \ + CPU_FTR_PPC_LE) #define CPU_FTRS_740_NOTAU (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \ CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \ - CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP) + CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_PPC_LE) #define CPU_FTRS_740 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \ CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \ - CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP) + CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \ + CPU_FTR_PPC_LE) #define CPU_FTRS_750 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \ CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \ - CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP) + CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \ + CPU_FTR_PPC_LE) #define CPU_FTRS_750FX1 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \ CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \ CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \ - CPU_FTR_DUAL_PLL_750FX | CPU_FTR_NO_DPM) + CPU_FTR_DUAL_PLL_750FX | CPU_FTR_NO_DPM | CPU_FTR_PPC_LE) #define CPU_FTRS_750FX2 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \ CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \ CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \ - CPU_FTR_NO_DPM) + CPU_FTR_NO_DPM | CPU_FTR_PPC_LE) #define CPU_FTRS_750FX (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \ CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \ CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \ - CPU_FTR_DUAL_PLL_750FX | CPU_FTR_HAS_HIGH_BATS) + CPU_FTR_DUAL_PLL_750FX | CPU_FTR_HAS_HIGH_BATS | CPU_FTR_PPC_LE) #define CPU_FTRS_750GX (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | \ CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_TAU | \ CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \ - CPU_FTR_DUAL_PLL_750FX | CPU_FTR_HAS_HIGH_BATS) + CPU_FTR_DUAL_PLL_750FX | CPU_FTR_HAS_HIGH_BATS | CPU_FTR_PPC_LE) #define CPU_FTRS_7400_NOTAU (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \ CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \ CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE | \ - CPU_FTR_MAYBE_CAN_NAP) + CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_PPC_LE) #define CPU_FTRS_7400 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \ CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \ CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE | \ - CPU_FTR_MAYBE_CAN_NAP) + CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_PPC_LE) #define CPU_FTRS_7450_20 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \ CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \ CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \ - CPU_FTR_NEED_COHERENT) + CPU_FTR_NEED_COHERENT | CPU_FTR_PPC_LE) #define CPU_FTRS_7450_21 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \ CPU_FTR_USE_TB | \ CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \ CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \ CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_L3_DISABLE_NAP | \ - CPU_FTR_NEED_COHERENT) + CPU_FTR_NEED_COHERENT | CPU_FTR_PPC_LE) #define CPU_FTRS_7450_23 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \ CPU_FTR_USE_TB | \ CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \ CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \ - CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_NEED_COHERENT) + CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_NEED_COHERENT | CPU_FTR_PPC_LE) #define CPU_FTRS_7455_1 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \ CPU_FTR_USE_TB | \ CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR | \ CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_HAS_HIGH_BATS | \ - CPU_FTR_NEED_COHERENT) + CPU_FTR_NEED_COHERENT | CPU_FTR_PPC_LE) #define CPU_FTRS_7455_20 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \ CPU_FTR_USE_TB | \ CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \ CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \ CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_L3_DISABLE_NAP | \ - CPU_FTR_NEED_COHERENT | CPU_FTR_HAS_HIGH_BATS) + CPU_FTR_NEED_COHERENT | CPU_FTR_HAS_HIGH_BATS | CPU_FTR_PPC_LE) #define CPU_FTRS_7455 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \ CPU_FTR_USE_TB | \ CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \ CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \ CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_HAS_HIGH_BATS | \ - CPU_FTR_NEED_COHERENT) + CPU_FTR_NEED_COHERENT | CPU_FTR_PPC_LE) #define CPU_FTRS_7447_10 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \ CPU_FTR_USE_TB | \ CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \ CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \ CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_HAS_HIGH_BATS | \ - CPU_FTR_NEED_COHERENT | CPU_FTR_NO_BTIC) + CPU_FTR_NEED_COHERENT | CPU_FTR_NO_BTIC | CPU_FTR_PPC_LE) #define CPU_FTRS_7447 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \ CPU_FTR_USE_TB | \ CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \ CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \ CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_HAS_HIGH_BATS | \ - CPU_FTR_NEED_COHERENT) + CPU_FTR_NEED_COHERENT | CPU_FTR_PPC_LE) #define CPU_FTRS_7447A (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \ CPU_FTR_USE_TB | \ CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \ CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \ CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_HAS_HIGH_BATS | \ - CPU_FTR_NEED_COHERENT) + CPU_FTR_NEED_COHERENT | CPU_FTR_PPC_LE) #define CPU_FTRS_82XX (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \ CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB) #define CPU_FTRS_G2_LE (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | \ @@ -312,7 +320,7 @@ extern void do_cpu_ftr_fixups(unsigned long offset); #define CPU_FTRS_GENERIC_32 (CPU_FTR_COMMON | CPU_FTR_NODSISRALIGN) #ifdef __powerpc64__ #define CPU_FTRS_POWER3 (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \ - CPU_FTR_HPTE_TABLE | CPU_FTR_IABR) + CPU_FTR_HPTE_TABLE | CPU_FTR_IABR | CPU_FTR_PPC_LE) #define CPU_FTRS_RS64 (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \ CPU_FTR_HPTE_TABLE | CPU_FTR_IABR | \ CPU_FTR_MMCRA | CPU_FTR_CTRL) @@ -330,7 +338,7 @@ extern void do_cpu_ftr_fixups(unsigned long offset); CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | \ CPU_FTR_MMCRA | CPU_FTR_SMT | \ CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \ - CPU_FTR_PURR | CPU_FTR_CI_LARGE_PAGE) + CPU_FTR_PURR | CPU_FTR_CI_LARGE_PAGE | CPU_FTR_REAL_LE) #define CPU_FTRS_CELL (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \ CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | \ CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \ diff --git a/include/asm-powerpc/processor.h b/include/asm-powerpc/processor.h index d5c7ef1cca26..fa6163268153 100644 --- a/include/asm-powerpc/processor.h +++ b/include/asm-powerpc/processor.h @@ -211,6 +211,12 @@ unsigned long get_wchan(struct task_struct *p); extern int get_fpexc_mode(struct task_struct *tsk, unsigned long adr); extern int set_fpexc_mode(struct task_struct *tsk, unsigned int val); +#define GET_ENDIAN(tsk, adr) get_endian((tsk), (adr)) +#define SET_ENDIAN(tsk, val) set_endian((tsk), (val)) + +extern int get_endian(struct task_struct *tsk, unsigned long adr); +extern int set_endian(struct task_struct *tsk, unsigned int val); + static inline unsigned int __unpack_fe01(unsigned long msr_bits) { return ((msr_bits & MSR_FE0) >> 10) | ((msr_bits & MSR_FE1) >> 8); -- cgit v1.2.3 From e9370ae15dc2f8ba1e1889ce26f13cda565b6ecb Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 7 Jun 2006 16:15:39 +1000 Subject: [PATCH] powerpc: Implement PR_[GS]ET_UNALIGN prctls for powerpc This gives the ability to control whether alignment exceptions get fixed up or reported to the process as a SIGBUS, using the existing PR_SET_UNALIGN and PR_GET_UNALIGN prctls. We do not implement the option of logging a message on alignment exceptions. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/process.c | 11 +++++++++++ arch/powerpc/kernel/traps.c | 6 ++++-- include/asm-powerpc/processor.h | 7 +++++++ 3 files changed, 22 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 2d35d83961b2..e4732459c485 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -752,6 +752,17 @@ int get_endian(struct task_struct *tsk, unsigned long adr) return put_user(val, (unsigned int __user *)adr); } +int set_unalign_ctl(struct task_struct *tsk, unsigned int val) +{ + tsk->thread.align_ctl = val; + return 0; +} + +int get_unalign_ctl(struct task_struct *tsk, unsigned long adr) +{ + return put_user(tsk->thread.align_ctl, (unsigned int __user *)adr); +} + #define TRUNC_PTR(x) ((typeof(x))(((unsigned long)(x)) & 0xffffffff)) int sys_clone(unsigned long clone_flags, unsigned long usp, diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 03def5715494..91a6e04d9741 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -805,9 +805,11 @@ void __kprobes program_check_exception(struct pt_regs *regs) void alignment_exception(struct pt_regs *regs) { - int fixed; + int fixed = 0; - fixed = fix_alignment(regs); + /* we don't implement logging of alignment exceptions */ + if (!(current->thread.align_ctl & PR_UNALIGN_SIGBUS)) + fixed = fix_alignment(regs); if (fixed == 1) { regs->nip += 4; /* skip over emulated instruction */ diff --git a/include/asm-powerpc/processor.h b/include/asm-powerpc/processor.h index fa6163268153..d2c2c95f913b 100644 --- a/include/asm-powerpc/processor.h +++ b/include/asm-powerpc/processor.h @@ -149,6 +149,7 @@ struct thread_struct { unsigned int val; /* Floating point status */ } fpscr; int fpexc_mode; /* floating-point exception mode */ + unsigned int align_ctl; /* alignment handling control */ #ifdef CONFIG_PPC64 unsigned long start_tb; /* Start purr when proc switched in */ unsigned long accum_tb; /* Total accumilated purr for process */ @@ -217,6 +218,12 @@ extern int set_fpexc_mode(struct task_struct *tsk, unsigned int val); extern int get_endian(struct task_struct *tsk, unsigned long adr); extern int set_endian(struct task_struct *tsk, unsigned int val); +#define GET_UNALIGN_CTL(tsk, adr) get_unalign_ctl((tsk), (adr)) +#define SET_UNALIGN_CTL(tsk, val) set_unalign_ctl((tsk), (val)) + +extern int get_unalign_ctl(struct task_struct *tsk, unsigned long adr); +extern int set_unalign_ctl(struct task_struct *tsk, unsigned int val); + static inline unsigned int __unpack_fe01(unsigned long msr_bits) { return ((msr_bits & MSR_FE0) >> 10) | ((msr_bits & MSR_FE1) >> 8); -- cgit v1.2.3 From beb40487508290f5d6565598c60a3f44261beef2 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sat, 10 Jun 2006 18:01:03 +0200 Subject: [SCSI] remove scsi_request infrastructure With Achim patch the last user (gdth) is switched away from scsi_request so we an kill it now. Also disables some code in i2o_scsi that was broken since the sg driver stopped using scsi_requests. Signed-off-by: Christoph Hellwig Signed-off-by: James Bottomley --- drivers/message/i2o/i2o_scsi.c | 4 +- drivers/scsi/constants.c | 12 +--- drivers/scsi/gdth.c | 8 +-- drivers/scsi/ipr.c | 1 - drivers/scsi/libata-scsi.c | 2 +- drivers/scsi/qlogicpti.c | 1 - drivers/scsi/scsi.c | 157 ----------------------------------------- drivers/scsi/scsi.h | 1 - drivers/scsi/scsi_error.c | 12 +--- drivers/scsi/scsi_ioctl.c | 2 +- drivers/scsi/scsi_lib.c | 80 +-------------------- drivers/scsi/scsi_priv.h | 10 --- drivers/scsi/scsi_scan.c | 2 +- drivers/scsi/scsi_typedefs.h | 1 - include/scsi/scsi_cmnd.h | 6 -- include/scsi/scsi_dbg.h | 2 - include/scsi/scsi_eh.h | 3 - include/scsi/scsi_request.h | 54 -------------- include/scsi/sg_request.h | 26 ------- 19 files changed, 14 insertions(+), 370 deletions(-) delete mode 100644 include/scsi/scsi_request.h delete mode 100644 include/scsi/sg_request.h (limited to 'include') diff --git a/drivers/message/i2o/i2o_scsi.c b/drivers/message/i2o/i2o_scsi.c index c08ddac3717d..6ebf38213f9f 100644 --- a/drivers/message/i2o/i2o_scsi.c +++ b/drivers/message/i2o/i2o_scsi.c @@ -65,9 +65,7 @@ #include #include #include -#include #include -#include #define OSM_NAME "scsi-osm" #define OSM_VERSION "1.316" @@ -588,6 +586,7 @@ static int i2o_scsi_queuecommand(struct scsi_cmnd *SCpnt, mptr = &msg->body[0]; +#if 0 /* this code can't work */ #ifdef CONFIG_I2O_EXT_ADAPTEC if (c->adaptec) { u32 adpt_flags = 0; @@ -624,6 +623,7 @@ static int i2o_scsi_queuecommand(struct scsi_cmnd *SCpnt, *mptr++ = cpu_to_le32(I2O_VENDOR_DPT << 16 | I2O_CMD_SCSI_EXEC); *mptr++ = cpu_to_le32(adpt_flags | tid); } +#endif #endif msg->u.head[1] = cpu_to_le32(cmd | HOST_TID << 12 | tid); diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c index e24835b38b54..d92d5040a9fe 100644 --- a/drivers/scsi/constants.c +++ b/drivers/scsi/constants.c @@ -13,9 +13,9 @@ #include #include +#include #include #include -#include #include #include @@ -1261,16 +1261,6 @@ void scsi_print_sense(const char *devclass, struct scsi_cmnd *cmd) } EXPORT_SYMBOL(scsi_print_sense); -void scsi_print_req_sense(const char *devclass, struct scsi_request *sreq) -{ - const char *name = devclass; - - if (sreq->sr_request->rq_disk) - name = sreq->sr_request->rq_disk->disk_name; - __scsi_print_sense(name, sreq->sr_sense_buffer, SCSI_SENSE_BUFFERSIZE); -} -EXPORT_SYMBOL(scsi_print_req_sense); - void scsi_print_command(struct scsi_cmnd *cmd) { /* Assume appended output (i.e. not at start of line) */ diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c index fc4d9f61cf3d..76071a158306 100644 --- a/drivers/scsi/gdth.c +++ b/drivers/scsi/gdth.c @@ -716,8 +716,8 @@ static void gdth_scsi_done(struct scsi_cmnd *scp) { TRACE2(("gdth_scsi_done()\n")); - if (scp->sc_request) - complete((struct completion *)scp->sc_request); + if (scp->request) + complete((struct completion *)scp->request); } int __gdth_execute(struct scsi_device *sdev, gdth_cmd_str *gdtcmd, char *cmnd, @@ -732,8 +732,8 @@ int __gdth_execute(struct scsi_device *sdev, gdth_cmd_str *gdtcmd, char *cmnd, return -ENOMEM; memset(scp, 0, sizeof(*scp)); scp->device = sdev; - /* use sc_request field to save the ptr. to completion struct. */ - scp->sc_request = (struct scsi_request *)&wait; + /* use request field to save the ptr. to completion struct. */ + scp->request = (struct request *)&wait; scp->timeout_per_command = timeout*HZ; scp->request_buffer = gdtcmd; scp->cmd_len = 12; diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 8b80e59c8c52..96b65b307dd0 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -79,7 +79,6 @@ #include #include #include -#include #include "ipr.h" /* diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 994015726ec8..f1e129b7c972 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -38,9 +38,9 @@ #include #include #include +#include #include #include -#include #include #include #include diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c index 00f4b846360e..417a121fcd42 100644 --- a/drivers/scsi/qlogicpti.c +++ b/drivers/scsi/qlogicpti.c @@ -43,7 +43,6 @@ #include #include #include -#include #include #include diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 73994e2ac2cb..3e90ba797df2 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -63,7 +63,6 @@ #include #include #include -#include #include "scsi_priv.h" #include "scsi_logging.h" @@ -116,79 +115,6 @@ const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE] = { }; EXPORT_SYMBOL(scsi_device_types); -/* - * Function: scsi_allocate_request - * - * Purpose: Allocate a request descriptor. - * - * Arguments: device - device for which we want a request - * gfp_mask - allocation flags passed to kmalloc - * - * Lock status: No locks assumed to be held. This function is SMP-safe. - * - * Returns: Pointer to request block. - */ -struct scsi_request *scsi_allocate_request(struct scsi_device *sdev, - gfp_t gfp_mask) -{ - const int offset = ALIGN(sizeof(struct scsi_request), 4); - const int size = offset + sizeof(struct request); - struct scsi_request *sreq; - - sreq = kzalloc(size, gfp_mask); - if (likely(sreq != NULL)) { - sreq->sr_request = (struct request *)(((char *)sreq) + offset); - sreq->sr_device = sdev; - sreq->sr_host = sdev->host; - sreq->sr_magic = SCSI_REQ_MAGIC; - sreq->sr_data_direction = DMA_BIDIRECTIONAL; - } - - return sreq; -} -EXPORT_SYMBOL(scsi_allocate_request); - -void __scsi_release_request(struct scsi_request *sreq) -{ - struct request *req = sreq->sr_request; - - /* unlikely because the tag was usually ended earlier by the - * mid-layer. However, for layering reasons ULD's don't end - * the tag of commands they generate. */ - if (unlikely(blk_rq_tagged(req))) { - unsigned long flags; - struct request_queue *q = req->q; - - spin_lock_irqsave(q->queue_lock, flags); - blk_queue_end_tag(q, req); - spin_unlock_irqrestore(q->queue_lock, flags); - } - - - if (likely(sreq->sr_command != NULL)) { - struct scsi_cmnd *cmd = sreq->sr_command; - - sreq->sr_command = NULL; - scsi_next_command(cmd); - } -} - -/* - * Function: scsi_release_request - * - * Purpose: Release a request descriptor. - * - * Arguments: sreq - request to release - * - * Lock status: No locks assumed to be held. This function is SMP-safe. - */ -void scsi_release_request(struct scsi_request *sreq) -{ - __scsi_release_request(sreq); - kfree(sreq); -} -EXPORT_SYMBOL(scsi_release_request); - struct scsi_host_cmd_pool { kmem_cache_t *slab; unsigned int users; @@ -646,73 +572,6 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd) return rtn; } -/* - * Function: scsi_init_cmd_from_req - * - * Purpose: Queue a SCSI command - * Purpose: Initialize a struct scsi_cmnd from a struct scsi_request - * - * Arguments: cmd - command descriptor. - * sreq - Request from the queue. - * - * Lock status: None needed. - * - * Returns: Nothing. - * - * Notes: Mainly transfer data from the request structure to the - * command structure. The request structure is allocated - * using the normal memory allocator, and requests can pile - * up to more or less any depth. The command structure represents - * a consumable resource, as these are allocated into a pool - * when the SCSI subsystem initializes. The preallocation is - * required so that in low-memory situations a disk I/O request - * won't cause the memory manager to try and write out a page. - * The request structure is generally used by ioctls and character - * devices. - */ -void scsi_init_cmd_from_req(struct scsi_cmnd *cmd, struct scsi_request *sreq) -{ - sreq->sr_command = cmd; - - cmd->cmd_len = sreq->sr_cmd_len; - cmd->use_sg = sreq->sr_use_sg; - - cmd->request = sreq->sr_request; - memcpy(cmd->data_cmnd, sreq->sr_cmnd, sizeof(cmd->data_cmnd)); - cmd->serial_number = 0; - cmd->bufflen = sreq->sr_bufflen; - cmd->buffer = sreq->sr_buffer; - cmd->retries = 0; - cmd->allowed = sreq->sr_allowed; - cmd->done = sreq->sr_done; - cmd->timeout_per_command = sreq->sr_timeout_per_command; - cmd->sc_data_direction = sreq->sr_data_direction; - cmd->sglist_len = sreq->sr_sglist_len; - cmd->underflow = sreq->sr_underflow; - cmd->sc_request = sreq; - memcpy(cmd->cmnd, sreq->sr_cmnd, sizeof(sreq->sr_cmnd)); - - /* - * Zero the sense buffer. Some host adapters automatically request - * sense on error. 0 is not a valid sense code. - */ - memset(cmd->sense_buffer, 0, sizeof(sreq->sr_sense_buffer)); - cmd->request_buffer = sreq->sr_buffer; - cmd->request_bufflen = sreq->sr_bufflen; - cmd->old_use_sg = cmd->use_sg; - if (cmd->cmd_len == 0) - cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]); - cmd->old_cmd_len = cmd->cmd_len; - cmd->sc_old_data_direction = cmd->sc_data_direction; - cmd->old_underflow = cmd->underflow; - - /* - * Start the timer ticking. - */ - cmd->result = 0; - - SCSI_LOG_MLQUEUE(3, printk("Leaving scsi_init_cmd_from_req()\n")); -} /* * Per-CPU I/O completion queue. @@ -809,7 +668,6 @@ void scsi_finish_command(struct scsi_cmnd *cmd) { struct scsi_device *sdev = cmd->device; struct Scsi_Host *shost = sdev->host; - struct scsi_request *sreq; scsi_device_unbusy(sdev); @@ -839,21 +697,6 @@ void scsi_finish_command(struct scsi_cmnd *cmd) * We can get here with use_sg=0, causing a panic in the upper level */ cmd->use_sg = cmd->old_use_sg; - - /* - * If there is an associated request structure, copy the data over - * before we call the completion function. - */ - sreq = cmd->sc_request; - if (sreq) { - sreq->sr_result = sreq->sr_command->result; - if (sreq->sr_result) { - memcpy(sreq->sr_sense_buffer, - sreq->sr_command->sense_buffer, - sizeof(sreq->sr_sense_buffer)); - } - } - cmd->done(cmd); } EXPORT_SYMBOL(scsi_finish_command); diff --git a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h index 5ee5d80a9931..f51e466893e7 100644 --- a/drivers/scsi/scsi.h +++ b/drivers/scsi/scsi.h @@ -25,7 +25,6 @@ #include #include #include -#include #include #include diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 1c75646f9689..471a43102923 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -26,13 +26,13 @@ #include #include +#include #include #include #include #include #include #include -#include #include "scsi_priv.h" #include "scsi_logging.h" @@ -1671,8 +1671,6 @@ scsi_reset_provider(struct scsi_device *dev, int flag) scmd->cmd_len = 0; scmd->sc_data_direction = DMA_BIDIRECTIONAL; - scmd->sc_request = NULL; - scmd->sc_magic = SCSI_CMND_MAGIC; init_timer(&scmd->eh_timeout); @@ -1769,14 +1767,6 @@ int scsi_normalize_sense(const u8 *sense_buffer, int sb_len, } EXPORT_SYMBOL(scsi_normalize_sense); -int scsi_request_normalize_sense(struct scsi_request *sreq, - struct scsi_sense_hdr *sshdr) -{ - return scsi_normalize_sense(sreq->sr_sense_buffer, - sizeof(sreq->sr_sense_buffer), sshdr); -} -EXPORT_SYMBOL(scsi_request_normalize_sense); - int scsi_command_normalize_sense(struct scsi_cmnd *cmd, struct scsi_sense_hdr *sshdr) { diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c index a89aff61d3d8..a89c4115cfba 100644 --- a/drivers/scsi/scsi_ioctl.c +++ b/drivers/scsi/scsi_ioctl.c @@ -15,11 +15,11 @@ #include #include +#include #include #include #include #include -#include #include #include diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index bdce9d1f5b71..3302d8068c41 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -19,12 +19,12 @@ #include #include +#include #include #include #include #include #include -#include #include "scsi_priv.h" #include "scsi_logging.h" @@ -83,7 +83,7 @@ static void scsi_unprep_request(struct request *req) struct scsi_cmnd *cmd = req->special; req->flags &= ~REQ_DONTPREP; - req->special = (req->flags & REQ_SPECIAL) ? cmd->sc_request : NULL; + req->special = NULL; scsi_put_command(cmd); } @@ -161,72 +161,6 @@ int scsi_queue_insert(struct scsi_cmnd *cmd, int reason) return 0; } -/* - * Function: scsi_do_req - * - * Purpose: Queue a SCSI request - * - * Arguments: sreq - command descriptor. - * cmnd - actual SCSI command to be performed. - * buffer - data buffer. - * bufflen - size of data buffer. - * done - completion function to be run. - * timeout - how long to let it run before timeout. - * retries - number of retries we allow. - * - * Lock status: No locks held upon entry. - * - * Returns: Nothing. - * - * Notes: This function is only used for queueing requests for things - * like ioctls and character device requests - this is because - * we essentially just inject a request into the queue for the - * device. - * - * In order to support the scsi_device_quiesce function, we - * now inject requests on the *head* of the device queue - * rather than the tail. - */ -void scsi_do_req(struct scsi_request *sreq, const void *cmnd, - void *buffer, unsigned bufflen, - void (*done)(struct scsi_cmnd *), - int timeout, int retries) -{ - /* - * If the upper level driver is reusing these things, then - * we should release the low-level block now. Another one will - * be allocated later when this request is getting queued. - */ - __scsi_release_request(sreq); - - /* - * Our own function scsi_done (which marks the host as not busy, - * disables the timeout counter, etc) will be called by us or by the - * scsi_hosts[host].queuecommand() function needs to also call - * the completion function for the high level driver. - */ - memcpy(sreq->sr_cmnd, cmnd, sizeof(sreq->sr_cmnd)); - sreq->sr_bufflen = bufflen; - sreq->sr_buffer = buffer; - sreq->sr_allowed = retries; - sreq->sr_done = done; - sreq->sr_timeout_per_command = timeout; - - if (sreq->sr_cmd_len == 0) - sreq->sr_cmd_len = COMMAND_SIZE(sreq->sr_cmnd[0]); - - /* - * head injection *required* here otherwise quiesce won't work - * - * Because users of this function are apt to reuse requests with no - * modification, we have to sanitise the request flags here - */ - sreq->sr_request->flags &= ~REQ_DONTPREP; - blk_insert_request(sreq->sr_device->request_queue, sreq->sr_request, - 1, sreq); -} -EXPORT_SYMBOL(scsi_do_req); - /** * scsi_execute - insert request and wait for the result * @sdev: scsi device @@ -1300,15 +1234,7 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req) * at request->cmd, as this tells us the real story. */ if (req->flags & REQ_SPECIAL && req->special) { - struct scsi_request *sreq = req->special; - - if (sreq->sr_magic == SCSI_REQ_MAGIC) { - cmd = scsi_get_command(sreq->sr_device, GFP_ATOMIC); - if (unlikely(!cmd)) - goto defer; - scsi_init_cmd_from_req(cmd, sreq); - } else - cmd = req->special; + cmd = req->special; } else if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) { if(unlikely(specials_only) && !(req->flags & REQ_SPECIAL)) { diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index 27c48274e8cb..a1727a0e1bdd 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -8,16 +8,9 @@ struct request_queue; struct scsi_cmnd; struct scsi_device; struct scsi_host_template; -struct scsi_request; struct Scsi_Host; -/* - * Magic values for certain scsi structs. Shouldn't ever be used. - */ -#define SCSI_CMND_MAGIC 0xE25C23A5 -#define SCSI_REQ_MAGIC 0x75F6D354 - /* * Scsi Error Handler Flags */ @@ -34,9 +27,6 @@ extern void scsi_exit_hosts(void); extern int scsi_dispatch_cmd(struct scsi_cmnd *cmd); extern int scsi_setup_command_freelist(struct Scsi_Host *shost); extern void scsi_destroy_command_freelist(struct Scsi_Host *shost); -extern void scsi_init_cmd_from_req(struct scsi_cmnd *cmd, - struct scsi_request *sreq); -extern void __scsi_release_request(struct scsi_request *sreq); extern void __scsi_done(struct scsi_cmnd *cmd); extern int scsi_retry_command(struct scsi_cmnd *cmd); #ifdef CONFIG_SCSI_LOGGING diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index fd97d07577ad..0f7e6f94d66b 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -33,11 +33,11 @@ #include #include +#include #include #include #include #include -#include #include #include diff --git a/drivers/scsi/scsi_typedefs.h b/drivers/scsi/scsi_typedefs.h index 29f038b42f60..2ed4c5cb7088 100644 --- a/drivers/scsi/scsi_typedefs.h +++ b/drivers/scsi/scsi_typedefs.h @@ -1,3 +1,2 @@ typedef struct scsi_cmnd Scsi_Cmnd; -typedef struct scsi_request Scsi_Request; diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h index 7602b9b15a03..b0caabec1bd1 100644 --- a/include/scsi/scsi_cmnd.h +++ b/include/scsi/scsi_cmnd.h @@ -9,7 +9,6 @@ struct request; struct scatterlist; struct scsi_device; -struct scsi_request; /* embedded in scsi_cmnd */ @@ -29,13 +28,8 @@ struct scsi_pointer { }; struct scsi_cmnd { - int sc_magic; - struct scsi_device *device; - struct scsi_request *sc_request; - struct list_head list; /* scsi_cmnd participates in queue lists */ - struct list_head eh_entry; /* entry for the host eh_cmd_q */ int eh_eflags; /* Used by error handlr */ void (*done) (struct scsi_cmnd *); /* Mid-level done function */ diff --git a/include/scsi/scsi_dbg.h b/include/scsi/scsi_dbg.h index 4d69dee66d4d..3bbbfbe8cbfc 100644 --- a/include/scsi/scsi_dbg.h +++ b/include/scsi/scsi_dbg.h @@ -2,14 +2,12 @@ #define _SCSI_SCSI_DBG_H struct scsi_cmnd; -struct scsi_request; struct scsi_sense_hdr; extern void scsi_print_command(struct scsi_cmnd *); extern void scsi_print_sense_hdr(const char *, struct scsi_sense_hdr *); extern void __scsi_print_command(unsigned char *); extern void scsi_print_sense(const char *, struct scsi_cmnd *); -extern void scsi_print_req_sense(const char *, struct scsi_request *); extern void __scsi_print_sense(const char *name, const unsigned char *sense_buffer, int sense_len); diff --git a/include/scsi/scsi_eh.h b/include/scsi/scsi_eh.h index d160880b2a87..c5c0f6762a01 100644 --- a/include/scsi/scsi_eh.h +++ b/include/scsi/scsi_eh.h @@ -3,7 +3,6 @@ struct scsi_cmnd; struct scsi_device; -struct scsi_request; struct Scsi_Host; /* @@ -43,8 +42,6 @@ extern void scsi_report_device_reset(struct Scsi_Host *, int, int); extern int scsi_block_when_processing_errors(struct scsi_device *); extern int scsi_normalize_sense(const u8 *sense_buffer, int sb_len, struct scsi_sense_hdr *sshdr); -extern int scsi_request_normalize_sense(struct scsi_request *sreq, - struct scsi_sense_hdr *sshdr); extern int scsi_command_normalize_sense(struct scsi_cmnd *cmd, struct scsi_sense_hdr *sshdr); diff --git a/include/scsi/scsi_request.h b/include/scsi/scsi_request.h deleted file mode 100644 index 98d69fdb851c..000000000000 --- a/include/scsi/scsi_request.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef _SCSI_SCSI_REQUEST_H -#define _SCSI_SCSI_REQUEST_H - -#include - -struct request; -struct scsi_cmnd; -struct scsi_device; -struct Scsi_Host; - - -/* - * This is essentially a slimmed down version of Scsi_Cmnd. The point of - * having this is that requests that are injected into the queue as result - * of things like ioctls and character devices shouldn't be using a - * Scsi_Cmnd until such a time that the command is actually at the head - * of the queue and being sent to the driver. - */ -struct scsi_request { - int sr_magic; - int sr_result; /* Status code from lower level driver */ - unsigned char sr_sense_buffer[SCSI_SENSE_BUFFERSIZE]; /* obtained by REQUEST SENSE - * when CHECK CONDITION is - * received on original command - * (auto-sense) */ - - struct Scsi_Host *sr_host; - struct scsi_device *sr_device; - struct scsi_cmnd *sr_command; - struct request *sr_request; /* A copy of the command we are - working on */ - unsigned sr_bufflen; /* Size of data buffer */ - void *sr_buffer; /* Data buffer */ - int sr_allowed; - enum dma_data_direction sr_data_direction; - unsigned char sr_cmd_len; - unsigned char sr_cmnd[MAX_COMMAND_SIZE]; - void (*sr_done) (struct scsi_cmnd *); /* Mid-level done function */ - int sr_timeout_per_command; - unsigned short sr_use_sg; /* Number of pieces of scatter-gather */ - unsigned short sr_sglist_len; /* size of malloc'd scatter-gather list */ - unsigned sr_underflow; /* Return error if less than - this amount is transferred */ - void *upper_private_data; /* reserved for owner (usually upper - level driver) of this request */ -}; - -extern struct scsi_request *scsi_allocate_request(struct scsi_device *, gfp_t); -extern void scsi_release_request(struct scsi_request *); -extern void scsi_do_req(struct scsi_request *, const void *cmnd, - void *buffer, unsigned bufflen, - void (*done) (struct scsi_cmnd *), - int timeout, int retries); -#endif /* _SCSI_SCSI_REQUEST_H */ diff --git a/include/scsi/sg_request.h b/include/scsi/sg_request.h deleted file mode 100644 index 57ff525bdd3b..000000000000 --- a/include/scsi/sg_request.h +++ /dev/null @@ -1,26 +0,0 @@ -typedef struct scsi_request Scsi_Request; - -static Scsi_Request *dummy_cmdp; /* only used for sizeof */ - -typedef struct sg_scatter_hold { /* holding area for scsi scatter gather info */ - unsigned short k_use_sg; /* Count of kernel scatter-gather pieces */ - unsigned short sglist_len; /* size of malloc'd scatter-gather list ++ */ - unsigned bufflen; /* Size of (aggregate) data buffer */ - unsigned b_malloc_len; /* actual len malloc'ed in buffer */ - void *buffer; /* Data buffer or scatter list (k_use_sg>0) */ - char dio_in_use; /* 0->indirect IO (or mmap), 1->dio */ - unsigned char cmd_opcode; /* first byte of command */ -} Sg_scatter_hold; - -typedef struct sg_request { /* SG_MAX_QUEUE requests outstanding per file */ - Scsi_Request *my_cmdp; /* != 0 when request with lower levels */ - struct sg_request *nextrp; /* NULL -> tail request (slist) */ - struct sg_fd *parentfp; /* NULL -> not in use */ - Sg_scatter_hold data; /* hold buffer, perhaps scatter list */ - sg_io_hdr_t header; /* scsi command+info, see */ - unsigned char sense_b[sizeof (dummy_cmdp->sr_sense_buffer)]; - char res_used; /* 1 -> using reserve buffer, 0 -> not ... */ - char orphan; /* 1 -> drop on sight, 0 -> normal */ - char sg_io_owned; /* 1 -> packet belongs to SG_IO */ - volatile char done; /* 0->before bh, 1->before read, 2->read */ -} Sg_request; -- cgit v1.2.3 From 8d7feac3c7504425aaf61dc7d804685a6b89ee43 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sat, 10 Jun 2006 18:37:19 +0200 Subject: [SCSI] remove RQ_SCSI_* flags The RQ_SCSI_* flags are a vestiage of a long past history. The EH code still sets them but we never make use of that information. The other users is pluto.c which never had a chance to work but needs to be kept compiling to keep Davem happy, so copy over the definition there. We could probably get rid of RQ_ACTIVE/RQ_INACTIVE aswell with some work, there's only two more or less bogus looking uses in ubd and scsi. Signed-off-by: Christoph Hellwig Signed-off-by: James Bottomley --- drivers/scsi/pluto.c | 3 +++ drivers/scsi/scsi_error.c | 3 --- include/linux/blkdev.h | 3 --- 3 files changed, 3 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/drivers/scsi/pluto.c b/drivers/scsi/pluto.c index 46624ab9c3d2..83a671799934 100644 --- a/drivers/scsi/pluto.c +++ b/drivers/scsi/pluto.c @@ -27,6 +27,9 @@ #include +#define RQ_SCSI_BUSY 0xffff +#define RQ_SCSI_DONE 0xfffe + /* #define PLUTO_DEBUG */ #define pluto_printk printk ("PLUTO %s: ", fc->name); printk diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 471a43102923..1c7d993fa8ad 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -452,7 +452,6 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, int timeout) (sdev->lun << 5 & 0xe0); shost->eh_action = &done; - scmd->request->rq_status = RQ_SCSI_BUSY; spin_lock_irqsave(shost->host_lock, flags); scsi_log_send(scmd); @@ -461,7 +460,6 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, int timeout) timeleft = wait_for_completion_timeout(&done, timeout); - scmd->request->rq_status = RQ_SCSI_DONE; shost->eh_action = NULL; scsi_log_completion(scmd, SUCCESS); @@ -1657,7 +1655,6 @@ scsi_reset_provider(struct scsi_device *dev, int flag) scmd->request = &req; memset(&scmd->eh_timeout, 0, sizeof(scmd->eh_timeout)); - scmd->request->rq_status = RQ_SCSI_BUSY; memset(&scmd->cmnd, '\0', sizeof(scmd->cmnd)); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 59e1259b1c40..c889c459fd1b 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -439,9 +439,6 @@ struct request_queue #define RQ_INACTIVE (-1) #define RQ_ACTIVE 1 -#define RQ_SCSI_BUSY 0xffff -#define RQ_SCSI_DONE 0xfffe -#define RQ_SCSI_DISCONNECTING 0xffe0 #define QUEUE_FLAG_CLUSTER 0 /* cluster several segments into 1 */ #define QUEUE_FLAG_QUEUED 1 /* uses generic tag queueing */ -- cgit v1.2.3 From 9a9c77dc4c4eed9dfb74080e768c0b3c9d905496 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 11 Jun 2006 11:19:00 +0900 Subject: [PATCH] libata: cosmetic change in struct ata_port Cosmetic change in struct ata_port. Signed-off-by: Tejun Heo --- include/linux/libata.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/libata.h b/include/linux/libata.h index a2a33a902917..39e6b77de1a9 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -520,7 +520,8 @@ struct ata_port { struct ata_host_set *host_set; struct device *dev; - struct work_struct port_task, hotplug_task; + struct work_struct port_task; + struct work_struct hotplug_task; unsigned int hsm_task_state; -- cgit v1.2.3 From 6218a761bbc27acc65248c80024875bcc06d52b1 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sun, 11 Jun 2006 14:15:17 +1000 Subject: powerpc: add context.vdso_base for 32-bit too This adds a vdso_base element to the mm_context_t for 32-bit compiles (both for ARCH=powerpc and ARCH=ppc). This fixes the compile errors that have been reported in arch/powerpc/kernel/signal_32.c. Signed-off-by: Paul Mackerras --- arch/powerpc/mm/mmu_context_32.c | 2 +- arch/powerpc/mm/ppc_mmu_32.c | 2 +- arch/powerpc/mm/tlb_32.c | 6 +++--- arch/powerpc/platforms/powermac/cpufreq_32.c | 2 +- arch/powerpc/platforms/powermac/setup.c | 2 +- arch/ppc/mm/mmu_context.c | 2 +- drivers/macintosh/via-pmu.c | 4 ++-- include/asm-ppc/mmu.h | 6 ++++-- include/asm-ppc/mmu_context.h | 27 ++++++++++++++++----------- include/asm-ppc/pgtable.h | 2 +- 10 files changed, 31 insertions(+), 24 deletions(-) (limited to 'include') diff --git a/arch/powerpc/mm/mmu_context_32.c b/arch/powerpc/mm/mmu_context_32.c index a8816e0f6a86..e326e4249e1a 100644 --- a/arch/powerpc/mm/mmu_context_32.c +++ b/arch/powerpc/mm/mmu_context_32.c @@ -30,7 +30,7 @@ #include #include -mm_context_t next_mmu_context; +unsigned long next_mmu_context; unsigned long context_map[LAST_CONTEXT / BITS_PER_LONG + 1]; #ifdef FEW_CONTEXTS atomic_t nr_free_contexts; diff --git a/arch/powerpc/mm/ppc_mmu_32.c b/arch/powerpc/mm/ppc_mmu_32.c index ed7fcfe5fd37..1df731e42b50 100644 --- a/arch/powerpc/mm/ppc_mmu_32.c +++ b/arch/powerpc/mm/ppc_mmu_32.c @@ -190,7 +190,7 @@ void hash_preload(struct mm_struct *mm, unsigned long ea, return; pmd = pmd_offset(pgd_offset(mm, ea), ea); if (!pmd_none(*pmd)) - add_hash_page(mm->context, ea, pmd_val(*pmd)); + add_hash_page(mm->context.id, ea, pmd_val(*pmd)); } /* diff --git a/arch/powerpc/mm/tlb_32.c b/arch/powerpc/mm/tlb_32.c index ad580f3742e5..02eb23e036d5 100644 --- a/arch/powerpc/mm/tlb_32.c +++ b/arch/powerpc/mm/tlb_32.c @@ -42,7 +42,7 @@ void flush_hash_entry(struct mm_struct *mm, pte_t *ptep, unsigned long addr) if (Hash != 0) { ptephys = __pa(ptep) & PAGE_MASK; - flush_hash_pages(mm->context, addr, ptephys, 1); + flush_hash_pages(mm->context.id, addr, ptephys, 1); } } @@ -102,7 +102,7 @@ static void flush_range(struct mm_struct *mm, unsigned long start, pmd_t *pmd; unsigned long pmd_end; int count; - unsigned int ctx = mm->context; + unsigned int ctx = mm->context.id; if (Hash == 0) { _tlbia(); @@ -172,7 +172,7 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr) mm = (vmaddr < TASK_SIZE)? vma->vm_mm: &init_mm; pmd = pmd_offset(pgd_offset(mm, vmaddr), vmaddr); if (!pmd_none(*pmd)) - flush_hash_pages(mm->context, vmaddr, pmd_val(*pmd), 1); + flush_hash_pages(mm->context.id, vmaddr, pmd_val(*pmd), 1); FINISH_FLUSH; } diff --git a/arch/powerpc/platforms/powermac/cpufreq_32.c b/arch/powerpc/platforms/powermac/cpufreq_32.c index cfd6527a0d7e..af2a8f9f1222 100644 --- a/arch/powerpc/platforms/powermac/cpufreq_32.c +++ b/arch/powerpc/platforms/powermac/cpufreq_32.c @@ -314,7 +314,7 @@ static int pmu_set_cpu_speed(int low_speed) _set_L3CR(save_l3cr); /* Restore userland MMU context */ - set_context(current->active_mm->context, current->active_mm->pgd); + set_context(current->active_mm->context.id, current->active_mm->pgd); #ifdef DEBUG_FREQ printk(KERN_DEBUG "HID1, after: %x\n", mfspr(SPRN_HID1)); diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index b9200fb07815..9cc7db7a8bdc 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c @@ -458,7 +458,7 @@ static int pmac_pm_finish(suspend_state_t state) printk(KERN_DEBUG "%s(%d)\n", __FUNCTION__, state); /* Restore userland MMU context */ - set_context(current->active_mm->context, current->active_mm->pgd); + set_context(current->active_mm->context.id, current->active_mm->pgd); return 0; } diff --git a/arch/ppc/mm/mmu_context.c b/arch/ppc/mm/mmu_context.c index b4a4b3f02a1c..8784f3715032 100644 --- a/arch/ppc/mm/mmu_context.c +++ b/arch/ppc/mm/mmu_context.c @@ -30,7 +30,7 @@ #include #include -mm_context_t next_mmu_context; +unsigned long next_mmu_context; unsigned long context_map[LAST_CONTEXT / BITS_PER_LONG + 1]; #ifdef FEW_CONTEXTS atomic_t nr_free_contexts; diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 0b5ff553e39a..c63d4e7984be 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -2268,7 +2268,7 @@ static int powerbook_sleep_grackle(void) _set_L2CR(save_l2cr); /* Restore userland MMU context */ - set_context(current->active_mm->context, current->active_mm->pgd); + set_context(current->active_mm->context.id, current->active_mm->pgd); /* Power things up */ pmu_unlock(); @@ -2366,7 +2366,7 @@ powerbook_sleep_Core99(void) _set_L3CR(save_l3cr); /* Restore userland MMU context */ - set_context(current->active_mm->context, current->active_mm->pgd); + set_context(current->active_mm->context.id, current->active_mm->pgd); /* Tell PMU we are ready */ pmu_unlock(); diff --git a/include/asm-ppc/mmu.h b/include/asm-ppc/mmu.h index 9205db404c7a..80ae60481fb7 100644 --- a/include/asm-ppc/mmu.h +++ b/include/asm-ppc/mmu.h @@ -24,8 +24,10 @@ extern phys_addr_t fixup_bigphys_addr(phys_addr_t, phys_addr_t); #define PHYS_FMT "%16Lx" #endif -/* Default "unsigned long" context */ -typedef unsigned long mm_context_t; +typedef struct { + unsigned long id; + unsigned long vdso_base; +} mm_context_t; /* Hardware Page Table Entry */ typedef struct _PTE { diff --git a/include/asm-ppc/mmu_context.h b/include/asm-ppc/mmu_context.h index 4f152cca13c1..4454ecf1aed5 100644 --- a/include/asm-ppc/mmu_context.h +++ b/include/asm-ppc/mmu_context.h @@ -71,7 +71,7 @@ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) #else /* PPC 6xx, 7xx CPUs */ -#define NO_CONTEXT ((mm_context_t) -1) +#define NO_CONTEXT ((unsigned long) -1) #define LAST_CONTEXT 32767 #define FIRST_CONTEXT 1 #endif @@ -86,7 +86,7 @@ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) * can be used for debugging on all processors (if you happen to have * an Abatron). */ -extern void set_context(mm_context_t context, pgd_t *pgd); +extern void set_context(unsigned long contextid, pgd_t *pgd); /* * Bitmap of contexts in use. @@ -99,7 +99,7 @@ extern unsigned long context_map[]; * Its use is an optimization only, we can't rely on this context * number to be free, but it usually will be. */ -extern mm_context_t next_mmu_context; +extern unsigned long next_mmu_context; /* * If we don't have sufficient contexts to give one to every task @@ -118,9 +118,9 @@ extern void steal_context(void); */ static inline void get_mmu_context(struct mm_struct *mm) { - mm_context_t ctx; + unsigned long ctx; - if (mm->context != NO_CONTEXT) + if (mm->context.id != NO_CONTEXT) return; #ifdef FEW_CONTEXTS while (atomic_dec_if_positive(&nr_free_contexts) < 0) @@ -133,7 +133,7 @@ static inline void get_mmu_context(struct mm_struct *mm) ctx = 0; } next_mmu_context = (ctx + 1) & LAST_CONTEXT; - mm->context = ctx; + mm->context.id = ctx; #ifdef FEW_CONTEXTS context_mm[ctx] = mm; #endif @@ -142,7 +142,12 @@ static inline void get_mmu_context(struct mm_struct *mm) /* * Set up the context for a new address space. */ -#define init_new_context(tsk,mm) (((mm)->context = NO_CONTEXT), 0) +static inline int init_new_context(struct task_struct *t, struct mm_struct *mm) +{ + mm->context.id = NO_CONTEXT; + mm->context.vdso_base = 0; + return 0; +} /* * We're finished using the context for an address space. @@ -150,9 +155,9 @@ static inline void get_mmu_context(struct mm_struct *mm) static inline void destroy_context(struct mm_struct *mm) { preempt_disable(); - if (mm->context != NO_CONTEXT) { - clear_bit(mm->context, context_map); - mm->context = NO_CONTEXT; + if (mm->context.id != NO_CONTEXT) { + clear_bit(mm->context.id, context_map); + mm->context.id = NO_CONTEXT; #ifdef FEW_CONTEXTS atomic_inc(&nr_free_contexts); #endif @@ -180,7 +185,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, /* Setup new userspace context */ get_mmu_context(next); - set_context(next->context, next->pgd); + set_context(next->context.id, next->pgd); } #define deactivate_mm(tsk,mm) do { } while (0) diff --git a/include/asm-ppc/pgtable.h b/include/asm-ppc/pgtable.h index 570b355162fa..f886066bd15c 100644 --- a/include/asm-ppc/pgtable.h +++ b/include/asm-ppc/pgtable.h @@ -663,7 +663,7 @@ static inline int __ptep_test_and_clear_young(unsigned int context, unsigned lon return (old & _PAGE_ACCESSED) != 0; } #define ptep_test_and_clear_young(__vma, __addr, __ptep) \ - __ptep_test_and_clear_young((__vma)->vm_mm->context, __addr, __ptep) + __ptep_test_and_clear_young((__vma)->vm_mm->context.id, __addr, __ptep) #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY static inline int ptep_test_and_clear_dirty(struct vm_area_struct *vma, -- cgit v1.2.3 From 3057ac3c1a992ee135cbb7b7d1a12e58d81f0739 Mon Sep 17 00:00:00 2001 From: "zhao, forrest" Date: Mon, 12 Jun 2006 12:01:34 +0800 Subject: [PATCH] Snoop SET FEATURES - WRITE CACHE ENABLE/DISABLE command(v5) This patch makes libata snoop 'SET FEATURES - WRITE CACHE ENABLE/DISABLE' command, executing requisite revalidation processes to update cached data. Signed-off-by: Forrest Zhao Signed-off-by: Jeff Garzik --- drivers/scsi/libata-core.c | 1 + drivers/scsi/libata-eh.c | 3 +++ drivers/scsi/libata-scsi.c | 36 ++++++++++++++++++++++++++++++++++++ drivers/scsi/libata.h | 1 + include/linux/ata.h | 3 +++ 5 files changed, 44 insertions(+) (limited to 'include') diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 51b3a0ddb238..ddaad1a4f1f1 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -5194,6 +5194,7 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host, INIT_WORK(&ap->port_task, NULL, NULL); INIT_WORK(&ap->hotplug_task, ata_scsi_hotplug, ap); + INIT_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan, ap); INIT_LIST_HEAD(&ap->eh_done_q); init_waitqueue_head(&ap->eh_wait_q); diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index 6285257a890d..f82799e22588 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c @@ -1554,6 +1554,9 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, if (rc) break; + /* schedule the scsi_rescan_device() here */ + queue_work(ata_aux_wq, &(ap->scsi_rescan_task)); + ehc->i.action &= ~ATA_EH_REVALIDATE; } else if (dev->class == ATA_DEV_UNKNOWN && ehc->tries[dev->devno] && diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 5f90d8e33546..45a49be65042 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -1306,6 +1306,17 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) u8 *cdb = cmd->cmnd; int need_sense = (qc->err_mask != 0); + /* We snoop the SET_FEATURES - Write Cache ON/OFF command, and + * schedule EH_REVALIDATE operation to update the IDENTIFY DEVICE + * cache + */ + if (!need_sense && (qc->tf.command == ATA_CMD_SET_FEATURES) && + ((qc->tf.feature == SETFEATURES_WC_ON) || + (qc->tf.feature == SETFEATURES_WC_OFF))) { + qc->ap->eh_info.action |= ATA_EH_REVALIDATE; + ata_port_schedule_eh(qc->ap); + } + /* For ATA pass thru (SAT) commands, generate a sense block if * user mandated it or if there's an error. Note that if we * generate because the user forced us to, a check condition @@ -2992,3 +3003,28 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, return rc; } + +/** + * ata_scsi_dev_rescan - initiate scsi_rescan_device() + * @data: Pointer to ATA port to perform scsi_rescan_device() + * + * After ATA pass thru (SAT) commands are executed successfully, + * libata need to propagate the changes to SCSI layer. + * + * LOCKING: + * Kernel thread context (may sleep). + */ +void ata_scsi_dev_rescan(void *data) +{ + struct ata_port *ap = data; + struct ata_device *dev; + unsigned int i; + + for (i = 0; i < ATA_MAX_DEVICES; i++) { + dev = &ap->device[i]; + + if (ata_dev_enabled(dev)) + scsi_rescan_device(&(dev->sdev->sdev_gendev)); + } +} + diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h index 1dd496f1f7ac..bdd488897096 100644 --- a/drivers/scsi/libata.h +++ b/drivers/scsi/libata.h @@ -104,6 +104,7 @@ extern void ata_scsi_rbuf_fill(struct ata_scsi_args *args, unsigned int (*actor) (struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen)); extern void ata_schedule_scsi_eh(struct Scsi_Host *shost); +extern void ata_scsi_dev_rescan(void *data); /* libata-eh.c */ extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd); diff --git a/include/linux/ata.h b/include/linux/ata.h index c494e1c0531e..3671af869696 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -181,6 +181,9 @@ enum { XFER_PIO_0 = 0x08, XFER_PIO_SLOW = 0x00, + SETFEATURES_WC_ON = 0x02, /* Enable write cache */ + SETFEATURES_WC_OFF = 0x82, /* Disable write cache */ + /* ATAPI stuff */ ATAPI_PKT_DMA = (1 << 0), ATAPI_DMADIR = (1 << 2), /* ATAPI data dir: -- cgit v1.2.3 From 3b01b8af2414b6684051da4a1507dfacdbf24f86 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Mon, 12 Jun 2006 00:22:04 -0400 Subject: libata: fix build, by adding required workqueue member to port struct --- include/linux/libata.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/linux/libata.h b/include/linux/libata.h index 39e6b77de1a9..61eea5795d5a 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -522,6 +522,7 @@ struct ata_port { struct work_struct port_task; struct work_struct hotplug_task; + struct work_struct scsi_rescan_task; unsigned int hsm_task_state; -- cgit v1.2.3 From 430644312810645a6e05855db50a978df9ba3ad3 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 12 Jun 2006 18:38:21 +1000 Subject: powerpc: Remove unused paca->pgdir field The pgdir field in the paca was a leftover from the dynamic VSIDs patch, and is not used in the current kernel code. This removes it. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/asm-offsets.c | 3 --- arch/powerpc/mm/slb.c | 3 --- arch/powerpc/mm/stab.c | 4 ---- include/asm-powerpc/mmu_context.h | 12 ------------ include/asm-powerpc/paca.h | 3 --- 5 files changed, 25 deletions(-) (limited to 'include') diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 8f85c5e8a55a..aa0486d552a3 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -122,9 +122,6 @@ int main(void) DEFINE(PACASLBCACHE, offsetof(struct paca_struct, slb_cache)); DEFINE(PACASLBCACHEPTR, offsetof(struct paca_struct, slb_cache_ptr)); DEFINE(PACACONTEXTID, offsetof(struct paca_struct, context.id)); -#ifdef CONFIG_PPC_64K_PAGES - DEFINE(PACAPGDIR, offsetof(struct paca_struct, pgdir)); -#endif #ifdef CONFIG_HUGETLB_PAGE DEFINE(PACALOWHTLBAREAS, offsetof(struct paca_struct, context.low_htlb_areas)); DEFINE(PACAHIGHHTLBAREAS, offsetof(struct paca_struct, context.high_htlb_areas)); diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c index ffc8ed4de62d..2cc61736feee 100644 --- a/arch/powerpc/mm/slb.c +++ b/arch/powerpc/mm/slb.c @@ -122,9 +122,6 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm) get_paca()->slb_cache_ptr = 0; get_paca()->context = mm->context; -#ifdef CONFIG_PPC_64K_PAGES - get_paca()->pgdir = mm->pgd; -#endif /* CONFIG_PPC_64K_PAGES */ /* * preload some userspace segments into the SLB. diff --git a/arch/powerpc/mm/stab.c b/arch/powerpc/mm/stab.c index 4a9291d9fef8..691320c90b78 100644 --- a/arch/powerpc/mm/stab.c +++ b/arch/powerpc/mm/stab.c @@ -200,10 +200,6 @@ void switch_stab(struct task_struct *tsk, struct mm_struct *mm) __get_cpu_var(stab_cache_ptr) = 0; -#ifdef CONFIG_PPC_64K_PAGES - get_paca()->pgdir = mm->pgd; -#endif /* CONFIG_PPC_64K_PAGES */ - /* Now preload some entries for the new task */ if (test_tsk_thread_flag(tsk, TIF_32BIT)) unmapped_base = TASK_UNMAPPED_BASE_USER32; diff --git a/include/asm-powerpc/mmu_context.h b/include/asm-powerpc/mmu_context.h index 1b8a25fd48f3..8c6b1a6d944f 100644 --- a/include/asm-powerpc/mmu_context.h +++ b/include/asm-powerpc/mmu_context.h @@ -20,16 +20,9 @@ * 2 of the License, or (at your option) any later version. */ -/* - * Getting into a kernel thread, there is no valid user segment, mark - * paca->pgdir NULL so that SLB miss on user addresses will fault - */ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) { -#ifdef CONFIG_PPC_64K_PAGES - get_paca()->pgdir = NULL; -#endif /* CONFIG_PPC_64K_PAGES */ } #define NO_CONTEXT 0 @@ -52,13 +45,8 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, cpu_set(smp_processor_id(), next->cpu_vm_mask); /* No need to flush userspace segments if the mm doesnt change */ -#ifdef CONFIG_PPC_64K_PAGES - if (prev == next && get_paca()->pgdir == next->pgd) - return; -#else if (prev == next) return; -#endif /* CONFIG_PPC_64K_PAGES */ #ifdef CONFIG_ALTIVEC if (cpu_has_feature(CPU_FTR_ALTIVEC)) diff --git a/include/asm-powerpc/paca.h b/include/asm-powerpc/paca.h index 706325f99a84..c17fd54d995b 100644 --- a/include/asm-powerpc/paca.h +++ b/include/asm-powerpc/paca.h @@ -79,9 +79,6 @@ struct paca_struct { u64 exmc[10]; /* used for machine checks */ u64 exslb[10]; /* used for SLB/segment table misses * on the linear mapping */ -#ifdef CONFIG_PPC_64K_PAGES - pgd_t *pgdir; -#endif /* CONFIG_PPC_64K_PAGES */ mm_context_t context; u16 slb_cache[SLB_CACHE_ENTRIES]; -- cgit v1.2.3 From f0eb62b81dd16bfc4034916418c3406ba20011e1 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 12 Jun 2006 23:05:38 +0900 Subject: [PATCH] libata: add host_set->next for legacy two host_sets case, take #3 For a legacy ATA controller, libata registers two separate host sets. There was no connection between the two hosts making it impossible to traverse all ports related to the controller. This patch adds host_set->next which points to the second host_set and makes ata_pci_remove_one() remove all associated host_sets. * On device removal, all ports hanging off the device are properly detached. Prior to this patch, ports on the first host_set weren't detached casuing oops on driver unloading. * On device removal, both host_sets are properly freed This will also be used by new power management code to suspend and resume all ports of a controller. host_set/port representation will be improved to handle legacy controllers better and this host_set linking will go away with it. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/scsi/libata-bmdma.c | 15 +++++++++++++-- drivers/scsi/libata-core.c | 4 ++++ include/linux/libata.h | 3 ++- 3 files changed, 19 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libata-bmdma.c b/drivers/scsi/libata-bmdma.c index 4bc05371737c..13fab97c840e 100644 --- a/drivers/scsi/libata-bmdma.c +++ b/drivers/scsi/libata-bmdma.c @@ -1076,10 +1076,21 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, /* FIXME: check ata_device_add return */ if (legacy_mode) { - if (legacy_mode & (1 << 0)) + struct device *dev = &pdev->dev; + struct ata_host_set *host_set = NULL; + + if (legacy_mode & (1 << 0)) { ata_device_add(probe_ent); - if (legacy_mode & (1 << 1)) + host_set = dev_get_drvdata(dev); + } + + if (legacy_mode & (1 << 1)) { ata_device_add(probe_ent2); + if (host_set) { + host_set->next = dev_get_drvdata(dev); + dev_set_drvdata(dev, host_set); + } + } } else ata_device_add(probe_ent); diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 014855e5a43a..d73cb3672d6a 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -5621,8 +5621,12 @@ void ata_pci_remove_one (struct pci_dev *pdev) { struct device *dev = pci_dev_to_dev(pdev); struct ata_host_set *host_set = dev_get_drvdata(dev); + struct ata_host_set *host_set2 = host_set->next; ata_host_set_remove(host_set); + if (host_set2) + ata_host_set_remove(host_set2); + pci_release_regions(pdev); pci_disable_device(pdev); dev_set_drvdata(dev, NULL); diff --git a/include/linux/libata.h b/include/linux/libata.h index 61eea5795d5a..f03b8664af11 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -356,7 +356,8 @@ struct ata_host_set { unsigned long flags; int simplex_claimed; /* Keep seperate in case we ever need to do this locked */ - struct ata_port * ports[0]; + struct ata_host_set *next; /* for legacy mode */ + struct ata_port *ports[0]; }; struct ata_queued_cmd { -- cgit v1.2.3 From 61686124f47d7c4b78610346c5f8f9d8a6d46bb5 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Fri, 17 Mar 2006 16:44:00 -0500 Subject: [ACPI] ACPICA 20060317 Implemented the use of a cache object for all internal namespace nodes. Since there are about 1000 static nodes in a typical system, this will decrease memory use for cache implementations that minimize per-allocation overhead (such as a slab allocator.) Removed the reference count mechanism for internal namespace nodes, since it was deemed unnecessary. This reduces the size of each namespace node by about 5%-10% on all platforms. Nodes are now 20 bytes for the 32-bit case, and 32 bytes for the 64-bit case. Optimized several internal data structures to reduce object size on 64-bit platforms by packing data within the 64-bit alignment. This includes the frequently used ACPI_OPERAND_OBJECT, of which there can be ~1000 static instances corresponding to the namespace objects. Added two new strings for the predefined _OSI method: "Windows 2001.1 SP1" and "Windows 2006". Split the allocation tracking mechanism out to a separate file, from utalloc.c to uttrack.c. This mechanism appears to be only useful for application-level code. Kernels may wish to not include uttrack.c in distributions. Removed all remnants of the obsolete ACPI_REPORT_* macros and the associated code. (These macros have been replaced by the ACPI_ERROR and ACPI_WARNING macros.) Signed-off-by: Bob Moore Signed-off-by: Len Brown --- drivers/acpi/bus.c | 4 +- drivers/acpi/dispatcher/dsmthdat.c | 12 +- drivers/acpi/dispatcher/dswscope.c | 2 +- drivers/acpi/dispatcher/dswstate.c | 12 +- drivers/acpi/events/evgpeblk.c | 2 +- drivers/acpi/events/evmisc.c | 3 +- drivers/acpi/events/evregion.c | 15 +- drivers/acpi/executer/excreate.c | 7 +- drivers/acpi/executer/exdump.c | 2 - drivers/acpi/namespace/nsalloc.c | 104 +------ drivers/acpi/namespace/nsutils.c | 4 +- drivers/acpi/osl.c | 5 +- drivers/acpi/parser/psscope.c | 12 +- drivers/acpi/parser/psutils.c | 2 +- drivers/acpi/resources/rscalc.c | 2 +- drivers/acpi/resources/rscreate.c | 7 +- drivers/acpi/resources/rslist.c | 110 +++---- drivers/acpi/resources/rsxface.c | 4 +- drivers/acpi/utilities/utalloc.c | 590 ++----------------------------------- drivers/acpi/utilities/utcache.c | 6 +- drivers/acpi/utilities/utdelete.c | 3 +- drivers/acpi/utilities/utglobal.c | 8 +- drivers/acpi/utilities/utmisc.c | 33 --- drivers/acpi/utilities/utresrc.c | 150 +++++++--- drivers/acpi/utilities/utstate.c | 10 +- include/acpi/acconfig.h | 5 +- include/acpi/acevents.h | 2 +- include/acpi/acglobal.h | 1 + include/acpi/aclocal.h | 208 ++++++------- include/acpi/acmacros.h | 20 +- include/acpi/acobject.h | 181 ++++++------ include/acpi/acoutput.h | 2 +- include/acpi/acparser.h | 7 +- include/acpi/acpixf.h | 4 +- include/acpi/acresrc.h | 5 +- include/acpi/acstruct.h | 39 +-- include/acpi/actypes.h | 36 +-- include/acpi/acutils.h | 49 ++- include/acpi/amlresrc.h | 31 +- include/acpi/platform/acenv.h | 12 +- 40 files changed, 558 insertions(+), 1153 deletions(-) (limited to 'include') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 606f8733a776..9c4ac0191f64 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -596,6 +596,8 @@ void __init acpi_early_init(void) if (acpi_disabled) return_VOID; + printk(KERN_INFO PREFIX "Core revision %08x\n", ACPI_CA_VERSION); + /* enable workarounds, unless strict ACPI spec. compliance */ if (!acpi_strict) acpi_gbl_enable_interpreter_slack = TRUE; @@ -743,8 +745,6 @@ static int __init acpi_init(void) ACPI_FUNCTION_TRACE("acpi_init"); - printk(KERN_INFO PREFIX "Subsystem revision %08x\n", ACPI_CA_VERSION); - if (acpi_disabled) { printk(KERN_INFO PREFIX "Interpreter disabled.\n"); return_VALUE(-ENODEV); diff --git a/drivers/acpi/dispatcher/dsmthdat.c b/drivers/acpi/dispatcher/dsmthdat.c index 2ed48439835d..ce4de18f1229 100644 --- a/drivers/acpi/dispatcher/dsmthdat.c +++ b/drivers/acpi/dispatcher/dsmthdat.c @@ -100,10 +100,10 @@ void acpi_ds_method_data_init(struct acpi_walk_state *walk_state) ACPI_MOVE_32_TO_32(&walk_state->arguments[i].name, NAMEOF_ARG_NTE); walk_state->arguments[i].name.integer |= (i << 24); - walk_state->arguments[i].descriptor = ACPI_DESC_TYPE_NAMED; + walk_state->arguments[i].descriptor_type = ACPI_DESC_TYPE_NAMED; walk_state->arguments[i].type = ACPI_TYPE_ANY; - walk_state->arguments[i].flags = ANOBJ_END_OF_PEER_LIST | - ANOBJ_METHOD_ARG; + walk_state->arguments[i].flags = + ANOBJ_END_OF_PEER_LIST | ANOBJ_METHOD_ARG; } /* Init the method locals */ @@ -113,11 +113,11 @@ void acpi_ds_method_data_init(struct acpi_walk_state *walk_state) NAMEOF_LOCAL_NTE); walk_state->local_variables[i].name.integer |= (i << 24); - walk_state->local_variables[i].descriptor = + walk_state->local_variables[i].descriptor_type = ACPI_DESC_TYPE_NAMED; walk_state->local_variables[i].type = ACPI_TYPE_ANY; - walk_state->local_variables[i].flags = ANOBJ_END_OF_PEER_LIST | - ANOBJ_METHOD_LOCAL; + walk_state->local_variables[i].flags = + ANOBJ_END_OF_PEER_LIST | ANOBJ_METHOD_LOCAL; } return_VOID; diff --git a/drivers/acpi/dispatcher/dswscope.c b/drivers/acpi/dispatcher/dswscope.c index e2954fff8c5e..3cd6895ed2c3 100644 --- a/drivers/acpi/dispatcher/dswscope.c +++ b/drivers/acpi/dispatcher/dswscope.c @@ -128,7 +128,7 @@ acpi_ds_scope_stack_push(struct acpi_namespace_node *node, /* Init new scope object */ - scope_info->common.data_type = ACPI_DESC_TYPE_STATE_WSCOPE; + scope_info->common.descriptor_type = ACPI_DESC_TYPE_STATE_WSCOPE; scope_info->scope.node = node; scope_info->common.value = (u16) type; diff --git a/drivers/acpi/dispatcher/dswstate.c b/drivers/acpi/dispatcher/dswstate.c index d2846ffc9773..4840eae47d34 100644 --- a/drivers/acpi/dispatcher/dswstate.c +++ b/drivers/acpi/dispatcher/dswstate.c @@ -337,7 +337,7 @@ acpi_status acpi_ds_result_stack_push(struct acpi_walk_state * walk_state) return (AE_NO_MEMORY); } - state->common.data_type = ACPI_DESC_TYPE_STATE_RESULT; + state->common.descriptor_type = ACPI_DESC_TYPE_STATE_RESULT; acpi_ut_push_generic_state(&walk_state->results, state); ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Results=%p State=%p\n", @@ -620,7 +620,7 @@ struct acpi_walk_state *acpi_ds_pop_walk_state(struct acpi_thread_state *thread) * * PARAMETERS: owner_id - ID for object creation * Origin - Starting point for this walk - * mth_desc - Method object + * method_desc - Method object * Thread - Current thread state * * RETURN: Pointer to the new walk state. @@ -634,7 +634,7 @@ struct acpi_walk_state *acpi_ds_create_walk_state(acpi_owner_id owner_id, union acpi_parse_object *origin, union acpi_operand_object - *mth_desc, + *method_desc, struct acpi_thread_state *thread) { @@ -648,10 +648,10 @@ struct acpi_walk_state *acpi_ds_create_walk_state(acpi_owner_id owner_id, return_PTR(NULL); } - walk_state->data_type = ACPI_DESC_TYPE_WALK; + walk_state->descriptor_type = ACPI_DESC_TYPE_WALK; + walk_state->method_desc = method_desc; walk_state->owner_id = owner_id; walk_state->origin = origin; - walk_state->method_desc = mth_desc; walk_state->thread = thread; walk_state->parser_state.start_op = origin; @@ -819,7 +819,7 @@ void acpi_ds_delete_walk_state(struct acpi_walk_state *walk_state) return; } - if (walk_state->data_type != ACPI_DESC_TYPE_WALK) { + if (walk_state->descriptor_type != ACPI_DESC_TYPE_WALK) { ACPI_ERROR((AE_INFO, "%p is not a valid walk state", walk_state)); return; diff --git a/drivers/acpi/events/evgpeblk.c b/drivers/acpi/events/evgpeblk.c index e8e72986f0d6..4e90c1f837c3 100644 --- a/drivers/acpi/events/evgpeblk.c +++ b/drivers/acpi/events/evgpeblk.c @@ -131,7 +131,7 @@ u8 acpi_ev_valid_gpe_event(struct acpi_gpe_event_info *gpe_event_info) * ******************************************************************************/ -acpi_status acpi_ev_walk_gpe_list(ACPI_GPE_CALLBACK gpe_walk_callback) +acpi_status acpi_ev_walk_gpe_list(acpi_gpe_callback gpe_walk_callback) { struct acpi_gpe_block_info *gpe_block; struct acpi_gpe_xrupt_info *gpe_xrupt_info; diff --git a/drivers/acpi/events/evmisc.c b/drivers/acpi/events/evmisc.c index 334407239f2f..b216b3229e27 100644 --- a/drivers/acpi/events/evmisc.c +++ b/drivers/acpi/events/evmisc.c @@ -185,7 +185,8 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node, return (AE_NO_MEMORY); } - notify_info->common.data_type = ACPI_DESC_TYPE_STATE_NOTIFY; + notify_info->common.descriptor_type = + ACPI_DESC_TYPE_STATE_NOTIFY; notify_info->notify.node = node; notify_info->notify.value = (u16) notify_value; notify_info->notify.handler_obj = handler_obj; diff --git a/drivers/acpi/events/evregion.c b/drivers/acpi/events/evregion.c index 2b900ef05fa9..0337ad222b26 100644 --- a/drivers/acpi/events/evregion.c +++ b/drivers/acpi/events/evregion.c @@ -250,7 +250,6 @@ acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function) cleanup: acpi_ut_remove_reference(params[0]); - return_ACPI_STATUS(status); } @@ -389,9 +388,8 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, acpi_ut_get_region_name(region_obj->region. space_id))); - if (! - (handler_desc->address_space. - hflags & ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) { + if (!(handler_desc->address_space.handler_flags & + ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) { /* * For handlers other than the default (supplied) handlers, we must * exit the interpreter because the handler *might* block -- we don't @@ -412,9 +410,8 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, space_id))); } - if (! - (handler_desc->address_space. - hflags & ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) { + if (!(handler_desc->address_space.handler_flags & + ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) { /* * We just returned from a non-default handler, we must re-enter the * interpreter @@ -772,7 +769,7 @@ acpi_ev_install_space_handler(struct acpi_namespace_node * node, union acpi_operand_object *handler_obj; acpi_status status; acpi_object_type type; - u16 flags = 0; + u8 flags = 0; ACPI_FUNCTION_TRACE("ev_install_space_handler"); @@ -930,7 +927,7 @@ acpi_ev_install_space_handler(struct acpi_namespace_node * node, /* Init handler obj */ handler_obj->address_space.space_id = (u8) space_id; - handler_obj->address_space.hflags = flags; + handler_obj->address_space.handler_flags = flags; handler_obj->address_space.region_list = NULL; handler_obj->address_space.node = node; handler_obj->address_space.handler = handler; diff --git a/drivers/acpi/executer/excreate.c b/drivers/acpi/executer/excreate.c index 680575402835..763e132da4c6 100644 --- a/drivers/acpi/executer/excreate.c +++ b/drivers/acpi/executer/excreate.c @@ -243,8 +243,9 @@ acpi_status acpi_ex_create_mutex(struct acpi_walk_state *walk_state) obj_desc->mutex.node = (struct acpi_namespace_node *)walk_state->operands[0]; - status = acpi_ns_attach_object(obj_desc->mutex.node, - obj_desc, ACPI_TYPE_MUTEX); + status = + acpi_ns_attach_object(obj_desc->mutex.node, obj_desc, + ACPI_TYPE_MUTEX); cleanup: /* @@ -464,9 +465,9 @@ acpi_status acpi_ex_create_processor(struct acpi_walk_state *walk_state) /* Initialize the processor object from the operands */ obj_desc->processor.proc_id = (u8) operand[1]->integer.value; + obj_desc->processor.length = (u8) operand[3]->integer.value; obj_desc->processor.address = (acpi_io_address) operand[2]->integer.value; - obj_desc->processor.length = (u8) operand[3]->integer.value; /* Install the processor object in the parent Node */ diff --git a/drivers/acpi/executer/exdump.c b/drivers/acpi/executer/exdump.c index 502293c35afa..56db58b8e23a 100644 --- a/drivers/acpi/executer/exdump.c +++ b/drivers/acpi/executer/exdump.c @@ -267,8 +267,6 @@ static struct acpi_exdump_info acpi_ex_dump_node[6] = { {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_node), NULL}, {ACPI_EXD_UINT8, ACPI_EXD_NSOFFSET(flags), "Flags"}, {ACPI_EXD_UINT8, ACPI_EXD_NSOFFSET(owner_id), "Owner Id"}, - {ACPI_EXD_UINT16, ACPI_EXD_NSOFFSET(reference_count), - "Reference Count"}, {ACPI_EXD_POINTER, ACPI_EXD_NSOFFSET(child), "Child List"}, {ACPI_EXD_POINTER, ACPI_EXD_NSOFFSET(peer), "Next Peer"} }; diff --git a/drivers/acpi/namespace/nsalloc.c b/drivers/acpi/namespace/nsalloc.c index acd4b6732ac4..8b921c96d6a5 100644 --- a/drivers/acpi/namespace/nsalloc.c +++ b/drivers/acpi/namespace/nsalloc.c @@ -47,9 +47,6 @@ #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsalloc") -/* Local prototypes */ -static void acpi_ns_remove_reference(struct acpi_namespace_node *node); - /******************************************************************************* * * FUNCTION: acpi_ns_create_node @@ -61,14 +58,13 @@ static void acpi_ns_remove_reference(struct acpi_namespace_node *node); * DESCRIPTION: Create a namespace node * ******************************************************************************/ - struct acpi_namespace_node *acpi_ns_create_node(u32 name) { struct acpi_namespace_node *node; ACPI_FUNCTION_TRACE("ns_create_node"); - node = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_namespace_node)); + node = acpi_os_acquire_object(acpi_gbl_namespace_cache); if (!node) { return_PTR(NULL); } @@ -76,9 +72,7 @@ struct acpi_namespace_node *acpi_ns_create_node(u32 name) ACPI_MEM_TRACKING(acpi_gbl_ns_node_list->total_allocated++); node->name.integer = name; - node->reference_count = 1; ACPI_SET_DESCRIPTOR_TYPE(node, ACPI_DESC_TYPE_NAMED); - return_PTR(node); } @@ -139,10 +133,10 @@ void acpi_ns_delete_node(struct acpi_namespace_node *node) ACPI_MEM_TRACKING(acpi_gbl_ns_node_list->total_freed++); /* - * Detach an object if there is one then delete the node + * Detach an object if there is one, then delete the node */ acpi_ns_detach_object(node); - ACPI_FREE(node); + (void)acpi_os_release_object(acpi_gbl_namespace_cache, node); return_VOID; } @@ -217,16 +211,6 @@ void acpi_ns_install_node(struct acpi_walk_state *walk_state, struct acpi_namesp acpi_ut_get_node_name(parent_node), acpi_ut_get_type_name(parent_node->type), parent_node)); - - /* - * Increment the reference count(s) of all parents up to - * the root! - */ - while ((node = acpi_ns_get_parent_node(node)) != NULL) { - node->reference_count++; - } - - return_VOID; } /******************************************************************************* @@ -246,7 +230,6 @@ void acpi_ns_delete_children(struct acpi_namespace_node *parent_node) { struct acpi_namespace_node *child_node; struct acpi_namespace_node *next_node; - struct acpi_namespace_node *node; u8 flags; ACPI_FUNCTION_TRACE_PTR("ns_delete_children", parent_node); @@ -292,26 +275,10 @@ void acpi_ns_delete_children(struct acpi_namespace_node *parent_node) */ acpi_ns_detach_object(child_node); - /* - * Decrement the reference count(s) of all parents up to - * the root! (counts were incremented when the node was created) - */ - node = child_node; - while ((node = acpi_ns_get_parent_node(node)) != NULL) { - node->reference_count--; - } - - /* There should be only one reference remaining on this node */ - - if (child_node->reference_count != 1) { - ACPI_WARNING((AE_INFO, - "Existing references (%d) on node being deleted (%p)", - child_node->reference_count, child_node)); - } - /* Now we can delete the node */ - ACPI_FREE(child_node); + (void)acpi_os_release_object(acpi_gbl_namespace_cache, + child_node); /* And move on to the next child in the list */ @@ -358,8 +325,9 @@ void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node) /* Get the next node in this scope (NULL if none) */ - child_node = acpi_ns_get_next_node(ACPI_TYPE_ANY, parent_node, - child_node); + child_node = + acpi_ns_get_next_node(ACPI_TYPE_ANY, parent_node, + child_node); if (child_node) { /* Found a child node - detach any attached object */ @@ -404,57 +372,6 @@ void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node) return_VOID; } -/******************************************************************************* - * - * FUNCTION: acpi_ns_remove_reference - * - * PARAMETERS: Node - Named node whose reference count is to be - * decremented - * - * RETURN: None. - * - * DESCRIPTION: Remove a Node reference. Decrements the reference count - * of all parent Nodes up to the root. Any node along - * the way that reaches zero references is freed. - * - ******************************************************************************/ - -static void acpi_ns_remove_reference(struct acpi_namespace_node *node) -{ - struct acpi_namespace_node *parent_node; - struct acpi_namespace_node *this_node; - - ACPI_FUNCTION_ENTRY(); - - /* - * Decrement the reference count(s) of this node and all - * nodes up to the root, Delete anything with zero remaining references. - */ - this_node = node; - while (this_node) { - - /* Prepare to move up to parent */ - - parent_node = acpi_ns_get_parent_node(this_node); - - /* Decrement the reference count on this node */ - - this_node->reference_count--; - - /* Delete the node if no more references */ - - if (!this_node->reference_count) { - - /* Delete all children and delete the node */ - - acpi_ns_delete_children(this_node); - acpi_ns_delete_node(this_node); - } - - this_node = parent_node; - } -} - /******************************************************************************* * * FUNCTION: acpi_ns_delete_namespace_by_owner @@ -482,9 +399,9 @@ void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id) return_VOID; } + deletion_node = NULL; parent_node = acpi_gbl_root_node; child_node = NULL; - deletion_node = NULL; level = 1; /* @@ -501,7 +418,8 @@ void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id) child_node); if (deletion_node) { - acpi_ns_remove_reference(deletion_node); + acpi_ns_delete_children(deletion_node); + acpi_ns_delete_node(deletion_node); deletion_node = NULL; } diff --git a/drivers/acpi/namespace/nsutils.c b/drivers/acpi/namespace/nsutils.c index 586014ecf24b..9fa38ffc2e6e 100644 --- a/drivers/acpi/namespace/nsutils.c +++ b/drivers/acpi/namespace/nsutils.c @@ -81,7 +81,7 @@ acpi_ns_report_error(char *module_name, u32 bad_name; char *name = NULL; - acpi_ut_report_error(module_name, line_number); + acpi_os_printf("ACPI Error (%s-%04d): ", module_name, line_number); if (lookup_status == AE_BAD_CHARACTER) { @@ -139,7 +139,7 @@ acpi_ns_report_method_error(char *module_name, acpi_status status; struct acpi_namespace_node *node = prefix_node; - acpi_ut_report_error(module_name, line_number); + acpi_os_printf("ACPI Error (%s-%04d): ", module_name, line_number); if (path) { status = acpi_ns_get_node_by_path(path, prefix_node, diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 56d97f1d108f..006b31a56559 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -1126,14 +1126,13 @@ acpi_status acpi_os_release_object(acpi_cache_t * cache, void *object) * * RETURN: Status * - * DESCRIPTION: Get an object from the specified cache. If cache is empty, - * the object is allocated. + * DESCRIPTION: Return a zero-filled object. * ******************************************************************************/ void *acpi_os_acquire_object(acpi_cache_t * cache) { - void *object = kmem_cache_alloc(cache, GFP_KERNEL); + void *object = kmem_cache_zalloc(cache, GFP_KERNEL); WARN_ON(!object); return object; } diff --git a/drivers/acpi/parser/psscope.c b/drivers/acpi/parser/psscope.c index edb7c9ba6ec2..9233a4044d6b 100644 --- a/drivers/acpi/parser/psscope.c +++ b/drivers/acpi/parser/psscope.c @@ -113,7 +113,7 @@ acpi_ps_init_scope(struct acpi_parse_state * parser_state, return_ACPI_STATUS(AE_NO_MEMORY); } - scope->common.data_type = ACPI_DESC_TYPE_STATE_RPSCOPE; + scope->common.descriptor_type = ACPI_DESC_TYPE_STATE_RPSCOPE; scope->parse_scope.op = root_op; scope->parse_scope.arg_count = ACPI_VAR_ARGS; scope->parse_scope.arg_end = parser_state->aml_end; @@ -143,7 +143,7 @@ acpi_ps_init_scope(struct acpi_parse_state * parser_state, acpi_status acpi_ps_push_scope(struct acpi_parse_state *parser_state, union acpi_parse_object *op, - u32 remaining_args, u32 arg_count) + u32 remaining_args, u8 arg_count) { union acpi_generic_state *scope; @@ -154,7 +154,7 @@ acpi_ps_push_scope(struct acpi_parse_state *parser_state, return_ACPI_STATUS(AE_NO_MEMORY); } - scope->common.data_type = ACPI_DESC_TYPE_STATE_PSCOPE; + scope->common.descriptor_type = ACPI_DESC_TYPE_STATE_PSCOPE; scope->parse_scope.op = op; scope->parse_scope.arg_list = remaining_args; scope->parse_scope.arg_count = arg_count; @@ -196,7 +196,7 @@ acpi_ps_push_scope(struct acpi_parse_state *parser_state, void acpi_ps_pop_scope(struct acpi_parse_state *parser_state, - union acpi_parse_object **op, u32 * arg_list, u32 * arg_count) + union acpi_parse_object **op, u32 * arg_list, u8 * arg_count) { union acpi_generic_state *scope = parser_state->scope; @@ -207,7 +207,7 @@ acpi_ps_pop_scope(struct acpi_parse_state *parser_state, if (scope->common.next) { scope = acpi_ut_pop_generic_state(&parser_state->scope); - /* return to parsing previous op */ + /* Return to parsing previous op */ *op = scope->parse_scope.op; *arg_list = scope->parse_scope.arg_list; @@ -218,7 +218,7 @@ acpi_ps_pop_scope(struct acpi_parse_state *parser_state, acpi_ut_delete_generic_state(scope); } else { - /* empty parse stack, prepare to fetch next opcode */ + /* Empty parse stack, prepare to fetch next opcode */ *op = NULL; *arg_list = 0; diff --git a/drivers/acpi/parser/psutils.c b/drivers/acpi/parser/psutils.c index a4c33a4bfe35..43e3190583e3 100644 --- a/drivers/acpi/parser/psutils.c +++ b/drivers/acpi/parser/psutils.c @@ -89,7 +89,7 @@ void acpi_ps_init_op(union acpi_parse_object *op, u16 opcode) { ACPI_FUNCTION_ENTRY(); - op->common.data_type = ACPI_DESC_TYPE_PARSER; + op->common.descriptor_type = ACPI_DESC_TYPE_PARSER; op->common.aml_opcode = opcode; ACPI_DISASM_ONLY_MEMBERS(ACPI_STRNCPY(op->common.aml_op_name, diff --git a/drivers/acpi/resources/rscalc.c b/drivers/acpi/resources/rscalc.c index 8e406d992f3b..dd5caa2c8fdd 100644 --- a/drivers/acpi/resources/rscalc.c +++ b/drivers/acpi/resources/rscalc.c @@ -456,7 +456,7 @@ acpi_rs_get_list_length(u8 * aml_buffer, *size_needed += buffer_size; ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, - "Type %.2X, Aml %.2X internal %.2X\n", + "Type %.2X, aml_length %.2X internal_length %.2X\n", acpi_ut_get_resource_type(aml_buffer), acpi_ut_get_descriptor_length(aml_buffer), buffer_size)); diff --git a/drivers/acpi/resources/rscreate.c b/drivers/acpi/resources/rscreate.c index 67c052af7bbe..01488cfc9bae 100644 --- a/drivers/acpi/resources/rscreate.c +++ b/drivers/acpi/resources/rscreate.c @@ -75,6 +75,7 @@ acpi_rs_create_resource_list(union acpi_operand_object *aml_buffer, u8 *aml_start; acpi_size list_size_needed = 0; u32 aml_buffer_length; + void *resource; ACPI_FUNCTION_TRACE("rs_create_resource_list"); @@ -107,8 +108,10 @@ acpi_rs_create_resource_list(union acpi_operand_object *aml_buffer, /* Do the conversion */ - status = acpi_rs_convert_aml_to_resources(aml_start, aml_buffer_length, - output_buffer->pointer); + resource = output_buffer->pointer; + status = acpi_ut_walk_aml_resources(aml_start, aml_buffer_length, + acpi_rs_convert_aml_to_resources, + &resource); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } diff --git a/drivers/acpi/resources/rslist.c b/drivers/acpi/resources/rslist.c index 6f2d8de39523..50bbb19bf4ae 100644 --- a/drivers/acpi/resources/rslist.c +++ b/drivers/acpi/resources/rslist.c @@ -51,92 +51,60 @@ ACPI_MODULE_NAME("rslist") * * FUNCTION: acpi_rs_convert_aml_to_resources * - * PARAMETERS: Aml - Pointer to the resource byte stream - * aml_length - Length of Aml - * output_buffer - Pointer to the buffer that will - * contain the output structures + * PARAMETERS: acpi_walk_aml_callback + * resource_ptr - Pointer to the buffer that will + * contain the output structures * * RETURN: Status * - * DESCRIPTION: Takes the resource byte stream and parses it, creating a - * linked list of resources in the caller's output buffer + * DESCRIPTION: Convert an AML resource to an internal representation of the + * resource that is aligned and easier to access. * ******************************************************************************/ acpi_status -acpi_rs_convert_aml_to_resources(u8 * aml, u32 aml_length, u8 * output_buffer) +acpi_rs_convert_aml_to_resources(u8 * aml, + u32 length, + u32 offset, + u8 resource_index, void **resource_ptr) { - struct acpi_resource *resource = (void *)output_buffer; + struct acpi_resource *resource = *resource_ptr; acpi_status status; - u8 resource_index; - u8 *end_aml; ACPI_FUNCTION_TRACE("rs_convert_aml_to_resources"); - end_aml = aml + aml_length; - - /* Loop until end-of-buffer or an end_tag is found */ - - while (aml < end_aml) { - /* - * Check that the input buffer and all subsequent pointers into it - * are aligned on a native word boundary. Most important on IA64 - */ - if (ACPI_IS_MISALIGNED(resource)) { - ACPI_WARNING((AE_INFO, - "Misaligned resource pointer %p", - resource)); - } - - /* Validate the Resource Type and Resource Length */ - - status = acpi_ut_validate_resource(aml, &resource_index); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* Convert the AML byte stream resource to a local resource struct */ - - status = - acpi_rs_convert_aml_to_resource(resource, - ACPI_CAST_PTR(union - aml_resource, - aml), - acpi_gbl_get_resource_dispatch - [resource_index]); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, - "Could not convert AML resource (Type %X)", - *aml)); - return_ACPI_STATUS(status); - } - - ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, - "Type %.2X, Aml %.2X internal %.2X\n", - acpi_ut_get_resource_type(aml), - acpi_ut_get_descriptor_length(aml), - resource->length)); - - /* Normal exit on completion of an end_tag resource descriptor */ - - if (acpi_ut_get_resource_type(aml) == - ACPI_RESOURCE_NAME_END_TAG) { - return_ACPI_STATUS(AE_OK); - } - - /* Point to the next input AML resource */ - - aml += acpi_ut_get_descriptor_length(aml); - - /* Point to the next structure in the output buffer */ + /* + * Check that the input buffer and all subsequent pointers into it + * are aligned on a native word boundary. Most important on IA64 + */ + if (ACPI_IS_MISALIGNED(resource)) { + ACPI_WARNING((AE_INFO, + "Misaligned resource pointer %p", resource)); + } - resource = - ACPI_ADD_PTR(struct acpi_resource, resource, - resource->length); + /* Convert the AML byte stream resource to a local resource struct */ + + status = + acpi_rs_convert_aml_to_resource(resource, + ACPI_CAST_PTR(union aml_resource, + aml), + acpi_gbl_get_resource_dispatch + [resource_index]); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, + "Could not convert AML resource (Type %X)", + *aml)); + return_ACPI_STATUS(status); } - /* Did not find an end_tag resource descriptor */ + ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, + "Type %.2X, aml_length %.2X internal_length %.2X\n", + acpi_ut_get_resource_type(aml), length, + resource->length)); - return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG); + /* Point to the next structure in the output buffer */ + + *resource_ptr = ACPI_ADD_PTR(void, resource, resource->length); + return_ACPI_STATUS(AE_OK); } /******************************************************************************* diff --git a/drivers/acpi/resources/rsxface.c b/drivers/acpi/resources/rsxface.c index b3feebbd8ca2..1d00d285a5a3 100644 --- a/drivers/acpi/resources/rsxface.c +++ b/drivers/acpi/resources/rsxface.c @@ -242,7 +242,7 @@ ACPI_EXPORT_SYMBOL(acpi_get_possible_resources) acpi_status acpi_walk_resources(acpi_handle device_handle, char *name, - ACPI_WALK_RESOURCE_CALLBACK user_function, void *context) + acpi_walk_resource_callback user_function, void *context) { acpi_status status; struct acpi_buffer buffer; @@ -469,7 +469,7 @@ ACPI_EXPORT_SYMBOL(acpi_get_vendor_resource) * * FUNCTION: acpi_rs_match_vendor_resource * - * PARAMETERS: ACPI_WALK_RESOURCE_CALLBACK + * PARAMETERS: acpi_walk_resource_callback * * RETURN: Status * diff --git a/drivers/acpi/utilities/utalloc.c b/drivers/acpi/utilities/utalloc.c index 7b35eb84d058..3b29aecaaca5 100644 --- a/drivers/acpi/utilities/utalloc.c +++ b/drivers/acpi/utilities/utalloc.c @@ -46,24 +46,6 @@ #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utalloc") -/* Local prototypes */ -#ifdef ACPI_DBG_TRACK_ALLOCATIONS -static struct acpi_debug_mem_block *acpi_ut_find_allocation(void *allocation); - -static acpi_status -acpi_ut_track_allocation(struct acpi_debug_mem_block *address, - acpi_size size, - u8 alloc_type, u32 component, char *module, u32 line); - -static acpi_status -acpi_ut_remove_allocation(struct acpi_debug_mem_block *address, - u32 component, char *module, u32 line); - -static acpi_status -acpi_ut_create_list(char *list_name, - u16 object_size, struct acpi_memory_list **return_cache); -#endif - /******************************************************************************* * * FUNCTION: acpi_ut_create_caches @@ -75,7 +57,6 @@ acpi_ut_create_list(char *list_name, * DESCRIPTION: Create all local caches * ******************************************************************************/ - acpi_status acpi_ut_create_caches(void) { acpi_status status; @@ -101,7 +82,16 @@ acpi_status acpi_ut_create_caches(void) /* Object Caches, for frequently used objects */ status = - acpi_os_create_cache("acpi_state", sizeof(union acpi_generic_state), + acpi_os_create_cache("Acpi-Namespace", + sizeof(struct acpi_namespace_node), + ACPI_MAX_NAMESPACE_CACHE_DEPTH, + &acpi_gbl_namespace_cache); + if (ACPI_FAILURE(status)) { + return (status); + } + + status = + acpi_os_create_cache("Acpi-State", sizeof(union acpi_generic_state), ACPI_MAX_STATE_CACHE_DEPTH, &acpi_gbl_state_cache); if (ACPI_FAILURE(status)) { @@ -109,7 +99,7 @@ acpi_status acpi_ut_create_caches(void) } status = - acpi_os_create_cache("acpi_parse", + acpi_os_create_cache("Acpi-Parse", sizeof(struct acpi_parse_obj_common), ACPI_MAX_PARSE_CACHE_DEPTH, &acpi_gbl_ps_node_cache); @@ -118,7 +108,7 @@ acpi_status acpi_ut_create_caches(void) } status = - acpi_os_create_cache("acpi_parse_ext", + acpi_os_create_cache("Acpi-parse_ext", sizeof(struct acpi_parse_obj_named), ACPI_MAX_EXTPARSE_CACHE_DEPTH, &acpi_gbl_ps_node_ext_cache); @@ -127,7 +117,7 @@ acpi_status acpi_ut_create_caches(void) } status = - acpi_os_create_cache("acpi_operand", + acpi_os_create_cache("Acpi-Operand", sizeof(union acpi_operand_object), ACPI_MAX_OBJECT_CACHE_DEPTH, &acpi_gbl_operand_cache); @@ -153,6 +143,9 @@ acpi_status acpi_ut_create_caches(void) acpi_status acpi_ut_delete_caches(void) { + (void)acpi_os_delete_cache(acpi_gbl_namespace_cache); + acpi_gbl_namespace_cache = NULL; + (void)acpi_os_delete_cache(acpi_gbl_state_cache); acpi_gbl_state_cache = NULL; @@ -288,7 +281,7 @@ acpi_ut_initialize_buffer(struct acpi_buffer * buffer, * * RETURN: Address of the allocated memory on success, NULL on failure. * - * DESCRIPTION: The subsystem's equivalent of malloc. + * DESCRIPTION: Subsystem equivalent of malloc. * ******************************************************************************/ @@ -301,8 +294,8 @@ void *acpi_ut_allocate(acpi_size size, u32 component, char *module, u32 line) /* Check for an inadvertent size of zero bytes */ if (!size) { - ACPI_ERROR((module, line, - "ut_allocate: Attempt to allocate zero bytes, allocating 1 byte")); + ACPI_WARNING((module, line, + "Attempt to allocate zero bytes, allocating 1 byte")); size = 1; } @@ -311,9 +304,8 @@ void *acpi_ut_allocate(acpi_size size, u32 component, char *module, u32 line) /* Report allocation error */ - ACPI_ERROR((module, line, - "ut_allocate: Could not allocate size %X", - (u32) size)); + ACPI_WARNING((module, line, + "Could not allocate size %X", (u32) size)); return_PTR(NULL); } @@ -323,7 +315,7 @@ void *acpi_ut_allocate(acpi_size size, u32 component, char *module, u32 line) /******************************************************************************* * - * FUNCTION: acpi_ut_callocate + * FUNCTION: acpi_ut_allocate_zeroed * * PARAMETERS: Size - Size of the allocation * Component - Component type of caller @@ -332,546 +324,24 @@ void *acpi_ut_allocate(acpi_size size, u32 component, char *module, u32 line) * * RETURN: Address of the allocated memory on success, NULL on failure. * - * DESCRIPTION: Subsystem equivalent of calloc. + * DESCRIPTION: Subsystem equivalent of calloc. Allocate and zero memory. * ******************************************************************************/ -void *acpi_ut_callocate(acpi_size size, u32 component, char *module, u32 line) +void *acpi_ut_allocate_zeroed(acpi_size size, + u32 component, char *module, u32 line) { void *allocation; - ACPI_FUNCTION_TRACE_U32("ut_callocate", size); - - /* Check for an inadvertent size of zero bytes */ - - if (!size) { - ACPI_ERROR((module, line, - "Attempt to allocate zero bytes, allocating 1 byte")); - size = 1; - } - - allocation = acpi_os_allocate(size); - if (!allocation) { - - /* Report allocation error */ - - ACPI_ERROR((module, line, - "Could not allocate size %X", (u32) size)); - return_PTR(NULL); - } - - /* Clear the memory block */ - - ACPI_MEMSET(allocation, 0, size); - return_PTR(allocation); -} - -#ifdef ACPI_DBG_TRACK_ALLOCATIONS -/* - * These procedures are used for tracking memory leaks in the subsystem, and - * they get compiled out when the ACPI_DBG_TRACK_ALLOCATIONS is not set. - * - * Each memory allocation is tracked via a doubly linked list. Each - * element contains the caller's component, module name, function name, and - * line number. acpi_ut_allocate and acpi_ut_callocate call - * acpi_ut_track_allocation to add an element to the list; deletion - * occurs in the body of acpi_ut_free. - */ - -/******************************************************************************* - * - * FUNCTION: acpi_ut_create_list - * - * PARAMETERS: cache_name - Ascii name for the cache - * object_size - Size of each cached object - * return_cache - Where the new cache object is returned - * - * RETURN: Status - * - * DESCRIPTION: Create a local memory list for tracking purposed - * - ******************************************************************************/ - -static acpi_status -acpi_ut_create_list(char *list_name, - u16 object_size, struct acpi_memory_list **return_cache) -{ - struct acpi_memory_list *cache; - - cache = acpi_os_allocate(sizeof(struct acpi_memory_list)); - if (!cache) { - return (AE_NO_MEMORY); - } - - ACPI_MEMSET(cache, 0, sizeof(struct acpi_memory_list)); - - cache->list_name = list_name; - cache->object_size = object_size; - - *return_cache = cache; - return (AE_OK); -} - -/******************************************************************************* - * - * FUNCTION: acpi_ut_allocate_and_track - * - * PARAMETERS: Size - Size of the allocation - * Component - Component type of caller - * Module - Source file name of caller - * Line - Line number of caller - * - * RETURN: Address of the allocated memory on success, NULL on failure. - * - * DESCRIPTION: The subsystem's equivalent of malloc. - * - ******************************************************************************/ - -void *acpi_ut_allocate_and_track(acpi_size size, - u32 component, char *module, u32 line) -{ - struct acpi_debug_mem_block *allocation; - acpi_status status; - - allocation = - acpi_ut_allocate(size + sizeof(struct acpi_debug_mem_header), - component, module, line); - if (!allocation) { - return (NULL); - } - - status = acpi_ut_track_allocation(allocation, size, - ACPI_MEM_MALLOC, component, module, - line); - if (ACPI_FAILURE(status)) { - acpi_os_free(allocation); - return (NULL); - } - - acpi_gbl_global_list->total_allocated++; - acpi_gbl_global_list->current_total_size += (u32) size; - - return ((void *)&allocation->user_space); -} - -/******************************************************************************* - * - * FUNCTION: acpi_ut_callocate_and_track - * - * PARAMETERS: Size - Size of the allocation - * Component - Component type of caller - * Module - Source file name of caller - * Line - Line number of caller - * - * RETURN: Address of the allocated memory on success, NULL on failure. - * - * DESCRIPTION: Subsystem equivalent of calloc. - * - ******************************************************************************/ - -void *acpi_ut_callocate_and_track(acpi_size size, - u32 component, char *module, u32 line) -{ - struct acpi_debug_mem_block *allocation; - acpi_status status; - - allocation = - acpi_ut_callocate(size + sizeof(struct acpi_debug_mem_header), - component, module, line); - if (!allocation) { - - /* Report allocation error */ - - ACPI_ERROR((module, line, - "Could not allocate size %X", (u32) size)); - return (NULL); - } - - status = acpi_ut_track_allocation(allocation, size, - ACPI_MEM_CALLOC, component, module, - line); - if (ACPI_FAILURE(status)) { - acpi_os_free(allocation); - return (NULL); - } - - acpi_gbl_global_list->total_allocated++; - acpi_gbl_global_list->current_total_size += (u32) size; - - return ((void *)&allocation->user_space); -} - -/******************************************************************************* - * - * FUNCTION: acpi_ut_free_and_track - * - * PARAMETERS: Allocation - Address of the memory to deallocate - * Component - Component type of caller - * Module - Source file name of caller - * Line - Line number of caller - * - * RETURN: None - * - * DESCRIPTION: Frees the memory at Allocation - * - ******************************************************************************/ - -void -acpi_ut_free_and_track(void *allocation, u32 component, char *module, u32 line) -{ - struct acpi_debug_mem_block *debug_block; - acpi_status status; - - ACPI_FUNCTION_TRACE_PTR("ut_free", allocation); - - if (NULL == allocation) { - ACPI_ERROR((module, line, "Attempt to delete a NULL address")); - - return_VOID; - } - - debug_block = ACPI_CAST_PTR(struct acpi_debug_mem_block, - (((char *)allocation) - - sizeof(struct acpi_debug_mem_header))); - - acpi_gbl_global_list->total_freed++; - acpi_gbl_global_list->current_total_size -= debug_block->size; - - status = acpi_ut_remove_allocation(debug_block, - component, module, line); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "Could not free memory")); - } - - acpi_os_free(debug_block); - ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "%p freed\n", allocation)); - return_VOID; -} - -/******************************************************************************* - * - * FUNCTION: acpi_ut_find_allocation - * - * PARAMETERS: Allocation - Address of allocated memory - * - * RETURN: A list element if found; NULL otherwise. - * - * DESCRIPTION: Searches for an element in the global allocation tracking list. - * - ******************************************************************************/ - -static struct acpi_debug_mem_block *acpi_ut_find_allocation(void *allocation) -{ - struct acpi_debug_mem_block *element; - ACPI_FUNCTION_ENTRY(); - element = acpi_gbl_global_list->list_head; - - /* Search for the address. */ - - while (element) { - if (element == allocation) { - return (element); - } - - element = element->next; - } - - return (NULL); -} - -/******************************************************************************* - * - * FUNCTION: acpi_ut_track_allocation - * - * PARAMETERS: Allocation - Address of allocated memory - * Size - Size of the allocation - * alloc_type - MEM_MALLOC or MEM_CALLOC - * Component - Component type of caller - * Module - Source file name of caller - * Line - Line number of caller - * - * RETURN: None. - * - * DESCRIPTION: Inserts an element into the global allocation tracking list. - * - ******************************************************************************/ - -static acpi_status -acpi_ut_track_allocation(struct acpi_debug_mem_block *allocation, - acpi_size size, - u8 alloc_type, u32 component, char *module, u32 line) -{ - struct acpi_memory_list *mem_list; - struct acpi_debug_mem_block *element; - acpi_status status = AE_OK; - - ACPI_FUNCTION_TRACE_PTR("ut_track_allocation", allocation); - - mem_list = acpi_gbl_global_list; - status = acpi_ut_acquire_mutex(ACPI_MTX_MEMORY); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* - * Search list for this address to make sure it is not already on the list. - * This will catch several kinds of problems. - */ - element = acpi_ut_find_allocation(allocation); - if (element) { - ACPI_ERROR((AE_INFO, - "ut_track_allocation: Allocation already present in list! (%p)", - allocation)); + allocation = acpi_ut_allocate(size, component, module, line); + if (allocation) { - ACPI_ERROR((AE_INFO, "Element %p Address %p", - element, allocation)); + /* Clear the memory block */ - goto unlock_and_exit; + ACPI_MEMSET(allocation, 0, size); } - /* Fill in the instance data. */ - - allocation->size = (u32) size; - allocation->alloc_type = alloc_type; - allocation->component = component; - allocation->line = line; - - ACPI_STRNCPY(allocation->module, module, ACPI_MAX_MODULE_NAME); - allocation->module[ACPI_MAX_MODULE_NAME - 1] = 0; - - /* Insert at list head */ - - if (mem_list->list_head) { - ((struct acpi_debug_mem_block *)(mem_list->list_head))-> - previous = allocation; - } - - allocation->next = mem_list->list_head; - allocation->previous = NULL; - - mem_list->list_head = allocation; - - unlock_and_exit: - status = acpi_ut_release_mutex(ACPI_MTX_MEMORY); - return_ACPI_STATUS(status); + return (allocation); } - -/******************************************************************************* - * - * FUNCTION: acpi_ut_remove_allocation - * - * PARAMETERS: Allocation - Address of allocated memory - * Component - Component type of caller - * Module - Source file name of caller - * Line - Line number of caller - * - * RETURN: - * - * DESCRIPTION: Deletes an element from the global allocation tracking list. - * - ******************************************************************************/ - -static acpi_status -acpi_ut_remove_allocation(struct acpi_debug_mem_block *allocation, - u32 component, char *module, u32 line) -{ - struct acpi_memory_list *mem_list; - acpi_status status; - - ACPI_FUNCTION_TRACE("ut_remove_allocation"); - - mem_list = acpi_gbl_global_list; - if (NULL == mem_list->list_head) { - - /* No allocations! */ - - ACPI_ERROR((module, line, - "Empty allocation list, nothing to free!")); - - return_ACPI_STATUS(AE_OK); - } - - status = acpi_ut_acquire_mutex(ACPI_MTX_MEMORY); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* Unlink */ - - if (allocation->previous) { - (allocation->previous)->next = allocation->next; - } else { - mem_list->list_head = allocation->next; - } - - if (allocation->next) { - (allocation->next)->previous = allocation->previous; - } - - /* Mark the segment as deleted */ - - ACPI_MEMSET(&allocation->user_space, 0xEA, allocation->size); - - ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "Freeing size 0%X\n", - allocation->size)); - - status = acpi_ut_release_mutex(ACPI_MTX_MEMORY); - return_ACPI_STATUS(status); -} - -/******************************************************************************* - * - * FUNCTION: acpi_ut_dump_allocation_info - * - * PARAMETERS: - * - * RETURN: None - * - * DESCRIPTION: Print some info about the outstanding allocations. - * - ******************************************************************************/ - -#ifdef ACPI_FUTURE_USAGE -void acpi_ut_dump_allocation_info(void) -{ -/* - struct acpi_memory_list *mem_list; -*/ - - ACPI_FUNCTION_TRACE("ut_dump_allocation_info"); - -/* - ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, - ("%30s: %4d (%3d Kb)\n", "Current allocations", - mem_list->current_count, - ROUND_UP_TO_1K (mem_list->current_size))); - - ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, - ("%30s: %4d (%3d Kb)\n", "Max concurrent allocations", - mem_list->max_concurrent_count, - ROUND_UP_TO_1K (mem_list->max_concurrent_size))); - - ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, - ("%30s: %4d (%3d Kb)\n", "Total (all) internal objects", - running_object_count, - ROUND_UP_TO_1K (running_object_size))); - - ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, - ("%30s: %4d (%3d Kb)\n", "Total (all) allocations", - running_alloc_count, - ROUND_UP_TO_1K (running_alloc_size))); - - ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, - ("%30s: %4d (%3d Kb)\n", "Current Nodes", - acpi_gbl_current_node_count, - ROUND_UP_TO_1K (acpi_gbl_current_node_size))); - - ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, - ("%30s: %4d (%3d Kb)\n", "Max Nodes", - acpi_gbl_max_concurrent_node_count, - ROUND_UP_TO_1K ((acpi_gbl_max_concurrent_node_count * - sizeof (struct acpi_namespace_node))))); -*/ - return_VOID; -} -#endif /* ACPI_FUTURE_USAGE */ - -/******************************************************************************* - * - * FUNCTION: acpi_ut_dump_allocations - * - * PARAMETERS: Component - Component(s) to dump info for. - * Module - Module to dump info for. NULL means all. - * - * RETURN: None - * - * DESCRIPTION: Print a list of all outstanding allocations. - * - ******************************************************************************/ - -void acpi_ut_dump_allocations(u32 component, char *module) -{ - struct acpi_debug_mem_block *element; - union acpi_descriptor *descriptor; - u32 num_outstanding = 0; - - ACPI_FUNCTION_TRACE("ut_dump_allocations"); - - /* - * Walk the allocation list. - */ - if (ACPI_FAILURE(acpi_ut_acquire_mutex(ACPI_MTX_MEMORY))) { - return; - } - - element = acpi_gbl_global_list->list_head; - while (element) { - if ((element->component & component) && - ((module == NULL) - || (0 == ACPI_STRCMP(module, element->module)))) { - - /* Ignore allocated objects that are in a cache */ - - descriptor = - ACPI_CAST_PTR(union acpi_descriptor, - &element->user_space); - if (descriptor->descriptor_id != ACPI_DESC_TYPE_CACHED) { - acpi_os_printf("%p Len %04X %9.9s-%d [%s] ", - descriptor, element->size, - element->module, element->line, - acpi_ut_get_descriptor_name - (descriptor)); - - /* Most of the elements will be Operand objects. */ - - switch (ACPI_GET_DESCRIPTOR_TYPE(descriptor)) { - case ACPI_DESC_TYPE_OPERAND: - acpi_os_printf("%12.12s R%hd", - acpi_ut_get_type_name - (descriptor->object. - common.type), - descriptor->object. - common.reference_count); - break; - - case ACPI_DESC_TYPE_PARSER: - acpi_os_printf("aml_opcode %04hX", - descriptor->op.asl. - aml_opcode); - break; - - case ACPI_DESC_TYPE_NAMED: - acpi_os_printf("%4.4s", - acpi_ut_get_node_name - (&descriptor->node)); - break; - - default: - break; - } - - acpi_os_printf("\n"); - num_outstanding++; - } - } - element = element->next; - } - - (void)acpi_ut_release_mutex(ACPI_MTX_MEMORY); - - /* Print summary */ - - if (!num_outstanding) { - ACPI_INFO((AE_INFO, "No outstanding allocations")); - } else { - ACPI_ERROR((AE_INFO, - "%d(%X) Outstanding allocations", - num_outstanding, num_outstanding)); - } - - return_VOID; -} - -#endif /* #ifdef ACPI_DBG_TRACK_ALLOCATIONS */ diff --git a/drivers/acpi/utilities/utcache.c b/drivers/acpi/utilities/utcache.c index 5d2f4b2802a5..593b08ccd6bf 100644 --- a/drivers/acpi/utilities/utcache.c +++ b/drivers/acpi/utilities/utcache.c @@ -272,9 +272,9 @@ void *acpi_os_acquire_object(struct acpi_memory_list *cache) cache->current_depth--; ACPI_MEM_TRACKING(cache->hits++); - ACPI_MEM_TRACKING(ACPI_DEBUG_PRINT((ACPI_DB_EXEC, - "Object %p from %s cache\n", - object, cache->list_name))); + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, + "Object %p from %s cache\n", object, + cache->list_name)); status = acpi_ut_release_mutex(ACPI_MTX_CACHES); if (ACPI_FAILURE(status)) { diff --git a/drivers/acpi/utilities/utdelete.c b/drivers/acpi/utilities/utdelete.c index 9c6867fcf009..51356e8eb999 100644 --- a/drivers/acpi/utilities/utdelete.c +++ b/drivers/acpi/utilities/utdelete.c @@ -200,8 +200,7 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object) */ handler_desc = object->region.handler; if (handler_desc) { - if (handler_desc->address_space. - hflags & + if (handler_desc->address_space.handler_flags & ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) { obj_pointer = second_desc->extra.region_context; diff --git a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c index 5bc8da7acc6c..8a05bb5ef4fe 100644 --- a/drivers/acpi/utilities/utglobal.c +++ b/drivers/acpi/utilities/utglobal.c @@ -191,12 +191,14 @@ const char *acpi_gbl_valid_osi_strings[ACPI_NUM_OSI_STRINGS] = { "Linux", "Windows 2000", "Windows 2001", - "Windows 2001.1", "Windows 2001 SP0", "Windows 2001 SP1", "Windows 2001 SP2", "Windows 2001 SP3", "Windows 2001 SP4", + "Windows 2001.1", + "Windows 2001.1 SP1", /* Added 03/2006 */ + "Windows 2006", /* Added 03/2006 */ /* Feature Group Strings */ @@ -633,7 +635,7 @@ char *acpi_ut_get_node_name(void *object) /* Descriptor must be a namespace node */ - if (node->descriptor != ACPI_DESC_TYPE_NAMED) { + if (ACPI_GET_DESCRIPTOR_TYPE(node) != ACPI_DESC_TYPE_NAMED) { return ("####"); } @@ -855,7 +857,7 @@ void acpi_ut_init_globals(void) acpi_gbl_root_node = NULL; acpi_gbl_root_node_struct.name.integer = ACPI_ROOT_NAME; - acpi_gbl_root_node_struct.descriptor = ACPI_DESC_TYPE_NAMED; + acpi_gbl_root_node_struct.descriptor_type = ACPI_DESC_TYPE_NAMED; acpi_gbl_root_node_struct.type = ACPI_TYPE_DEVICE; acpi_gbl_root_node_struct.child = NULL; acpi_gbl_root_node_struct.peer = NULL; diff --git a/drivers/acpi/utilities/utmisc.c b/drivers/acpi/utilities/utmisc.c index 77268ba86291..017a87ebc40b 100644 --- a/drivers/acpi/utilities/utmisc.c +++ b/drivers/acpi/utilities/utmisc.c @@ -881,36 +881,3 @@ acpi_ut_info(char *module_name, u32 line_number, char *format, ...) acpi_os_vprintf(format, args); acpi_os_printf(" [%X]\n", ACPI_CA_VERSION); } - -/******************************************************************************* - * - * FUNCTION: acpi_ut_report_error, Warning, Info - * - * PARAMETERS: module_name - Caller's module name (for error output) - * line_number - Caller's line number (for error output) - * - * RETURN: None - * - * DESCRIPTION: Print error message - * - * Note: Legacy only, should be removed when no longer used by drivers. - * - ******************************************************************************/ - -void acpi_ut_report_error(char *module_name, u32 line_number) -{ - - acpi_os_printf("ACPI Error (%s-%04d): ", module_name, line_number); -} - -void acpi_ut_report_warning(char *module_name, u32 line_number) -{ - - acpi_os_printf("ACPI Warning (%s-%04d): ", module_name, line_number); -} - -void acpi_ut_report_info(char *module_name, u32 line_number) -{ - - acpi_os_printf("ACPI (%s-%04d): ", module_name, line_number); -} diff --git a/drivers/acpi/utilities/utresrc.c b/drivers/acpi/utilities/utresrc.c index 27158dd0f877..4c24e6d5400a 100644 --- a/drivers/acpi/utilities/utresrc.c +++ b/drivers/acpi/utilities/utresrc.c @@ -238,6 +238,104 @@ static const u8 acpi_gbl_resource_types[] = { ACPI_FIXED_LENGTH }; +/******************************************************************************* + * + * FUNCTION: acpi_ut_walk_aml_resources + * + * PARAMETERS: Aml - Pointer to the raw AML resource template + * aml_length - Length of the entire template + * user_function - Called once for each descriptor found. If + * NULL, a pointer to the end_tag is returned + * Context - Passed to user_function + * + * RETURN: Status + * + * DESCRIPTION: Walk a raw AML resource list(buffer). User function called + * once for each resource found. + * + ******************************************************************************/ + +acpi_status +acpi_ut_walk_aml_resources(u8 * aml, + acpi_size aml_length, + acpi_walk_aml_callback user_function, void *context) +{ + acpi_status status; + u8 *end_aml; + u8 resource_index; + u32 length; + u32 offset = 0; + + ACPI_FUNCTION_TRACE("ut_walk_aml_resources"); + + /* The absolute minimum resource template is one end_tag descriptor */ + + if (aml_length < sizeof(struct aml_resource_end_tag)) { + return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG); + } + + /* Point to the end of the resource template buffer */ + + end_aml = aml + aml_length; + + /* Walk the byte list, abort on any invalid descriptor type or length */ + + while (aml < end_aml) { + + /* Validate the Resource Type and Resource Length */ + + status = acpi_ut_validate_resource(aml, &resource_index); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + /* Get the length of this descriptor */ + + length = acpi_ut_get_descriptor_length(aml); + + /* Invoke the user function */ + + if (user_function) { + status = + user_function(aml, length, offset, resource_index, + context); + if (ACPI_FAILURE(status)) { + return (status); + } + } + + /* An end_tag descriptor terminates this resource template */ + + if (acpi_ut_get_resource_type(aml) == + ACPI_RESOURCE_NAME_END_TAG) { + /* + * There must be at least one more byte in the buffer for + * the 2nd byte of the end_tag + */ + if ((aml + 1) >= end_aml) { + return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG); + } + + /* Return the pointer to the end_tag if requested */ + + if (!user_function) { + *(void **)context = aml; + } + + /* Normal exit */ + + return_ACPI_STATUS(AE_OK); + } + + aml += length; + offset += length; + } + + /* Did not find an end_tag descriptor */ + + return (AE_AML_NO_RESOURCE_END_TAG); +} + /******************************************************************************* * * FUNCTION: acpi_ut_validate_resource @@ -498,61 +596,21 @@ acpi_ut_get_resource_end_tag(union acpi_operand_object * obj_desc, u8 ** end_tag) { acpi_status status; - u8 *aml; - u8 *end_aml; ACPI_FUNCTION_TRACE("ut_get_resource_end_tag"); - /* Get start and end pointers */ - - aml = obj_desc->buffer.pointer; - end_aml = aml + obj_desc->buffer.length; - /* Allow a buffer length of zero */ if (!obj_desc->buffer.length) { - *end_tag = aml; + *end_tag = obj_desc->buffer.pointer; return_ACPI_STATUS(AE_OK); } - /* Walk the resource template, one descriptor per iteration */ - - while (aml < end_aml) { - - /* Validate the Resource Type and Resource Length */ - - status = acpi_ut_validate_resource(aml, NULL); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* end_tag resource indicates the end of the resource template */ - - if (acpi_ut_get_resource_type(aml) == - ACPI_RESOURCE_NAME_END_TAG) { - /* - * There must be at least one more byte in the buffer for - * the 2nd byte of the end_tag - */ - if ((aml + 1) >= end_aml) { - return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG); - } - - /* Return the pointer to the end_tag */ - - *end_tag = aml; - return_ACPI_STATUS(AE_OK); - } - - /* - * Point to the next resource descriptor in the AML buffer. The - * descriptor length is guaranteed to be non-zero by resource - * validation above. - */ - aml += acpi_ut_get_descriptor_length(aml); - } + /* Validate the template and get a pointer to the end_tag */ - /* Did not find an end_tag resource descriptor */ + status = acpi_ut_walk_aml_resources(obj_desc->buffer.pointer, + obj_desc->buffer.length, NULL, + end_tag); - return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG); + return_ACPI_STATUS(status); } diff --git a/drivers/acpi/utilities/utstate.c b/drivers/acpi/utilities/utstate.c index 69f2bfdc26ab..637c5f964879 100644 --- a/drivers/acpi/utilities/utstate.c +++ b/drivers/acpi/utilities/utstate.c @@ -162,7 +162,7 @@ union acpi_generic_state *acpi_ut_create_generic_state(void) /* Initialize */ memset(state, 0, sizeof(union acpi_generic_state)); - state->common.data_type = ACPI_DESC_TYPE_STATE; + state->common.descriptor_type = ACPI_DESC_TYPE_STATE; } return (state); @@ -196,7 +196,7 @@ struct acpi_thread_state *acpi_ut_create_thread_state(void) /* Init fields specific to the update struct */ - state->common.data_type = ACPI_DESC_TYPE_STATE_THREAD; + state->common.descriptor_type = ACPI_DESC_TYPE_STATE_THREAD; state->thread.thread_id = acpi_os_get_thread_id(); return_PTR((struct acpi_thread_state *)state); @@ -233,7 +233,7 @@ union acpi_generic_state *acpi_ut_create_update_state(union acpi_operand_object /* Init fields specific to the update struct */ - state->common.data_type = ACPI_DESC_TYPE_STATE_UPDATE; + state->common.descriptor_type = ACPI_DESC_TYPE_STATE_UPDATE; state->update.object = object; state->update.value = action; @@ -270,7 +270,7 @@ union acpi_generic_state *acpi_ut_create_pkg_state(void *internal_object, /* Init fields specific to the update struct */ - state->common.data_type = ACPI_DESC_TYPE_STATE_PACKAGE; + state->common.descriptor_type = ACPI_DESC_TYPE_STATE_PACKAGE; state->pkg.source_object = (union acpi_operand_object *)internal_object; state->pkg.dest_object = external_object; state->pkg.index = index; @@ -307,7 +307,7 @@ union acpi_generic_state *acpi_ut_create_control_state(void) /* Init fields specific to the control struct */ - state->common.data_type = ACPI_DESC_TYPE_STATE_CONTROL; + state->common.descriptor_type = ACPI_DESC_TYPE_STATE_CONTROL; state->common.state = ACPI_CONTROL_CONDITIONAL_EXECUTING; return_PTR(state); diff --git a/include/acpi/acconfig.h b/include/acpi/acconfig.h index ebe793fc137f..f3acfd9249fc 100644 --- a/include/acpi/acconfig.h +++ b/include/acpi/acconfig.h @@ -63,7 +63,7 @@ /* Current ACPICA subsystem version in YYYYMMDD format */ -#define ACPI_CA_VERSION 0x20060310 +#define ACPI_CA_VERSION 0x20060317 /* * OS name, used for the _OS object. The _OS object is essentially obsolete, @@ -81,6 +81,7 @@ #define ACPI_MAX_PARSE_CACHE_DEPTH 96 /* Parse tree objects */ #define ACPI_MAX_EXTPARSE_CACHE_DEPTH 96 /* Parse tree objects */ #define ACPI_MAX_OBJECT_CACHE_DEPTH 96 /* Interpreter operand objects */ +#define ACPI_MAX_NAMESPACE_CACHE_DEPTH 96 /* Namespace objects */ /* * Should the subsystem abort the loading of an ACPI table if the @@ -189,7 +190,7 @@ /* Number of strings associated with the _OSI reserved method */ -#define ACPI_NUM_OSI_STRINGS 10 +#define ACPI_NUM_OSI_STRINGS 12 /****************************************************************************** * diff --git a/include/acpi/acevents.h b/include/acpi/acevents.h index f2717be4fe0d..272bd0480ec7 100644 --- a/include/acpi/acevents.h +++ b/include/acpi/acevents.h @@ -93,7 +93,7 @@ struct acpi_gpe_event_info *acpi_ev_get_gpe_event_info(acpi_handle gpe_device, */ u8 acpi_ev_valid_gpe_event(struct acpi_gpe_event_info *gpe_event_info); -acpi_status acpi_ev_walk_gpe_list(ACPI_GPE_CALLBACK gpe_walk_callback); +acpi_status acpi_ev_walk_gpe_list(acpi_gpe_callback gpe_walk_callback); acpi_status acpi_ev_delete_gpe_handlers(struct acpi_gpe_xrupt_info *gpe_xrupt_info, diff --git a/include/acpi/acglobal.h b/include/acpi/acglobal.h index 734cc77bf2c7..f9eb5925511f 100644 --- a/include/acpi/acglobal.h +++ b/include/acpi/acglobal.h @@ -203,6 +203,7 @@ ACPI_EXTERN struct acpi_memory_list *acpi_gbl_ns_node_list; /* Object caches */ +ACPI_EXTERN acpi_cache_t *acpi_gbl_namespace_cache; ACPI_EXTERN acpi_cache_t *acpi_gbl_state_cache; ACPI_EXTERN acpi_cache_t *acpi_gbl_ps_node_cache; ACPI_EXTERN acpi_cache_t *acpi_gbl_ps_node_ext_cache; diff --git a/include/acpi/aclocal.h b/include/acpi/aclocal.h index 94fbf96ed3df..5956431784d5 100644 --- a/include/acpi/aclocal.h +++ b/include/acpi/aclocal.h @@ -44,7 +44,10 @@ #ifndef __ACLOCAL_H__ #define __ACLOCAL_H__ +/* acpisrc:struct_defs -- for acpisrc conversion */ + #define ACPI_WAIT_FOREVER 0xFFFF /* u16, as per ACPI spec */ +#define ACPI_INFINITE_CONCURRENCY 0xFF typedef void *acpi_mutex; typedef u32 acpi_mutex_handle; @@ -144,6 +147,8 @@ struct acpi_mutex_info { #define ACPI_FIELD_DWORD_GRANULARITY 4 #define ACPI_FIELD_QWORD_GRANULARITY 8 +#define ACPI_ENTRY_NOT_FOUND NULL + /***************************************************************************** * * Namespace typedefs and structs @@ -158,49 +163,45 @@ typedef enum { ACPI_IMODE_EXECUTE = 0x0E } acpi_interpreter_mode; -/* - * The Node describes a named object that appears in the AML - * An acpi_node is used to store Nodes. - * - * data_type is used to differentiate between internal descriptors, and MUST - * be the first byte in this structure. - */ union acpi_name_union { u32 integer; char ascii[4]; }; +/* + * The Namespace Node describes a named object that appears in the AML. + * descriptor_type is used to differentiate between internal descriptors. + * + * The node is optimized for both 32-bit and 64-bit platforms: + * 20 bytes for the 32-bit case, 32 bytes for the 64-bit case. + */ struct acpi_namespace_node { - u8 descriptor; /* Used to differentiate object descriptor types */ - u8 type; /* Type associated with this name */ - u16 reference_count; /* Current count of references and children */ + union acpi_operand_object *object; /* Interpreter object */ + u8 descriptor_type; /* Differentiate object descriptor types */ + u8 flags; /* Miscellaneous flags */ + acpi_owner_id owner_id; /* Node creator */ + u8 type; /* ACPI Type associated with this name */ union acpi_name_union name; /* ACPI Name, always 4 chars per ACPI spec */ - union acpi_operand_object *object; /* Pointer to attached ACPI object (optional) */ struct acpi_namespace_node *child; /* First child */ - struct acpi_namespace_node *peer; /* Next peer */ - u8 owner_id; /* Who created this node */ - u8 flags; + struct acpi_namespace_node *peer; /* Peer. Parent if ANOBJ_END_OF_PEER_LIST set */ - /* Fields used by the ASL compiler and disassembler only */ + /* Fields used by the ASL compiler and disassembler only: */ #ifdef ACPI_LARGE_NAMESPACE_NODE - u32 value; union acpi_parse_object *op; + u32 value; #endif }; -#define ACPI_ENTRY_NOT_FOUND NULL - -/* Node flags */ +/* Namespace Node flags */ -#define ANOBJ_RESERVED 0x01 -#define ANOBJ_END_OF_PEER_LIST 0x02 -#define ANOBJ_DATA_WIDTH_32 0x04 /* Parent table is 64-bits */ -#define ANOBJ_METHOD_ARG 0x08 -#define ANOBJ_METHOD_LOCAL 0x10 -#define ANOBJ_METHOD_NO_RETVAL 0x20 -#define ANOBJ_METHOD_SOME_NO_RETVAL 0x40 -#define ANOBJ_IS_BIT_OFFSET 0x80 +#define ANOBJ_END_OF_PEER_LIST 0x01 /* End-of-list, Peer field points to parent */ +#define ANOBJ_DATA_WIDTH_32 0x02 /* Parent table uses 32-bit math */ +#define ANOBJ_METHOD_ARG 0x04 /* Node is a method argument */ +#define ANOBJ_METHOD_LOCAL 0x08 /* Node is a method local */ +#define ANOBJ_METHOD_NO_RETVal 0x10 /* i_aSL only: Method has no return value */ +#define ANOBJ_METHOD_SOME_NO_RETVal 0x20 /* i_aSL only: Method has at least one return value */ +#define ANOBJ_IS_BIT_OFFSet 0x40 /* i_aSL only: Reference is a bit offset */ /* * ACPI Table Descriptor. One per ACPI table @@ -212,8 +213,8 @@ struct acpi_table_desc { struct acpi_table_header *pointer; u8 *aml_start; u64 physical_address; - u32 aml_length; acpi_size length; + u32 aml_length; acpi_owner_id owner_id; u8 type; u8 allocation; @@ -276,6 +277,9 @@ struct acpi_create_field_info { u8 field_type; }; +typedef +acpi_status(*ACPI_INTERNAL_METHOD) (struct acpi_walk_state * walk_state); + /* * Bitmapped ACPI types. Used internally only */ @@ -377,7 +381,7 @@ struct acpi_gpe_walk_info { struct acpi_gpe_block_info *gpe_block; }; -typedef acpi_status(*ACPI_GPE_CALLBACK) (struct acpi_gpe_xrupt_info * +typedef acpi_status(*acpi_gpe_callback) (struct acpi_gpe_xrupt_info * gpe_xrupt_info, struct acpi_gpe_block_info * gpe_block); @@ -416,13 +420,14 @@ struct acpi_field_info { #define ACPI_CONTROL_PREDICATE_FALSE 0xC3 #define ACPI_CONTROL_PREDICATE_TRUE 0xC4 -#define ACPI_STATE_COMMON /* Two 32-bit fields and a pointer */\ - u8 data_type; /* To differentiate various internal objs */\ - u8 flags; \ - u16 value; \ - u16 state; \ - u16 reserved; \ - void *next; +#define ACPI_STATE_COMMON \ + void *next; \ + u8 descriptor_type; /* To differentiate various internal objs */\ + u8 flags; \ + u16 value; \ + u16 state; + + /* There are 2 bytes available here until the next natural alignment boundary */ struct acpi_common_state { ACPI_STATE_COMMON}; @@ -438,12 +443,12 @@ struct acpi_update_state { * Pkg state - used to traverse nested package structures */ struct acpi_pkg_state { - ACPI_STATE_COMMON union acpi_operand_object *source_object; + ACPI_STATE_COMMON u16 index; + union acpi_operand_object *source_object; union acpi_operand_object *dest_object; struct acpi_walk_state *walk_state; void *this_target_obj; u32 num_packages; - u16 index; }; /* @@ -451,10 +456,10 @@ struct acpi_pkg_state { * Allows nesting of these constructs */ struct acpi_control_state { - ACPI_STATE_COMMON union acpi_parse_object *predicate_op; + ACPI_STATE_COMMON u16 opcode; + union acpi_parse_object *predicate_op; u8 *aml_predicate_start; /* Start of if/while predicate */ u8 *package_end; /* End of if/while block */ - u16 opcode; }; /* @@ -465,11 +470,11 @@ struct acpi_scope_state { }; struct acpi_pscope_state { - ACPI_STATE_COMMON union acpi_parse_object *op; /* Current op being parsed */ + ACPI_STATE_COMMON u8 arg_count; /* Number of fixed arguments */ + union acpi_parse_object *op; /* Current op being parsed */ u8 *arg_end; /* Current argument end */ u8 *pkg_end; /* Current package end */ u32 arg_list; /* Next argument to parse */ - u32 arg_count; /* Number of fixed arguments */ }; /* @@ -477,10 +482,10 @@ struct acpi_pscope_state { * states are created when there are nested control methods executing. */ struct acpi_thread_state { - ACPI_STATE_COMMON struct acpi_walk_state *walk_state_list; /* Head of list of walk_states for this thread */ + ACPI_STATE_COMMON u8 current_sync_level; /* Mutex Sync (nested acquire) level */ + struct acpi_walk_state *walk_state_list; /* Head of list of walk_states for this thread */ union acpi_operand_object *acquired_mutex_list; /* List of all currently acquired mutexes */ acpi_thread_id thread_id; /* Running thread ID */ - u8 current_sync_level; /* Mutex Sync (nested acquire) level */ }; /* @@ -488,10 +493,9 @@ struct acpi_thread_state { * AML arguments */ struct acpi_result_values { - ACPI_STATE_COMMON - union acpi_operand_object *obj_desc[ACPI_OBJ_NUM_OPERANDS]; - u8 num_results; + ACPI_STATE_COMMON u8 num_results; u8 last_insert; + union acpi_operand_object *obj_desc[ACPI_OBJ_NUM_OPERANDS]; }; typedef @@ -546,7 +550,7 @@ struct acpi_opcode_info { #endif u32 parse_args; /* Grammar/Parse time arguments */ u32 runtime_args; /* Interpret time arguments */ - u32 flags; /* Misc flags */ + u16 flags; /* Misc flags */ u8 object_type; /* Corresponding internal object type */ u8 class; /* Opcode class */ u8 type; /* Opcode type */ @@ -563,29 +567,28 @@ union acpi_parse_value { }; #define ACPI_PARSE_COMMON \ - u8 data_type; /* To differentiate various internal objs */\ - u8 flags; /* Type of Op */\ - u16 aml_opcode; /* AML opcode */\ - u32 aml_offset; /* Offset of declaration in AML */\ - union acpi_parse_object *parent; /* Parent op */\ - union acpi_parse_object *next; /* Next op */\ + union acpi_parse_object *parent; /* Parent op */\ + u8 descriptor_type; /* To differentiate various internal objs */\ + u8 flags; /* Type of Op */\ + u16 aml_opcode; /* AML opcode */\ + u32 aml_offset; /* Offset of declaration in AML */\ + union acpi_parse_object *next; /* Next op */\ + struct acpi_namespace_node *node; /* For use by interpreter */\ + union acpi_parse_value value; /* Value or args associated with the opcode */\ ACPI_DISASM_ONLY_MEMBERS (\ - u8 disasm_flags; /* Used during AML disassembly */\ - u8 disasm_opcode; /* Subtype used for disassembly */\ - char aml_op_name[16]) /* Op name (debug only) */\ - /* NON-DEBUG members below: */\ - struct acpi_namespace_node *node; /* For use by interpreter */\ - union acpi_parse_value value; /* Value or args associated with the opcode */ - -#define ACPI_DASM_BUFFER 0x00 -#define ACPI_DASM_RESOURCE 0x01 -#define ACPI_DASM_STRING 0x02 -#define ACPI_DASM_UNICODE 0x03 -#define ACPI_DASM_EISAID 0x04 -#define ACPI_DASM_MATCHOP 0x05 + u8 disasm_flags; /* Used during AML disassembly */\ + u8 disasm_opcode; /* Subtype used for disassembly */\ + char aml_op_name[16]) /* Op name (debug only) */ + +#define ACPI_DASM_BUFFER 0x00 +#define ACPI_DASM_RESOURCE 0x01 +#define ACPI_DASM_STRING 0x02 +#define ACPI_DASM_UNICODE 0x03 +#define ACPI_DASM_EISAID 0x04 +#define ACPI_DASM_MATCHOP 0x05 /* - * generic operation (for example: If, While, Store) + * Generic operation (for example: If, While, Store) */ struct acpi_parse_obj_common { ACPI_PARSE_COMMON}; @@ -601,7 +604,7 @@ struct acpi_parse_obj_named { u32 name; /* 4-byte name or zero if no name */ }; -/* The parse node is the fundamental element of the parse tree */ +/* this version is used by the i_aSL compiler only */ #define ACPI_MAX_PARSEOP_NAME 20 @@ -643,7 +646,6 @@ union acpi_parse_object { * method. */ struct acpi_parse_state { - u32 aml_size; u8 *aml_start; /* First AML byte */ u8 *aml; /* Next AML byte */ u8 *aml_end; /* (last + 1) AML byte */ @@ -653,22 +655,23 @@ struct acpi_parse_state { struct acpi_namespace_node *start_node; union acpi_generic_state *scope; /* Current scope */ union acpi_parse_object *start_scope; + u32 aml_size; }; /* Parse object flags */ -#define ACPI_PARSEOP_GENERIC 0x01 -#define ACPI_PARSEOP_NAMED 0x02 -#define ACPI_PARSEOP_DEFERRED 0x04 -#define ACPI_PARSEOP_BYTELIST 0x08 -#define ACPI_PARSEOP_IN_CACHE 0x80 +#define ACPI_PARSEOP_GENERIC 0x01 +#define ACPI_PARSEOP_NAMED 0x02 +#define ACPI_PARSEOP_DEFERRED 0x04 +#define ACPI_PARSEOP_BYTELIST 0x08 +#define ACPI_PARSEOP_IN_CACHE 0x80 /* Parse object disasm_flags */ -#define ACPI_PARSEOP_IGNORE 0x01 -#define ACPI_PARSEOP_PARAMLIST 0x02 -#define ACPI_PARSEOP_EMPTY_TERMLIST 0x04 -#define ACPI_PARSEOP_SPECIAL 0x10 +#define ACPI_PARSEOP_IGNORE 0x01 +#define ACPI_PARSEOP_PARAMLIST 0x02 +#define ACPI_PARSEOP_EMPTY_TERMLIST 0x04 +#define ACPI_PARSEOP_SPECIAL 0x10 /***************************************************************************** * @@ -676,8 +679,8 @@ struct acpi_parse_state { * ****************************************************************************/ -#define PCI_ROOT_HID_STRING "PNP0A03" -#define PCI_EXPRESS_ROOT_HID_STRING "PNP0A08" +#define PCI_ROOT_HID_STRING "PNP0A03" +#define PCI_EXPRESS_ROOT_HID_STRING "PNP0A08" struct acpi_bit_register_info { u8 parent_register; @@ -710,13 +713,14 @@ struct acpi_bit_register_info { #define ACPI_BITMASK_PCIEXP_WAKE_STATUS 0x4000 /* ACPI 3.0 */ #define ACPI_BITMASK_WAKE_STATUS 0x8000 -#define ACPI_BITMASK_ALL_FIXED_STATUS (ACPI_BITMASK_TIMER_STATUS | \ - ACPI_BITMASK_BUS_MASTER_STATUS | \ - ACPI_BITMASK_GLOBAL_LOCK_STATUS | \ - ACPI_BITMASK_POWER_BUTTON_STATUS | \ - ACPI_BITMASK_SLEEP_BUTTON_STATUS | \ - ACPI_BITMASK_RT_CLOCK_STATUS | \ - ACPI_BITMASK_WAKE_STATUS) +#define ACPI_BITMASK_ALL_FIXED_STATUS (\ + ACPI_BITMASK_TIMER_STATUS | \ + ACPI_BITMASK_BUS_MASTER_STATUS | \ + ACPI_BITMASK_GLOBAL_LOCK_STATUS | \ + ACPI_BITMASK_POWER_BUTTON_STATUS | \ + ACPI_BITMASK_SLEEP_BUTTON_STATUS | \ + ACPI_BITMASK_RT_CLOCK_STATUS | \ + ACPI_BITMASK_WAKE_STATUS) #define ACPI_BITMASK_TIMER_ENABLE 0x0001 #define ACPI_BITMASK_GLOBAL_LOCK_ENABLE 0x0020 @@ -820,7 +824,7 @@ struct acpi_bit_register_info { * ****************************************************************************/ -#define ACPI_ASCII_ZERO 0x30 +#define ACPI_ASCII_ZERO 0x30 /***************************************************************************** * @@ -842,9 +846,9 @@ struct acpi_integrity_info { u32 objects; }; -#define ACPI_DB_REDIRECTABLE_OUTPUT 0x01 -#define ACPI_DB_CONSOLE_OUTPUT 0x02 -#define ACPI_DB_DUPLICATE_OUTPUT 0x03 +#define ACPI_DB_REDIRECTABLE_OUTPUT 0x01 +#define ACPI_DB_CONSOLE_OUTPUT 0x02 +#define ACPI_DB_DUPLICATE_OUTPUT 0x03 /***************************************************************************** * @@ -854,18 +858,18 @@ struct acpi_integrity_info { /* Entry for a memory allocation (debug only) */ -#define ACPI_MEM_MALLOC 0 -#define ACPI_MEM_CALLOC 1 -#define ACPI_MAX_MODULE_NAME 16 +#define ACPI_MEM_MALLOC 0 +#define ACPI_MEM_CALLOC 1 +#define ACPI_MAX_MODULE_NAME 16 #define ACPI_COMMON_DEBUG_MEM_HEADER \ - struct acpi_debug_mem_block *previous; \ - struct acpi_debug_mem_block *next; \ - u32 size; \ - u32 component; \ - u32 line; \ - char module[ACPI_MAX_MODULE_NAME]; \ - u8 alloc_type; + struct acpi_debug_mem_block *previous; \ + struct acpi_debug_mem_block *next; \ + u32 size; \ + u32 component; \ + u32 line; \ + char module[ACPI_MAX_MODULE_NAME]; \ + u8 alloc_type; struct acpi_debug_mem_header { ACPI_COMMON_DEBUG_MEM_HEADER}; diff --git a/include/acpi/acmacros.h b/include/acpi/acmacros.h index c8aa73fc6dd3..c495670aa11a 100644 --- a/include/acpi/acmacros.h +++ b/include/acpi/acmacros.h @@ -400,8 +400,8 @@ * * The "Descriptor" field is the first field in both structures. */ -#define ACPI_GET_DESCRIPTOR_TYPE(d) (((union acpi_descriptor *)(void *)(d))->descriptor_id) -#define ACPI_SET_DESCRIPTOR_TYPE(d,t) (((union acpi_descriptor *)(void *)(d))->descriptor_id = t) +#define ACPI_GET_DESCRIPTOR_TYPE(d) (((union acpi_descriptor *)(void *)(d))->common.descriptor_type) +#define ACPI_SET_DESCRIPTOR_TYPE(d,t) (((union acpi_descriptor *)(void *)(d))->common.descriptor_type = t) /* Macro to test the object type */ @@ -490,7 +490,6 @@ #define ACPI_ERROR(plist) #define ACPI_ERROR_NAMESPACE(s,e) #define ACPI_ERROR_METHOD(s,n,p,e) - #endif /* @@ -532,13 +531,13 @@ #endif #define ACPI_FUNCTION_TRACE(a) ACPI_FUNCTION_NAME(a) \ - acpi_ut_trace(ACPI_DEBUG_PARAMETERS) + acpi_ut_trace(ACPI_DEBUG_PARAMETERS) #define ACPI_FUNCTION_TRACE_PTR(a,b) ACPI_FUNCTION_NAME(a) \ - acpi_ut_trace_ptr(ACPI_DEBUG_PARAMETERS,(void *)b) + acpi_ut_trace_ptr(ACPI_DEBUG_PARAMETERS,(void *)b) #define ACPI_FUNCTION_TRACE_U32(a,b) ACPI_FUNCTION_NAME(a) \ - acpi_ut_trace_u32(ACPI_DEBUG_PARAMETERS,(u32)b) + acpi_ut_trace_u32(ACPI_DEBUG_PARAMETERS,(u32)b) #define ACPI_FUNCTION_TRACE_STR(a,b) ACPI_FUNCTION_NAME(a) \ - acpi_ut_trace_str(ACPI_DEBUG_PARAMETERS,(char *)b) + acpi_ut_trace_str(ACPI_DEBUG_PARAMETERS,(char *)b) #define ACPI_FUNCTION_ENTRY() acpi_ut_track_stack_ptr() @@ -658,6 +657,7 @@ #define ACPI_DUMP_STACK_ENTRY(a) #define ACPI_DUMP_OPERANDS(a,b,c,d,e) #define ACPI_DUMP_ENTRY(a,b) +#define ACPI_DUMP_TABLES(a,b) #define ACPI_DUMP_PATHNAME(a,b,c,d) #define ACPI_DUMP_RESOURCE_LIST(a) #define ACPI_DUMP_BUFFER(a,b) @@ -714,7 +714,7 @@ /* Memory allocation */ #define ACPI_ALLOCATE(a) acpi_ut_allocate((acpi_size)(a),_COMPONENT,_acpi_module_name,__LINE__) -#define ACPI_ALLOCATE_ZEROED(a) acpi_ut_callocate((acpi_size)(a), _COMPONENT,_acpi_module_name,__LINE__) +#define ACPI_ALLOCATE_ZEROED(a) acpi_ut_allocate_zeroed((acpi_size)(a), _COMPONENT,_acpi_module_name,__LINE__) #define ACPI_FREE(a) acpi_os_free(a) #define ACPI_MEM_TRACKING(a) @@ -723,9 +723,9 @@ /* Memory allocation */ #define ACPI_ALLOCATE(a) acpi_ut_allocate_and_track((acpi_size)(a),_COMPONENT,_acpi_module_name,__LINE__) -#define ACPI_ALLOCATE_ZEROED(a) acpi_ut_callocate_and_track((acpi_size)(a), _COMPONENT,_acpi_module_name,__LINE__) +#define ACPI_ALLOCATE_ZEROED(a) acpi_ut_allocate_zeroed_and_track((acpi_size)(a), _COMPONENT,_acpi_module_name,__LINE__) #define ACPI_FREE(a) acpi_ut_free_and_track(a,_COMPONENT,_acpi_module_name,__LINE__) -#define ACPI_MEM_TRACKING(a) a +#define ACPI_MEM_TRACKING(a) a #endif /* ACPI_DBG_TRACK_ALLOCATIONS */ diff --git a/include/acpi/acobject.h b/include/acpi/acobject.h index d130cfed8d55..28241aa15de9 100644 --- a/include/acpi/acobject.h +++ b/include/acpi/acobject.h @@ -1,7 +1,7 @@ /****************************************************************************** * - * Name: acobject.h - Definition of union acpi_operand_object (Internal object only) + * Name: acobject.h - Definition of union acpi_operand_object (Internal object only) * *****************************************************************************/ @@ -45,10 +45,12 @@ #ifndef _ACOBJECT_H #define _ACOBJECT_H +/* acpisrc:struct_defs -- for acpisrc conversion */ + /* - * The union acpi_operand_object is used to pass AML operands from the dispatcher + * The union acpi_operand_object is used to pass AML operands from the dispatcher * to the interpreter, and to keep track of the various handlers such as - * address space handlers and notify handlers. The object is a constant + * address space handlers and notify handlers. The object is a constant * size in order to allow it to be cached and reused. */ @@ -61,17 +63,21 @@ /* * Common area for all objects. * - * data_type is used to differentiate between internal descriptors, and MUST - * be the first byte in this structure. + * descriptor_type is used to differentiate between internal descriptors, and + * must be in the same place across all descriptors */ -#define ACPI_OBJECT_COMMON_HEADER /* SIZE/ALIGNMENT: 32 bits, one ptr plus trailing 8-bit flag */\ - u8 descriptor; /* To differentiate various internal objs */\ - u8 type; /* acpi_object_type */\ - u16 reference_count; /* For object deletion management */\ - union acpi_operand_object *next_object; /* Objects linked to parent NS node */\ - u8 flags; - -/* Values for flag byte above */ +#define ACPI_OBJECT_COMMON_HEADER \ + union acpi_operand_object *next_object; /* Objects linked to parent NS node */\ + u8 descriptor_type; /* To differentiate various internal objs */\ + u8 type; /* acpi_object_type */\ + u16 reference_count; /* For object deletion management */\ + u8 flags; + /* + * Note: There are 3 bytes available here before the + * next natural alignment boundary (for both 32/64 cases) + */ + +/* Values for Flag byte above */ #define AOPOBJ_AML_CONSTANT 0x01 #define AOPOBJ_STATIC_POINTER 0x02 @@ -80,36 +86,6 @@ #define AOPOBJ_SETUP_COMPLETE 0x10 #define AOPOBJ_SINGLE_DATUM 0x20 -/* - * Common bitfield for the field objects - * "Field Datum" -- a datum from the actual field object - * "Buffer Datum" -- a datum from a user buffer, read from or to be written to the field - */ -#define ACPI_COMMON_FIELD_INFO /* SIZE/ALIGNMENT: 24 bits + three 32-bit values */\ - u8 field_flags; /* Access, update, and lock bits */\ - u8 attribute; /* From access_as keyword */\ - u8 access_byte_width; /* Read/Write size in bytes */\ - u32 bit_length; /* Length of field in bits */\ - u32 base_byte_offset; /* Byte offset within containing object */\ - u8 start_field_bit_offset;/* Bit offset within first field datum (0-63) */\ - u8 access_bit_width; /* Read/Write size in bits (8-64) */\ - u32 value; /* Value to store into the Bank or Index register */\ - struct acpi_namespace_node *node; /* Link back to parent node */ - -/* - * Fields common to both Strings and Buffers - */ -#define ACPI_COMMON_BUFFER_INFO \ - u32 length; - -/* - * Common fields for objects that support ASL notifications - */ -#define ACPI_COMMON_NOTIFY_INFO \ - union acpi_operand_object *system_notify; /* Handler for system notifies */\ - union acpi_operand_object *device_notify; /* Handler for driver notifies */\ - union acpi_operand_object *handler; /* Handler for Address space */ - /****************************************************************************** * * Basic data types @@ -125,25 +101,31 @@ struct acpi_object_integer { /* * Note: The String and Buffer object must be identical through the Pointer - * element. There is code that depends on this. + * and length elements. There is code that depends on this. + * + * Fields common to both Strings and Buffers */ +#define ACPI_COMMON_BUFFER_INFO(_type) \ + _type *pointer; \ + u32 length; + struct acpi_object_string { /* Null terminated, ASCII characters only */ - ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_BUFFER_INFO char *pointer; /* String in AML stream or allocated string */ + ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_BUFFER_INFO(char) /* String in AML stream or allocated string */ }; struct acpi_object_buffer { - ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_BUFFER_INFO u8 * pointer; /* Buffer in AML stream or allocated buffer */ - struct acpi_namespace_node *node; /* Link back to parent node */ - u8 *aml_start; + ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_BUFFER_INFO(u8) /* Buffer in AML stream or allocated buffer */ u32 aml_length; + u8 *aml_start; + struct acpi_namespace_node *node; /* Link back to parent node */ }; struct acpi_object_package { - ACPI_OBJECT_COMMON_HEADER u32 count; /* # of elements in package */ - u32 aml_length; - u8 *aml_start; - struct acpi_namespace_node *node; /* Link back to parent node */ + ACPI_OBJECT_COMMON_HEADER struct acpi_namespace_node *node; /* Link back to parent node */ union acpi_operand_object **elements; /* Array of pointers to acpi_objects */ + u8 *aml_start; + u32 aml_length; + u32 count; /* # of elements in package */ }; /****************************************************************************** @@ -156,23 +138,6 @@ struct acpi_object_event { ACPI_OBJECT_COMMON_HEADER void *semaphore; }; -#define ACPI_INFINITE_CONCURRENCY 0xFF - -typedef -acpi_status(*ACPI_INTERNAL_METHOD) (struct acpi_walk_state * walk_state); - -struct acpi_object_method { - ACPI_OBJECT_COMMON_HEADER u8 method_flags; - u8 param_count; - u32 aml_length; - void *semaphore; - u8 *aml_start; - ACPI_INTERNAL_METHOD implementation; - u8 concurrency; - u8 thread_count; - acpi_owner_id owner_id; -}; - struct acpi_object_mutex { ACPI_OBJECT_COMMON_HEADER u8 sync_level; /* 0-15, specified in Mutex() call */ u16 acquisition_depth; /* Allow multiple Acquires, same thread */ @@ -186,11 +151,23 @@ struct acpi_object_mutex { struct acpi_object_region { ACPI_OBJECT_COMMON_HEADER u8 space_id; - union acpi_operand_object *handler; /* Handler for region access */ struct acpi_namespace_node *node; /* Containing namespace node */ + union acpi_operand_object *handler; /* Handler for region access */ union acpi_operand_object *next; - u32 length; acpi_physical_address address; + u32 length; +}; + +struct acpi_object_method { + ACPI_OBJECT_COMMON_HEADER u8 method_flags; + u8 param_count; + u8 concurrency; + void *semaphore; + u8 *aml_start; + ACPI_INTERNAL_METHOD implementation; + u32 aml_length; + u8 thread_count; + acpi_owner_id owner_id; }; /****************************************************************************** @@ -199,6 +176,14 @@ struct acpi_object_region { * *****************************************************************************/ +/* + * Common fields for objects that support ASL notifications + */ +#define ACPI_COMMON_NOTIFY_INFO \ + union acpi_operand_object *system_notify; /* Handler for system notifies */\ + union acpi_operand_object *device_notify; /* Handler for driver notifies */\ + union acpi_operand_object *handler; /* Handler for Address space */ + struct acpi_object_notify_common { /* COMMON NOTIFY for POWER, PROCESSOR, DEVICE, and THERMAL */ ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_NOTIFY_INFO}; @@ -213,9 +198,9 @@ struct acpi_object_power_resource { }; struct acpi_object_processor { - ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_NOTIFY_INFO u32 proc_id; - u32 length; - acpi_io_address address; + ACPI_OBJECT_COMMON_HEADER u8 proc_id; + u8 length; + ACPI_COMMON_NOTIFY_INFO acpi_io_address address; }; struct acpi_object_thermal_zone { @@ -227,9 +212,24 @@ ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_NOTIFY_INFO}; * *****************************************************************************/ +/* + * Common bitfield for the field objects + * "Field Datum" -- a datum from the actual field object + * "Buffer Datum" -- a datum from a user buffer, read from or to be written to the field + */ +#define ACPI_COMMON_FIELD_INFO \ + u8 field_flags; /* Access, update, and lock bits */\ + u8 attribute; /* From access_as keyword */\ + u8 access_byte_width; /* Read/Write size in bytes */\ + struct acpi_namespace_node *node; /* Link back to parent node */\ + u32 bit_length; /* Length of field in bits */\ + u32 base_byte_offset; /* Byte offset within containing object */\ + u32 value; /* Value to store into the Bank or Index register */\ + u8 start_field_bit_offset;/* Bit offset within first field datum (0-63) */\ + u8 access_bit_width; /* Read/Write size in bits (8-64) */ + struct acpi_object_field_common { /* COMMON FIELD (for BUFFER, REGION, BANK, and INDEX fields) */ - ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO union acpi_operand_object *region_obj; /* Containing Operation Region object */ - /* (REGION/BANK fields only) */ + ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO union acpi_operand_object *region_obj; /* Parent Operation Region object (REGION/BANK fields only) */ }; struct acpi_object_region_field { @@ -269,13 +269,9 @@ struct acpi_object_notify_handler { void *context; }; -/* Flags for address handler */ - -#define ACPI_ADDR_HANDLER_DEFAULT_INSTALLED 0x1 - struct acpi_object_addr_handler { ACPI_OBJECT_COMMON_HEADER u8 space_id; - u16 hflags; + u8 handler_flags; acpi_adr_space_handler handler; struct acpi_namespace_node *node; /* Parent device */ void *context; @@ -284,6 +280,10 @@ struct acpi_object_addr_handler { union acpi_operand_object *next; }; +/* Flags for address handler (handler_flags) */ + +#define ACPI_ADDR_HANDLER_DEFAULT_INSTALLED 0x01 + /****************************************************************************** * * Special internal objects @@ -297,10 +297,10 @@ struct acpi_object_addr_handler { struct acpi_object_reference { ACPI_OBJECT_COMMON_HEADER u8 target_type; /* Used for index_op */ u16 opcode; - u32 offset; /* Used for arg_op, local_op, and index_op */ - void *object; /* name_op=>HANDLE to obj, index_op=>union acpi_operand_object */ + void *object; /* name_op=>HANDLE to obj, index_op=>union acpi_operand_object */ struct acpi_namespace_node *node; union acpi_operand_object **where; + u32 offset; /* Used for arg_op, local_op, and index_op */ }; /* @@ -311,12 +311,10 @@ struct acpi_object_reference { * Currently: Region and field_unit types */ struct acpi_object_extra { - ACPI_OBJECT_COMMON_HEADER u8 byte_fill1; - u16 word_fill1; - u32 aml_length; - u8 *aml_start; - struct acpi_namespace_node *method_REG; /* _REG method for this region (if any) */ + ACPI_OBJECT_COMMON_HEADER struct acpi_namespace_node *method_REG; /* _REG method for this region (if any) */ void *region_context; /* Region-specific data */ + u8 *aml_start; + u32 aml_length; }; /* Additional data that can be attached to namespace nodes */ @@ -391,8 +389,13 @@ union acpi_operand_object { #define ACPI_DESC_TYPE_NAMED 0x0F #define ACPI_DESC_TYPE_MAX 0x0F +struct acpi_common_descriptor { + void *common_pointer; + u8 descriptor_type; /* To differentiate various internal objs */ +}; + union acpi_descriptor { - u8 descriptor_id; /* To differentiate various internal objs */ + struct acpi_common_descriptor common; union acpi_operand_object object; struct acpi_namespace_node node; union acpi_parse_object op; diff --git a/include/acpi/acoutput.h b/include/acpi/acoutput.h index 7785d481dc3e..621fe23bb4fb 100644 --- a/include/acpi/acoutput.h +++ b/include/acpi/acoutput.h @@ -144,7 +144,7 @@ /* * These two levels are essentially obsolete, all instances in the - * ACPICA core code have been replaced by REPORT_ERROR and REPORT_WARNING + * ACPICA core code have been replaced by ACPI_ERROR and ACPI_WARNING * (Kept here because some drivers may still use them) */ #define ACPI_DB_ERROR ACPI_DEBUG_LEVEL (ACPI_LV_ERROR) diff --git a/include/acpi/acparser.h b/include/acpi/acparser.h index 5a1ff484af33..53ac4ce8753a 100644 --- a/include/acpi/acparser.h +++ b/include/acpi/acparser.h @@ -48,7 +48,7 @@ /* variable # arguments */ -#define ACPI_VAR_ARGS ACPI_UINT32_MAX +#define ACPI_VAR_ARGS ACPI_UINT8_MAX #define ACPI_PARSE_DELETE_TREE 0x0001 #define ACPI_PARSE_NO_TREE_DELETE 0x0000 @@ -146,13 +146,12 @@ u8 acpi_ps_has_completed_scope(struct acpi_parse_state *parser_state); void acpi_ps_pop_scope(struct acpi_parse_state *parser_state, - union acpi_parse_object **op, - u32 * arg_list, u32 * arg_count); + union acpi_parse_object **op, u32 * arg_list, u8 * arg_count); acpi_status acpi_ps_push_scope(struct acpi_parse_state *parser_state, union acpi_parse_object *op, - u32 remaining_args, u32 arg_count); + u32 remaining_args, u8 arg_count); void acpi_ps_cleanup_scope(struct acpi_parse_state *state); diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 66cf2ecef57a..049e9aa1b867 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -268,7 +268,7 @@ acpi_status acpi_remove_gpe_block(acpi_handle gpe_device); * Resource interfaces */ typedef -acpi_status(*ACPI_WALK_RESOURCE_CALLBACK) (struct acpi_resource * resource, +acpi_status(*acpi_walk_resource_callback) (struct acpi_resource * resource, void *context); acpi_status @@ -290,7 +290,7 @@ acpi_get_possible_resources(acpi_handle device_handle, acpi_status acpi_walk_resources(acpi_handle device_handle, char *name, - ACPI_WALK_RESOURCE_CALLBACK user_function, void *context); + acpi_walk_resource_callback user_function, void *context); acpi_status acpi_set_current_resources(acpi_handle device_handle, diff --git a/include/acpi/acresrc.h b/include/acpi/acresrc.h index fa02e8083381..bdd6584bbcf1 100644 --- a/include/acpi/acresrc.h +++ b/include/acpi/acresrc.h @@ -198,8 +198,9 @@ acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object, acpi_size * buffer_size_needed); acpi_status -acpi_rs_convert_aml_to_resources(u8 * aml_buffer, - u32 aml_buffer_length, u8 * output_buffer); +acpi_rs_convert_aml_to_resources(u8 * aml, + u32 length, + u32 offset, u8 resource_index, void **context); acpi_status acpi_rs_convert_resources_to_aml(struct acpi_resource *resource, diff --git a/include/acpi/acstruct.h b/include/acpi/acstruct.h index d8c1c2cdac0c..04e8966a377d 100644 --- a/include/acpi/acstruct.h +++ b/include/acpi/acstruct.h @@ -44,6 +44,8 @@ #ifndef __ACSTRUCT_H__ #define __ACSTRUCT_H__ +/* acpisrc:struct_defs -- for acpisrc conversion */ + /***************************************************************************** * * Tree walking typedefs and structs @@ -64,54 +66,55 @@ #define ACPI_WALK_CONST_OPTIONAL 4 struct acpi_walk_state { - u8 data_type; /* To differentiate various internal objs MUST BE FIRST! */ + struct acpi_walk_state *next; /* Next walk_state in list */ + u8 descriptor_type; /* To differentiate various internal objs */ u8 walk_type; - acpi_owner_id owner_id; /* Owner of objects created during the walk */ - u8 last_predicate; /* Result of last predicate */ - u8 current_result; /* */ + u16 opcode; /* Current AML opcode */ u8 next_op_info; /* Info about next_op */ u8 num_operands; /* Stack pointer for Operands[] array */ + acpi_owner_id owner_id; /* Owner of objects created during the walk */ + u8 last_predicate; /* Result of last predicate */ + u8 current_result; u8 return_used; - u16 opcode; /* Current AML opcode */ u8 scope_depth; u8 pass_number; /* Parse pass during table load */ - u32 arg_count; /* push for fixed or var args */ u32 aml_offset; u32 arg_types; u32 method_breakpoint; /* For single stepping */ u32 user_breakpoint; /* User AML breakpoint */ u32 parse_flags; + + struct acpi_parse_state parser_state; /* Current state of parser */ u32 prev_arg_types; + u8 arg_count; /* push for fixed or var args */ - u8 *aml_last_while; struct acpi_namespace_node arguments[ACPI_METHOD_NUM_ARGS]; /* Control method arguments */ + struct acpi_namespace_node local_variables[ACPI_METHOD_NUM_LOCALS]; /* Control method locals */ + union acpi_operand_object *operands[ACPI_OBJ_NUM_OPERANDS + 1]; /* Operands passed to the interpreter (+1 for NULL terminator) */ + union acpi_operand_object **params; + + u8 *aml_last_while; union acpi_operand_object **caller_return_desc; union acpi_generic_state *control_state; /* List of control states (nested IFs) */ struct acpi_namespace_node *deferred_node; /* Used when executing deferred opcodes */ struct acpi_gpe_event_info *gpe_event_info; /* Info for GPE (_Lxx/_Exx methods only */ union acpi_operand_object *implicit_return_obj; - struct acpi_namespace_node local_variables[ACPI_METHOD_NUM_LOCALS]; /* Control method locals */ struct acpi_namespace_node *method_call_node; /* Called method Node */ union acpi_parse_object *method_call_op; /* method_call Op if running a method */ union acpi_operand_object *method_desc; /* Method descriptor if running a method */ struct acpi_namespace_node *method_node; /* Method node if running a method. */ union acpi_parse_object *op; /* Current parser op */ - union acpi_operand_object *operands[ACPI_OBJ_NUM_OPERANDS + 1]; /* Operands passed to the interpreter (+1 for NULL terminator) */ const struct acpi_opcode_info *op_info; /* Info on current opcode */ union acpi_parse_object *origin; /* Start of walk [Obsolete] */ - union acpi_operand_object **params; - struct acpi_parse_state parser_state; /* Current state of parser */ union acpi_operand_object *result_obj; union acpi_generic_state *results; /* Stack of accumulated results */ union acpi_operand_object *return_desc; /* Return object, if any */ union acpi_generic_state *scope_info; /* Stack of nested scopes */ - union acpi_parse_object *prev_op; /* Last op that was processed */ union acpi_parse_object *next_op; /* next op to be processed */ + struct acpi_thread_state *thread; acpi_parse_downwards descending_callback; acpi_parse_upwards ascending_callback; - struct acpi_thread_state *thread; - struct acpi_walk_state *next; /* Next walk_state in list */ }; /* Info used by acpi_ps_init_objects */ @@ -151,11 +154,11 @@ struct acpi_walk_info { /* Display Types */ -#define ACPI_DISPLAY_SUMMARY (u8) 0 -#define ACPI_DISPLAY_OBJECTS (u8) 1 -#define ACPI_DISPLAY_MASK (u8) 1 +#define ACPI_DISPLAY_SUMMARY (u8) 0 +#define ACPI_DISPLAY_OBJECTS (u8) 1 +#define ACPI_DISPLAY_MASK (u8) 1 -#define ACPI_DISPLAY_SHORT (u8) 2 +#define ACPI_DISPLAY_SHORT (u8) 2 struct acpi_get_devices_info { acpi_walk_callback user_function; diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index 520f315dd53a..091dd2567172 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -44,6 +44,8 @@ #ifndef __ACTYPES_H__ #define __ACTYPES_H__ +/* acpisrc:struct_defs -- for acpisrc conversion */ + /* * ACPI_MACHINE_WIDTH must be specified in an OS- or compiler-dependent header * and must be either 16, 32, or 64 @@ -250,7 +252,7 @@ typedef acpi_native_uint acpi_size; /* Use C99 uintptr_t for pointer casting if available, "void *" otherwise */ #ifndef acpi_uintptr_t -#define acpi_uintptr_t void * +#define acpi_uintptr_t void * #endif /* @@ -259,7 +261,7 @@ typedef acpi_native_uint acpi_size; * manager implementation is to be used (ACPI_USE_LOCAL_CACHE) */ #ifndef acpi_cache_t -#define acpi_cache_t struct acpi_memory_list +#define acpi_cache_t struct acpi_memory_list #endif /* @@ -267,7 +269,7 @@ typedef acpi_native_uint acpi_size; * lock and unlock OSL interfaces. */ #ifndef acpi_cpu_flags -#define acpi_cpu_flags acpi_native_uint +#define acpi_cpu_flags acpi_native_uint #endif /* @@ -300,7 +302,7 @@ typedef acpi_native_uint acpi_size; * thread_id is returned by acpi_os_get_thread_id. */ #ifndef acpi_thread_id -#define acpi_thread_id acpi_native_uint +#define acpi_thread_id acpi_native_uint #endif /******************************************************************************* @@ -869,7 +871,7 @@ acpi_status(*acpi_adr_space_handler) (u32 function, void *handler_context, void *region_context); -#define ACPI_DEFAULT_HANDLER NULL +#define ACPI_DEFAULT_HANDLER NULL typedef acpi_status(*acpi_adr_space_setup) (acpi_handle region_handle, @@ -926,8 +928,8 @@ struct acpi_compatible_id_list { #define ACPI_STA_BATTERY_PRESENT 0x10 #define ACPI_COMMON_OBJ_INFO \ - acpi_object_type type; /* ACPI object type */ \ - acpi_name name /* ACPI object Name */ + acpi_object_type type; /* ACPI object type */ \ + acpi_name name /* ACPI object Name */ struct acpi_obj_info_header { ACPI_COMMON_OBJ_INFO; @@ -1182,12 +1184,12 @@ struct acpi_resource_source { /* Fields common to all address descriptors, 16/32/64 bit */ #define ACPI_RESOURCE_ADDRESS_COMMON \ - u8 resource_type; \ - u8 producer_consumer; \ - u8 decode; \ - u8 min_address_fixed; \ - u8 max_address_fixed; \ - union acpi_resource_attribute info; + u8 resource_type; \ + u8 producer_consumer; \ + u8 decode; \ + u8 min_address_fixed; \ + u8 max_address_fixed; \ + union acpi_resource_attribute info; struct acpi_resource_address { ACPI_RESOURCE_ADDRESS_COMMON}; @@ -1308,10 +1310,6 @@ struct acpi_resource { #define ACPI_NEXT_RESOURCE(res) (struct acpi_resource *)((u8 *) res + res->length) -/* - * END: of definitions for Resource Attributes - */ - struct acpi_pci_routing_table { u32 length; u32 pin; @@ -1320,8 +1318,4 @@ struct acpi_pci_routing_table { char source[4]; /* pad to 64 bits so sizeof() works in all cases */ }; -/* - * END: of definitions for PCI Routing tables - */ - #endif /* __ACTYPES_H__ */ diff --git a/include/acpi/acutils.h b/include/acpi/acutils.h index 71ff78c75441..5e69a80c7850 100644 --- a/include/acpi/acutils.h +++ b/include/acpi/acutils.h @@ -77,6 +77,12 @@ extern const char *acpi_gbl_TYPdecode[4]; #define ACPI_VARIABLE_LENGTH 2 #define ACPI_SMALL_VARIABLE_LENGTH 3 +typedef +acpi_status(*acpi_walk_aml_callback) (u8 * aml, + u32 length, + u32 offset, + u8 resource_index, void *context); + typedef acpi_status(*acpi_pkg_callback) (u8 object_type, union acpi_operand_object * source_object, @@ -469,6 +475,25 @@ acpi_ut_strtoul64(char *string, u32 base, acpi_integer * ret_integer); #define ACPI_ANY_BASE 0 +u32 acpi_ut_dword_byte_swap(u32 value); + +void acpi_ut_set_integer_width(u8 revision); + +#ifdef ACPI_DEBUG_OUTPUT +void +acpi_ut_display_init_pathname(u8 type, + struct acpi_namespace_node *obj_handle, + char *path); +#endif + +/* + * utresrc + */ +acpi_status +acpi_ut_walk_aml_resources(u8 * aml, + acpi_size aml_length, + acpi_walk_aml_callback user_function, void *context); + acpi_status acpi_ut_validate_resource(void *aml, u8 * return_index); u32 acpi_ut_get_descriptor_length(void *aml); @@ -483,18 +508,6 @@ acpi_status acpi_ut_get_resource_end_tag(union acpi_operand_object *obj_desc, u8 ** end_tag); -u32 acpi_ut_dword_byte_swap(u32 value); - -void acpi_ut_set_integer_width(u8 revision); - -#ifdef ACPI_DEBUG_OUTPUT -void -acpi_ut_display_init_pathname(u8 type, - struct acpi_namespace_node *obj_handle, - char *path); - -#endif - /* * utmutex - mutex support */ @@ -521,14 +534,15 @@ acpi_ut_initialize_buffer(struct acpi_buffer *buffer, void *acpi_ut_allocate(acpi_size size, u32 component, char *module, u32 line); -void *acpi_ut_callocate(acpi_size size, u32 component, char *module, u32 line); +void *acpi_ut_allocate_zeroed(acpi_size size, + u32 component, char *module, u32 line); #ifdef ACPI_DBG_TRACK_ALLOCATIONS void *acpi_ut_allocate_and_track(acpi_size size, u32 component, char *module, u32 line); -void *acpi_ut_callocate_and_track(acpi_size size, - u32 component, char *module, u32 line); +void *acpi_ut_allocate_zeroed_and_track(acpi_size size, + u32 component, char *module, u32 line); void acpi_ut_free_and_track(void *address, u32 component, char *module, u32 line); @@ -538,6 +552,11 @@ void acpi_ut_dump_allocation_info(void); #endif /* ACPI_FUTURE_USAGE */ void acpi_ut_dump_allocations(u32 component, char *module); + +acpi_status +acpi_ut_create_list(char *list_name, + u16 object_size, struct acpi_memory_list **return_cache); + #endif #endif /* _ACUTILS_H */ diff --git a/include/acpi/amlresrc.h b/include/acpi/amlresrc.h index e5b42eb38190..64736860bdd5 100644 --- a/include/acpi/amlresrc.h +++ b/include/acpi/amlresrc.h @@ -42,9 +42,17 @@ * POSSIBILITY OF SUCH DAMAGES. */ +/* acpisrc:struct_defs -- for acpisrc conversion */ + #ifndef __AMLRESRC_H #define __AMLRESRC_H +/*! [Begin] no source code translation */ + +/* + * Resource descriptor tags, as defined in the ACPI specification. + * Used to symbolically reference fields within a descriptor. + */ #define ACPI_RESTAG_ADDRESS "_ADR" #define ACPI_RESTAG_ALIGNMENT "_ALN" #define ACPI_RESTAG_ADDRESSSPACE "_ASI" @@ -57,12 +65,12 @@ #define ACPI_RESTAG_DMATYPE "_TYP" /* Compatible(0), A(1), B(2), F(3) */ #define ACPI_RESTAG_GRANULARITY "_GRA" #define ACPI_RESTAG_INTERRUPT "_INT" -#define ACPI_RESTAG_INTERRUPTLEVEL "_LL_" /* active_lo(1), active_hi(0) */ -#define ACPI_RESTAG_INTERRUPTSHARE "_SHR" /* Shareable(1), no_share(0) */ +#define ACPI_RESTAG_INTERRUPTLEVEL "_LL_" /* ActiveLo(1), ActiveHi(0) */ +#define ACPI_RESTAG_INTERRUPTSHARE "_SHR" /* Shareable(1), NoShare(0) */ #define ACPI_RESTAG_INTERRUPTTYPE "_HE_" /* Edge(1), Level(0) */ #define ACPI_RESTAG_LENGTH "_LEN" #define ACPI_RESTAG_MEMATTRIBUTES "_MTP" /* Memory(0), Reserved(1), ACPI(2), NVS(3) */ -#define ACPI_RESTAG_MEMTYPE "_MEM" /* non_cache(0), Cacheable(1) Cache+combine(2), Cache+prefetch(3) */ +#define ACPI_RESTAG_MEMTYPE "_MEM" /* NonCache(0), Cacheable(1) Cache+combine(2), Cache+prefetch(3) */ #define ACPI_RESTAG_MAXADDR "_MAX" #define ACPI_RESTAG_MINADDR "_MIN" #define ACPI_RESTAG_MAXTYPE "_MAF" @@ -70,11 +78,12 @@ #define ACPI_RESTAG_REGISTERBITOFFSET "_RBO" #define ACPI_RESTAG_REGISTERBITWIDTH "_RBW" #define ACPI_RESTAG_RANGETYPE "_RNG" -#define ACPI_RESTAG_READWRITETYPE "_RW_" /* read_only(0), Writeable (1) */ +#define ACPI_RESTAG_READWRITETYPE "_RW_" /* ReadOnly(0), Writeable (1) */ #define ACPI_RESTAG_TRANSLATION "_TRA" #define ACPI_RESTAG_TRANSTYPE "_TRS" /* Sparse(1), Dense(0) */ #define ACPI_RESTAG_TYPE "_TTP" /* Translation(1), Static (0) */ -#define ACPI_RESTAG_XFERTYPE "_SIz" /* 8(0), 8_and16(1), 16(2) */ +#define ACPI_RESTAG_XFERTYPE "_SIZ" /* 8(0), 8And16(1), 16(2) */ +/*! [End] no source code translation !*/ /* Default sizes for "small" resource descriptors */ @@ -109,7 +118,7 @@ struct asl_resource_node { * SMALL descriptors */ #define AML_RESOURCE_SMALL_HEADER_COMMON \ - u8 descriptor_type; + u8 descriptor_type; struct aml_resource_small_header { AML_RESOURCE_SMALL_HEADER_COMMON}; @@ -162,8 +171,8 @@ struct aml_resource_end_tag { * LARGE descriptors */ #define AML_RESOURCE_LARGE_HEADER_COMMON \ - u8 descriptor_type;\ - u16 resource_length; + u8 descriptor_type;\ + u16 resource_length; struct aml_resource_large_header { AML_RESOURCE_LARGE_HEADER_COMMON}; @@ -194,9 +203,9 @@ struct aml_resource_fixed_memory32 { }; #define AML_RESOURCE_ADDRESS_COMMON \ - u8 resource_type; \ - u8 flags; \ - u8 specific_flags; + u8 resource_type; \ + u8 flags; \ + u8 specific_flags; struct aml_resource_address { AML_RESOURCE_LARGE_HEADER_COMMON AML_RESOURCE_ADDRESS_COMMON}; diff --git a/include/acpi/platform/acenv.h b/include/acpi/platform/acenv.h index d5a7f566c018..2270bdd5e530 100644 --- a/include/acpi/platform/acenv.h +++ b/include/acpi/platform/acenv.h @@ -70,6 +70,7 @@ #define ACPI_DEBUGGER #define ACPI_DISASSEMBLER #define ACPI_MUTEX_DEBUG +#define ACPI_DBG_TRACK_ALLOCATIONS #endif #ifdef ACPI_ASL_COMPILER @@ -165,17 +166,6 @@ #endif -/* - * Memory allocation tracking. Used only if - * 1) This is the debug version - * 2) This is NOT a 16-bit version of the code (not enough real-mode memory) - */ -#ifdef ACPI_DEBUG_OUTPUT -#if ACPI_MACHINE_WIDTH != 16 -#define ACPI_DBG_TRACK_ALLOCATIONS -#endif -#endif - /*! [End] no source code translation !*/ /* -- cgit v1.2.3 From 793c2388cae3fd023b3b5166354931752d42353c Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Fri, 31 Mar 2006 00:00:00 -0500 Subject: ACPI: ACPICA 20060331 Implemented header file support for the following additional ACPI tables: ASF!, BOOT, CPEP, DBGP, MCFG, SPCR, SPMI, TCPA, and WDRT. With this support, all current and known ACPI tables are now defined in the ACPICA headers and are available for use by device drivers and other software. Implemented support to allow tables that contain ACPI names with invalid characters to be loaded. Previously, this would cause the table load to fail, but since there are several known cases of such tables on existing machines, this change was made to enable ACPI support for them. Also, this matches the behavior of the Microsoft ACPI implementation. https://bugzilla.novell.com/show_bug.cgi?id=147621 Fixed a couple regressions introduced during the memory optimization in the 20060317 release. The namespace node definition required additional reorganization and an internal datatype that had been changed to 8-bit was restored to 32-bit. (Valery Podrezov) Fixed a problem where a null pointer passed to acpi_ut_delete_generic_state() could be passed through to acpi_os_release_object which is unexpected. Such null pointers are now trapped and ignored, matching the behavior of the previous implementation before the deployment of acpi_os_release_object(). (Valery Podrezov, Fiodor Suietov) Fixed a memory mapping leak during the deletion of a SystemMemory operation region where a cached memory mapping was not deleted. This became a noticeable problem for operation regions that are defined within frequently used control methods. (Dana Meyers) Reorganized the ACPI table header files into two main files: one for the ACPI tables consumed by the ACPICA core, and another for the miscellaneous ACPI tables that are consumed by the drivers and other software. The various FADT definitions were merged into one common section and three different tables (ACPI 1.0, 1.0+, and 2.0) Signed-off-by: Bob Moore Signed-off-by: Len Brown --- arch/i386/kernel/acpi/boot.c | 4 +- drivers/acpi/bus.c | 2 +- drivers/acpi/dispatcher/dsmethod.c | 2 +- drivers/acpi/dispatcher/dswexec.c | 1 - drivers/acpi/events/evrgnini.c | 13 +- drivers/acpi/executer/exdump.c | 6 +- drivers/acpi/executer/exnames.c | 2 +- drivers/acpi/hardware/hwtimer.c | 4 +- drivers/acpi/namespace/nsalloc.c | 2 + drivers/acpi/namespace/nsdump.c | 3 + drivers/acpi/namespace/nssearch.c | 50 +-- drivers/acpi/parser/psloop.c | 12 + drivers/acpi/parser/psscope.c | 4 +- drivers/acpi/resources/rslist.c | 8 +- drivers/acpi/system.c | 2 +- drivers/acpi/tables.c | 4 +- drivers/acpi/tables/tbconvrt.c | 31 +- drivers/acpi/tables/tbrsdt.c | 3 +- drivers/acpi/tables/tbutils.c | 122 ++++--- drivers/acpi/tables/tbxfroot.c | 9 +- drivers/acpi/utilities/utdebug.c | 38 ++- drivers/acpi/utilities/utdelete.c | 16 +- drivers/acpi/utilities/utglobal.c | 2 +- drivers/acpi/utilities/utinit.c | 6 +- drivers/acpi/utilities/utmisc.c | 104 +++++- drivers/acpi/utilities/utresrc.c | 6 +- drivers/acpi/utilities/utstate.c | 10 +- include/acpi/acconfig.h | 2 +- include/acpi/acdisasm.h | 141 +++++++- include/acpi/acglobal.h | 7 +- include/acpi/aclocal.h | 14 +- include/acpi/acmacros.h | 7 +- include/acpi/acobject.h | 4 + include/acpi/acparser.h | 9 +- include/acpi/acpi_bus.h | 2 +- include/acpi/acpiosxf.h | 2 - include/acpi/acstruct.h | 2 +- include/acpi/actables.h | 6 +- include/acpi/actbl.h | 400 +++++++++++++---------- include/acpi/actbl1.h | 639 +++++++++++++++++++++++++++++++++---- include/acpi/actbl2.h | 230 +------------ include/acpi/acutils.h | 10 +- include/acpi/platform/acenv.h | 4 +- 43 files changed, 1314 insertions(+), 631 deletions(-) (limited to 'include') diff --git a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c index 033066176b3e..a6fe91225202 100644 --- a/arch/i386/kernel/acpi/boot.c +++ b/arch/i386/kernel/acpi/boot.c @@ -621,9 +621,9 @@ extern u32 pmtmr_ioport; static int __init acpi_parse_fadt(unsigned long phys, unsigned long size) { - struct fadt_descriptor_rev2 *fadt = NULL; + struct fadt_descriptor *fadt = NULL; - fadt = (struct fadt_descriptor_rev2 *)__acpi_map_table(phys, size); + fadt = (struct fadt_descriptor *)__acpi_map_table(phys, size); if (!fadt) { printk(KERN_WARNING PREFIX "Unable to map FADT\n"); return 0; diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 9c4ac0191f64..b3a214db56f6 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -43,7 +43,7 @@ ACPI_MODULE_NAME("acpi_bus") extern void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger); #endif -FADT_DESCRIPTOR acpi_fadt; +struct fadt_descriptor acpi_fadt; EXPORT_SYMBOL(acpi_fadt); struct acpi_device *acpi_root; diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c index 238916ce5412..7dc59fc7344f 100644 --- a/drivers/acpi/dispatcher/dsmethod.c +++ b/drivers/acpi/dispatcher/dsmethod.c @@ -502,7 +502,7 @@ void acpi_ds_terminate_control_method(struct acpi_walk_state *walk_state) * Delete any namespace entries created immediately underneath * the method */ - if (method_node->child) { + if (method_node && method_node->child) { acpi_ns_delete_namespace_subtree(method_node); } diff --git a/drivers/acpi/dispatcher/dswexec.c b/drivers/acpi/dispatcher/dswexec.c index 198949f41048..8b740b370eb1 100644 --- a/drivers/acpi/dispatcher/dswexec.c +++ b/drivers/acpi/dispatcher/dswexec.c @@ -49,7 +49,6 @@ #include #include #include -#include #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME("dswexec") diff --git a/drivers/acpi/events/evrgnini.c b/drivers/acpi/events/evrgnini.c index db98747fe54d..d1809f4240a4 100644 --- a/drivers/acpi/events/evrgnini.c +++ b/drivers/acpi/events/evrgnini.c @@ -75,7 +75,18 @@ acpi_ev_system_memory_region_setup(acpi_handle handle, if (function == ACPI_REGION_DEACTIVATE) { if (*region_context) { - ACPI_FREE(*region_context); + local_region_context = + (struct acpi_mem_space_context *)*region_context; + + /* Delete a cached mapping if present */ + + if (local_region_context->mapped_length) { + acpi_os_unmap_memory(local_region_context-> + mapped_logical_address, + local_region_context-> + mapped_length); + } + ACPI_FREE(local_region_context); *region_context = NULL; } return_ACPI_STATUS(AE_OK); diff --git a/drivers/acpi/executer/exdump.c b/drivers/acpi/executer/exdump.c index 56db58b8e23a..1dfebf9e7074 100644 --- a/drivers/acpi/executer/exdump.c +++ b/drivers/acpi/executer/exdump.c @@ -61,6 +61,10 @@ static void acpi_ex_out_pointer(char *title, void *value); static void acpi_ex_out_address(char *title, acpi_physical_address value); +static void +acpi_ex_dump_object(union acpi_operand_object *obj_desc, + struct acpi_exdump_info *info); + static void acpi_ex_dump_reference_obj(union acpi_operand_object *obj_desc); static void @@ -263,7 +267,7 @@ static struct acpi_exdump_info acpi_ex_dump_field_common[7] = { {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(common_field.node), "Parent Node"} }; -static struct acpi_exdump_info acpi_ex_dump_node[6] = { +static struct acpi_exdump_info acpi_ex_dump_node[5] = { {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_node), NULL}, {ACPI_EXD_UINT8, ACPI_EXD_NSOFFSET(flags), "Flags"}, {ACPI_EXD_UINT8, ACPI_EXD_NSOFFSET(owner_id), "Owner Id"}, diff --git a/drivers/acpi/executer/exnames.c b/drivers/acpi/executer/exnames.c index 80bbc20756a1..085b18f8dd00 100644 --- a/drivers/acpi/executer/exnames.c +++ b/drivers/acpi/executer/exnames.c @@ -179,7 +179,7 @@ static acpi_status acpi_ex_name_segment(u8 ** in_aml_address, char *name_string) for (index = 0; (index < ACPI_NAME_SIZE) - && (acpi_ut_valid_acpi_character(*aml_address)); index++) { + && (acpi_ut_valid_acpi_char(*aml_address, 0)); index++) { char_buf[index] = *aml_address++; ACPI_DEBUG_PRINT((ACPI_DB_LOAD, "%c\n", char_buf[index])); } diff --git a/drivers/acpi/hardware/hwtimer.c b/drivers/acpi/hardware/hwtimer.c index 9d53e46bc331..a559ac17b132 100644 --- a/drivers/acpi/hardware/hwtimer.c +++ b/drivers/acpi/hardware/hwtimer.c @@ -66,7 +66,7 @@ acpi_status acpi_get_timer_resolution(u32 * resolution) return_ACPI_STATUS(AE_BAD_PARAMETER); } - if (0 == acpi_gbl_FADT->tmr_val_ext) { + if (acpi_gbl_FADT->tmr_val_ext == 0) { *resolution = 24; } else { *resolution = 32; @@ -153,7 +153,7 @@ acpi_get_timer_duration(u32 start_ticks, u32 end_ticks, u32 * time_elapsed) if (start_ticks < end_ticks) { delta_ticks = end_ticks - start_ticks; } else if (start_ticks > end_ticks) { - if (0 == acpi_gbl_FADT->tmr_val_ext) { + if (acpi_gbl_FADT->tmr_val_ext == 0) { /* 24-bit Timer */ diff --git a/drivers/acpi/namespace/nsalloc.c b/drivers/acpi/namespace/nsalloc.c index 8b921c96d6a5..c92c03693a16 100644 --- a/drivers/acpi/namespace/nsalloc.c +++ b/drivers/acpi/namespace/nsalloc.c @@ -211,6 +211,8 @@ void acpi_ns_install_node(struct acpi_walk_state *walk_state, struct acpi_namesp acpi_ut_get_node_name(parent_node), acpi_ut_get_type_name(parent_node->type), parent_node)); + + return_VOID; } /******************************************************************************* diff --git a/drivers/acpi/namespace/nsdump.c b/drivers/acpi/namespace/nsdump.c index e275373b1705..5662d2def62f 100644 --- a/drivers/acpi/namespace/nsdump.c +++ b/drivers/acpi/namespace/nsdump.c @@ -204,6 +204,9 @@ acpi_ns_dump_one_object(acpi_handle obj_handle, } if (!acpi_ut_valid_acpi_name(this_node->name.integer)) { + this_node->name.integer = + acpi_ut_repair_name(this_node->name.integer); + ACPI_WARNING((AE_INFO, "Invalid ACPI Name %08X", this_node->name.integer)); } diff --git a/drivers/acpi/namespace/nssearch.c b/drivers/acpi/namespace/nssearch.c index c929f45071c0..51adec5a23d6 100644 --- a/drivers/acpi/namespace/nssearch.c +++ b/drivers/acpi/namespace/nssearch.c @@ -128,9 +128,8 @@ acpi_ns_search_node(u32 target_name, next_node->object); } - /* - * Found matching entry. - */ + /* Found matching entry */ + ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Name [%4.4s] (%s) %p found in scope [%4.4s] %p\n", ACPI_CAST_PTR(char, &target_name), @@ -248,10 +247,8 @@ acpi_ns_search_parent_tree(u32 target_name, return_ACPI_STATUS(status); } - /* - * Not found here, go up another level - * (until we reach the root) - */ + /* Not found here, go up another level (until we reach the root) */ + parent_node = acpi_ns_get_parent_node(parent_node); } @@ -307,12 +304,29 @@ acpi_ns_search_and_enter(u32 target_name, return_ACPI_STATUS(AE_BAD_PARAMETER); } - /* Name must consist of printable characters */ - + /* + * Name must consist of valid ACPI characters. We will repair the name if + * necessary because we don't want to abort because of this, but we want + * all namespace names to be printable. A warning message is appropriate. + * + * This issue came up because there are in fact machines that exhibit + * this problem, and we want to be able to enable ACPI support for them, + * even though there are a few bad names. + */ if (!acpi_ut_valid_acpi_name(target_name)) { - ACPI_ERROR((AE_INFO, "Bad character in ACPI Name: %X", - target_name)); - return_ACPI_STATUS(AE_BAD_CHARACTER); + target_name = acpi_ut_repair_name(target_name); + + /* Report warning only if in strict mode or debug mode */ + + if (!acpi_gbl_enable_interpreter_slack) { + ACPI_WARNING((AE_INFO, + "Found bad character(s) in name, repaired: [%4.4s]\n", + ACPI_CAST_PTR(char, &target_name))); + } else { + ACPI_DEBUG_PRINT((ACPI_DB_WARN, + "Found bad character(s) in name, repaired: [%4.4s]\n", + ACPI_CAST_PTR(char, &target_name))); + } } /* Try to find the name in the namespace level specified by the caller */ @@ -328,10 +342,8 @@ acpi_ns_search_and_enter(u32 target_name, status = AE_ALREADY_EXISTS; } - /* - * Either found it or there was an error - * -- finished either way - */ + /* Either found it or there was an error: finished either way */ + return_ACPI_STATUS(status); } @@ -357,9 +369,8 @@ acpi_ns_search_and_enter(u32 target_name, } } - /* - * In execute mode, just search, never add names. Exit now. - */ + /* In execute mode, just search, never add names. Exit now */ + if (interpreter_mode == ACPI_IMODE_EXECUTE) { ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "%4.4s Not found in %p [Not adding]\n", @@ -379,6 +390,5 @@ acpi_ns_search_and_enter(u32 target_name, acpi_ns_install_node(walk_state, node, new_node, type); *return_node = new_node; - return_ACPI_STATUS(AE_OK); } diff --git a/drivers/acpi/parser/psloop.c b/drivers/acpi/parser/psloop.c index 14052cb648c1..3a29ce680370 100644 --- a/drivers/acpi/parser/psloop.c +++ b/drivers/acpi/parser/psloop.c @@ -747,7 +747,19 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) if (ACPI_FAILURE(status2)) { return_ACPI_STATUS(status2); } + + status2 = + acpi_ds_result_stack_pop + (walk_state); + if (ACPI_FAILURE(status2)) { + return_ACPI_STATUS(status2); + } + + acpi_ut_delete_generic_state + (acpi_ut_pop_generic_state + (&walk_state->control_state)); } + acpi_ps_pop_scope(parser_state, &op, &walk_state->arg_types, &walk_state->arg_count); diff --git a/drivers/acpi/parser/psscope.c b/drivers/acpi/parser/psscope.c index 9233a4044d6b..424ab1c20da5 100644 --- a/drivers/acpi/parser/psscope.c +++ b/drivers/acpi/parser/psscope.c @@ -143,7 +143,7 @@ acpi_ps_init_scope(struct acpi_parse_state * parser_state, acpi_status acpi_ps_push_scope(struct acpi_parse_state *parser_state, union acpi_parse_object *op, - u32 remaining_args, u8 arg_count) + u32 remaining_args, u32 arg_count) { union acpi_generic_state *scope; @@ -196,7 +196,7 @@ acpi_ps_push_scope(struct acpi_parse_state *parser_state, void acpi_ps_pop_scope(struct acpi_parse_state *parser_state, - union acpi_parse_object **op, u32 * arg_list, u8 * arg_count) + union acpi_parse_object **op, u32 * arg_list, u32 * arg_count) { union acpi_generic_state *scope = parser_state->scope; diff --git a/drivers/acpi/resources/rslist.c b/drivers/acpi/resources/rslist.c index 50bbb19bf4ae..1b2d1e717e74 100644 --- a/drivers/acpi/resources/rslist.c +++ b/drivers/acpi/resources/rslist.c @@ -64,10 +64,11 @@ ACPI_MODULE_NAME("rslist") acpi_status acpi_rs_convert_aml_to_resources(u8 * aml, u32 length, - u32 offset, - u8 resource_index, void **resource_ptr) + u32 offset, u8 resource_index, void **context) { - struct acpi_resource *resource = *resource_ptr; + struct acpi_resource **resource_ptr = + ACPI_CAST_INDIRECT_PTR(struct acpi_resource, context); + struct acpi_resource *resource; acpi_status status; ACPI_FUNCTION_TRACE("rs_convert_aml_to_resources"); @@ -76,6 +77,7 @@ acpi_rs_convert_aml_to_resources(u8 * aml, * Check that the input buffer and all subsequent pointers into it * are aligned on a native word boundary. Most important on IA64 */ + resource = *resource_ptr; if (ACPI_IS_MISALIGNED(resource)) { ACPI_WARNING((AE_INFO, "Misaligned resource pointer %p", resource)); diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c index e4308c7a6743..1943bec18848 100644 --- a/drivers/acpi/system.c +++ b/drivers/acpi/system.c @@ -39,7 +39,7 @@ ACPI_MODULE_NAME("acpi_system") #define ACPI_SYSTEM_FILE_EVENT "event" #define ACPI_SYSTEM_FILE_DSDT "dsdt" #define ACPI_SYSTEM_FILE_FADT "fadt" -extern FADT_DESCRIPTOR acpi_fadt; +extern struct fadt_descriptor acpi_fadt; /* -------------------------------------------------------------------------- FS Interface (/proc) diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index 7f37c7cc5ef1..ed5e8816d83d 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -282,8 +282,8 @@ acpi_get_table_header_early(enum acpi_table_id id, /* Map the DSDT header via the pointer in the FADT */ if (id == ACPI_DSDT) { - struct fadt_descriptor_rev2 *fadt = - (struct fadt_descriptor_rev2 *)*header; + struct fadt_descriptor *fadt = + (struct fadt_descriptor *)*header; if (fadt->revision == 3 && fadt->Xdsdt) { *header = (void *)__acpi_map_table(fadt->Xdsdt, diff --git a/drivers/acpi/tables/tbconvrt.c b/drivers/acpi/tables/tbconvrt.c index 5155b27cf032..a913a927d321 100644 --- a/drivers/acpi/tables/tbconvrt.c +++ b/drivers/acpi/tables/tbconvrt.c @@ -54,12 +54,12 @@ acpi_tb_init_generic_address(struct acpi_generic_address *new_gas_struct, acpi_physical_address address); static void -acpi_tb_convert_fadt1(struct fadt_descriptor_rev2 *local_fadt, +acpi_tb_convert_fadt1(struct fadt_descriptor *local_fadt, struct fadt_descriptor_rev1 *original_fadt); static void -acpi_tb_convert_fadt2(struct fadt_descriptor_rev2 *local_fadt, - struct fadt_descriptor_rev2 *original_fadt); +acpi_tb_convert_fadt2(struct fadt_descriptor *local_fadt, + struct fadt_descriptor *original_fadt); u8 acpi_fadt_is_v1; ACPI_EXPORT_SYMBOL(acpi_fadt_is_v1) @@ -120,7 +120,7 @@ acpi_status acpi_tb_convert_to_xsdt(struct acpi_table_desc *table_info) { acpi_size table_size; u32 i; - XSDT_DESCRIPTOR *new_table; + struct xsdt_descriptor *new_table; ACPI_FUNCTION_ENTRY(); @@ -151,12 +151,12 @@ acpi_status acpi_tb_convert_to_xsdt(struct acpi_table_desc *table_info) if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) { ACPI_STORE_ADDRESS(new_table->table_offset_entry[i], (ACPI_CAST_PTR - (struct rsdt_descriptor_rev1, + (struct rsdt_descriptor, table_info->pointer))-> table_offset_entry[i]); } else { new_table->table_offset_entry[i] = - (ACPI_CAST_PTR(XSDT_DESCRIPTOR, + (ACPI_CAST_PTR(struct xsdt_descriptor, table_info->pointer))-> table_offset_entry[i]; } @@ -218,7 +218,7 @@ acpi_tb_init_generic_address(struct acpi_generic_address *new_gas_struct, ******************************************************************************/ static void -acpi_tb_convert_fadt1(struct fadt_descriptor_rev2 *local_fadt, +acpi_tb_convert_fadt1(struct fadt_descriptor *local_fadt, struct fadt_descriptor_rev1 *original_fadt) { @@ -364,14 +364,13 @@ acpi_tb_convert_fadt1(struct fadt_descriptor_rev2 *local_fadt, ******************************************************************************/ static void -acpi_tb_convert_fadt2(struct fadt_descriptor_rev2 *local_fadt, - struct fadt_descriptor_rev2 *original_fadt) +acpi_tb_convert_fadt2(struct fadt_descriptor *local_fadt, + struct fadt_descriptor *original_fadt) { /* We have an ACPI 2.0 FADT but we must copy it to our local buffer */ - ACPI_MEMCPY(local_fadt, original_fadt, - sizeof(struct fadt_descriptor_rev2)); + ACPI_MEMCPY(local_fadt, original_fadt, sizeof(struct fadt_descriptor)); /* * "X" fields are optional extensions to the original V1.0 fields, so @@ -490,7 +489,7 @@ acpi_tb_convert_fadt2(struct fadt_descriptor_rev2 *local_fadt, acpi_status acpi_tb_convert_table_fadt(void) { - struct fadt_descriptor_rev2 *local_fadt; + struct fadt_descriptor *local_fadt; struct acpi_table_desc *table_desc; ACPI_FUNCTION_TRACE("tb_convert_table_fadt"); @@ -507,13 +506,13 @@ acpi_status acpi_tb_convert_table_fadt(void) /* Allocate buffer for the ACPI 2.0(+) FADT */ - local_fadt = ACPI_ALLOCATE_ZEROED(sizeof(struct fadt_descriptor_rev2)); + local_fadt = ACPI_ALLOCATE_ZEROED(sizeof(struct fadt_descriptor)); if (!local_fadt) { return_ACPI_STATUS(AE_NO_MEMORY); } if (acpi_gbl_FADT->revision >= FADT2_REVISION_ID) { - if (acpi_gbl_FADT->length < sizeof(struct fadt_descriptor_rev2)) { + if (acpi_gbl_FADT->length < sizeof(struct fadt_descriptor)) { /* Length is too short to be a V2.0 table */ @@ -538,7 +537,7 @@ acpi_status acpi_tb_convert_table_fadt(void) /* Global FADT pointer will point to the new common V2.0 FADT */ acpi_gbl_FADT = local_fadt; - acpi_gbl_FADT->length = sizeof(FADT_DESCRIPTOR); + acpi_gbl_FADT->length = sizeof(struct fadt_descriptor); /* Free the original table */ @@ -550,7 +549,7 @@ acpi_status acpi_tb_convert_table_fadt(void) table_desc->pointer = ACPI_CAST_PTR(struct acpi_table_header, acpi_gbl_FADT); table_desc->allocation = ACPI_MEM_ALLOCATED; - table_desc->length = sizeof(struct fadt_descriptor_rev2); + table_desc->length = sizeof(struct fadt_descriptor); /* Dump the entire FADT */ diff --git a/drivers/acpi/tables/tbrsdt.c b/drivers/acpi/tables/tbrsdt.c index 946d2f2d611d..9e0ebe625ed9 100644 --- a/drivers/acpi/tables/tbrsdt.c +++ b/drivers/acpi/tables/tbrsdt.c @@ -280,7 +280,8 @@ acpi_status acpi_tb_get_table_rsdt(void) return_ACPI_STATUS(status); } - acpi_gbl_XSDT = ACPI_CAST_PTR(XSDT_DESCRIPTOR, table_info.pointer); + acpi_gbl_XSDT = + ACPI_CAST_PTR(struct xsdt_descriptor, table_info.pointer); ACPI_DEBUG_PRINT((ACPI_DB_INFO, "XSDT located at %p\n", acpi_gbl_XSDT)); return_ACPI_STATUS(status); diff --git a/drivers/acpi/tables/tbutils.c b/drivers/acpi/tables/tbutils.c index b463d4b88823..f8d28ae8811d 100644 --- a/drivers/acpi/tables/tbutils.c +++ b/drivers/acpi/tables/tbutils.c @@ -193,73 +193,119 @@ acpi_tb_validate_table_header(struct acpi_table_header *table_header) /******************************************************************************* * - * FUNCTION: acpi_tb_verify_table_checksum + * FUNCTION: acpi_tb_sum_table * - * PARAMETERS: *table_header - ACPI table to verify + * PARAMETERS: Buffer - Buffer to sum + * Length - Size of the buffer * - * RETURN: 8 bit checksum of table + * RETURN: 8 bit sum of buffer * - * DESCRIPTION: Does an 8 bit checksum of table and returns status. A correct - * table should have a checksum of 0. + * DESCRIPTION: Computes an 8 bit sum of the buffer(length) and returns it. * ******************************************************************************/ -acpi_status -acpi_tb_verify_table_checksum(struct acpi_table_header * table_header) +u8 acpi_tb_sum_table(void *buffer, u32 length) +{ + acpi_native_uint i; + u8 sum = 0; + + if (!buffer || !length) { + return (0); + } + + for (i = 0; i < length; i++) { + sum = (u8) (sum + ((u8 *) buffer)[i]); + } + return (sum); +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_generate_checksum + * + * PARAMETERS: Table - Pointer to a valid ACPI table (with a + * standard ACPI header) + * + * RETURN: 8 bit checksum of buffer + * + * DESCRIPTION: Computes an 8 bit checksum of the table. + * + ******************************************************************************/ + +u8 acpi_tb_generate_checksum(struct acpi_table_header * table) { u8 checksum; - acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE("tb_verify_table_checksum"); + /* Sum the entire table as-is */ - /* Compute the checksum on the table */ + checksum = acpi_tb_sum_table(table, table->length); - checksum = - acpi_tb_generate_checksum(table_header, table_header->length); + /* Subtract off the existing checksum value in the table */ - /* Return the appropriate exception */ + checksum = (u8) (checksum - table->checksum); - if (checksum) { - ACPI_WARNING((AE_INFO, - "Invalid checksum in table [%4.4s] (%02X, sum %02X is not zero)", - table_header->signature, - (u32) table_header->checksum, (u32) checksum)); + /* Compute the final checksum */ - status = AE_BAD_CHECKSUM; - } - return_ACPI_STATUS(status); + checksum = (u8) (0 - checksum); + return (checksum); } /******************************************************************************* * - * FUNCTION: acpi_tb_generate_checksum + * FUNCTION: acpi_tb_set_checksum * - * PARAMETERS: Buffer - Buffer to checksum - * Length - Size of the buffer + * PARAMETERS: Table - Pointer to a valid ACPI table (with a + * standard ACPI header) * - * RETURN: 8 bit checksum of buffer + * RETURN: None. Sets the table checksum field * - * DESCRIPTION: Computes an 8 bit checksum of the buffer(length) and returns it. + * DESCRIPTION: Computes an 8 bit checksum of the table and inserts the + * checksum into the table header. * ******************************************************************************/ -u8 acpi_tb_generate_checksum(void *buffer, u32 length) +void acpi_tb_set_checksum(struct acpi_table_header *table) { - u8 *end_buffer; - u8 *rover; - u8 sum = 0; - if (buffer && length) { + table->checksum = acpi_tb_generate_checksum(table); +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_verify_table_checksum + * + * PARAMETERS: *table_header - ACPI table to verify + * + * RETURN: 8 bit checksum of table + * + * DESCRIPTION: Generates an 8 bit checksum of table and returns and compares + * it to the existing checksum value. + * + ******************************************************************************/ + +acpi_status +acpi_tb_verify_table_checksum(struct acpi_table_header *table_header) +{ + u8 checksum; + + ACPI_FUNCTION_TRACE("tb_verify_table_checksum"); + + /* Compute the checksum on the table */ - /* Buffer and Length are valid */ + checksum = acpi_tb_generate_checksum(table_header); - end_buffer = ACPI_ADD_PTR(u8, buffer, length); + /* Checksum ok? */ - for (rover = buffer; rover < end_buffer; rover++) { - sum = (u8) (sum + *rover); - } + if (checksum == table_header->checksum) { + return_ACPI_STATUS(AE_OK); } - return (sum); + + ACPI_WARNING((AE_INFO, + "Incorrect checksum in table [%4.4s] - is %2.2X, should be %2.2X", + table_header->signature, table_header->checksum, + checksum)); + + return_ACPI_STATUS(AE_BAD_CHECKSUM); } #ifdef ACPI_OBSOLETE_FUNCTIONS @@ -278,7 +324,7 @@ u8 acpi_tb_generate_checksum(void *buffer, u32 length) acpi_status acpi_tb_handle_to_object(u16 table_id, - struct acpi_table_desc ** return_table_desc) + struct acpi_table_desc **return_table_desc) { u32 i; struct acpi_table_desc *table_desc; diff --git a/drivers/acpi/tables/tbxfroot.c b/drivers/acpi/tables/tbxfroot.c index 1b6d8c510e95..550284f5d1ed 100644 --- a/drivers/acpi/tables/tbxfroot.c +++ b/drivers/acpi/tables/tbxfroot.c @@ -81,15 +81,14 @@ acpi_status acpi_tb_validate_rsdp(struct rsdp_descriptor *rsdp) /* Check the standard checksum */ - if (acpi_tb_generate_checksum(rsdp, ACPI_RSDP_CHECKSUM_LENGTH) != 0) { + if (acpi_tb_sum_table(rsdp, ACPI_RSDP_CHECKSUM_LENGTH) != 0) { return (AE_BAD_CHECKSUM); } /* Check extended checksum if table version >= 2 */ if ((rsdp->revision >= 2) && - (acpi_tb_generate_checksum(rsdp, ACPI_RSDP_XCHECKSUM_LENGTH) != - 0)) { + (acpi_tb_sum_table(rsdp, ACPI_RSDP_XCHECKSUM_LENGTH) != 0)) { return (AE_BAD_CHECKSUM); } @@ -308,12 +307,12 @@ acpi_get_firmware_table(acpi_string signature, if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) { address.pointer.value = (ACPI_CAST_PTR - (RSDT_DESCRIPTOR, + (struct rsdt_descriptor, rsdt_info->pointer))->table_offset_entry[i]; } else { address.pointer.value = (ACPI_CAST_PTR - (XSDT_DESCRIPTOR, + (struct xsdt_descriptor, rsdt_info->pointer))->table_offset_entry[i]; } diff --git a/drivers/acpi/utilities/utdebug.c b/drivers/acpi/utilities/utdebug.c index a8c350643d57..5ec1cfcc611d 100644 --- a/drivers/acpi/utilities/utdebug.c +++ b/drivers/acpi/utilities/utdebug.c @@ -517,20 +517,13 @@ acpi_ut_ptr_exit(u32 line_number, * ******************************************************************************/ -void acpi_ut_dump_buffer(u8 * buffer, u32 count, u32 display, u32 component_id) +void acpi_ut_dump_buffer2(u8 * buffer, u32 count, u32 display) { acpi_native_uint i = 0; acpi_native_uint j; u32 temp32; u8 buf_char; - /* Only dump the buffer if tracing is enabled */ - - if (!((ACPI_LV_TABLES & acpi_dbg_level) && - (component_id & acpi_dbg_layer))) { - return; - } - if ((count < 4) || (count & 0x01)) { display = DB_BYTE_DISPLAY; } @@ -556,6 +549,7 @@ void acpi_ut_dump_buffer(u8 * buffer, u32 count, u32 display, u32 component_id) } switch (display) { + case DB_BYTE_DISPLAY: default: /* Default is BYTE display */ acpi_os_printf("%02X ", buffer[i + j]); @@ -613,3 +607,31 @@ void acpi_ut_dump_buffer(u8 * buffer, u32 count, u32 display, u32 component_id) return; } + +/******************************************************************************* + * + * FUNCTION: acpi_ut_dump_buffer + * + * PARAMETERS: Buffer - Buffer to dump + * Count - Amount to dump, in bytes + * Display - BYTE, WORD, DWORD, or QWORD display + * component_iD - Caller's component ID + * + * RETURN: None + * + * DESCRIPTION: Generic dump buffer in both hex and ascii. + * + ******************************************************************************/ + +void acpi_ut_dump_buffer(u8 * buffer, u32 count, u32 display, u32 component_id) +{ + + /* Only dump the buffer if tracing is enabled */ + + if (!((ACPI_LV_TABLES & acpi_dbg_level) && + (component_id & acpi_dbg_layer))) { + return; + } + + acpi_ut_dump_buffer2(buffer, count, display); +} diff --git a/drivers/acpi/utilities/utdelete.c b/drivers/acpi/utilities/utdelete.c index 51356e8eb999..b4e34a2f81f7 100644 --- a/drivers/acpi/utilities/utdelete.c +++ b/drivers/acpi/utilities/utdelete.c @@ -202,8 +202,20 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object) if (handler_desc) { if (handler_desc->address_space.handler_flags & ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) { - obj_pointer = - second_desc->extra.region_context; + + /* Deactivate region and free region context */ + + if (handler_desc->address_space.setup) { + (void)handler_desc-> + address_space.setup(object, + ACPI_REGION_DEACTIVATE, + handler_desc-> + address_space. + context, + &second_desc-> + extra. + region_context); + } } acpi_ut_remove_reference(handler_desc); diff --git a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c index 8a05bb5ef4fe..e8ae417c9848 100644 --- a/drivers/acpi/utilities/utglobal.c +++ b/drivers/acpi/utilities/utglobal.c @@ -642,7 +642,7 @@ char *acpi_ut_get_node_name(void *object) /* Name must be a valid ACPI name */ if (!acpi_ut_valid_acpi_name(node->name.integer)) { - return ("????"); + node->name.integer = acpi_ut_repair_name(node->name.integer); } /* Return the name */ diff --git a/drivers/acpi/utilities/utinit.c b/drivers/acpi/utilities/utinit.c index 40313de6977d..7538b165b6e5 100644 --- a/drivers/acpi/utilities/utinit.c +++ b/drivers/acpi/utilities/utinit.c @@ -50,7 +50,7 @@ ACPI_MODULE_NAME("utinit") /* Local prototypes */ static void -acpi_ut_fadt_register_error(char *register_name, u32 value, acpi_size offset); +acpi_ut_fadt_register_error(char *register_name, u32 value, u8 offset); static void acpi_ut_terminate(void); @@ -69,12 +69,12 @@ static void acpi_ut_terminate(void); ******************************************************************************/ static void -acpi_ut_fadt_register_error(char *register_name, u32 value, acpi_size offset) +acpi_ut_fadt_register_error(char *register_name, u32 value, u8 offset) { ACPI_WARNING((AE_INFO, "Invalid FADT value %s=%X at offset %X FADT=%p", - register_name, value, (u32) offset, acpi_gbl_FADT)); + register_name, value, offset, acpi_gbl_FADT)); } /****************************************************************************** diff --git a/drivers/acpi/utilities/utmisc.c b/drivers/acpi/utilities/utmisc.c index 017a87ebc40b..4623d7e215d3 100644 --- a/drivers/acpi/utilities/utmisc.c +++ b/drivers/acpi/utilities/utmisc.c @@ -47,6 +47,33 @@ #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utmisc") +/******************************************************************************* + * + * FUNCTION: acpi_ut_is_aml_table + * + * PARAMETERS: Table - An ACPI table + * + * RETURN: TRUE if table contains executable AML; FALSE otherwise + * + * DESCRIPTION: Check ACPI Signature for a table that contains AML code. + * Currently, these are DSDT,SSDT,PSDT. All other table types are + * data tables that do not contain AML code. + * + ******************************************************************************/ +u8 acpi_ut_is_aml_table(struct acpi_table_header *table) +{ + + /* Ignore tables that contain AML */ + + if (ACPI_COMPARE_NAME(table->signature, DSDT_SIG) || + ACPI_COMPARE_NAME(table->signature, PSDT_SIG) || + ACPI_COMPARE_NAME(table->signature, SSDT_SIG)) { + return (TRUE); + } + + return (FALSE); +} + /******************************************************************************* * * FUNCTION: acpi_ut_allocate_owner_id @@ -60,6 +87,7 @@ ACPI_MODULE_NAME("utmisc") * when the method exits or the table is unloaded. * ******************************************************************************/ + acpi_status acpi_ut_allocate_owner_id(acpi_owner_id * owner_id) { acpi_native_uint i; @@ -467,6 +495,41 @@ acpi_ut_display_init_pathname(u8 type, } #endif +/******************************************************************************* + * + * FUNCTION: acpi_ut_valid_acpi_char + * + * PARAMETERS: Char - The character to be examined + * + * RETURN: TRUE if the character is valid, FALSE otherwise + * + * DESCRIPTION: Check for a valid ACPI character. Must be one of: + * 1) Upper case alpha + * 2) numeric + * 3) underscore + * + * We allow a '!' as the last character because of the ASF! table + * + ******************************************************************************/ + +u8 acpi_ut_valid_acpi_char(char character, acpi_native_uint position) +{ + + if (!((character >= 'A' && character <= 'Z') || + (character >= '0' && character <= '9') || (character == '_'))) { + + /* Allow a '!' in the last position */ + + if (character == '!' && position == 3) { + return (TRUE); + } + + return (FALSE); + } + + return (TRUE); +} + /******************************************************************************* * * FUNCTION: acpi_ut_valid_acpi_name @@ -484,19 +547,13 @@ acpi_ut_display_init_pathname(u8 type, u8 acpi_ut_valid_acpi_name(u32 name) { - char *name_ptr = (char *)&name; - char character; acpi_native_uint i; ACPI_FUNCTION_ENTRY(); for (i = 0; i < ACPI_NAME_SIZE; i++) { - character = *name_ptr; - name_ptr++; - - if (!((character == '_') || - (character >= 'A' && character <= 'Z') || - (character >= '0' && character <= '9'))) { + if (!acpi_ut_valid_acpi_char + ((ACPI_CAST_PTR(char, &name))[i], i)) { return (FALSE); } } @@ -506,24 +563,37 @@ u8 acpi_ut_valid_acpi_name(u32 name) /******************************************************************************* * - * FUNCTION: acpi_ut_valid_acpi_character + * FUNCTION: acpi_ut_repair_name * - * PARAMETERS: Character - The character to be examined + * PARAMETERS: Name - The ACPI name to be repaired * - * RETURN: 1 if Character may appear in a name, else 0 + * RETURN: Repaired version of the name * - * DESCRIPTION: Check for a printable character + * DESCRIPTION: Repair an ACPI name: Change invalid characters to '*' and + * return the new name. * ******************************************************************************/ -u8 acpi_ut_valid_acpi_character(char character) +acpi_name acpi_ut_repair_name(acpi_name name) { + char *name_ptr = ACPI_CAST_PTR(char, &name); + char new_name[ACPI_NAME_SIZE]; + acpi_native_uint i; - ACPI_FUNCTION_ENTRY(); + for (i = 0; i < ACPI_NAME_SIZE; i++) { + new_name[i] = name_ptr[i]; + + /* + * Replace a bad character with something printable, yet technically + * still invalid. This prevents any collisions with existing "good" + * names in the namespace. + */ + if (!acpi_ut_valid_acpi_char(name_ptr[i], i)) { + new_name[i] = '*'; + } + } - return ((u8) ((character == '_') || - (character >= 'A' && character <= 'Z') || - (character >= '0' && character <= '9'))); + return (*ACPI_CAST_PTR(u32, new_name)); } /******************************************************************************* diff --git a/drivers/acpi/utilities/utresrc.c b/drivers/acpi/utilities/utresrc.c index 4c24e6d5400a..1e680794c6df 100644 --- a/drivers/acpi/utilities/utresrc.c +++ b/drivers/acpi/utilities/utresrc.c @@ -258,7 +258,7 @@ static const u8 acpi_gbl_resource_types[] = { acpi_status acpi_ut_walk_aml_resources(u8 * aml, acpi_size aml_length, - acpi_walk_aml_callback user_function, void *context) + acpi_walk_aml_callback user_function, void **context) { acpi_status status; u8 *end_aml; @@ -319,7 +319,7 @@ acpi_ut_walk_aml_resources(u8 * aml, /* Return the pointer to the end_tag if requested */ if (!user_function) { - *(void **)context = aml; + *context = aml; } /* Normal exit */ @@ -610,7 +610,7 @@ acpi_ut_get_resource_end_tag(union acpi_operand_object * obj_desc, status = acpi_ut_walk_aml_resources(obj_desc->buffer.pointer, obj_desc->buffer.length, NULL, - end_tag); + (void **)end_tag); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/utilities/utstate.c b/drivers/acpi/utilities/utstate.c index 637c5f964879..aec5034cd978 100644 --- a/drivers/acpi/utilities/utstate.c +++ b/drivers/acpi/utilities/utstate.c @@ -321,8 +321,8 @@ union acpi_generic_state *acpi_ut_create_control_state(void) * * RETURN: None * - * DESCRIPTION: Put a state object back into the global state cache. The object - * is not actually freed at this time. + * DESCRIPTION: Release a state object to the state cache. NULL state objects + * are ignored. * ******************************************************************************/ @@ -330,6 +330,10 @@ void acpi_ut_delete_generic_state(union acpi_generic_state *state) { ACPI_FUNCTION_TRACE("ut_delete_generic_state"); - (void)acpi_os_release_object(acpi_gbl_state_cache, state); + /* Ignore null state */ + + if (state) { + (void)acpi_os_release_object(acpi_gbl_state_cache, state); + } return_VOID; } diff --git a/include/acpi/acconfig.h b/include/acpi/acconfig.h index f3acfd9249fc..b6bba7db52d9 100644 --- a/include/acpi/acconfig.h +++ b/include/acpi/acconfig.h @@ -63,7 +63,7 @@ /* Current ACPICA subsystem version in YYYYMMDD format */ -#define ACPI_CA_VERSION 0x20060317 +#define ACPI_CA_VERSION 0x20060331 /* * OS name, used for the _OS object. The _OS object is essentially obsolete, diff --git a/include/acpi/acdisasm.h b/include/acpi/acdisasm.h index f004461a7753..70b52ffa969e 100644 --- a/include/acpi/acdisasm.h +++ b/include/acpi/acdisasm.h @@ -59,14 +59,52 @@ struct acpi_external_list { extern struct acpi_external_list *acpi_gbl_external_list; -/* Strings used for decoding flags to ASL keywords */ +typedef const struct acpi_dmtable_info { + u8 opcode; + u8 offset; + char *name; -extern const char *acpi_gbl_word_decode[4]; -extern const char *acpi_gbl_irq_decode[2]; -extern const char *acpi_gbl_lock_rule[ACPI_NUM_LOCK_RULES]; -extern const char *acpi_gbl_access_types[ACPI_NUM_ACCESS_TYPES]; -extern const char *acpi_gbl_update_rules[ACPI_NUM_UPDATE_RULES]; -extern const char *acpi_gbl_match_ops[ACPI_NUM_MATCH_OPS]; +} acpi_dmtable_info; + +/* + * Values for Opcode above. + * Note: 0-7 must not change, used as a flag shift value + */ +#define ACPI_DMT_FLAG0 0 +#define ACPI_DMT_FLAG1 1 +#define ACPI_DMT_FLAG2 2 +#define ACPI_DMT_FLAG3 3 +#define ACPI_DMT_FLAG4 4 +#define ACPI_DMT_FLAG5 5 +#define ACPI_DMT_FLAG6 6 +#define ACPI_DMT_FLAG7 7 +#define ACPI_DMT_FLAGS0 8 +#define ACPI_DMT_FLAGS2 9 +#define ACPI_DMT_UINT8 10 +#define ACPI_DMT_UINT16 11 +#define ACPI_DMT_UINT24 12 +#define ACPI_DMT_UINT32 13 +#define ACPI_DMT_UINT56 14 +#define ACPI_DMT_UINT64 15 +#define ACPI_DMT_STRING 16 +#define ACPI_DMT_NAME4 17 +#define ACPI_DMT_NAME6 18 +#define ACPI_DMT_NAME8 19 +#define ACPI_DMT_CHKSUM 20 +#define ACPI_DMT_SPACEID 21 +#define ACPI_DMT_GAS 22 +#define ACPI_DMT_MADT 23 +#define ACPI_DMT_SRAT 24 +#define ACPI_DMT_EXIT 25 + +typedef +void (*ACPI_TABLE_HANDLER) (struct acpi_table_header * table); + +struct acpi_dmtable_data { + char *signature; + struct acpi_dmtable_info *table_info; + ACPI_TABLE_HANDLER table_handler; +}; struct acpi_op_walk_info { u32 level; @@ -84,6 +122,95 @@ struct acpi_resource_tag { char *tag; }; +/* Strings used for decoding flags to ASL keywords */ + +extern const char *acpi_gbl_word_decode[4]; +extern const char *acpi_gbl_irq_decode[2]; +extern const char *acpi_gbl_lock_rule[ACPI_NUM_LOCK_RULES]; +extern const char *acpi_gbl_access_types[ACPI_NUM_ACCESS_TYPES]; +extern const char *acpi_gbl_update_rules[ACPI_NUM_UPDATE_RULES]; +extern const char *acpi_gbl_match_ops[ACPI_NUM_MATCH_OPS]; + +extern struct acpi_dmtable_info acpi_dm_table_info_asf0[]; +extern struct acpi_dmtable_info acpi_dm_table_info_asf1[]; +extern struct acpi_dmtable_info acpi_dm_table_info_asf2[]; +extern struct acpi_dmtable_info acpi_dm_table_info_asf3[]; +extern struct acpi_dmtable_info acpi_dm_table_info_asf4[]; +extern struct acpi_dmtable_info acpi_dm_table_info_asf_hdr[]; +extern struct acpi_dmtable_info acpi_dm_table_info_boot[]; +extern struct acpi_dmtable_info acpi_dm_table_info_cpep[]; +extern struct acpi_dmtable_info acpi_dm_table_info_cpep0[]; +extern struct acpi_dmtable_info acpi_dm_table_info_dbgp[]; +extern struct acpi_dmtable_info acpi_dm_table_info_ecdt[]; +extern struct acpi_dmtable_info acpi_dm_table_info_facs[]; +extern struct acpi_dmtable_info acpi_dm_table_info_fadt1[]; +extern struct acpi_dmtable_info acpi_dm_table_info_fadt2[]; +extern struct acpi_dmtable_info acpi_dm_table_info_gas[]; +extern struct acpi_dmtable_info acpi_dm_table_info_header[]; +extern struct acpi_dmtable_info acpi_dm_table_info_hpet[]; +extern struct acpi_dmtable_info acpi_dm_table_info_madt[]; +extern struct acpi_dmtable_info acpi_dm_table_info_madt0[]; +extern struct acpi_dmtable_info acpi_dm_table_info_madt1[]; +extern struct acpi_dmtable_info acpi_dm_table_info_madt2[]; +extern struct acpi_dmtable_info acpi_dm_table_info_madt3[]; +extern struct acpi_dmtable_info acpi_dm_table_info_madt4[]; +extern struct acpi_dmtable_info acpi_dm_table_info_madt5[]; +extern struct acpi_dmtable_info acpi_dm_table_info_madt6[]; +extern struct acpi_dmtable_info acpi_dm_table_info_madt7[]; +extern struct acpi_dmtable_info acpi_dm_table_info_madt8[]; +extern struct acpi_dmtable_info acpi_dm_table_info_madt_hdr[]; +extern struct acpi_dmtable_info acpi_dm_table_info_mcfg[]; +extern struct acpi_dmtable_info acpi_dm_table_info_mcfg0[]; +extern struct acpi_dmtable_info acpi_dm_table_info_rsdp1[]; +extern struct acpi_dmtable_info acpi_dm_table_info_rsdp2[]; +extern struct acpi_dmtable_info acpi_dm_table_info_sbst[]; +extern struct acpi_dmtable_info acpi_dm_table_info_slit[]; +extern struct acpi_dmtable_info acpi_dm_table_info_spcr[]; +extern struct acpi_dmtable_info acpi_dm_table_info_spmi[]; +extern struct acpi_dmtable_info acpi_dm_table_info_srat[]; +extern struct acpi_dmtable_info acpi_dm_table_info_srat0[]; +extern struct acpi_dmtable_info acpi_dm_table_info_srat1[]; +extern struct acpi_dmtable_info acpi_dm_table_info_tcpa[]; +extern struct acpi_dmtable_info acpi_dm_table_info_wdrt[]; + +/* + * dmtable + */ +void acpi_dm_dump_data_table(struct acpi_table_header *table); + +void +acpi_dm_dump_table(u32 table_length, + u32 table_offset, + void *table, + u32 sub_table_length, struct acpi_dmtable_info *info); + +void acpi_dm_line_header(u32 offset, u32 byte_length, char *name); + +void acpi_dm_line_header2(u32 offset, u32 byte_length, char *name, u32 value); + +/* + * dmtbdump + */ +void acpi_dm_dump_asf(struct acpi_table_header *table); + +void acpi_dm_dump_cpep(struct acpi_table_header *table); + +void acpi_dm_dump_fadt(struct acpi_table_header *table); + +void acpi_dm_dump_srat(struct acpi_table_header *table); + +void acpi_dm_dump_mcfg(struct acpi_table_header *table); + +void acpi_dm_dump_madt(struct acpi_table_header *table); + +u32 acpi_dm_dump_rsdp(struct acpi_table_header *table); + +void acpi_dm_dump_rsdt(struct acpi_table_header *table); + +void acpi_dm_dump_slit(struct acpi_table_header *table); + +void acpi_dm_dump_xsdt(struct acpi_table_header *table); + /* * dmwalk */ diff --git a/include/acpi/acglobal.h b/include/acpi/acglobal.h index f9eb5925511f..17c5b462676e 100644 --- a/include/acpi/acglobal.h +++ b/include/acpi/acglobal.h @@ -107,6 +107,7 @@ ACPI_EXTERN u32 acpi_gbl_trace_flags; * 3) Allow access to uninitialized locals/args (auto-init to integer 0) * 4) Allow ANY object type to be a source operand for the Store() operator * 5) Allow unresolved references (invalid target name) in package objects + * 6) Enable warning messages for behavior that is not ACPI spec compliant */ ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_enable_interpreter_slack, FALSE); @@ -149,10 +150,10 @@ ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_leave_wake_gpes_disabled, TRUE); ACPI_EXTERN u32 acpi_gbl_table_flags; ACPI_EXTERN u32 acpi_gbl_rsdt_table_count; ACPI_EXTERN struct rsdp_descriptor *acpi_gbl_RSDP; -ACPI_EXTERN XSDT_DESCRIPTOR *acpi_gbl_XSDT; -ACPI_EXTERN FADT_DESCRIPTOR *acpi_gbl_FADT; +ACPI_EXTERN struct xsdt_descriptor *acpi_gbl_XSDT; +ACPI_EXTERN struct fadt_descriptor *acpi_gbl_FADT; ACPI_EXTERN struct acpi_table_header *acpi_gbl_DSDT; -ACPI_EXTERN FACS_DESCRIPTOR *acpi_gbl_FACS; +ACPI_EXTERN struct facs_descriptor *acpi_gbl_FACS; ACPI_EXTERN struct acpi_common_facs acpi_gbl_common_fACS; /* * Since there may be multiple SSDTs and PSDTs, a single pointer is not diff --git a/include/acpi/aclocal.h b/include/acpi/aclocal.h index 5956431784d5..99785bae59b3 100644 --- a/include/acpi/aclocal.h +++ b/include/acpi/aclocal.h @@ -174,22 +174,28 @@ union acpi_name_union { * * The node is optimized for both 32-bit and 64-bit platforms: * 20 bytes for the 32-bit case, 32 bytes for the 64-bit case. + * + * Note: The descriptor_type and Type fields must appear in the identical + * position in both the struct acpi_namespace_node and union acpi_operand_object + * structures. */ struct acpi_namespace_node { union acpi_operand_object *object; /* Interpreter object */ u8 descriptor_type; /* Differentiate object descriptor types */ + u8 type; /* ACPI Type associated with this name */ u8 flags; /* Miscellaneous flags */ acpi_owner_id owner_id; /* Node creator */ - u8 type; /* ACPI Type associated with this name */ union acpi_name_union name; /* ACPI Name, always 4 chars per ACPI spec */ struct acpi_namespace_node *child; /* First child */ struct acpi_namespace_node *peer; /* Peer. Parent if ANOBJ_END_OF_PEER_LIST set */ - /* Fields used by the ASL compiler and disassembler only: */ - + /* + * The following fields are used by the ASL compiler and disassembler only + */ #ifdef ACPI_LARGE_NAMESPACE_NODE union acpi_parse_object *op; u32 value; + u32 length; #endif }; @@ -470,7 +476,7 @@ struct acpi_scope_state { }; struct acpi_pscope_state { - ACPI_STATE_COMMON u8 arg_count; /* Number of fixed arguments */ + ACPI_STATE_COMMON u32 arg_count; /* Number of fixed arguments */ union acpi_parse_object *op; /* Current op being parsed */ u8 *arg_end; /* Current argument end */ u8 *pkg_end; /* Current package end */ diff --git a/include/acpi/acmacros.h b/include/acpi/acmacros.h index c495670aa11a..60ceed4c81bf 100644 --- a/include/acpi/acmacros.h +++ b/include/acpi/acmacros.h @@ -130,7 +130,6 @@ #define ACPI_TO_POINTER(i) ACPI_ADD_PTR (void,(void *) NULL,(acpi_native_uint) i) #define ACPI_TO_INTEGER(p) ACPI_PTR_DIFF (p,(void *) NULL) #define ACPI_OFFSET(d,f) (acpi_size) ACPI_PTR_DIFF (&(((d *)0)->f),(void *) NULL) -#define ACPI_FADT_OFFSET(f) ACPI_OFFSET (FADT_DESCRIPTOR, f) #if ACPI_MACHINE_WIDTH == 16 #define ACPI_STORE_POINTER(d,s) ACPI_MOVE_32_TO_32(d,s) @@ -141,6 +140,12 @@ #define ACPI_PTR_TO_PHYSADDR(i) ACPI_TO_INTEGER(i) #endif +#ifndef ACPI_MISALIGNMENT_NOT_SUPPORTED +#define ACPI_COMPARE_NAME(a,b) (*ACPI_CAST_PTR (u32,(a)) == *ACPI_CAST_PTR (u32,(b))) +#else +#define ACPI_COMPARE_NAME(a,b) (!ACPI_STRNCMP (ACPI_CAST_PTR (char,(a)), ACPI_CAST_PTR (char,(b)), 4)) +#endif + /* * Macros for moving data around to/from buffers that are possibly unaligned. * If the hardware supports the transfer of unaligned data, just do the store. diff --git a/include/acpi/acobject.h b/include/acpi/acobject.h index 28241aa15de9..d9442d346b9b 100644 --- a/include/acpi/acobject.h +++ b/include/acpi/acobject.h @@ -65,6 +65,10 @@ * * descriptor_type is used to differentiate between internal descriptors, and * must be in the same place across all descriptors + * + * Note: The descriptor_type and Type fields must appear in the identical + * position in both the struct acpi_namespace_node and union acpi_operand_object + * structures. */ #define ACPI_OBJECT_COMMON_HEADER \ union acpi_operand_object *next_object; /* Objects linked to parent NS node */\ diff --git a/include/acpi/acparser.h b/include/acpi/acparser.h index 53ac4ce8753a..de14492a5985 100644 --- a/include/acpi/acparser.h +++ b/include/acpi/acparser.h @@ -46,9 +46,9 @@ #define OP_HAS_RETURN_VALUE 1 -/* variable # arguments */ +/* Variable number of arguments. This field must be 32 bits */ -#define ACPI_VAR_ARGS ACPI_UINT8_MAX +#define ACPI_VAR_ARGS ACPI_UINT32_MAX #define ACPI_PARSE_DELETE_TREE 0x0001 #define ACPI_PARSE_NO_TREE_DELETE 0x0000 @@ -146,12 +146,13 @@ u8 acpi_ps_has_completed_scope(struct acpi_parse_state *parser_state); void acpi_ps_pop_scope(struct acpi_parse_state *parser_state, - union acpi_parse_object **op, u32 * arg_list, u8 * arg_count); + union acpi_parse_object **op, + u32 * arg_list, u32 * arg_count); acpi_status acpi_ps_push_scope(struct acpi_parse_state *parser_state, union acpi_parse_object *op, - u32 remaining_args, u8 arg_count); + u32 remaining_args, u32 arg_count); void acpi_ps_cleanup_scope(struct acpi_parse_state *state); diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 6dca3d542080..43f8c2a23a24 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -59,7 +59,7 @@ acpi_evaluate_reference(acpi_handle handle, #define ACPI_BUS_FILE_ROOT "acpi" extern struct proc_dir_entry *acpi_root_dir; -extern FADT_DESCRIPTOR acpi_fadt; +extern struct fadt_descriptor acpi_fadt; enum acpi_bus_removal_type { ACPI_BUS_REMOVAL_NORMAL = 0, diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h index 91c3cdff28bb..42307d948c1b 100644 --- a/include/acpi/acpiosxf.h +++ b/include/acpi/acpiosxf.h @@ -169,8 +169,6 @@ acpi_os_queue_for_execution(u32 priority, void acpi_os_wait_events_complete(void *context); -void acpi_os_wait_events_complete(void *context); - void acpi_os_sleep(acpi_integer milliseconds); void acpi_os_stall(u32 microseconds); diff --git a/include/acpi/acstruct.h b/include/acpi/acstruct.h index 04e8966a377d..b8a6d6110d57 100644 --- a/include/acpi/acstruct.h +++ b/include/acpi/acstruct.h @@ -86,7 +86,7 @@ struct acpi_walk_state { struct acpi_parse_state parser_state; /* Current state of parser */ u32 prev_arg_types; - u8 arg_count; /* push for fixed or var args */ + u32 arg_count; /* push for fixed or var args */ struct acpi_namespace_node arguments[ACPI_METHOD_NUM_ARGS]; /* Control method arguments */ struct acpi_namespace_node local_variables[ACPI_METHOD_NUM_LOCALS]; /* Control method locals */ diff --git a/include/acpi/actables.h b/include/acpi/actables.h index 30a47542e1c8..4dbaf02fe526 100644 --- a/include/acpi/actables.h +++ b/include/acpi/actables.h @@ -136,7 +136,11 @@ acpi_status acpi_tb_is_table_installed(struct acpi_table_desc *new_table_desc); acpi_status acpi_tb_verify_table_checksum(struct acpi_table_header *table_header); -u8 acpi_tb_generate_checksum(void *buffer, u32 length); +u8 acpi_tb_sum_table(void *buffer, u32 length); + +u8 acpi_tb_generate_checksum(struct acpi_table_header *table); + +void acpi_tb_set_checksum(struct acpi_table_header *table); acpi_status acpi_tb_validate_table_header(struct acpi_table_header *table_header); diff --git a/include/acpi/actbl.h b/include/acpi/actbl.h index ed53f842dad4..e1a40135f707 100644 --- a/include/acpi/actbl.h +++ b/include/acpi/actbl.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Name: actbl.h - Table data structures defined in ACPI specification + * Name: actbl.h - Basic ACPI Table Definitions * *****************************************************************************/ @@ -45,66 +45,45 @@ #define __ACTBL_H__ /* - * Note about bitfields: The u8 type is used for bitfields in ACPI tables. - * This is the only type that is even remotely portable. Anything else is not - * portable, so do not use any other bitfield types. - */ - -/* - * Values for description table header signatures + * Values for description table header signatures. Useful because they make + * it more difficult to inadvertently type in the wrong signature. */ -#define RSDP_NAME "RSDP" -#define RSDP_SIG "RSD PTR " /* RSDT Pointer signature */ -#define APIC_SIG "APIC" /* Multiple APIC Description Table */ #define DSDT_SIG "DSDT" /* Differentiated System Description Table */ #define FADT_SIG "FACP" /* Fixed ACPI Description Table */ #define FACS_SIG "FACS" /* Firmware ACPI Control Structure */ #define PSDT_SIG "PSDT" /* Persistent System Description Table */ +#define RSDP_SIG "RSD PTR " /* Root System Description Pointer */ #define RSDT_SIG "RSDT" /* Root System Description Table */ #define XSDT_SIG "XSDT" /* Extended System Description Table */ #define SSDT_SIG "SSDT" /* Secondary System Description Table */ -#define SBST_SIG "SBST" /* Smart Battery Specification Table */ -#define SPIC_SIG "SPIC" /* IOSAPIC table */ -#define BOOT_SIG "BOOT" /* Boot table */ - -#define GL_OWNED 0x02 /* Ownership of global lock is bit 1 */ +#define RSDP_NAME "RSDP" /* - * Common table types. The base code can remain - * constant if the underlying tables are changed + * All tables and structures must be byte-packed to match the ACPI + * specification, since the tables are provided by the system BIOS */ -#define RSDT_DESCRIPTOR struct rsdt_descriptor_rev2 -#define XSDT_DESCRIPTOR struct xsdt_descriptor_rev2 -#define FACS_DESCRIPTOR struct facs_descriptor_rev2 -#define FADT_DESCRIPTOR struct fadt_descriptor_rev2 - #pragma pack(1) /* - * ACPI Version-independent tables + * These are the ACPI tables that are directly consumed by the subsystem. + * + * The RSDP and FACS do not use the common ACPI table header. All other ACPI + * tables use the header. * - * NOTE: The tables that are specific to ACPI versions (1.0, 2.0, etc.) - * are in separate files. + * Note about bitfields: The u8 type is used for bitfields in ACPI tables. + * This is the only type that is even remotely portable. Anything else is not + * portable, so do not use any other bitfield types. */ -struct rsdp_descriptor { /* Root System Descriptor Pointer */ - char signature[8]; /* ACPI signature, contains "RSD PTR " */ - u8 checksum; /* ACPI 1.0 checksum */ - char oem_id[6]; /* OEM identification */ - u8 revision; /* Must be (0) for ACPI 1.0 or (2) for ACPI 2.0+ */ - u32 rsdt_physical_address; /* 32-bit physical address of the RSDT */ - u32 length; /* XSDT Length in bytes, including header */ - u64 xsdt_physical_address; /* 64-bit physical address of the XSDT */ - u8 extended_checksum; /* Checksum of entire table (ACPI 2.0) */ - char reserved[3]; /* Reserved, must be zero */ -}; -struct acpi_common_facs { /* Common FACS for internal use */ - u32 *global_lock; - u64 *firmware_waking_vector; - u8 vector_width; -}; +/******************************************************************************* + * + * ACPI Table Header. This common header is used by all tables except the + * RSDP and FACS. The define is used for direct inclusion of header into + * other ACPI tables + * + ******************************************************************************/ -#define ACPI_TABLE_HEADER_DEF /* ACPI common table header */ \ +#define ACPI_TABLE_HEADER_DEF \ char signature[4]; /* ASCII table signature */\ u32 length; /* Length of table in bytes, including this header */\ u8 revision; /* ACPI Specification minor version # */\ @@ -112,153 +91,238 @@ struct acpi_common_facs { /* Common FACS for internal use */ char oem_id[6]; /* ASCII OEM identification */\ char oem_table_id[8]; /* ASCII OEM table identification */\ u32 oem_revision; /* OEM revision number */\ - char asl_compiler_id [4]; /* ASCII ASL compiler vendor ID */\ + char asl_compiler_id[4]; /* ASCII ASL compiler vendor ID */\ u32 asl_compiler_revision; /* ASL compiler version */ -struct acpi_table_header { /* ACPI common table header */ +struct acpi_table_header { ACPI_TABLE_HEADER_DEF}; /* - * MADT values and structures + * GAS - Generic Address Structure (ACPI 2.0+) */ +struct acpi_generic_address { + u8 address_space_id; /* Address space where struct or register exists */ + u8 register_bit_width; /* Size in bits of given register */ + u8 register_bit_offset; /* Bit offset within the register */ + u8 access_width; /* Minimum Access size (ACPI 3.0) */ + u64 address; /* 64-bit address of struct or register */ +}; -/* Values for MADT PCATCompat */ +/******************************************************************************* + * + * RSDP - Root System Description Pointer (Signature is "RSD PTR ") + * + ******************************************************************************/ + +struct rsdp_descriptor { + char signature[8]; /* ACPI signature, contains "RSD PTR " */ + u8 checksum; /* ACPI 1.0 checksum */ + char oem_id[6]; /* OEM identification */ + u8 revision; /* Must be (0) for ACPI 1.0 or (2) for ACPI 2.0+ */ + u32 rsdt_physical_address; /* 32-bit physical address of the RSDT */ + u32 length; /* Table length in bytes, including header (ACPI 2.0+) */ + u64 xsdt_physical_address; /* 64-bit physical address of the XSDT (ACPI 2.0+) */ + u8 extended_checksum; /* Checksum of entire table (ACPI 2.0+) */ + u8 reserved[3]; /* Reserved, must be zero */ +}; -#define DUAL_PIC 0 -#define MULTIPLE_APIC 1 +#define ACPI_RSDP_REV0_SIZE 20 /* Size of original ACPI 1.0 RSDP */ -/* Master MADT */ +/******************************************************************************* + * + * RSDT/XSDT - Root System Description Tables + * + ******************************************************************************/ -struct multiple_apic_table { - ACPI_TABLE_HEADER_DEF /* ACPI common table header */ - u32 local_apic_address; /* Physical address of local APIC */ +struct rsdt_descriptor { + ACPI_TABLE_HEADER_DEF u32 table_offset_entry[1]; /* Array of pointers to ACPI tables */ +}; + +struct xsdt_descriptor { + ACPI_TABLE_HEADER_DEF u64 table_offset_entry[1]; /* Array of pointers to ACPI tables */ +}; + +/******************************************************************************* + * + * FACS - Firmware ACPI Control Structure (FACS) + * + ******************************************************************************/ + +struct facs_descriptor { + char signature[4]; /* ASCII table signature */ + u32 length; /* Length of structure, in bytes */ + u32 hardware_signature; /* Hardware configuration signature */ + u32 firmware_waking_vector; /* 32-bit physical address of the Firmware Waking Vector */ + u32 global_lock; /* Global Lock for shared hardware resources */ /* Flags (32 bits) */ - u8 PCATcompat:1; /* 00: System also has dual 8259s */ + u8 S4bios_f:1; /* 00: S4BIOS support is present */ u8:7; /* 01-07: Reserved, must be zero */ u8 reserved1[3]; /* 08-31: Reserved, must be zero */ -}; -/* Values for Type in APIC_HEADER_DEF */ + u64 xfirmware_waking_vector; /* 64-bit version of the Firmware Waking Vector (ACPI 2.0+) */ + u8 version; /* Version of this table (ACPI 2.0+) */ + u8 reserved[31]; /* Reserved, must be zero */ +}; -#define APIC_PROCESSOR 0 -#define APIC_IO 1 -#define APIC_XRUPT_OVERRIDE 2 -#define APIC_NMI 3 -#define APIC_LOCAL_NMI 4 -#define APIC_ADDRESS_OVERRIDE 5 -#define APIC_IO_SAPIC 6 -#define APIC_LOCAL_SAPIC 7 -#define APIC_XRUPT_SOURCE 8 -#define APIC_RESERVED 9 /* 9 and greater are reserved */ +#define ACPI_GLOCK_PENDING 0x01 /* 00: Pending global lock ownership */ +#define ACPI_GLOCK_OWNED 0x02 /* 01: Global lock is owned */ /* - * MADT sub-structures (Follow MULTIPLE_APIC_DESCRIPTION_TABLE) + * Common FACS - This is a version-independent FACS structure used for internal use only */ -#define APIC_HEADER_DEF /* Common APIC sub-structure header */\ - u8 type; \ - u8 length; - -struct apic_header { -APIC_HEADER_DEF}; - -/* Values for MPS INTI flags */ - -#define POLARITY_CONFORMS 0 -#define POLARITY_ACTIVE_HIGH 1 -#define POLARITY_RESERVED 2 -#define POLARITY_ACTIVE_LOW 3 - -#define TRIGGER_CONFORMS 0 -#define TRIGGER_EDGE 1 -#define TRIGGER_RESERVED 2 -#define TRIGGER_LEVEL 3 - -/* Common flag definitions (16 bits each) */ - -#define MPS_INTI_FLAGS \ - u8 polarity : 2; /* 00-01: Polarity of APIC I/O input signals */\ - u8 trigger_mode : 2; /* 02-03: Trigger mode of APIC input signals */\ - u8 : 4; /* 04-07: Reserved, must be zero */\ - u8 reserved1; /* 08-15: Reserved, must be zero */ - -#define LOCAL_APIC_FLAGS \ - u8 processor_enabled: 1; /* 00: Processor is usable if set */\ - u8 : 7; /* 01-07: Reserved, must be zero */\ - u8 reserved2; /* 08-15: Reserved, must be zero */ - -/* Sub-structures for MADT */ - -struct madt_processor_apic { - APIC_HEADER_DEF u8 processor_id; /* ACPI processor id */ - u8 local_apic_id; /* Processor's local APIC id */ - LOCAL_APIC_FLAGS}; - -struct madt_io_apic { - APIC_HEADER_DEF u8 io_apic_id; /* I/O APIC ID */ - u8 reserved; /* Reserved - must be zero */ - u32 address; /* APIC physical address */ - u32 interrupt; /* Global system interrupt where INTI - * lines start */ +struct acpi_common_facs { + u32 *global_lock; + u64 *firmware_waking_vector; + u8 vector_width; }; -struct madt_interrupt_override { - APIC_HEADER_DEF u8 bus; /* 0 - ISA */ - u8 source; /* Interrupt source (IRQ) */ - u32 interrupt; /* Global system interrupt */ - MPS_INTI_FLAGS}; +/******************************************************************************* + * + * FADT - Fixed ACPI Description Table (Signature "FACP") + * + ******************************************************************************/ + +/* Fields common to all versions of the FADT */ + +#define ACPI_FADT_COMMON \ + ACPI_TABLE_HEADER_DEF \ + u32 V1_firmware_ctrl; /* 32-bit physical address of FACS */ \ + u32 V1_dsdt; /* 32-bit physical address of DSDT */ \ + u8 reserved1; /* System Interrupt Model isn't used in ACPI 2.0*/ \ + u8 prefer_PM_profile; /* Conveys preferred power management profile to OSPM. */ \ + u16 sci_int; /* System vector of SCI interrupt */ \ + u32 smi_cmd; /* Port address of SMI command port */ \ + u8 acpi_enable; /* Value to write to smi_cmd to enable ACPI */ \ + u8 acpi_disable; /* Value to write to smi_cmd to disable ACPI */ \ + u8 S4bios_req; /* Value to write to SMI CMD to enter S4BIOS state */ \ + u8 pstate_cnt; /* Processor performance state control*/ \ + u32 V1_pm1a_evt_blk; /* Port address of Power Mgt 1a Event Reg Blk */ \ + u32 V1_pm1b_evt_blk; /* Port address of Power Mgt 1b Event Reg Blk */ \ + u32 V1_pm1a_cnt_blk; /* Port address of Power Mgt 1a Control Reg Blk */ \ + u32 V1_pm1b_cnt_blk; /* Port address of Power Mgt 1b Control Reg Blk */ \ + u32 V1_pm2_cnt_blk; /* Port address of Power Mgt 2 Control Reg Blk */ \ + u32 V1_pm_tmr_blk; /* Port address of Power Mgt Timer Ctrl Reg Blk */ \ + u32 V1_gpe0_blk; /* Port addr of General Purpose acpi_event 0 Reg Blk */ \ + u32 V1_gpe1_blk; /* Port addr of General Purpose acpi_event 1 Reg Blk */ \ + u8 pm1_evt_len; /* Byte length of ports at pm1_x_evt_blk */ \ + u8 pm1_cnt_len; /* Byte length of ports at pm1_x_cnt_blk */ \ + u8 pm2_cnt_len; /* Byte Length of ports at pm2_cnt_blk */ \ + u8 pm_tm_len; /* Byte Length of ports at pm_tm_blk */ \ + u8 gpe0_blk_len; /* Byte Length of ports at gpe0_blk */ \ + u8 gpe1_blk_len; /* Byte Length of ports at gpe1_blk */ \ + u8 gpe1_base; /* Offset in gpe model where gpe1 events start */ \ + u8 cst_cnt; /* Support for the _CST object and C States change notification.*/ \ + u16 plvl2_lat; /* Worst case HW latency to enter/exit C2 state */ \ + u16 plvl3_lat; /* Worst case HW latency to enter/exit C3 state */ \ + u16 flush_size; /* Processor's memory cache line width, in bytes */ \ + u16 flush_stride; /* Number of flush strides that need to be read */ \ + u8 duty_offset; /* Processor's duty cycle index in processor's P_CNT reg*/ \ + u8 duty_width; /* Processor's duty cycle value bit width in P_CNT register.*/ \ + u8 day_alrm; /* Index to day-of-month alarm in RTC CMOS RAM */ \ + u8 mon_alrm; /* Index to month-of-year alarm in RTC CMOS RAM */ \ + u8 century; /* Index to century in RTC CMOS RAM */ \ + u16 iapc_boot_arch; /* IA-PC Boot Architecture Flags. See Table 5-10 for description*/ \ + u8 reserved2; /* Reserved, must be zero */ -struct madt_nmi_source { - APIC_HEADER_DEF MPS_INTI_FLAGS u32 interrupt; /* Global system interrupt */ +/* + * ACPI 2.0+ FADT + */ +struct fadt_descriptor { + ACPI_FADT_COMMON + /* Flags (32 bits) */ + u8 wb_invd:1; /* 00: The wbinvd instruction works properly */ + u8 wb_invd_flush:1; /* 01: The wbinvd flushes but does not invalidate */ + u8 proc_c1:1; /* 02: All processors support C1 state */ + u8 plvl2_up:1; /* 03: C2 state works on MP system */ + u8 pwr_button:1; /* 04: Power button is handled as a generic feature */ + u8 sleep_button:1; /* 05: Sleep button is handled as a generic feature, or not present */ + u8 fixed_rTC:1; /* 06: RTC wakeup stat not in fixed register space */ + u8 rtcs4:1; /* 07: RTC wakeup stat not possible from S4 */ + u8 tmr_val_ext:1; /* 08: tmr_val is 32 bits 0=24-bits */ + u8 dock_cap:1; /* 09: Docking supported */ + u8 reset_reg_sup:1; /* 10: System reset via the FADT RESET_REG supported */ + u8 sealed_case:1; /* 11: No internal expansion capabilities and case is sealed */ + u8 headless:1; /* 12: No local video capabilities or local input devices */ + u8 cpu_sw_sleep:1; /* 13: Must execute native instruction after writing SLP_TYPx register */ + + u8 pci_exp_wak:1; /* 14: System supports PCIEXP_WAKE (STS/EN) bits (ACPI 3.0) */ + u8 use_platform_clock:1; /* 15: OSPM should use platform-provided timer (ACPI 3.0) */ + u8 S4rtc_sts_valid:1; /* 16: Contents of RTC_STS valid after S4 wake (ACPI 3.0) */ + u8 remote_power_on_capable:1; /* 17: System is compatible with remote power on (ACPI 3.0) */ + u8 force_apic_cluster_model:1; /* 18: All local APICs must use cluster model (ACPI 3.0) */ + u8 force_apic_physical_destination_mode:1; /* 19: all local x_aPICs must use physical dest mode (ACPI 3.0) */ + u8:4; /* 20-23: Reserved, must be zero */ + u8 reserved3; /* 24-31: Reserved, must be zero */ + + struct acpi_generic_address reset_register; /* Reset register address in GAS format */ + u8 reset_value; /* Value to write to the reset_register port to reset the system */ + u8 reserved4[3]; /* These three bytes must be zero */ + u64 xfirmware_ctrl; /* 64-bit physical address of FACS */ + u64 Xdsdt; /* 64-bit physical address of DSDT */ + struct acpi_generic_address xpm1a_evt_blk; /* Extended Power Mgt 1a acpi_event Reg Blk address */ + struct acpi_generic_address xpm1b_evt_blk; /* Extended Power Mgt 1b acpi_event Reg Blk address */ + struct acpi_generic_address xpm1a_cnt_blk; /* Extended Power Mgt 1a Control Reg Blk address */ + struct acpi_generic_address xpm1b_cnt_blk; /* Extended Power Mgt 1b Control Reg Blk address */ + struct acpi_generic_address xpm2_cnt_blk; /* Extended Power Mgt 2 Control Reg Blk address */ + struct acpi_generic_address xpm_tmr_blk; /* Extended Power Mgt Timer Ctrl Reg Blk address */ + struct acpi_generic_address xgpe0_blk; /* Extended General Purpose acpi_event 0 Reg Blk address */ + struct acpi_generic_address xgpe1_blk; /* Extended General Purpose acpi_event 1 Reg Blk address */ }; -struct madt_local_apic_nmi { - APIC_HEADER_DEF u8 processor_id; /* ACPI processor id */ - MPS_INTI_FLAGS u8 lint; /* LINTn to which NMI is connected */ +/* + * "Down-revved" ACPI 2.0 FADT descriptor + * Defined here to allow compiler to generate the length of the struct + */ +struct fadt_descriptor_rev2_minus { + ACPI_FADT_COMMON u32 flags; + struct acpi_generic_address reset_register; /* Reset register address in GAS format */ + u8 reset_value; /* Value to write to the reset_register port to reset the system. */ + u8 reserved7[3]; /* Reserved, must be zero */ }; -struct madt_address_override { - APIC_HEADER_DEF u16 reserved; /* Reserved, must be zero */ - u64 address; /* APIC physical address */ +/* + * ACPI 1.0 FADT + * Defined here to allow compiler to generate the length of the struct + */ +struct fadt_descriptor_rev1 { + ACPI_FADT_COMMON u32 flags; }; -struct madt_io_sapic { - APIC_HEADER_DEF u8 io_sapic_id; /* I/O SAPIC ID */ - u8 reserved; /* Reserved, must be zero */ - u32 interrupt_base; /* Glocal interrupt for SAPIC start */ - u64 address; /* SAPIC physical address */ -}; +/* FADT: Prefered Power Management Profiles */ -struct madt_local_sapic { - APIC_HEADER_DEF u8 processor_id; /* ACPI processor id */ - u8 local_sapic_id; /* SAPIC ID */ - u8 local_sapic_eid; /* SAPIC EID */ - u8 reserved[3]; /* Reserved, must be zero */ - LOCAL_APIC_FLAGS u32 processor_uID; /* Numeric UID - ACPI 3.0 */ - char processor_uIDstring[1]; /* String UID - ACPI 3.0 */ -}; +#define PM_UNSPECIFIED 0 +#define PM_DESKTOP 1 +#define PM_MOBILE 2 +#define PM_WORKSTATION 3 +#define PM_ENTERPRISE_SERVER 4 +#define PM_SOHO_SERVER 5 +#define PM_APPLIANCE_PC 6 -struct madt_interrupt_source { - APIC_HEADER_DEF MPS_INTI_FLAGS u8 interrupt_type; /* 1=PMI, 2=INIT, 3=corrected */ - u8 processor_id; /* Processor ID */ - u8 processor_eid; /* Processor EID */ - u8 io_sapic_vector; /* Vector value for PMI interrupts */ - u32 interrupt; /* Global system interrupt */ - u32 flags; /* Interrupt Source Flags */ -}; +/* FADT: Boot Arch Flags */ -/* - * Smart Battery - */ -struct smart_battery_table { - ACPI_TABLE_HEADER_DEF u32 warning_level; - u32 low_level; - u32 critical_level; -}; +#define BAF_LEGACY_DEVICES 0x0001 +#define BAF_8042_KEYBOARD_CONTROLLER 0x0002 + +#define FADT2_REVISION_ID 3 +#define FADT2_MINUS_REVISION_ID 2 + +/* Reset to default packing */ #pragma pack() +/* + * This macro is temporary until the table bitfield flag definitions + * are removed and replaced by a Flags field. + */ +#define ACPI_FLAG_OFFSET(d,f,o) (u8) (ACPI_OFFSET (d,f) + \ + sizeof(((d *)0)->f) + o) +/* + * Get the remaining ACPI tables + */ +#include "actbl1.h" + /* * ACPI Table information. We save the table address, length, * and type of memory allocation (mapped or allocated) for each @@ -290,27 +354,17 @@ struct acpi_table_support { u8 flags; }; -/* - * Get the ACPI version-specific tables - */ -#include "actbl1.h" /* Acpi 1.0 table definitions */ -#include "actbl2.h" /* Acpi 2.0 table definitions */ - extern u8 acpi_fadt_is_v1; /* is set to 1 if FADT is revision 1, * needed for certain workarounds */ +/* Macros used to generate offsets to specific table fields */ -#pragma pack(1) -/* - * High performance timer - */ -struct hpet_table { - ACPI_TABLE_HEADER_DEF u32 hardware_id; - struct acpi_generic_address base_address; - u8 hpet_number; - u16 clock_tick; - u8 attributes; -}; +#define ACPI_FACS_OFFSET(f) (u8) ACPI_OFFSET (struct facs_descriptor,f) +#define ACPI_FADT_OFFSET(f) (u8) ACPI_OFFSET (struct fadt_descriptor, f) +#define ACPI_GAS_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_generic_address,f) +#define ACPI_HDR_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_table_header,f) +#define ACPI_RSDP_OFFSET(f) (u8) ACPI_OFFSET (struct rsdp_descriptor,f) -#pragma pack() +#define ACPI_FADT_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct fadt_descriptor,f,o) +#define ACPI_FACS_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct facs_descriptor,f,o) #endif /* __ACTBL_H__ */ diff --git a/include/acpi/actbl1.h b/include/acpi/actbl1.h index cd428d57add0..745a6445a4f9 100644 --- a/include/acpi/actbl1.h +++ b/include/acpi/actbl1.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Name: actbl1.h - ACPI 1.0 tables + * Name: actbl1.h - Additional ACPI table definitions * *****************************************************************************/ @@ -44,92 +44,599 @@ #ifndef __ACTBL1_H__ #define __ACTBL1_H__ +/******************************************************************************* + * + * Additional ACPI Tables + * + * These tables are not consumed directly by the ACPICA subsystem, but are + * included here to support device drivers and the AML disassembler. + * + ******************************************************************************/ + +/* + * Values for description table header signatures. Useful because they make + * it more difficult to inadvertently type in the wrong signature. + */ +#define ACPI_SIG_ASF "ASF!" /* Alert Standard Format table */ +#define ACPI_SIG_BOOT "BOOT" /* Simple Boot Flag Table */ +#define ACPI_SIG_CPEP "CPEP" /* Corrected Platform Error Polling table */ +#define ACPI_SIG_DBGP "DBGP" /* Debug Port table */ +#define ACPI_SIG_ECDT "ECDT" /* Embedded Controller Boot Resources Table */ +#define ACPI_SIG_HPET "HPET" /* High Precision Event Timer table */ +#define ACPI_SIG_MADT "APIC" /* Multiple APIC Description Table */ +#define ACPI_SIG_MCFG "MCFG" /* PCI Memory Mapped Configuration table */ +#define ACPI_SIG_SBST "SBST" /* Smart Battery Specification Table */ +#define ACPI_SIG_SLIT "SLIT" /* System Locality Distance Information Table */ +#define ACPI_SIG_SPCR "SPCR" /* Serial Port Console Redirection table */ +#define ACPI_SIG_SPMI "SPMI" /* Server Platform Management Interface table */ +#define ACPI_SIG_SRAT "SRAT" /* System Resource Affinity Table */ +#define ACPI_SIG_TCPA "TCPA" /* Trusted Computing Platform Alliance table */ +#define ACPI_SIG_WDRT "WDRT" /* Watchdog Resource Table */ + +/* Legacy names */ + +#define APIC_SIG "APIC" /* Multiple APIC Description Table */ +#define BOOT_SIG "BOOT" /* Simple Boot Flag Table */ +#define SBST_SIG "SBST" /* Smart Battery Specification Table */ + +/* + * All tables must be byte-packed to match the ACPI specification, since + * the tables are provided by the system BIOS. + */ #pragma pack(1) /* - * ACPI 1.0 Root System Description Table (RSDT) + * Note about bitfields: The u8 type is used for bitfields in ACPI tables. + * This is the only type that is even remotely portable. Anything else is not + * portable, so do not use any other bitfield types. */ -struct rsdt_descriptor_rev1 { - ACPI_TABLE_HEADER_DEF /* ACPI common table header */ - u32 table_offset_entry[1]; /* Array of pointers to ACPI tables */ -}; + +/******************************************************************************* + * + * ASF - Alert Standard Format table (Signature "ASF!") + * + ******************************************************************************/ + +struct acpi_table_asf { +ACPI_TABLE_HEADER_DEF}; + +#define ACPI_ASF_HEADER_DEF \ + u8 type; \ + u8 reserved; \ + u16 length; + +struct acpi_asf_header { +ACPI_ASF_HEADER_DEF}; + +/* Values for Type field */ + +#define ASF_INFO 0 +#define ASF_ALERT 1 +#define ASF_CONTROL 2 +#define ASF_BOOT 3 +#define ASF_ADDRESS 4 +#define ASF_RESERVED 5 /* - * ACPI 1.0 Firmware ACPI Control Structure (FACS) + * ASF subtables */ -struct facs_descriptor_rev1 { - char signature[4]; /* ASCII table signature */ - u32 length; /* Length of structure in bytes */ - u32 hardware_signature; /* Hardware configuration signature */ - u32 firmware_waking_vector; /* ACPI OS waking vector */ - u32 global_lock; /* Global Lock */ + +/* 0: ASF Information */ + +struct acpi_asf_info { + ACPI_ASF_HEADER_DEF u8 min_reset_value; + u8 min_poll_interval; + u16 system_id; + u32 mfg_id; + u8 flags; + u8 reserved2[3]; +}; + +/* 1: ASF Alerts */ + +struct acpi_asf_alert { + ACPI_ASF_HEADER_DEF u8 assert_mask; + u8 deassert_mask; + u8 alerts; + u8 data_length; + u8 array[1]; +}; + +/* 2: ASF Remote Control */ + +struct acpi_asf_remote { + ACPI_ASF_HEADER_DEF u8 controls; + u8 data_length; + u16 reserved2; + u8 array[1]; +}; + +/* 3: ASF RMCP Boot Options */ + +struct acpi_asf_rmcp { + ACPI_ASF_HEADER_DEF u8 capabilities[7]; + u8 completion_code; + u32 enterprise_id; + u8 command; + u16 parameter; + u16 boot_options; + u16 oem_parameters; +}; + +/* 4: ASF Address */ + +struct acpi_asf_address { + ACPI_ASF_HEADER_DEF u8 eprom_address; + u8 devices; + u8 smbus_addresses[1]; +}; + +/******************************************************************************* + * + * BOOT - Simple Boot Flag Table + * + ******************************************************************************/ + +struct acpi_table_boot { + ACPI_TABLE_HEADER_DEF u8 cmos_index; /* Index in CMOS RAM for the boot register */ + u8 reserved[3]; +}; + +/******************************************************************************* + * + * CPEP - Corrected Platform Error Polling table + * + ******************************************************************************/ + +struct acpi_table_cpep { + ACPI_TABLE_HEADER_DEF u64 reserved; +}; + +/* Subtable */ + +struct acpi_cpep_polling { + u8 type; + u8 length; + u8 processor_id; /* Processor ID */ + u8 processor_eid; /* Processor EID */ + u32 polling_interval; /* Polling interval (msec) */ +}; + +/******************************************************************************* + * + * DBGP - Debug Port table + * + ******************************************************************************/ + +struct acpi_table_dbgp { + ACPI_TABLE_HEADER_DEF u8 interface_type; /* 0=full 16550, 1=subset of 16550 */ + u8 reserved[3]; + struct acpi_generic_address debug_port; +}; + +/******************************************************************************* + * + * ECDT - Embedded Controller Boot Resources Table + * + ******************************************************************************/ + +struct ec_boot_resources { + ACPI_TABLE_HEADER_DEF struct acpi_generic_address ec_control; /* Address of EC command/status register */ + struct acpi_generic_address ec_data; /* Address of EC data register */ + u32 uid; /* Unique ID - must be same as the EC _UID method */ + u8 gpe_bit; /* The GPE for the EC */ + u8 ec_id[1]; /* Full namepath of the EC in the ACPI namespace */ +}; + +/******************************************************************************* + * + * HPET - High Precision Event Timer table + * + ******************************************************************************/ + +struct acpi_hpet_table { + ACPI_TABLE_HEADER_DEF u32 hardware_id; /* Hardware ID of event timer block */ + struct acpi_generic_address base_address; /* Address of event timer block */ + u8 hpet_number; /* HPET sequence number */ + u16 clock_tick; /* Main counter min tick, periodic mode */ + u8 attributes; +}; + +#if 0 /* HPET flags to be converted to macros */ +struct { /* Flags (8 bits) */ + u8 page_protect:1; /* 00: No page protection */ + u8 page_protect4:1; /* 01: 4_kB page protected */ + u8 page_protect64:1; /* 02: 64_kB page protected */ + u8:5; /* 03-07: Reserved, must be zero */ +} flags; +#endif + +/******************************************************************************* + * + * MADT - Multiple APIC Description Table + * + ******************************************************************************/ + +struct multiple_apic_table { + ACPI_TABLE_HEADER_DEF u32 local_apic_address; /* Physical address of local APIC */ /* Flags (32 bits) */ - u8 S4bios_f:1; /* 00: S4BIOS support is present */ + u8 PCATcompat:1; /* 00: System also has dual 8259s */ u8:7; /* 01-07: Reserved, must be zero */ u8 reserved1[3]; /* 08-31: Reserved, must be zero */ - - u8 reserved2[40]; /* Reserved, must be zero */ }; +/* Values for MADT PCATCompat */ + +#define DUAL_PIC 0 +#define MULTIPLE_APIC 1 + +/* Common MADT Sub-table header */ + +#define APIC_HEADER_DEF \ + u8 type; \ + u8 length; + +struct apic_header { +APIC_HEADER_DEF}; + +/* Values for Type in struct apic_header */ + +#define APIC_PROCESSOR 0 +#define APIC_IO 1 +#define APIC_XRUPT_OVERRIDE 2 +#define APIC_NMI 3 +#define APIC_LOCAL_NMI 4 +#define APIC_ADDRESS_OVERRIDE 5 +#define APIC_IO_SAPIC 6 +#define APIC_LOCAL_SAPIC 7 +#define APIC_XRUPT_SOURCE 8 +#define APIC_RESERVED 9 /* 9 and greater are reserved */ + +/* Flag definitions for MADT sub-tables */ + +#define ACPI_MADT_IFLAGS /* INTI flags (16 bits) */ \ + u8 polarity : 2; /* 00-01: Polarity of APIC I/O input signals */\ + u8 trigger_mode : 2; /* 02-03: Trigger mode of APIC input signals */\ + u8 : 4; /* 04-07: Reserved, must be zero */\ + u8 reserved1; /* 08-15: Reserved, must be zero */ + +#define ACPI_MADT_LFLAGS /* Local Sapic flags (32 bits) */ \ + u8 processor_enabled: 1; /* 00: Processor is usable if set */\ + u8 : 7; /* 01-07: Reserved, must be zero */\ + u8 reserved2[3]; /* 08-31: Reserved, must be zero */ + +/* Values for MPS INTI flags */ + +#define POLARITY_CONFORMS 0 +#define POLARITY_ACTIVE_HIGH 1 +#define POLARITY_RESERVED 2 +#define POLARITY_ACTIVE_LOW 3 + +#define TRIGGER_CONFORMS 0 +#define TRIGGER_EDGE 1 +#define TRIGGER_RESERVED 2 +#define TRIGGER_LEVEL 3 + /* - * ACPI 1.0 Fixed ACPI Description Table (FADT) + * MADT Sub-tables, correspond to Type in struct apic_header */ -struct fadt_descriptor_rev1 { - ACPI_TABLE_HEADER_DEF /* ACPI common table header */ - u32 firmware_ctrl; /* Physical address of FACS */ - u32 dsdt; /* Physical address of DSDT */ - u8 model; /* System Interrupt Model */ - u8 reserved1; /* Reserved, must be zero */ - u16 sci_int; /* System vector of SCI interrupt */ - u32 smi_cmd; /* Port address of SMI command port */ - u8 acpi_enable; /* Value to write to smi_cmd to enable ACPI */ - u8 acpi_disable; /* Value to write to smi_cmd to disable ACPI */ - u8 S4bios_req; /* Value to write to SMI CMD to enter S4BIOS state */ - u8 reserved2; /* Reserved, must be zero */ - u32 pm1a_evt_blk; /* Port address of Power Mgt 1a acpi_event Reg Blk */ - u32 pm1b_evt_blk; /* Port address of Power Mgt 1b acpi_event Reg Blk */ - u32 pm1a_cnt_blk; /* Port address of Power Mgt 1a Control Reg Blk */ - u32 pm1b_cnt_blk; /* Port address of Power Mgt 1b Control Reg Blk */ - u32 pm2_cnt_blk; /* Port address of Power Mgt 2 Control Reg Blk */ - u32 pm_tmr_blk; /* Port address of Power Mgt Timer Ctrl Reg Blk */ - u32 gpe0_blk; /* Port addr of General Purpose acpi_event 0 Reg Blk */ - u32 gpe1_blk; /* Port addr of General Purpose acpi_event 1 Reg Blk */ - u8 pm1_evt_len; /* Byte length of ports at pm1_x_evt_blk */ - u8 pm1_cnt_len; /* Byte length of ports at pm1_x_cnt_blk */ - u8 pm2_cnt_len; /* Byte Length of ports at pm2_cnt_blk */ - u8 pm_tm_len; /* Byte Length of ports at pm_tm_blk */ - u8 gpe0_blk_len; /* Byte Length of ports at gpe0_blk */ - u8 gpe1_blk_len; /* Byte Length of ports at gpe1_blk */ - u8 gpe1_base; /* Offset in gpe model where gpe1 events start */ - u8 reserved3; /* Reserved, must be zero */ - u16 plvl2_lat; /* Worst case HW latency to enter/exit C2 state */ - u16 plvl3_lat; /* Worst case HW latency to enter/exit C3 state */ - u16 flush_size; /* Size of area read to flush caches */ - u16 flush_stride; /* Stride used in flushing caches */ - u8 duty_offset; /* Bit location of duty cycle field in p_cnt reg */ - u8 duty_width; /* Bit width of duty cycle field in p_cnt reg */ - u8 day_alrm; /* Index to day-of-month alarm in RTC CMOS RAM */ - u8 mon_alrm; /* Index to month-of-year alarm in RTC CMOS RAM */ - u8 century; /* Index to century in RTC CMOS RAM */ - u8 reserved4[3]; /* Reserved, must be zero */ + +/* 0: processor APIC */ + +struct madt_processor_apic { + APIC_HEADER_DEF u8 processor_id; /* ACPI processor id */ + u8 local_apic_id; /* Processor's local APIC id */ + ACPI_MADT_LFLAGS}; + +/* 1: IO APIC */ + +struct madt_io_apic { + APIC_HEADER_DEF u8 io_apic_id; /* I/O APIC ID */ + u8 reserved; /* Reserved - must be zero */ + u32 address; /* APIC physical address */ + u32 interrupt; /* Global system interrupt where INTI lines start */ +}; + +/* 2: Interrupt Override */ + +struct madt_interrupt_override { + APIC_HEADER_DEF u8 bus; /* 0 - ISA */ + u8 source; /* Interrupt source (IRQ) */ + u32 interrupt; /* Global system interrupt */ + ACPI_MADT_IFLAGS}; + +/* 3: NMI Sources */ + +struct madt_nmi_source { + APIC_HEADER_DEF ACPI_MADT_IFLAGS u32 interrupt; /* Global system interrupt */ +}; + +/* 4: Local APIC NMI */ + +struct madt_local_apic_nmi { + APIC_HEADER_DEF u8 processor_id; /* ACPI processor id */ + ACPI_MADT_IFLAGS u8 lint; /* LINTn to which NMI is connected */ +}; + +/* 5: Address Override */ + +struct madt_address_override { + APIC_HEADER_DEF u16 reserved; /* Reserved, must be zero */ + u64 address; /* APIC physical address */ +}; + +/* 6: I/O Sapic */ + +struct madt_io_sapic { + APIC_HEADER_DEF u8 io_sapic_id; /* I/O SAPIC ID */ + u8 reserved; /* Reserved, must be zero */ + u32 interrupt_base; /* Glocal interrupt for SAPIC start */ + u64 address; /* SAPIC physical address */ +}; + +/* 7: Local Sapic */ + +struct madt_local_sapic { + APIC_HEADER_DEF u8 processor_id; /* ACPI processor id */ + u8 local_sapic_id; /* SAPIC ID */ + u8 local_sapic_eid; /* SAPIC EID */ + u8 reserved[3]; /* Reserved, must be zero */ + ACPI_MADT_LFLAGS u32 processor_uID; /* Numeric UID - ACPI 3.0 */ + char processor_uIDstring[1]; /* String UID - ACPI 3.0 */ +}; + +/* 8: Platform Interrupt Source */ + +struct madt_interrupt_source { + APIC_HEADER_DEF ACPI_MADT_IFLAGS u8 interrupt_type; /* 1=PMI, 2=INIT, 3=corrected */ + u8 processor_id; /* Processor ID */ + u8 processor_eid; /* Processor EID */ + u8 io_sapic_vector; /* Vector value for PMI interrupts */ + u32 interrupt; /* Global system interrupt */ + u32 flags; /* Interrupt Source Flags */ +}; + +#ifdef DUPLICATE_DEFINITION_WITH_LINUX_ACPI_H +/******************************************************************************* + * + * MCFG - PCI Memory Mapped Configuration table and sub-table + * + ******************************************************************************/ + +struct acpi_table_mcfg { + ACPI_TABLE_HEADER_DEF u8 reserved[8]; +}; + +struct acpi_mcfg_allocation { + u64 base_address; /* Base address, processor-relative */ + u16 pci_segment; /* PCI segment group number */ + u8 start_bus_number; /* Starting PCI Bus number */ + u8 end_bus_number; /* Final PCI Bus number */ + u32 reserved; +}; +#endif + +/******************************************************************************* + * + * SBST - Smart Battery Specification Table + * + ******************************************************************************/ + +struct smart_battery_table { + ACPI_TABLE_HEADER_DEF u32 warning_level; + u32 low_level; + u32 critical_level; +}; + +/******************************************************************************* + * + * SLIT - System Locality Distance Information Table + * + ******************************************************************************/ + +struct system_locality_info { + ACPI_TABLE_HEADER_DEF u64 locality_count; + u8 entry[1][1]; +}; + +/******************************************************************************* + * + * SPCR - Serial Port Console Redirection table + * + ******************************************************************************/ + +struct acpi_table_spcr { + ACPI_TABLE_HEADER_DEF u8 interface_type; /* 0=full 16550, 1=subset of 16550 */ + u8 reserved[3]; + struct acpi_generic_address serial_port; + u8 interrupt_type; + u8 pc_interrupt; + u32 interrupt; + u8 baud_rate; + u8 parity; + u8 stop_bits; + u8 flow_control; + u8 terminal_type; + u8 reserved2; + u16 pci_device_id; + u16 pci_vendor_id; + u8 pci_bus; + u8 pci_device; + u8 pci_function; + u32 pci_flags; + u8 pci_segment; + u32 reserved3; +}; + +/******************************************************************************* + * + * SPMI - Server Platform Management Interface table + * + ******************************************************************************/ + +struct acpi_table_spmi { + ACPI_TABLE_HEADER_DEF u8 reserved; + u8 interface_type; + u16 spec_revision; /* Version of IPMI */ + u8 interrupt_type; + u8 gpe_number; /* GPE assigned */ + u8 reserved2; + u8 pci_device_flag; + u32 interrupt; + struct acpi_generic_address ipmi_register; + u8 pci_segment; + u8 pci_bus; + u8 pci_device; + u8 pci_function; +}; + +/******************************************************************************* + * + * SRAT - System Resource Affinity Table + * + ******************************************************************************/ + +struct system_resource_affinity { + ACPI_TABLE_HEADER_DEF u32 reserved1; /* Must be value '1' */ + u64 reserved2; /* Reserved, must be zero */ +}; + +/* SRAT common sub-table header */ + +#define SRAT_SUBTABLE_HEADER \ + u8 type; \ + u8 length; + +/* Values for Type above */ + +#define SRAT_CPU_AFFINITY 0 +#define SRAT_MEMORY_AFFINITY 1 +#define SRAT_RESERVED 2 + +/* SRAT sub-tables */ + +struct static_resource_alloc { + SRAT_SUBTABLE_HEADER u8 proximity_domain_lo; + u8 apic_id; + + /* Flags (32 bits) */ + + u8 enabled:1; /* 00: Use affinity structure */ + u8:7; /* 01-07: Reserved, must be zero */ + u8 reserved3[3]; /* 08-31: Reserved, must be zero */ + + u8 local_sapic_eid; + u8 proximity_domain_hi[3]; + u32 reserved4; /* Reserved, must be zero */ +}; + +struct memory_affinity { + SRAT_SUBTABLE_HEADER u32 proximity_domain; + u16 reserved3; + u64 base_address; + u64 address_length; + u32 reserved4; /* Flags (32 bits) */ - u8 wb_invd:1; /* 00: The wbinvd instruction works properly */ - u8 wb_invd_flush:1; /* 01: The wbinvd flushes but does not invalidate */ - u8 proc_c1:1; /* 02: All processors support C1 state */ - u8 plvl2_up:1; /* 03: C2 state works on MP system */ - u8 pwr_button:1; /* 04: Power button is handled as a generic feature */ - u8 sleep_button:1; /* 05: Sleep button is handled as a generic feature, or not present */ - u8 fixed_rTC:1; /* 06: RTC wakeup stat not in fixed register space */ - u8 rtcs4:1; /* 07: RTC wakeup stat not possible from S4 */ - u8 tmr_val_ext:1; /* 08: tmr_val width is 32 bits (0 = 24 bits) */ - u8:7; /* 09-15: Reserved, must be zero */ - u8 reserved5[2]; /* 16-31: Reserved, must be zero */ + u8 enabled:1; /* 00: Use affinity structure */ + u8 hot_pluggable:1; /* 01: Memory region is hot pluggable */ + u8 non_volatile:1; /* 02: Memory is non-volatile */ + u8:5; /* 03-07: Reserved, must be zero */ + u8 reserved5[3]; /* 08-31: Reserved, must be zero */ + + u64 reserved6; /* Reserved, must be zero */ +}; + +/******************************************************************************* + * + * TCPA - Trusted Computing Platform Alliance table + * + ******************************************************************************/ + +struct acpi_table_tcpa { + ACPI_TABLE_HEADER_DEF u16 reserved; + u32 max_log_length; /* Maximum length for the event log area */ + u64 log_address; /* Address of the event log area */ }; +/******************************************************************************* + * + * WDRT - Watchdog Resource Table + * + ******************************************************************************/ + +struct acpi_table_wdrt { + ACPI_TABLE_HEADER_DEF u32 header_length; /* Watchdog Header Length */ + u8 pci_segment; /* PCI Segment number */ + u8 pci_bus; /* PCI Bus number */ + u8 pci_device; /* PCI Device number */ + u8 pci_function; /* PCI Function number */ + u32 timer_period; /* Period of one timer count (msec) */ + u32 max_count; /* Maximum counter value supported */ + u32 min_count; /* Minimum counter value */ + u8 flags; + u8 reserved[3]; + u32 entries; /* Number of watchdog entries that follow */ +}; + +#if 0 /* Flags, will be converted to macros */ +u8 enabled:1; /* 00: Timer enabled */ +u8:6; /* 01-06: Reserved */ +u8 sleep_stop:1; /* 07: Timer stopped in sleep state */ +#endif + +/* Macros used to generate offsets to specific table fields */ + +#define ACPI_ASF0_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_asf_info,f) +#define ACPI_ASF1_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_asf_alert,f) +#define ACPI_ASF2_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_asf_remote,f) +#define ACPI_ASF3_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_asf_rmcp,f) +#define ACPI_ASF4_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_asf_address,f) +#define ACPI_BOOT_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_table_boot,f) +#define ACPI_CPEP_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_table_cpep,f) +#define ACPI_CPEP0_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_cpep_polling,f) +#define ACPI_DBGP_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_table_dbgp,f) +#define ACPI_ECDT_OFFSET(f) (u8) ACPI_OFFSET (struct ec_boot_resources,f) +#define ACPI_HPET_OFFSET(f) (u8) ACPI_OFFSET (struct hpet_table,f) +#define ACPI_MADT_OFFSET(f) (u8) ACPI_OFFSET (struct multiple_apic_table,f) +#define ACPI_MADT0_OFFSET(f) (u8) ACPI_OFFSET (struct madt_processor_apic,f) +#define ACPI_MADT1_OFFSET(f) (u8) ACPI_OFFSET (struct madt_io_apic,f) +#define ACPI_MADT2_OFFSET(f) (u8) ACPI_OFFSET (struct madt_interrupt_override,f) +#define ACPI_MADT3_OFFSET(f) (u8) ACPI_OFFSET (struct madt_nmi_source,f) +#define ACPI_MADT4_OFFSET(f) (u8) ACPI_OFFSET (struct madt_local_apic_nmi,f) +#define ACPI_MADT5_OFFSET(f) (u8) ACPI_OFFSET (struct madt_address_override,f) +#define ACPI_MADT6_OFFSET(f) (u8) ACPI_OFFSET (struct madt_io_sapic,f) +#define ACPI_MADT7_OFFSET(f) (u8) ACPI_OFFSET (struct madt_local_sapic,f) +#define ACPI_MADT8_OFFSET(f) (u8) ACPI_OFFSET (struct madt_interrupt_source,f) +#define ACPI_MADTH_OFFSET(f) (u8) ACPI_OFFSET (struct apic_header,f) +#define ACPI_MCFG_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_table_mcfg,f) +#define ACPI_MCFG0_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_mcfg_allocation,f) +#define ACPI_SBST_OFFSET(f) (u8) ACPI_OFFSET (struct smart_battery_table,f) +#define ACPI_SLIT_OFFSET(f) (u8) ACPI_OFFSET (struct system_locality_info,f) +#define ACPI_SPCR_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_table_spcr,f) +#define ACPI_SPMI_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_table_spmi,f) +#define ACPI_SRAT_OFFSET(f) (u8) ACPI_OFFSET (struct system_resource_affinity,f) +#define ACPI_SRAT0_OFFSET(f) (u8) ACPI_OFFSET (struct static_resource_alloc,f) +#define ACPI_SRAT1_OFFSET(f) (u8) ACPI_OFFSET (struct memory_affinity,f) +#define ACPI_TCPA_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_table_tcpa,f) +#define ACPI_WDRT_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_table_wdrt,f) + +#define ACPI_HPET_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct hpet_table,f,o) +#define ACPI_SRAT0_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct static_resource_alloc,f,o) +#define ACPI_SRAT1_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct memory_affinity,f,o) +#define ACPI_MADT_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct multiple_apic_table,f,o) +#define ACPI_MADT0_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct madt_processor_apic,f,o) +#define ACPI_MADT2_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct madt_interrupt_override,f,o) +#define ACPI_MADT3_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct madt_nmi_source,f,o) +#define ACPI_MADT4_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct madt_local_apic_nmi,f,o) +#define ACPI_MADT7_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct madt_local_sapic,f,o) +#define ACPI_MADT8_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct madt_interrupt_source,f,o) + +/* Reset to default packing */ + #pragma pack() #endif /* __ACTBL1_H__ */ diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h index dfc7ac1094bb..67efe6cad27b 100644 --- a/include/acpi/actbl2.h +++ b/include/acpi/actbl2.h @@ -44,234 +44,6 @@ #ifndef __ACTBL2_H__ #define __ACTBL2_H__ -/* - * Prefered Power Management Profiles - */ -#define PM_UNSPECIFIED 0 -#define PM_DESKTOP 1 -#define PM_MOBILE 2 -#define PM_WORKSTATION 3 -#define PM_ENTERPRISE_SERVER 4 -#define PM_SOHO_SERVER 5 -#define PM_APPLIANCE_PC 6 - -/* - * ACPI Boot Arch Flags - */ -#define BAF_LEGACY_DEVICES 0x0001 -#define BAF_8042_KEYBOARD_CONTROLLER 0x0002 - -#define FADT2_REVISION_ID 3 -#define FADT2_MINUS_REVISION_ID 2 - -#pragma pack(1) - -/* - * ACPI 2.0 Root System Description Table (RSDT) - */ -struct rsdt_descriptor_rev2 { - ACPI_TABLE_HEADER_DEF /* ACPI common table header */ - u32 table_offset_entry[1]; /* Array of pointers to ACPI tables */ -}; - -/* - * ACPI 2.0 Extended System Description Table (XSDT) - */ -struct xsdt_descriptor_rev2 { - ACPI_TABLE_HEADER_DEF /* ACPI common table header */ - u64 table_offset_entry[1]; /* Array of pointers to ACPI tables */ -}; - -/* - * ACPI 2.0 Firmware ACPI Control Structure (FACS) - */ -struct facs_descriptor_rev2 { - char signature[4]; /* ASCII table signature */ - u32 length; /* Length of structure, in bytes */ - u32 hardware_signature; /* Hardware configuration signature */ - u32 firmware_waking_vector; /* 32-bit physical address of the Firmware Waking Vector. */ - u32 global_lock; /* Global Lock used to synchronize access to shared hardware resources */ - - /* Flags (32 bits) */ - - u8 S4bios_f:1; /* 00: S4BIOS support is present */ - u8:7; /* 01-07: Reserved, must be zero */ - u8 reserved1[3]; /* 08-31: Reserved, must be zero */ - - u64 xfirmware_waking_vector; /* 64-bit physical address of the Firmware Waking Vector. */ - u8 version; /* Version of this table */ - u8 reserved3[31]; /* Reserved, must be zero */ -}; - -/* - * ACPI 2.0+ Generic Address Structure (GAS) - */ -struct acpi_generic_address { - u8 address_space_id; /* Address space where struct or register exists. */ - u8 register_bit_width; /* Size in bits of given register */ - u8 register_bit_offset; /* Bit offset within the register */ - u8 access_width; /* Minimum Access size (ACPI 3.0) */ - u64 address; /* 64-bit address of struct or register */ -}; - -#define FADT_REV2_COMMON \ - u32 V1_firmware_ctrl; /* 32-bit physical address of FACS */ \ - u32 V1_dsdt; /* 32-bit physical address of DSDT */ \ - u8 reserved1; /* System Interrupt Model isn't used in ACPI 2.0*/ \ - u8 prefer_PM_profile; /* Conveys preferred power management profile to OSPM. */ \ - u16 sci_int; /* System vector of SCI interrupt */ \ - u32 smi_cmd; /* Port address of SMI command port */ \ - u8 acpi_enable; /* Value to write to smi_cmd to enable ACPI */ \ - u8 acpi_disable; /* Value to write to smi_cmd to disable ACPI */ \ - u8 S4bios_req; /* Value to write to SMI CMD to enter S4BIOS state */ \ - u8 pstate_cnt; /* Processor performance state control*/ \ - u32 V1_pm1a_evt_blk; /* Port address of Power Mgt 1a acpi_event Reg Blk */ \ - u32 V1_pm1b_evt_blk; /* Port address of Power Mgt 1b acpi_event Reg Blk */ \ - u32 V1_pm1a_cnt_blk; /* Port address of Power Mgt 1a Control Reg Blk */ \ - u32 V1_pm1b_cnt_blk; /* Port address of Power Mgt 1b Control Reg Blk */ \ - u32 V1_pm2_cnt_blk; /* Port address of Power Mgt 2 Control Reg Blk */ \ - u32 V1_pm_tmr_blk; /* Port address of Power Mgt Timer Ctrl Reg Blk */ \ - u32 V1_gpe0_blk; /* Port addr of General Purpose acpi_event 0 Reg Blk */ \ - u32 V1_gpe1_blk; /* Port addr of General Purpose acpi_event 1 Reg Blk */ \ - u8 pm1_evt_len; /* Byte length of ports at pm1_x_evt_blk */ \ - u8 pm1_cnt_len; /* Byte length of ports at pm1_x_cnt_blk */ \ - u8 pm2_cnt_len; /* Byte Length of ports at pm2_cnt_blk */ \ - u8 pm_tm_len; /* Byte Length of ports at pm_tm_blk */ \ - u8 gpe0_blk_len; /* Byte Length of ports at gpe0_blk */ \ - u8 gpe1_blk_len; /* Byte Length of ports at gpe1_blk */ \ - u8 gpe1_base; /* Offset in gpe model where gpe1 events start */ \ - u8 cst_cnt; /* Support for the _CST object and C States change notification.*/ \ - u16 plvl2_lat; /* Worst case HW latency to enter/exit C2 state */ \ - u16 plvl3_lat; /* Worst case HW latency to enter/exit C3 state */ \ - u16 flush_size; /* Number of flush strides that need to be read */ \ - u16 flush_stride; /* Processor's memory cache line width, in bytes */ \ - u8 duty_offset; /* Processor's duty cycle index in processor's P_CNT reg*/ \ - u8 duty_width; /* Processor's duty cycle value bit width in P_CNT register.*/ \ - u8 day_alrm; /* Index to day-of-month alarm in RTC CMOS RAM */ \ - u8 mon_alrm; /* Index to month-of-year alarm in RTC CMOS RAM */ \ - u8 century; /* Index to century in RTC CMOS RAM */ \ - u16 iapc_boot_arch; /* IA-PC Boot Architecture Flags. See Table 5-10 for description*/ - -/* - * ACPI 2.0+ Fixed ACPI Description Table (FADT) - */ -struct fadt_descriptor_rev2 { - ACPI_TABLE_HEADER_DEF /* ACPI common table header */ - FADT_REV2_COMMON u8 reserved2; /* Reserved, must be zero */ - - /* Flags (32 bits) */ - - u8 wb_invd:1; /* 00: The wbinvd instruction works properly */ - u8 wb_invd_flush:1; /* 01: The wbinvd flushes but does not invalidate */ - u8 proc_c1:1; /* 02: All processors support C1 state */ - u8 plvl2_up:1; /* 03: C2 state works on MP system */ - u8 pwr_button:1; /* 04: Power button is handled as a generic feature */ - u8 sleep_button:1; /* 05: Sleep button is handled as a generic feature, or not present */ - u8 fixed_rTC:1; /* 06: RTC wakeup stat not in fixed register space */ - u8 rtcs4:1; /* 07: RTC wakeup stat not possible from S4 */ - u8 tmr_val_ext:1; /* 08: tmr_val is 32 bits 0=24-bits */ - u8 dock_cap:1; /* 09: Docking supported */ - u8 reset_reg_sup:1; /* 10: System reset via the FADT RESET_REG supported */ - u8 sealed_case:1; /* 11: No internal expansion capabilities and case is sealed */ - u8 headless:1; /* 12: No local video capabilities or local input devices */ - u8 cpu_sw_sleep:1; /* 13: Must execute native instruction after writing SLP_TYPx register */ - - u8 pci_exp_wak:1; /* 14: System supports PCIEXP_WAKE (STS/EN) bits (ACPI 3.0) */ - u8 use_platform_clock:1; /* 15: OSPM should use platform-provided timer (ACPI 3.0) */ - u8 S4rtc_sts_valid:1; /* 16: Contents of RTC_STS valid after S4 wake (ACPI 3.0) */ - u8 remote_power_on_capable:1; /* 17: System is compatible with remote power on (ACPI 3.0) */ - u8 force_apic_cluster_model:1; /* 18: All local APICs must use cluster model (ACPI 3.0) */ - u8 force_apic_physical_destination_mode:1; /* 19: all local x_aPICs must use physical dest mode (ACPI 3.0) */ - u8:4; /* 20-23: Reserved, must be zero */ - u8 reserved3; /* 24-31: Reserved, must be zero */ - - struct acpi_generic_address reset_register; /* Reset register address in GAS format */ - u8 reset_value; /* Value to write to the reset_register port to reset the system */ - u8 reserved4[3]; /* These three bytes must be zero */ - u64 xfirmware_ctrl; /* 64-bit physical address of FACS */ - u64 Xdsdt; /* 64-bit physical address of DSDT */ - struct acpi_generic_address xpm1a_evt_blk; /* Extended Power Mgt 1a acpi_event Reg Blk address */ - struct acpi_generic_address xpm1b_evt_blk; /* Extended Power Mgt 1b acpi_event Reg Blk address */ - struct acpi_generic_address xpm1a_cnt_blk; /* Extended Power Mgt 1a Control Reg Blk address */ - struct acpi_generic_address xpm1b_cnt_blk; /* Extended Power Mgt 1b Control Reg Blk address */ - struct acpi_generic_address xpm2_cnt_blk; /* Extended Power Mgt 2 Control Reg Blk address */ - struct acpi_generic_address xpm_tmr_blk; /* Extended Power Mgt Timer Ctrl Reg Blk address */ - struct acpi_generic_address xgpe0_blk; /* Extended General Purpose acpi_event 0 Reg Blk address */ - struct acpi_generic_address xgpe1_blk; /* Extended General Purpose acpi_event 1 Reg Blk address */ -}; - -/* "Down-revved" ACPI 2.0 FADT descriptor */ - -struct fadt_descriptor_rev2_minus { - ACPI_TABLE_HEADER_DEF /* ACPI common table header */ - FADT_REV2_COMMON u8 reserved2; /* Reserved, must be zero */ - u32 flags; - struct acpi_generic_address reset_register; /* Reset register address in GAS format */ - u8 reset_value; /* Value to write to the reset_register port to reset the system. */ - u8 reserved7[3]; /* Reserved, must be zero */ -}; - -/* ECDT - Embedded Controller Boot Resources Table */ - -struct ec_boot_resources { - ACPI_TABLE_HEADER_DEF struct acpi_generic_address ec_control; /* Address of EC command/status register */ - struct acpi_generic_address ec_data; /* Address of EC data register */ - u32 uid; /* Unique ID - must be same as the EC _UID method */ - u8 gpe_bit; /* The GPE for the EC */ - u8 ec_id[1]; /* Full namepath of the EC in the ACPI namespace */ -}; - -/* SRAT - System Resource Affinity Table */ - -struct static_resource_alloc { - u8 type; - u8 length; - u8 proximity_domain_lo; - u8 apic_id; - - /* Flags (32 bits) */ - - u8 enabled:1; /* 00: Use affinity structure */ - u8:7; /* 01-07: Reserved, must be zero */ - u8 reserved3[3]; /* 08-31: Reserved, must be zero */ - - u8 local_sapic_eid; - u8 proximity_domain_hi[3]; - u32 reserved4; /* Reserved, must be zero */ -}; - -struct memory_affinity { - u8 type; - u8 length; - u32 proximity_domain; - u16 reserved3; - u64 base_address; - u64 address_length; - u32 reserved4; - - /* Flags (32 bits) */ - - u8 enabled:1; /* 00: Use affinity structure */ - u8 hot_pluggable:1; /* 01: Memory region is hot pluggable */ - u8 non_volatile:1; /* 02: Memory is non-volatile */ - u8:5; /* 03-07: Reserved, must be zero */ - u8 reserved5[3]; /* 08-31: Reserved, must be zero */ - - u64 reserved6; /* Reserved, must be zero */ -}; - -struct system_resource_affinity { - ACPI_TABLE_HEADER_DEF u32 reserved1; /* Must be value '1' */ - u64 reserved2; /* Reserved, must be zero */ -}; - -/* SLIT - System Locality Distance Information Table */ - -struct system_locality_info { - ACPI_TABLE_HEADER_DEF u64 locality_count; - u8 entry[1][1]; -}; - -#pragma pack() +/* Code moved to both actbl.h and actbl1.h */ #endif /* __ACTBL2_H__ */ diff --git a/include/acpi/acutils.h b/include/acpi/acutils.h index 5e69a80c7850..115b0cbc370f 100644 --- a/include/acpi/acutils.h +++ b/include/acpi/acutils.h @@ -283,6 +283,8 @@ acpi_ut_ptr_exit(u32 line_number, void acpi_ut_dump_buffer(u8 * buffer, u32 count, u32 display, u32 component_id); +void acpi_ut_dump_buffer2(u8 * buffer, u32 count, u32 display); + void acpi_ut_report_error(char *module_name, u32 line_number); void acpi_ut_report_info(char *module_name, u32 line_number); @@ -451,6 +453,8 @@ acpi_ut_short_divide(acpi_integer in_dividend, /* * utmisc */ +u8 acpi_ut_is_aml_table(struct acpi_table_header *table); + acpi_status acpi_ut_allocate_owner_id(acpi_owner_id * owner_id); void acpi_ut_release_owner_id(acpi_owner_id * owner_id); @@ -466,7 +470,9 @@ void acpi_ut_print_string(char *string, u8 max_length); u8 acpi_ut_valid_acpi_name(u32 name); -u8 acpi_ut_valid_acpi_character(char character); +acpi_name acpi_ut_repair_name(acpi_name name); + +u8 acpi_ut_valid_acpi_char(char character, acpi_native_uint position); acpi_status acpi_ut_strtoul64(char *string, u32 base, acpi_integer * ret_integer); @@ -492,7 +498,7 @@ acpi_ut_display_init_pathname(u8 type, acpi_status acpi_ut_walk_aml_resources(u8 * aml, acpi_size aml_length, - acpi_walk_aml_callback user_function, void *context); + acpi_walk_aml_callback user_function, void **context); acpi_status acpi_ut_validate_resource(void *aml, u8 * return_index); diff --git a/include/acpi/platform/acenv.h b/include/acpi/platform/acenv.h index 2270bdd5e530..fd189d425c78 100644 --- a/include/acpi/platform/acenv.h +++ b/include/acpi/platform/acenv.h @@ -60,6 +60,7 @@ #define ACPI_DISASSEMBLER #define ACPI_NO_METHOD_EXECUTION #define ACPI_LARGE_NAMESPACE_NODE +#define ACPI_DATA_TABLE_DISASSEMBLY #endif #ifdef ACPI_EXEC_APP @@ -79,6 +80,7 @@ #define ACPI_DISASSEMBLER #define ACPI_CONSTANT_EVAL_ONLY #define ACPI_LARGE_NAMESPACE_NODE +#define ACPI_DATA_TABLE_DISASSEMBLY #endif #ifdef ACPI_APPLICATION @@ -140,7 +142,7 @@ #elif defined(MSDOS) /* Must appear after WIN32 and WIN64 check */ #include "acdos16.h" -#elif defined(__FreeBSD__) +#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) #include "acfreebsd.h" #elif defined(__NetBSD__) -- cgit v1.2.3 From b229cf92eee616c7cb5ad8cdb35a19b119f00bc8 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Fri, 21 Apr 2006 17:15:00 -0400 Subject: ACPI: ACPICA 20060421 Removed a device initialization optimization introduced in 20051216 where the _STA method was not run unless an _INI was also present for the same device. This optimization could cause problems because it could allow _INI methods to be run within a not-present device subtree (If a not-present device had no _INI, _STA would not be run, the not-present status would not be discovered, and the children of the device would be incorrectly traversed.) Implemented a new _STA optimization where namespace subtrees that do not contain _INI are identified and ignored during device initialization. Selectively running _STA can significantly improve boot time on large machines (with assistance from Len Brown.) Implemented support for the device initialization case where the returned _STA flags indicate a device not-present but functioning. In this case, _INI is not run, but the device children are examined for presence, as per the ACPI specification. Implemented an additional change to the IndexField support in order to conform to MS behavior. The value written to the Index Register is not simply a byte offset, it is a byte offset in units of the access width of the parent Index Field. (Fiodor Suietov) Defined and deployed a new OSL interface, acpi_os_validate_address(). This interface is called during the creation of all AML operation regions, and allows the host OS to exert control over what addresses it will allow the AML code to access. Operation Regions whose addresses are disallowed will cause a runtime exception when they are actually accessed (will not affect or abort table loading.) Defined and deployed a new OSL interface, acpi_os_validate_interface(). This interface allows the host OS to match the various "optional" interface/behavior strings for the _OSI predefined control method as appropriate (with assistance from Bjorn Helgaas.) Restructured and corrected various problems in the exception handling code paths within DsCallControlMethod and DsTerminateControlMethod in dsmethod (with assistance from Takayoshi Kochi.) Modified the Linux source converter to ignore quoted string literals while converting identifiers from mixed to lower case. This will correct problems with the disassembler and other areas where such strings must not be modified. The ACPI_FUNCTION_* macros no longer require quotes around the function name. This allows the Linux source converter to convert the names, now that the converter ignores quoted strings. Signed-off-by: Bob Moore Signed-off-by: Len Brown --- drivers/acpi/asus_acpi.c | 2 +- drivers/acpi/bus.c | 2 +- drivers/acpi/dispatcher/dsfield.c | 12 +- drivers/acpi/dispatcher/dsinit.c | 6 +- drivers/acpi/dispatcher/dsmethod.c | 180 ++++++++++++++----------- drivers/acpi/dispatcher/dsmthdat.c | 22 +-- drivers/acpi/dispatcher/dsobject.c | 10 +- drivers/acpi/dispatcher/dsopcode.c | 59 ++++++--- drivers/acpi/dispatcher/dsutils.c | 16 +-- drivers/acpi/dispatcher/dswexec.c | 20 +-- drivers/acpi/dispatcher/dswload.c | 16 +-- drivers/acpi/dispatcher/dswscope.c | 6 +- drivers/acpi/dispatcher/dswstate.c | 42 +++--- drivers/acpi/events/evevent.c | 8 +- drivers/acpi/events/evgpe.c | 18 +-- drivers/acpi/events/evgpeblk.c | 42 +++--- drivers/acpi/events/evmisc.c | 12 +- drivers/acpi/events/evregion.c | 18 +-- drivers/acpi/events/evrgnini.c | 18 +-- drivers/acpi/events/evsci.c | 8 +- drivers/acpi/events/evxface.c | 14 +- drivers/acpi/events/evxfevnt.c | 26 ++-- drivers/acpi/events/evxfregn.c | 6 +- drivers/acpi/executer/exconfig.c | 18 +-- drivers/acpi/executer/exconvrt.c | 10 +- drivers/acpi/executer/excreate.c | 18 +-- drivers/acpi/executer/exdump.c | 24 ++-- drivers/acpi/executer/exfield.c | 12 +- drivers/acpi/executer/exfldio.c | 30 +++-- drivers/acpi/executer/exmisc.c | 10 +- drivers/acpi/executer/exmutex.c | 12 +- drivers/acpi/executer/exnames.c | 16 +-- drivers/acpi/executer/exoparg1.c | 12 +- drivers/acpi/executer/exoparg2.c | 10 +- drivers/acpi/executer/exoparg3.c | 6 +- drivers/acpi/executer/exoparg6.c | 2 +- drivers/acpi/executer/exprep.c | 40 +++--- drivers/acpi/executer/exregion.c | 14 +- drivers/acpi/executer/exresnte.c | 6 +- drivers/acpi/executer/exresolv.c | 14 +- drivers/acpi/executer/exresop.c | 8 +- drivers/acpi/executer/exstore.c | 13 +- drivers/acpi/executer/exstoren.c | 4 +- drivers/acpi/executer/exstorob.c | 4 +- drivers/acpi/executer/exsystem.c | 10 +- drivers/acpi/executer/exutils.c | 10 +- drivers/acpi/hardware/hwacpi.c | 6 +- drivers/acpi/hardware/hwgpe.c | 6 +- drivers/acpi/hardware/hwregs.c | 24 ++-- drivers/acpi/hardware/hwsleep.c | 12 +- drivers/acpi/hardware/hwtimer.c | 6 +- drivers/acpi/namespace/nsaccess.c | 6 +- drivers/acpi/namespace/nsalloc.c | 12 +- drivers/acpi/namespace/nsdump.c | 8 +- drivers/acpi/namespace/nsdumpdv.c | 4 +- drivers/acpi/namespace/nseval.c | 10 +- drivers/acpi/namespace/nsinit.c | 265 ++++++++++++++++++++++++++----------- drivers/acpi/namespace/nsload.c | 24 ++-- drivers/acpi/namespace/nsnames.c | 4 +- drivers/acpi/namespace/nsobject.c | 12 +- drivers/acpi/namespace/nsparse.c | 4 +- drivers/acpi/namespace/nssearch.c | 8 +- drivers/acpi/namespace/nsutils.c | 18 +-- drivers/acpi/namespace/nswalk.c | 2 +- drivers/acpi/namespace/nsxfeval.c | 8 +- drivers/acpi/osl.c | 63 ++++++++- drivers/acpi/parser/psargs.c | 18 +-- drivers/acpi/parser/psloop.c | 6 +- drivers/acpi/parser/psopcode.c | 4 +- drivers/acpi/parser/psparse.c | 28 ++-- drivers/acpi/parser/psscope.c | 8 +- drivers/acpi/parser/psutils.c | 2 +- drivers/acpi/parser/pswalk.c | 2 +- drivers/acpi/parser/psxface.c | 7 +- drivers/acpi/resources/rscalc.c | 8 +- drivers/acpi/resources/rscreate.c | 24 ++-- drivers/acpi/resources/rsdump.c | 42 +++--- drivers/acpi/resources/rslist.c | 6 +- drivers/acpi/resources/rsmisc.c | 4 +- drivers/acpi/resources/rsutils.c | 10 +- drivers/acpi/resources/rsxface.c | 14 +- drivers/acpi/system.c | 4 +- drivers/acpi/tables/tbconvrt.c | 6 +- drivers/acpi/tables/tbget.c | 16 +-- drivers/acpi/tables/tbgetall.c | 10 +- drivers/acpi/tables/tbinstal.c | 41 +++--- drivers/acpi/tables/tbrsdt.c | 25 ++-- drivers/acpi/tables/tbutils.c | 10 +- drivers/acpi/tables/tbxface.c | 24 ++-- drivers/acpi/tables/tbxfroot.c | 24 ++-- drivers/acpi/utilities/utalloc.c | 4 +- drivers/acpi/utilities/utcache.c | 2 +- drivers/acpi/utilities/utcopy.c | 16 +-- drivers/acpi/utilities/utdelete.c | 12 +- drivers/acpi/utilities/uteval.c | 88 +++++++++--- drivers/acpi/utilities/utglobal.c | 38 +----- drivers/acpi/utilities/utinit.c | 4 +- drivers/acpi/utilities/utmath.c | 8 +- drivers/acpi/utilities/utmisc.c | 16 +-- drivers/acpi/utilities/utmutex.c | 12 +- drivers/acpi/utilities/utobject.c | 16 +-- drivers/acpi/utilities/utresrc.c | 106 +++++++-------- drivers/acpi/utilities/utstate.c | 14 +- drivers/acpi/utilities/utxface.c | 20 +-- include/acpi/acconfig.h | 12 +- include/acpi/acdisasm.h | 12 +- include/acpi/acdispat.h | 4 +- include/acpi/acexcep.h | 6 +- include/acpi/acglobal.h | 7 +- include/acpi/aclocal.h | 9 +- include/acpi/acmacros.h | 12 +- include/acpi/acobject.h | 3 +- include/acpi/acoutput.h | 8 +- include/acpi/acpiosxf.h | 7 + include/acpi/actypes.h | 23 ++-- include/acpi/acutils.h | 38 +++--- include/acpi/platform/acenv.h | 25 ++-- 117 files changed, 1240 insertions(+), 993 deletions(-) (limited to 'include') diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c index f4c87750dbf2..216c072dee5e 100644 --- a/drivers/acpi/asus_acpi.c +++ b/drivers/acpi/asus_acpi.c @@ -970,7 +970,7 @@ static int __init asus_hotk_get_info(void) * HID), this bit will be moved. A global variable asus_info contains * the DSDT header. */ - status = acpi_get_table(ACPI_TABLE_DSDT, 1, &dsdt); + status = acpi_get_table(ACPI_TABLE_ID_DSDT, 1, &dsdt); if (ACPI_FAILURE(status)) printk(KERN_WARNING " Couldn't get the DSDT table header\n"); else diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index b3a214db56f6..b77f03d51f0b 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -619,7 +619,7 @@ void __init acpi_early_init(void) /* * Get a separate copy of the FADT for use by other drivers. */ - status = acpi_get_table(ACPI_TABLE_FADT, 1, &buffer); + status = acpi_get_table(ACPI_TABLE_ID_FADT, 1, &buffer); if (ACPI_FAILURE(status)) { printk(KERN_ERR PREFIX "Unable to get the FADT\n"); goto error0; diff --git a/drivers/acpi/dispatcher/dsfield.c b/drivers/acpi/dispatcher/dsfield.c index 3d33bcc98678..a6d77efb41a0 100644 --- a/drivers/acpi/dispatcher/dsfield.c +++ b/drivers/acpi/dispatcher/dsfield.c @@ -87,7 +87,7 @@ acpi_ds_create_buffer_field(union acpi_parse_object *op, union acpi_operand_object *second_desc = NULL; u32 flags; - ACPI_FUNCTION_TRACE("ds_create_buffer_field"); + ACPI_FUNCTION_TRACE(ds_create_buffer_field); /* Get the name_string argument */ @@ -210,7 +210,7 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info, acpi_status status; acpi_integer position; - ACPI_FUNCTION_TRACE_PTR("ds_get_field_names", info); + ACPI_FUNCTION_TRACE_PTR(ds_get_field_names, info); /* First field starts at bit zero */ @@ -342,7 +342,7 @@ acpi_ds_create_field(union acpi_parse_object *op, union acpi_parse_object *arg; struct acpi_create_field_info info; - ACPI_FUNCTION_TRACE_PTR("ds_create_field", op); + ACPI_FUNCTION_TRACE_PTR(ds_create_field, op); /* First arg is the name of the parent op_region (must already exist) */ @@ -399,7 +399,7 @@ acpi_ds_init_field_objects(union acpi_parse_object *op, struct acpi_namespace_node *node; u8 type = 0; - ACPI_FUNCTION_TRACE_PTR("ds_init_field_objects", op); + ACPI_FUNCTION_TRACE_PTR(ds_init_field_objects, op); switch (walk_state->opcode) { case AML_FIELD_OP: @@ -482,7 +482,7 @@ acpi_ds_create_bank_field(union acpi_parse_object *op, union acpi_parse_object *arg; struct acpi_create_field_info info; - ACPI_FUNCTION_TRACE_PTR("ds_create_bank_field", op); + ACPI_FUNCTION_TRACE_PTR(ds_create_bank_field, op); /* First arg is the name of the parent op_region (must already exist) */ @@ -555,7 +555,7 @@ acpi_ds_create_index_field(union acpi_parse_object *op, union acpi_parse_object *arg; struct acpi_create_field_info info; - ACPI_FUNCTION_TRACE_PTR("ds_create_index_field", op); + ACPI_FUNCTION_TRACE_PTR(ds_create_index_field, op); /* First arg is the name of the Index register (must already exist) */ diff --git a/drivers/acpi/dispatcher/dsinit.c b/drivers/acpi/dispatcher/dsinit.c index e65a07ad2422..bbdf990e9f65 100644 --- a/drivers/acpi/dispatcher/dsinit.c +++ b/drivers/acpi/dispatcher/dsinit.c @@ -184,7 +184,7 @@ acpi_ds_init_one_object(acpi_handle obj_handle, * * RETURN: Status * - * DESCRIPTION: Walk the namespace starting at "start_node" and perform any + * DESCRIPTION: Walk the namespace starting at "StartNode" and perform any * necessary initialization on the objects found therein * ******************************************************************************/ @@ -196,7 +196,7 @@ acpi_ds_initialize_objects(struct acpi_table_desc * table_desc, acpi_status status; struct acpi_init_walk_info info; - ACPI_FUNCTION_TRACE("ds_initialize_objects"); + ACPI_FUNCTION_TRACE(ds_initialize_objects); ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "**** Starting initialization of namespace objects ****\n")); @@ -213,7 +213,7 @@ acpi_ds_initialize_objects(struct acpi_table_desc * table_desc, status = acpi_walk_namespace(ACPI_TYPE_ANY, start_node, ACPI_UINT32_MAX, acpi_ds_init_one_object, &info, NULL); if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "During walk_namespace")); + ACPI_EXCEPTION((AE_INFO, status, "During WalkNamespace")); } ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c index 7dc59fc7344f..651f2b68531b 100644 --- a/drivers/acpi/dispatcher/dsmethod.c +++ b/drivers/acpi/dispatcher/dsmethod.c @@ -134,7 +134,7 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node * method_node, { acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE_PTR("ds_begin_method_execution", method_node); + ACPI_FUNCTION_TRACE_PTR(ds_begin_method_execution, method_node); if (!method_node) { return_ACPI_STATUS(AE_NULL_ENTRY); @@ -170,11 +170,14 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node * method_node, /* * Get a unit from the method semaphore. This releases the - * interpreter if we block + * interpreter if we block (then reacquires it) */ status = acpi_ex_system_wait_semaphore(obj_desc->method.semaphore, ACPI_WAIT_FOREVER); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } } /* @@ -185,7 +188,7 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node * method_node, if (!obj_desc->method.owner_id) { status = acpi_ut_allocate_owner_id(&obj_desc->method.owner_id); if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); + goto cleanup; } } @@ -195,6 +198,14 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node * method_node, */ obj_desc->method.thread_count++; return_ACPI_STATUS(status); + + cleanup: + /* On error, must signal the method semaphore if present */ + + if (obj_desc->method.semaphore) { + (void)acpi_os_signal_semaphore(obj_desc->method.semaphore, 1); + } + return_ACPI_STATUS(status); } /******************************************************************************* @@ -223,7 +234,7 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread, struct acpi_parameter_info info; u32 i; - ACPI_FUNCTION_TRACE_PTR("ds_call_control_method", this_walk_state); + ACPI_FUNCTION_TRACE_PTR(ds_call_control_method, this_walk_state); ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Execute method %p, currentstate=%p\n", @@ -242,26 +253,31 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread, return_ACPI_STATUS(AE_NULL_OBJECT); } - /* Init for new method, wait on concurrency semaphore */ + /* Init for new method, possibly wait on concurrency semaphore */ status = acpi_ds_begin_method_execution(method_node, obj_desc, this_walk_state->method_node); if (ACPI_FAILURE(status)) { - goto cleanup; + return_ACPI_STATUS(status); } + /* + * 1) Parse the method. All "normal" methods are parsed for each execution. + * Internal methods (_OSI, etc.) do not require parsing. + */ if (!(obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY)) { - /* 1) Parse: Create a new walk state for the preempting walk */ + /* Create a new walk state for the parse */ next_walk_state = acpi_ds_create_walk_state(obj_desc->method.owner_id, op, obj_desc, NULL); if (!next_walk_state) { - return_ACPI_STATUS(AE_NO_MEMORY); + status = AE_NO_MEMORY; + goto cleanup; } - /* Create and init a Root Node */ + /* Create and init a parse tree root */ op = acpi_ps_create_scope_op(); if (!op) { @@ -274,17 +290,20 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread, obj_desc->method.aml_length, NULL, 1); if (ACPI_FAILURE(status)) { - acpi_ds_delete_walk_state(next_walk_state); + acpi_ps_delete_parse_tree(op); goto cleanup; } - /* Begin AML parse */ + /* Begin AML parse (deletes next_walk_state) */ status = acpi_ps_parse_aml(next_walk_state); acpi_ps_delete_parse_tree(op); + if (ACPI_FAILURE(status)) { + goto cleanup; + } } - /* 2) Execute: Create a new state for the preempting walk */ + /* 2) Begin method execution. Create a new walk state */ next_walk_state = acpi_ds_create_walk_state(obj_desc->method.owner_id, NULL, obj_desc, thread); @@ -292,6 +311,7 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread, status = AE_NO_MEMORY; goto cleanup; } + /* * The resolved arguments were put on the previous walk state's operand * stack. Operands on the previous walk state stack always @@ -326,6 +346,8 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread, "Starting nested execution, newstate=%p\n", next_walk_state)); + /* Invoke an internal method if necessary */ + if (obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) { status = obj_desc->method.implementation(next_walk_state); } @@ -333,16 +355,14 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread, return_ACPI_STATUS(status); cleanup: - /* Decrement the thread count on the method parse tree */ - if (next_walk_state && (next_walk_state->method_desc)) { - next_walk_state->method_desc->method.thread_count--; - } + /* On error, we must terminate the method properly */ - /* On error, we must delete the new walk state */ + acpi_ds_terminate_control_method(obj_desc, next_walk_state); + if (next_walk_state) { + acpi_ds_delete_walk_state(next_walk_state); + } - acpi_ds_terminate_control_method(next_walk_state); - acpi_ds_delete_walk_state(next_walk_state); return_ACPI_STATUS(status); } @@ -366,15 +386,15 @@ acpi_ds_restart_control_method(struct acpi_walk_state *walk_state, { acpi_status status; - ACPI_FUNCTION_TRACE_PTR("ds_restart_control_method", walk_state); + ACPI_FUNCTION_TRACE_PTR(ds_restart_control_method, walk_state); ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, - "****Restart [%4.4s] Op %p return_value_from_callee %p\n", + "****Restart [%4.4s] Op %p ReturnValueFromCallee %p\n", (char *)&walk_state->method_node->name, walk_state->method_call_op, return_desc)); ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, - " return_from_this_method_used?=%X res_stack %p Walk %p\n", + " ReturnFromThisMethodUsed?=%X ResStack %p Walk %p\n", walk_state->return_used, walk_state->results, walk_state)); @@ -426,7 +446,8 @@ acpi_ds_restart_control_method(struct acpi_walk_state *walk_state, * * FUNCTION: acpi_ds_terminate_control_method * - * PARAMETERS: walk_state - State of the method + * PARAMETERS: method_desc - Method object + * walk_state - State associated with the method * * RETURN: None * @@ -436,28 +457,27 @@ acpi_ds_restart_control_method(struct acpi_walk_state *walk_state, * ******************************************************************************/ -void acpi_ds_terminate_control_method(struct acpi_walk_state *walk_state) +void +acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, + struct acpi_walk_state *walk_state) { - union acpi_operand_object *obj_desc; struct acpi_namespace_node *method_node; acpi_status status; - ACPI_FUNCTION_TRACE_PTR("ds_terminate_control_method", walk_state); - - if (!walk_state) { - return_VOID; - } + ACPI_FUNCTION_TRACE_PTR(ds_terminate_control_method, walk_state); - /* The current method object was saved in the walk state */ + /* method_desc is required, walk_state is optional */ - obj_desc = walk_state->method_desc; - if (!obj_desc) { + if (!method_desc) { return_VOID; } - /* Delete all arguments and locals */ + if (walk_state) { - acpi_ds_method_data_delete_all(walk_state); + /* Delete all arguments and locals */ + + acpi_ds_method_data_delete_all(walk_state); + } /* * Lock the parser while we terminate this method. @@ -471,60 +491,66 @@ void acpi_ds_terminate_control_method(struct acpi_walk_state *walk_state) /* Signal completion of the execution of this method if necessary */ - if (walk_state->method_desc->method.semaphore) { + if (method_desc->method.semaphore) { status = - acpi_os_signal_semaphore(walk_state->method_desc->method. - semaphore, 1); + acpi_os_signal_semaphore(method_desc->method.semaphore, 1); if (ACPI_FAILURE(status)) { - ACPI_ERROR((AE_INFO, - "Could not signal method semaphore")); - /* Ignore error and continue cleanup */ + /* Ignore error and continue */ + + ACPI_EXCEPTION((AE_INFO, status, + "Could not signal method semaphore")); } } - /* - * There are no more threads executing this method. Perform - * additional cleanup. - * - * The method Node is stored in the walk state - */ - method_node = walk_state->method_node; + if (walk_state) { + /* + * Delete any objects created by this method during execution. + * The method Node is stored in the walk state + */ + method_node = walk_state->method_node; - /* Lock namespace for possible update */ + /* Lock namespace for possible update */ - status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE(status)) { - goto exit; - } + status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE(status)) { + goto exit; + } - /* - * Delete any namespace entries created immediately underneath - * the method - */ - if (method_node && method_node->child) { - acpi_ns_delete_namespace_subtree(method_node); + /* + * Delete any namespace entries created immediately underneath + * the method + */ + if (method_node && method_node->child) { + acpi_ns_delete_namespace_subtree(method_node); + } + + /* + * Delete any namespace entries created anywhere else within + * the namespace by the execution of this method + */ + acpi_ns_delete_namespace_by_owner(method_desc->method.owner_id); + status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); } - /* - * Delete any namespace entries created anywhere else within - * the namespace by the execution of this method - */ - acpi_ns_delete_namespace_by_owner(walk_state->method_desc->method. - owner_id); - status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); + /* Decrement the thread count on the method */ + + if (method_desc->method.thread_count) { + method_desc->method.thread_count--; + } else { + ACPI_ERROR((AE_INFO, "Invalid zero thread count in method")); + } /* Are there any other threads currently executing this method? */ - if (walk_state->method_desc->method.thread_count) { + if (method_desc->method.thread_count) { /* * Additional threads. Do not release the owner_id in this case, * we immediately reuse it for the next thread executing this method */ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "*** Completed execution of one thread, %d threads remaining\n", - walk_state->method_desc->method. - thread_count)); + method_desc->method.thread_count)); } else { /* This is the only executing thread for this method */ @@ -538,18 +564,16 @@ void acpi_ds_terminate_control_method(struct acpi_walk_state *walk_state) * This code is here because we must wait until the last thread exits * before creating the synchronization semaphore. */ - if ((walk_state->method_desc->method.concurrency == 1) && - (!walk_state->method_desc->method.semaphore)) { + if ((method_desc->method.concurrency == 1) && + (!method_desc->method.semaphore)) { status = acpi_os_create_semaphore(1, 1, - &walk_state-> - method_desc->method. + &method_desc->method. semaphore); } /* No more threads, we can free the owner_id */ - acpi_ut_release_owner_id(&walk_state->method_desc->method. - owner_id); + acpi_ut_release_owner_id(&method_desc->method.owner_id); } exit: @@ -586,7 +610,7 @@ acpi_status acpi_ds_parse_method(struct acpi_namespace_node *node) union acpi_parse_object *op; struct acpi_walk_state *walk_state; - ACPI_FUNCTION_TRACE_PTR("ds_parse_method", node); + ACPI_FUNCTION_TRACE_PTR(ds_parse_method, node); /* Parameter Validation */ @@ -595,7 +619,7 @@ acpi_status acpi_ds_parse_method(struct acpi_namespace_node *node) } ACPI_DEBUG_PRINT((ACPI_DB_PARSE, - "**** Parsing [%4.4s] **** named_obj=%p\n", + "**** Parsing [%4.4s] **** NamedObj=%p\n", acpi_ut_get_node_name(node), node)); /* Extract the method object from the method Node */ @@ -674,7 +698,7 @@ acpi_status acpi_ds_parse_method(struct acpi_namespace_node *node) } ACPI_DEBUG_PRINT((ACPI_DB_PARSE, - "**** [%4.4s] Parsed **** named_obj=%p Op=%p\n", + "**** [%4.4s] Parsed **** NamedObj=%p Op=%p\n", acpi_ut_get_node_name(node), node, op)); /* diff --git a/drivers/acpi/dispatcher/dsmthdat.c b/drivers/acpi/dispatcher/dsmthdat.c index ce4de18f1229..b47c54fad86d 100644 --- a/drivers/acpi/dispatcher/dsmthdat.c +++ b/drivers/acpi/dispatcher/dsmthdat.c @@ -92,7 +92,7 @@ void acpi_ds_method_data_init(struct acpi_walk_state *walk_state) { u32 i; - ACPI_FUNCTION_TRACE("ds_method_data_init"); + ACPI_FUNCTION_TRACE(ds_method_data_init); /* Init the method arguments */ @@ -140,7 +140,7 @@ void acpi_ds_method_data_delete_all(struct acpi_walk_state *walk_state) { u32 index; - ACPI_FUNCTION_TRACE("ds_method_data_delete_all"); + ACPI_FUNCTION_TRACE(ds_method_data_delete_all); /* Detach the locals */ @@ -199,7 +199,7 @@ acpi_ds_method_data_init_args(union acpi_operand_object **params, acpi_status status; u32 index = 0; - ACPI_FUNCTION_TRACE_PTR("ds_method_data_init_args", params); + ACPI_FUNCTION_TRACE_PTR(ds_method_data_init_args, params); if (!params) { ACPI_DEBUG_PRINT((ACPI_DB_EXEC, @@ -251,7 +251,7 @@ acpi_ds_method_data_get_node(u16 opcode, struct acpi_walk_state *walk_state, struct acpi_namespace_node **node) { - ACPI_FUNCTION_TRACE("ds_method_data_get_node"); + ACPI_FUNCTION_TRACE(ds_method_data_get_node); /* * Method Locals and Arguments are supported @@ -318,10 +318,10 @@ acpi_ds_method_data_set_value(u16 opcode, acpi_status status; struct acpi_namespace_node *node; - ACPI_FUNCTION_TRACE("ds_method_data_set_value"); + ACPI_FUNCTION_TRACE(ds_method_data_set_value); ACPI_DEBUG_PRINT((ACPI_DB_EXEC, - "new_obj %p Opcode %X, Refs=%d [%s]\n", object, + "NewObj %p Opcode %X, Refs=%d [%s]\n", object, opcode, object->common.reference_count, acpi_ut_get_type_name(object->common.type))); @@ -372,7 +372,7 @@ acpi_ds_method_data_get_value(u16 opcode, struct acpi_namespace_node *node; union acpi_operand_object *object; - ACPI_FUNCTION_TRACE("ds_method_data_get_value"); + ACPI_FUNCTION_TRACE(ds_method_data_get_value); /* Validate the object descriptor */ @@ -477,7 +477,7 @@ acpi_ds_method_data_delete_value(u16 opcode, struct acpi_namespace_node *node; union acpi_operand_object *object; - ACPI_FUNCTION_TRACE("ds_method_data_delete_value"); + ACPI_FUNCTION_TRACE(ds_method_data_delete_value); /* Get the namespace node for the arg/local */ @@ -538,7 +538,7 @@ acpi_ds_store_object_to_local(u16 opcode, union acpi_operand_object *current_obj_desc; union acpi_operand_object *new_obj_desc; - ACPI_FUNCTION_TRACE("ds_store_object_to_local"); + ACPI_FUNCTION_TRACE(ds_store_object_to_local); ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Opcode=%X Index=%d Obj=%p\n", opcode, index, obj_desc)); @@ -614,7 +614,7 @@ acpi_ds_store_object_to_local(u16 opcode, && (current_obj_desc->reference.opcode == AML_REF_OF_OP)) { ACPI_DEBUG_PRINT((ACPI_DB_EXEC, - "Arg (%p) is an obj_ref(Node), storing in node %p\n", + "Arg (%p) is an ObjRef(Node), storing in node %p\n", new_obj_desc, current_obj_desc)); @@ -688,7 +688,7 @@ acpi_ds_method_data_get_type(u16 opcode, struct acpi_namespace_node *node; union acpi_operand_object *object; - ACPI_FUNCTION_TRACE("ds_method_data_get_type"); + ACPI_FUNCTION_TRACE(ds_method_data_get_type); /* Get the namespace node for the arg/local */ diff --git a/drivers/acpi/dispatcher/dsobject.c b/drivers/acpi/dispatcher/dsobject.c index ce54715f13ad..72190abb1d59 100644 --- a/drivers/acpi/dispatcher/dsobject.c +++ b/drivers/acpi/dispatcher/dsobject.c @@ -81,7 +81,7 @@ acpi_ds_build_internal_object(struct acpi_walk_state *walk_state, union acpi_operand_object *obj_desc; acpi_status status; - ACPI_FUNCTION_TRACE("ds_build_internal_object"); + ACPI_FUNCTION_TRACE(ds_build_internal_object); *obj_desc_ptr = NULL; if (op->common.aml_opcode == AML_INT_NAMEPATH_OP) { @@ -187,7 +187,7 @@ acpi_ds_build_internal_buffer_obj(struct acpi_walk_state *walk_state, union acpi_parse_object *byte_list; u32 byte_list_length = 0; - ACPI_FUNCTION_TRACE("ds_build_internal_buffer_obj"); + ACPI_FUNCTION_TRACE(ds_build_internal_buffer_obj); /* * If we are evaluating a Named buffer object "Name (xxxx, Buffer)". @@ -293,7 +293,7 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state, acpi_status status = AE_OK; acpi_native_uint i; - ACPI_FUNCTION_TRACE("ds_build_internal_package_obj"); + ACPI_FUNCTION_TRACE(ds_build_internal_package_obj); /* Find the parent of a possibly nested package */ @@ -400,7 +400,7 @@ acpi_ds_create_node(struct acpi_walk_state *walk_state, acpi_status status; union acpi_operand_object *obj_desc; - ACPI_FUNCTION_TRACE_PTR("ds_create_node", op); + ACPI_FUNCTION_TRACE_PTR(ds_create_node, op); /* * Because of the execution pass through the non-control-method @@ -469,7 +469,7 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state, union acpi_operand_object *obj_desc; acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE("ds_init_object_from_op"); + ACPI_FUNCTION_TRACE(ds_init_object_from_op); obj_desc = *ret_obj_desc; op_info = acpi_ps_get_opcode_info(opcode); diff --git a/drivers/acpi/dispatcher/dsopcode.c b/drivers/acpi/dispatcher/dsopcode.c index 8a690a9963f2..5b974a8fe614 100644 --- a/drivers/acpi/dispatcher/dsopcode.c +++ b/drivers/acpi/dispatcher/dsopcode.c @@ -91,7 +91,7 @@ acpi_ds_execute_arguments(struct acpi_namespace_node *node, union acpi_parse_object *op; struct acpi_walk_state *walk_state; - ACPI_FUNCTION_TRACE("ds_execute_arguments"); + ACPI_FUNCTION_TRACE(ds_execute_arguments); /* * Allocate a new parser op to be the root of the parsed tree @@ -193,7 +193,7 @@ acpi_ds_get_buffer_field_arguments(union acpi_operand_object *obj_desc) struct acpi_namespace_node *node; acpi_status status; - ACPI_FUNCTION_TRACE_PTR("ds_get_buffer_field_arguments", obj_desc); + ACPI_FUNCTION_TRACE_PTR(ds_get_buffer_field_arguments, obj_desc); if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { return_ACPI_STATUS(AE_OK); @@ -206,7 +206,7 @@ acpi_ds_get_buffer_field_arguments(union acpi_operand_object *obj_desc) ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname (ACPI_TYPE_BUFFER_FIELD, node, NULL)); - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "[%4.4s] buffer_field Arg Init\n", + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "[%4.4s] BufferField Arg Init\n", acpi_ut_get_node_name(node))); /* Execute the AML code for the term_arg arguments */ @@ -235,7 +235,7 @@ acpi_status acpi_ds_get_buffer_arguments(union acpi_operand_object *obj_desc) struct acpi_namespace_node *node; acpi_status status; - ACPI_FUNCTION_TRACE_PTR("ds_get_buffer_arguments", obj_desc); + ACPI_FUNCTION_TRACE_PTR(ds_get_buffer_arguments, obj_desc); if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { return_ACPI_STATUS(AE_OK); @@ -279,7 +279,7 @@ acpi_status acpi_ds_get_package_arguments(union acpi_operand_object *obj_desc) struct acpi_namespace_node *node; acpi_status status; - ACPI_FUNCTION_TRACE_PTR("ds_get_package_arguments", obj_desc); + ACPI_FUNCTION_TRACE_PTR(ds_get_package_arguments, obj_desc); if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { return_ACPI_STATUS(AE_OK); @@ -324,7 +324,7 @@ acpi_status acpi_ds_get_region_arguments(union acpi_operand_object *obj_desc) acpi_status status; union acpi_operand_object *extra_desc; - ACPI_FUNCTION_TRACE_PTR("ds_get_region_arguments", obj_desc); + ACPI_FUNCTION_TRACE_PTR(ds_get_region_arguments, obj_desc); if (obj_desc->region.flags & AOPOBJ_DATA_VALID) { return_ACPI_STATUS(AE_OK); @@ -342,8 +342,7 @@ acpi_status acpi_ds_get_region_arguments(union acpi_operand_object *obj_desc) ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname (ACPI_TYPE_REGION, node, NULL)); - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, - "[%4.4s] op_region Arg Init at AML %p\n", + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "[%4.4s] OpRegion Arg Init at AML %p\n", acpi_ut_get_node_name(node), extra_desc->extra.aml_start)); @@ -352,6 +351,28 @@ acpi_status acpi_ds_get_region_arguments(union acpi_operand_object *obj_desc) status = acpi_ds_execute_arguments(node, acpi_ns_get_parent_node(node), extra_desc->extra.aml_length, extra_desc->extra.aml_start); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + /* Validate the region address/length via the host OS */ + + status = acpi_os_validate_address(obj_desc->region.space_id, + obj_desc->region.address, + (acpi_size) obj_desc->region.length); + if (ACPI_FAILURE(status)) { + /* + * Invalid address/length. We will emit an error message and mark + * the region as invalid, so that it will cause an additional error if + * it is ever used. Then return AE_OK. + */ + ACPI_EXCEPTION((AE_INFO, status, + "During address validation of OpRegion [%4.4s]", + node->name.ascii)); + obj_desc->common.flags |= AOPOBJ_INVALID; + status = AE_OK; + } + return_ACPI_STATUS(status); } @@ -411,7 +432,7 @@ acpi_ds_init_buffer_field(u16 aml_opcode, u8 field_flags; acpi_status status; - ACPI_FUNCTION_TRACE_PTR("ds_init_buffer_field", obj_desc); + ACPI_FUNCTION_TRACE_PTR(ds_init_buffer_field, obj_desc); /* Host object must be a Buffer */ @@ -457,7 +478,7 @@ acpi_ds_init_buffer_field(u16 aml_opcode, if (bit_count == 0) { ACPI_ERROR((AE_INFO, - "Attempt to create_field of length zero")); + "Attempt to CreateField of length zero")); status = AE_AML_OPERAND_VALUE; goto cleanup; } @@ -595,7 +616,7 @@ acpi_ds_eval_buffer_field_operands(struct acpi_walk_state *walk_state, struct acpi_namespace_node *node; union acpi_parse_object *next_op; - ACPI_FUNCTION_TRACE_PTR("ds_eval_buffer_field_operands", op); + ACPI_FUNCTION_TRACE_PTR(ds_eval_buffer_field_operands, op); /* * This is where we evaluate the address and length fields of the @@ -627,7 +648,7 @@ acpi_ds_eval_buffer_field_operands(struct acpi_walk_state *walk_state, ACPI_DUMP_OPERANDS(ACPI_WALK_OPERANDS, ACPI_IMODE_EXECUTE, acpi_ps_get_opcode_name(op->common.aml_opcode), walk_state->num_operands, - "after acpi_ex_resolve_operands"); + "after AcpiExResolveOperands"); if (ACPI_FAILURE(status)) { ACPI_ERROR((AE_INFO, "(%s) bad operand(s) (%X)", @@ -686,7 +707,7 @@ acpi_ds_eval_region_operands(struct acpi_walk_state *walk_state, struct acpi_namespace_node *node; union acpi_parse_object *next_op; - ACPI_FUNCTION_TRACE_PTR("ds_eval_region_operands", op); + ACPI_FUNCTION_TRACE_PTR(ds_eval_region_operands, op); /* * This is where we evaluate the address and length fields of the @@ -719,7 +740,7 @@ acpi_ds_eval_region_operands(struct acpi_walk_state *walk_state, ACPI_DUMP_OPERANDS(ACPI_WALK_OPERANDS, ACPI_IMODE_EXECUTE, acpi_ps_get_opcode_name(op->common.aml_opcode), - 1, "after acpi_ex_resolve_operands"); + 1, "after AcpiExResolveOperands"); obj_desc = acpi_ns_get_attached_object(node); if (!obj_desc) { @@ -745,7 +766,7 @@ acpi_ds_eval_region_operands(struct acpi_walk_state *walk_state, operand_desc->integer.value; acpi_ut_remove_reference(operand_desc); - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "rgn_obj %p Addr %8.8X%8.8X Len %X\n", + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "RgnObj %p Addr %8.8X%8.8X Len %X\n", obj_desc, ACPI_FORMAT_UINT64(obj_desc->region.address), obj_desc->region.length)); @@ -781,7 +802,7 @@ acpi_ds_eval_data_object_operands(struct acpi_walk_state *walk_state, union acpi_operand_object *arg_desc; u32 length; - ACPI_FUNCTION_TRACE("ds_eval_data_object_operands"); + ACPI_FUNCTION_TRACE(ds_eval_data_object_operands); /* The first operand (for all of these data objects) is the length */ @@ -875,7 +896,7 @@ acpi_ds_exec_begin_control_op(struct acpi_walk_state *walk_state, acpi_status status = AE_OK; union acpi_generic_state *control_state; - ACPI_FUNCTION_NAME("ds_exec_begin_control_op"); + ACPI_FUNCTION_NAME(ds_exec_begin_control_op); ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Op=%p Opcode=%2.2X State=%p\n", op, op->common.aml_opcode, walk_state)); @@ -953,7 +974,7 @@ acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state, acpi_status status = AE_OK; union acpi_generic_state *control_state; - ACPI_FUNCTION_NAME("ds_exec_end_control_op"); + ACPI_FUNCTION_NAME(ds_exec_end_control_op); switch (op->common.aml_opcode) { case AML_IF_OP: @@ -1099,7 +1120,7 @@ acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state, } ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, - "Completed RETURN_OP State=%p, ret_val=%p\n", + "Completed RETURN_OP State=%p, RetVal=%p\n", walk_state, walk_state->return_desc)); /* End the control method execution right now */ diff --git a/drivers/acpi/dispatcher/dsutils.c b/drivers/acpi/dispatcher/dsutils.c index ab24aa88e2fa..05230baf5de8 100644 --- a/drivers/acpi/dispatcher/dsutils.c +++ b/drivers/acpi/dispatcher/dsutils.c @@ -68,7 +68,7 @@ ACPI_MODULE_NAME("dsutils") ******************************************************************************/ void acpi_ds_clear_implicit_return(struct acpi_walk_state *walk_state) { - ACPI_FUNCTION_NAME("ds_clear_implicit_return"); + ACPI_FUNCTION_NAME(ds_clear_implicit_return); /* * Slack must be enabled for this feature @@ -115,7 +115,7 @@ u8 acpi_ds_do_implicit_return(union acpi_operand_object *return_desc, struct acpi_walk_state *walk_state, u8 add_reference) { - ACPI_FUNCTION_NAME("ds_do_implicit_return"); + ACPI_FUNCTION_NAME(ds_do_implicit_return); /* * Slack must be enabled for this feature, and we must @@ -171,7 +171,7 @@ acpi_ds_is_result_used(union acpi_parse_object * op, { const struct acpi_opcode_info *parent_info; - ACPI_FUNCTION_TRACE_PTR("ds_is_result_used", op); + ACPI_FUNCTION_TRACE_PTR(ds_is_result_used, op); /* Must have both an Op and a Result Object */ @@ -341,7 +341,7 @@ acpi_ds_delete_result_if_not_used(union acpi_parse_object *op, union acpi_operand_object *obj_desc; acpi_status status; - ACPI_FUNCTION_TRACE_PTR("ds_delete_result_if_not_used", result_obj); + ACPI_FUNCTION_TRACE_PTR(ds_delete_result_if_not_used, result_obj); if (!op) { ACPI_ERROR((AE_INFO, "Null Op")); @@ -384,7 +384,7 @@ acpi_status acpi_ds_resolve_operands(struct acpi_walk_state *walk_state) u32 i; acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE_PTR("ds_resolve_operands", walk_state); + ACPI_FUNCTION_TRACE_PTR(ds_resolve_operands, walk_state); /* * Attempt to resolve each of the valid operands @@ -419,7 +419,7 @@ void acpi_ds_clear_operands(struct acpi_walk_state *walk_state) { u32 i; - ACPI_FUNCTION_TRACE_PTR("ds_clear_operands", walk_state); + ACPI_FUNCTION_TRACE_PTR(ds_clear_operands, walk_state); /* Remove a reference on each operand on the stack */ @@ -467,7 +467,7 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state, acpi_interpreter_mode interpreter_mode; const struct acpi_opcode_info *op_info; - ACPI_FUNCTION_TRACE_PTR("ds_create_operand", arg); + ACPI_FUNCTION_TRACE_PTR(ds_create_operand, arg); /* A valid name must be looked up in the namespace */ @@ -701,7 +701,7 @@ acpi_ds_create_operands(struct acpi_walk_state *walk_state, union acpi_parse_object *arg; u32 arg_count = 0; - ACPI_FUNCTION_TRACE_PTR("ds_create_operands", first_arg); + ACPI_FUNCTION_TRACE_PTR(ds_create_operands, first_arg); /* For all arguments in the list... */ diff --git a/drivers/acpi/dispatcher/dswexec.c b/drivers/acpi/dispatcher/dswexec.c index 8b740b370eb1..8afb20384e96 100644 --- a/drivers/acpi/dispatcher/dswexec.c +++ b/drivers/acpi/dispatcher/dswexec.c @@ -92,7 +92,7 @@ acpi_ds_get_predicate_value(struct acpi_walk_state *walk_state, union acpi_operand_object *obj_desc; union acpi_operand_object *local_obj_desc = NULL; - ACPI_FUNCTION_TRACE_PTR("ds_get_predicate_value", walk_state); + ACPI_FUNCTION_TRACE_PTR(ds_get_predicate_value, walk_state); walk_state->control_state->common.state = 0; @@ -122,7 +122,7 @@ acpi_ds_get_predicate_value(struct acpi_walk_state *walk_state, if (!obj_desc) { ACPI_ERROR((AE_INFO, - "No predicate obj_desc=%p State=%p", + "No predicate ObjDesc=%p State=%p", obj_desc, walk_state)); return_ACPI_STATUS(AE_AML_NO_OPERAND); @@ -139,7 +139,7 @@ acpi_ds_get_predicate_value(struct acpi_walk_state *walk_state, if (ACPI_GET_OBJECT_TYPE(local_obj_desc) != ACPI_TYPE_INTEGER) { ACPI_ERROR((AE_INFO, - "Bad predicate (not an integer) obj_desc=%p State=%p Type=%X", + "Bad predicate (not an integer) ObjDesc=%p State=%p Type=%X", obj_desc, walk_state, ACPI_GET_OBJECT_TYPE(obj_desc))); @@ -213,7 +213,7 @@ acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state, acpi_status status = AE_OK; u32 opcode_class; - ACPI_FUNCTION_TRACE_PTR("ds_exec_begin_op", walk_state); + ACPI_FUNCTION_TRACE_PTR(ds_exec_begin_op, walk_state); op = walk_state->op; if (!op) { @@ -353,7 +353,7 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state) union acpi_parse_object *next_op; union acpi_parse_object *first_arg; - ACPI_FUNCTION_TRACE_PTR("ds_exec_end_op", walk_state); + ACPI_FUNCTION_TRACE_PTR(ds_exec_end_op, walk_state); op = walk_state->op; op_type = walk_state->op_info->type; @@ -423,7 +423,7 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state) acpi_ps_get_opcode_name (walk_state->opcode), walk_state->num_operands, - "after ex_resolve_operands"); + "after ExResolveOperands"); } } @@ -437,7 +437,7 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state) acpi_gbl_op_type_dispatch[op_type] (walk_state); } else { /* - * Treat constructs of the form "Store(local_x,local_x)" as noops when the + * Treat constructs of the form "Store(LocalX,LocalX)" as noops when the * Local is uninitialized. */ if ((status == AE_AML_UNINITIALIZED_LOCAL) && @@ -570,7 +570,7 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state) case AML_TYPE_CREATE_FIELD: ACPI_DEBUG_PRINT((ACPI_DB_EXEC, - "Executing create_field Buffer/Index Op=%p\n", + "Executing CreateField Buffer/Index Op=%p\n", op)); status = acpi_ds_load2_end_op(walk_state); @@ -585,7 +585,7 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state) case AML_TYPE_CREATE_OBJECT: ACPI_DEBUG_PRINT((ACPI_DB_EXEC, - "Executing create_object (Buffer/Package) Op=%p\n", + "Executing CreateObject (Buffer/Package) Op=%p\n", op)); switch (op->common.parent->common.aml_opcode) { @@ -658,7 +658,7 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state) if (op->common.aml_opcode == AML_REGION_OP) { ACPI_DEBUG_PRINT((ACPI_DB_EXEC, - "Executing op_region Address/Length Op=%p\n", + "Executing OpRegion Address/Length Op=%p\n", op)); status = diff --git a/drivers/acpi/dispatcher/dswload.c b/drivers/acpi/dispatcher/dswload.c index 1ad7870101fb..a8deb700cf33 100644 --- a/drivers/acpi/dispatcher/dswload.c +++ b/drivers/acpi/dispatcher/dswload.c @@ -127,7 +127,7 @@ acpi_ds_load1_begin_op(struct acpi_walk_state * walk_state, char *path; u32 flags; - ACPI_FUNCTION_TRACE("ds_load1_begin_op"); + ACPI_FUNCTION_TRACE(ds_load1_begin_op); op = walk_state->op; ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Op=%p State=%p\n", op, @@ -361,7 +361,7 @@ acpi_status acpi_ds_load1_end_op(struct acpi_walk_state *walk_state) acpi_object_type object_type; acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE("ds_load1_end_op"); + ACPI_FUNCTION_TRACE(ds_load1_end_op); op = walk_state->op; ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Op=%p State=%p\n", op, @@ -448,7 +448,7 @@ acpi_status acpi_ds_load1_end_op(struct acpi_walk_state *walk_state) * arguments.) */ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, - "LOADING-Method: State=%p Op=%p named_obj=%p\n", + "LOADING-Method: State=%p Op=%p NamedObj=%p\n", walk_state, op, op->named.node)); if (!acpi_ns_get_attached_object(op->named.node)) { @@ -514,7 +514,7 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state, acpi_object_type object_type; char *buffer_ptr; - ACPI_FUNCTION_TRACE("ds_load2_begin_op"); + ACPI_FUNCTION_TRACE(ds_load2_begin_op); op = walk_state->op; ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Op=%p State=%p\n", op, @@ -785,7 +785,7 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state) u32 i; #endif - ACPI_FUNCTION_TRACE("ds_load2_end_op"); + ACPI_FUNCTION_TRACE(ds_load2_end_op); op = walk_state->op; ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Opcode [%s] Op %p State %p\n", @@ -879,7 +879,7 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state) */ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, - "Create-Load [%s] State=%p Op=%p named_obj=%p\n", + "Create-Load [%s] State=%p Op=%p NamedObj=%p\n", acpi_ps_get_opcode_name(op->common.aml_opcode), walk_state, op, node)); @@ -1054,7 +1054,7 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state) * arguments.) */ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, - "LOADING-Method: State=%p Op=%p named_obj=%p\n", + "LOADING-Method: State=%p Op=%p NamedObj=%p\n", walk_state, op, op->named.node)); if (!acpi_ns_get_attached_object(op->named.node)) { @@ -1099,7 +1099,7 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state) case AML_CLASS_METHOD_CALL: ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, - "RESOLVING-method_call: State=%p Op=%p named_obj=%p\n", + "RESOLVING-MethodCall: State=%p Op=%p NamedObj=%p\n", walk_state, op, node)); /* diff --git a/drivers/acpi/dispatcher/dswscope.c b/drivers/acpi/dispatcher/dswscope.c index 3cd6895ed2c3..c9228972f5f6 100644 --- a/drivers/acpi/dispatcher/dswscope.c +++ b/drivers/acpi/dispatcher/dswscope.c @@ -63,7 +63,7 @@ void acpi_ds_scope_stack_clear(struct acpi_walk_state *walk_state) { union acpi_generic_state *scope_info; - ACPI_FUNCTION_NAME("ds_scope_stack_clear"); + ACPI_FUNCTION_NAME(ds_scope_stack_clear); while (walk_state->scope_info) { @@ -103,7 +103,7 @@ acpi_ds_scope_stack_push(struct acpi_namespace_node *node, union acpi_generic_state *scope_info; union acpi_generic_state *old_scope_info; - ACPI_FUNCTION_TRACE("ds_scope_stack_push"); + ACPI_FUNCTION_TRACE(ds_scope_stack_push); if (!node) { @@ -178,7 +178,7 @@ acpi_status acpi_ds_scope_stack_pop(struct acpi_walk_state *walk_state) union acpi_generic_state *scope_info; union acpi_generic_state *new_scope_info; - ACPI_FUNCTION_TRACE("ds_scope_stack_pop"); + ACPI_FUNCTION_TRACE(ds_scope_stack_pop); /* * Pop scope info object off the stack. diff --git a/drivers/acpi/dispatcher/dswstate.c b/drivers/acpi/dispatcher/dswstate.c index 4840eae47d34..82c1e219bf15 100644 --- a/drivers/acpi/dispatcher/dswstate.c +++ b/drivers/acpi/dispatcher/dswstate.c @@ -87,7 +87,7 @@ acpi_ds_result_remove(union acpi_operand_object **object, { union acpi_generic_state *state; - ACPI_FUNCTION_NAME("ds_result_remove"); + ACPI_FUNCTION_NAME(ds_result_remove); state = walk_state->results; if (!state) { @@ -150,7 +150,7 @@ acpi_ds_result_pop(union acpi_operand_object ** object, acpi_native_uint index; union acpi_generic_state *state; - ACPI_FUNCTION_NAME("ds_result_pop"); + ACPI_FUNCTION_NAME(ds_result_pop); state = walk_state->results; if (!state) { @@ -212,7 +212,7 @@ acpi_ds_result_pop_from_bottom(union acpi_operand_object ** object, acpi_native_uint index; union acpi_generic_state *state; - ACPI_FUNCTION_NAME("ds_result_pop_from_bottom"); + ACPI_FUNCTION_NAME(ds_result_pop_from_bottom); state = walk_state->results; if (!state) { @@ -277,7 +277,7 @@ acpi_ds_result_push(union acpi_operand_object * object, { union acpi_generic_state *state; - ACPI_FUNCTION_NAME("ds_result_push"); + ACPI_FUNCTION_NAME(ds_result_push); state = walk_state->results; if (!state) { @@ -330,7 +330,7 @@ acpi_status acpi_ds_result_stack_push(struct acpi_walk_state * walk_state) { union acpi_generic_state *state; - ACPI_FUNCTION_NAME("ds_result_stack_push"); + ACPI_FUNCTION_NAME(ds_result_stack_push); state = acpi_ut_create_generic_state(); if (!state) { @@ -362,7 +362,7 @@ acpi_status acpi_ds_result_stack_pop(struct acpi_walk_state * walk_state) { union acpi_generic_state *state; - ACPI_FUNCTION_NAME("ds_result_stack_pop"); + ACPI_FUNCTION_NAME(ds_result_stack_pop); /* Check for stack underflow */ @@ -375,7 +375,7 @@ acpi_status acpi_ds_result_stack_pop(struct acpi_walk_state * walk_state) state = acpi_ut_pop_generic_state(&walk_state->results); ACPI_DEBUG_PRINT((ACPI_DB_EXEC, - "Result=%p remaining_results=%X State=%p\n", + "Result=%p RemainingResults=%X State=%p\n", state, state->results.num_results, walk_state)); acpi_ut_delete_generic_state(state); @@ -399,7 +399,7 @@ acpi_status acpi_ds_result_stack_pop(struct acpi_walk_state * walk_state) acpi_status acpi_ds_obj_stack_push(void *object, struct acpi_walk_state * walk_state) { - ACPI_FUNCTION_NAME("ds_obj_stack_push"); + ACPI_FUNCTION_NAME(ds_obj_stack_push); /* Check for stack overflow */ @@ -444,7 +444,7 @@ acpi_ds_obj_stack_pop(u32 pop_count, struct acpi_walk_state * walk_state) { u32 i; - ACPI_FUNCTION_NAME("ds_obj_stack_pop"); + ACPI_FUNCTION_NAME(ds_obj_stack_pop); for (i = 0; i < pop_count; i++) { @@ -491,7 +491,7 @@ acpi_ds_obj_stack_pop_and_delete(u32 pop_count, u32 i; union acpi_operand_object *obj_desc; - ACPI_FUNCTION_NAME("ds_obj_stack_pop_and_delete"); + ACPI_FUNCTION_NAME(ds_obj_stack_pop_and_delete); for (i = 0; i < pop_count; i++) { @@ -539,13 +539,13 @@ acpi_ds_obj_stack_pop_and_delete(u32 pop_count, struct acpi_walk_state *acpi_ds_get_current_walk_state(struct acpi_thread_state *thread) { - ACPI_FUNCTION_NAME("ds_get_current_walk_state"); + ACPI_FUNCTION_NAME(ds_get_current_walk_state); if (!thread) { return (NULL); } - ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "Current walk_state %p\n", + ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "Current WalkState %p\n", thread->walk_state_list)); return (thread->walk_state_list); @@ -568,7 +568,7 @@ void acpi_ds_push_walk_state(struct acpi_walk_state *walk_state, struct acpi_thread_state *thread) { - ACPI_FUNCTION_TRACE("ds_push_walk_state"); + ACPI_FUNCTION_TRACE(ds_push_walk_state); walk_state->next = thread->walk_state_list; thread->walk_state_list = walk_state; @@ -594,7 +594,7 @@ struct acpi_walk_state *acpi_ds_pop_walk_state(struct acpi_thread_state *thread) { struct acpi_walk_state *walk_state; - ACPI_FUNCTION_TRACE("ds_pop_walk_state"); + ACPI_FUNCTION_TRACE(ds_pop_walk_state); walk_state = thread->walk_state_list; @@ -641,7 +641,7 @@ struct acpi_walk_state *acpi_ds_create_walk_state(acpi_owner_id owner_id, struct acpi_walk_state *walk_state; acpi_status status; - ACPI_FUNCTION_TRACE("ds_create_walk_state"); + ACPI_FUNCTION_TRACE(ds_create_walk_state); walk_state = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_walk_state)); if (!walk_state) { @@ -709,7 +709,7 @@ acpi_ds_init_aml_walk(struct acpi_walk_state *walk_state, struct acpi_parse_state *parser_state = &walk_state->parser_state; union acpi_parse_object *extra_op; - ACPI_FUNCTION_TRACE("ds_init_aml_walk"); + ACPI_FUNCTION_TRACE(ds_init_aml_walk); walk_state->parser_state.aml = walk_state->parser_state.aml_start = aml_start; @@ -813,7 +813,7 @@ void acpi_ds_delete_walk_state(struct acpi_walk_state *walk_state) { union acpi_generic_state *state; - ACPI_FUNCTION_TRACE_PTR("ds_delete_walk_state", walk_state); + ACPI_FUNCTION_TRACE_PTR(ds_delete_walk_state, walk_state); if (!walk_state) { return; @@ -882,7 +882,7 @@ acpi_ds_result_insert(void *object, { union acpi_generic_state *state; - ACPI_FUNCTION_NAME("ds_result_insert"); + ACPI_FUNCTION_NAME(ds_result_insert); state = walk_state->results; if (!state) { @@ -940,7 +940,7 @@ acpi_status acpi_ds_obj_stack_delete_all(struct acpi_walk_state * walk_state) { u32 i; - ACPI_FUNCTION_TRACE_PTR("ds_obj_stack_delete_all", walk_state); + ACPI_FUNCTION_TRACE_PTR(ds_obj_stack_delete_all, walk_state); /* The stack size is configurable, but fixed */ @@ -972,7 +972,7 @@ acpi_status acpi_ds_obj_stack_pop_object(union acpi_operand_object **object, struct acpi_walk_state *walk_state) { - ACPI_FUNCTION_NAME("ds_obj_stack_pop_object"); + ACPI_FUNCTION_NAME(ds_obj_stack_pop_object); /* Check for stack underflow */ @@ -1028,7 +1028,7 @@ acpi_ds_obj_stack_pop_object(union acpi_operand_object **object, void *acpi_ds_obj_stack_get_value(u32 index, struct acpi_walk_state *walk_state) { - ACPI_FUNCTION_TRACE_PTR("ds_obj_stack_get_value", walk_state); + ACPI_FUNCTION_TRACE_PTR(ds_obj_stack_get_value, walk_state); /* Can't do it if the stack is empty */ diff --git a/drivers/acpi/events/evevent.c b/drivers/acpi/events/evevent.c index c8d9752e3128..919037d6acff 100644 --- a/drivers/acpi/events/evevent.c +++ b/drivers/acpi/events/evevent.c @@ -68,7 +68,7 @@ acpi_status acpi_ev_initialize_events(void) { acpi_status status; - ACPI_FUNCTION_TRACE("ev_initialize_events"); + ACPI_FUNCTION_TRACE(ev_initialize_events); /* Make sure we have ACPI tables */ @@ -118,7 +118,7 @@ acpi_status acpi_ev_install_fadt_gpes(void) { acpi_status status; - ACPI_FUNCTION_TRACE("ev_install_fadt_gpes"); + ACPI_FUNCTION_TRACE(ev_install_fadt_gpes); /* Namespace must be locked */ @@ -157,7 +157,7 @@ acpi_status acpi_ev_install_xrupt_handlers(void) { acpi_status status; - ACPI_FUNCTION_TRACE("ev_install_xrupt_handlers"); + ACPI_FUNCTION_TRACE(ev_install_xrupt_handlers); /* Install the SCI handler */ @@ -241,7 +241,7 @@ u32 acpi_ev_fixed_event_detect(void) u32 fixed_enable; acpi_native_uint i; - ACPI_FUNCTION_NAME("ev_fixed_event_detect"); + ACPI_FUNCTION_NAME(ev_fixed_event_detect); /* * Read the fixed feature status and enable registers, as all the cases diff --git a/drivers/acpi/events/evgpe.c b/drivers/acpi/events/evgpe.c index 7d7b81af972e..25fd12a29a29 100644 --- a/drivers/acpi/events/evgpe.c +++ b/drivers/acpi/events/evgpe.c @@ -69,7 +69,7 @@ acpi_ev_set_gpe_type(struct acpi_gpe_event_info *gpe_event_info, u8 type) { acpi_status status; - ACPI_FUNCTION_TRACE("ev_set_gpe_type"); + ACPI_FUNCTION_TRACE(ev_set_gpe_type); /* Validate type and update register enable masks */ @@ -115,7 +115,7 @@ acpi_ev_update_gpe_enable_masks(struct acpi_gpe_event_info *gpe_event_info, struct acpi_gpe_register_info *gpe_register_info; u8 register_bit; - ACPI_FUNCTION_TRACE("ev_update_gpe_enable_masks"); + ACPI_FUNCTION_TRACE(ev_update_gpe_enable_masks); gpe_register_info = gpe_event_info->register_info; if (!gpe_register_info) { @@ -178,7 +178,7 @@ acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info, { acpi_status status; - ACPI_FUNCTION_TRACE("ev_enable_gpe"); + ACPI_FUNCTION_TRACE(ev_enable_gpe); /* Make sure HW enable masks are updated */ @@ -244,7 +244,7 @@ acpi_status acpi_ev_disable_gpe(struct acpi_gpe_event_info *gpe_event_info) { acpi_status status; - ACPI_FUNCTION_TRACE("ev_disable_gpe"); + ACPI_FUNCTION_TRACE(ev_disable_gpe); if (!(gpe_event_info->flags & ACPI_GPE_ENABLE_MASK)) { return_ACPI_STATUS(AE_OK); @@ -385,7 +385,7 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list) acpi_native_uint i; acpi_native_uint j; - ACPI_FUNCTION_NAME("ev_gpe_detect"); + ACPI_FUNCTION_NAME(ev_gpe_detect); /* Check for the case where there are no GPEs */ @@ -504,7 +504,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) struct acpi_gpe_event_info local_gpe_event_info; struct acpi_parameter_info info; - ACPI_FUNCTION_TRACE("ev_asynch_execute_gpe_method"); + ACPI_FUNCTION_TRACE(ev_asynch_execute_gpe_method); status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); if (ACPI_FAILURE(status)) { @@ -598,7 +598,7 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number) { acpi_status status; - ACPI_FUNCTION_TRACE("ev_gpe_dispatch"); + ACPI_FUNCTION_TRACE(ev_gpe_dispatch); /* * If edge-triggered, clear the GPE status bit now. Note that @@ -721,7 +721,7 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number) * * DESCRIPTION: Determine if a a GPE is "wake-only". * - * Called from Notify() code in interpreter when a "device_wake" + * Called from Notify() code in interpreter when a "DeviceWake" * Notify comes in. * ******************************************************************************/ @@ -731,7 +731,7 @@ acpi_ev_check_for_wake_only_gpe(struct acpi_gpe_event_info *gpe_event_info) { acpi_status status; - ACPI_FUNCTION_TRACE("ev_check_for_wake_only_gpe"); + ACPI_FUNCTION_TRACE(ev_check_for_wake_only_gpe); if ((gpe_event_info) && /* Only >0 for _Lxx/_Exx */ ((gpe_event_info->flags & ACPI_GPE_SYSTEM_MASK) == ACPI_GPE_SYSTEM_RUNNING)) { /* System state at GPE time */ diff --git a/drivers/acpi/events/evgpeblk.c b/drivers/acpi/events/evgpeblk.c index 4e90c1f837c3..95ddeb48bc0f 100644 --- a/drivers/acpi/events/evgpeblk.c +++ b/drivers/acpi/events/evgpeblk.c @@ -138,7 +138,7 @@ acpi_status acpi_ev_walk_gpe_list(acpi_gpe_callback gpe_walk_callback) acpi_status status = AE_OK; acpi_cpu_flags flags; - ACPI_FUNCTION_TRACE("ev_walk_gpe_list"); + ACPI_FUNCTION_TRACE(ev_walk_gpe_list); flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); @@ -192,7 +192,7 @@ acpi_ev_delete_gpe_handlers(struct acpi_gpe_xrupt_info *gpe_xrupt_info, acpi_native_uint i; acpi_native_uint j; - ACPI_FUNCTION_TRACE("ev_delete_gpe_handlers"); + ACPI_FUNCTION_TRACE(ev_delete_gpe_handlers); /* Examine each GPE Register within the block */ @@ -251,7 +251,7 @@ acpi_ev_save_method_info(acpi_handle obj_handle, u8 type; acpi_status status; - ACPI_FUNCTION_TRACE("ev_save_method_info"); + ACPI_FUNCTION_TRACE(ev_save_method_info); /* * _Lxx and _Exx GPE method support @@ -282,9 +282,9 @@ acpi_ev_save_method_info(acpi_handle obj_handle, default: /* Unknown method type, just ignore it! */ - ACPI_ERROR((AE_INFO, - "Unknown GPE method type: %s (name not of form _Lxx or _Exx)", - name)); + ACPI_DEBUG_PRINT((ACPI_DB_LOAD, + "Ignoring unknown GPE method type: %s (name not of form _Lxx or _Exx)", + name)); return_ACPI_STATUS(AE_OK); } @@ -295,9 +295,9 @@ acpi_ev_save_method_info(acpi_handle obj_handle, /* Conversion failed; invalid method, just ignore it */ - ACPI_ERROR((AE_INFO, - "Could not extract GPE number from name: %s (name is not of form _Lxx or _Exx)", - name)); + ACPI_DEBUG_PRINT((ACPI_DB_LOAD, + "Could not extract GPE number from name: %s (name is not of form _Lxx or _Exx)", + name)); return_ACPI_STATUS(AE_OK); } @@ -368,7 +368,7 @@ acpi_ev_match_prw_and_gpe(acpi_handle obj_handle, u32 gpe_number; acpi_status status; - ACPI_FUNCTION_TRACE("ev_match_prw_and_gpe"); + ACPI_FUNCTION_TRACE(ev_match_prw_and_gpe); /* Check for a _PRW method under this device */ @@ -489,7 +489,7 @@ static struct acpi_gpe_xrupt_info *acpi_ev_get_gpe_xrupt_block(u32 acpi_status status; acpi_cpu_flags flags; - ACPI_FUNCTION_TRACE("ev_get_gpe_xrupt_block"); + ACPI_FUNCTION_TRACE(ev_get_gpe_xrupt_block); /* No need for lock since we are not changing any list elements here */ @@ -563,7 +563,7 @@ acpi_ev_delete_gpe_xrupt(struct acpi_gpe_xrupt_info *gpe_xrupt) acpi_status status; acpi_cpu_flags flags; - ACPI_FUNCTION_TRACE("ev_delete_gpe_xrupt"); + ACPI_FUNCTION_TRACE(ev_delete_gpe_xrupt); /* We never want to remove the SCI interrupt handler */ @@ -621,7 +621,7 @@ acpi_ev_install_gpe_block(struct acpi_gpe_block_info *gpe_block, acpi_status status; acpi_cpu_flags flags; - ACPI_FUNCTION_TRACE("ev_install_gpe_block"); + ACPI_FUNCTION_TRACE(ev_install_gpe_block); status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); if (ACPI_FAILURE(status)) { @@ -674,7 +674,7 @@ acpi_status acpi_ev_delete_gpe_block(struct acpi_gpe_block_info *gpe_block) acpi_status status; acpi_cpu_flags flags; - ACPI_FUNCTION_TRACE("ev_install_gpe_block"); + ACPI_FUNCTION_TRACE(ev_install_gpe_block); status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); if (ACPI_FAILURE(status)) { @@ -744,7 +744,7 @@ acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block) acpi_native_uint j; acpi_status status; - ACPI_FUNCTION_TRACE("ev_create_gpe_info_blocks"); + ACPI_FUNCTION_TRACE(ev_create_gpe_info_blocks); /* Allocate the GPE register information block */ @@ -754,7 +754,7 @@ acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block) acpi_gpe_register_info)); if (!gpe_register_info) { ACPI_ERROR((AE_INFO, - "Could not allocate the gpe_register_info table")); + "Could not allocate the GpeRegisterInfo table")); return_ACPI_STATUS(AE_NO_MEMORY); } @@ -769,7 +769,7 @@ acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block) acpi_gpe_event_info)); if (!gpe_event_info) { ACPI_ERROR((AE_INFO, - "Could not allocate the gpe_event_info table")); + "Could not allocate the GpeEventInfo table")); status = AE_NO_MEMORY; goto error_exit; } @@ -888,7 +888,7 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device, acpi_status status; struct acpi_gpe_block_info *gpe_block; - ACPI_FUNCTION_TRACE("ev_create_gpe_block"); + ACPI_FUNCTION_TRACE(ev_create_gpe_block); if (!register_count) { return_ACPI_STATUS(AE_OK); @@ -981,7 +981,7 @@ acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device, acpi_native_uint i; acpi_native_uint j; - ACPI_FUNCTION_TRACE("ev_initialize_gpe_block"); + ACPI_FUNCTION_TRACE(ev_initialize_gpe_block); /* Ignore a null GPE block (e.g., if no GPE block 1 exists) */ @@ -1051,7 +1051,7 @@ acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device, status = acpi_hw_enable_runtime_gpe_block(NULL, gpe_block); if (ACPI_FAILURE(status)) { - ACPI_ERROR((AE_INFO, "Could not enable GPEs in gpe_block %p", + ACPI_ERROR((AE_INFO, "Could not enable GPEs in GpeBlock %p", gpe_block)); } @@ -1077,7 +1077,7 @@ acpi_status acpi_ev_gpe_initialize(void) u32 gpe_number_max = 0; acpi_status status; - ACPI_FUNCTION_TRACE("ev_gpe_initialize"); + ACPI_FUNCTION_TRACE(ev_gpe_initialize); status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { diff --git a/drivers/acpi/events/evmisc.c b/drivers/acpi/events/evmisc.c index b216b3229e27..97e05481aa7c 100644 --- a/drivers/acpi/events/evmisc.c +++ b/drivers/acpi/events/evmisc.c @@ -124,7 +124,7 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node, union acpi_generic_state *notify_info; acpi_status status = AE_OK; - ACPI_FUNCTION_NAME("ev_queue_notify_request"); + ACPI_FUNCTION_NAME(ev_queue_notify_request); /* * For value 3 (Ejection Request), some device method may need to be run. @@ -376,7 +376,7 @@ acpi_status acpi_ev_init_global_lock_handler(void) { acpi_status status; - ACPI_FUNCTION_TRACE("ev_init_global_lock_handler"); + ACPI_FUNCTION_TRACE(ev_init_global_lock_handler); acpi_gbl_global_lock_present = TRUE; status = acpi_install_fixed_event_handler(ACPI_EVENT_GLOBAL, @@ -418,7 +418,7 @@ acpi_status acpi_ev_acquire_global_lock(u16 timeout) acpi_status status = AE_OK; u8 acquired = FALSE; - ACPI_FUNCTION_TRACE("ev_acquire_global_lock"); + ACPI_FUNCTION_TRACE(ev_acquire_global_lock); #ifndef ACPI_APPLICATION /* Make sure that we actually have a global lock */ @@ -486,7 +486,7 @@ acpi_status acpi_ev_release_global_lock(void) u8 pending = FALSE; acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE("ev_release_global_lock"); + ACPI_FUNCTION_TRACE(ev_release_global_lock); if (!acpi_gbl_global_lock_thread_count) { ACPI_WARNING((AE_INFO, @@ -540,7 +540,7 @@ void acpi_ev_terminate(void) acpi_native_uint i; acpi_status status; - ACPI_FUNCTION_TRACE("ev_terminate"); + ACPI_FUNCTION_TRACE(ev_terminate); if (acpi_gbl_events_initialized) { /* @@ -580,7 +580,7 @@ void acpi_ev_terminate(void) if (acpi_gbl_original_mode == ACPI_SYS_MODE_LEGACY) { status = acpi_disable(); if (ACPI_FAILURE(status)) { - ACPI_WARNING((AE_INFO, "acpi_disable failed")); + ACPI_WARNING((AE_INFO, "AcpiDisable failed")); } } return_VOID; diff --git a/drivers/acpi/events/evregion.c b/drivers/acpi/events/evregion.c index 0337ad222b26..eb29e96f053c 100644 --- a/drivers/acpi/events/evregion.c +++ b/drivers/acpi/events/evregion.c @@ -83,7 +83,7 @@ acpi_status acpi_ev_install_region_handlers(void) acpi_status status; acpi_native_uint i; - ACPI_FUNCTION_TRACE("ev_install_region_handlers"); + ACPI_FUNCTION_TRACE(ev_install_region_handlers); status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { @@ -153,7 +153,7 @@ acpi_status acpi_ev_initialize_op_regions(void) acpi_status status; acpi_native_uint i; - ACPI_FUNCTION_TRACE("ev_initialize_op_regions"); + ACPI_FUNCTION_TRACE(ev_initialize_op_regions); status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { @@ -198,7 +198,7 @@ acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function) union acpi_operand_object *region_obj2; acpi_status status; - ACPI_FUNCTION_TRACE("ev_execute_reg_method"); + ACPI_FUNCTION_TRACE(ev_execute_reg_method); region_obj2 = acpi_ns_get_secondary_object(region_obj); if (!region_obj2) { @@ -284,7 +284,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, union acpi_operand_object *region_obj2; void *region_context = NULL; - ACPI_FUNCTION_TRACE("ev_address_space_dispatch"); + ACPI_FUNCTION_TRACE(ev_address_space_dispatch); region_obj2 = acpi_ns_get_secondary_object(region_obj); if (!region_obj2) { @@ -451,7 +451,7 @@ acpi_ev_detach_region(union acpi_operand_object *region_obj, union acpi_operand_object *region_obj2; acpi_status status; - ACPI_FUNCTION_TRACE("ev_detach_region"); + ACPI_FUNCTION_TRACE(ev_detach_region); region_obj2 = acpi_ns_get_secondary_object(region_obj); if (!region_obj2) { @@ -585,7 +585,7 @@ acpi_ev_attach_region(union acpi_operand_object *handler_obj, u8 acpi_ns_is_locked) { - ACPI_FUNCTION_TRACE("ev_attach_region"); + ACPI_FUNCTION_TRACE(ev_attach_region); ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, "Adding Region [%4.4s] %p to address handler %p [%s]\n", @@ -638,7 +638,7 @@ acpi_ev_install_handler(acpi_handle obj_handle, struct acpi_namespace_node *node; acpi_status status; - ACPI_FUNCTION_NAME("ev_install_handler"); + ACPI_FUNCTION_NAME(ev_install_handler); handler_obj = (union acpi_operand_object *)context; @@ -771,7 +771,7 @@ acpi_ev_install_space_handler(struct acpi_namespace_node * node, acpi_object_type type; u8 flags = 0; - ACPI_FUNCTION_TRACE("ev_install_space_handler"); + ACPI_FUNCTION_TRACE(ev_install_space_handler); /* * This registration is valid for only the types below @@ -985,7 +985,7 @@ acpi_ev_execute_reg_methods(struct acpi_namespace_node *node, { acpi_status status; - ACPI_FUNCTION_TRACE("ev_execute_reg_methods"); + ACPI_FUNCTION_TRACE(ev_execute_reg_methods); /* * Run all _REG methods for all Operation Regions for this diff --git a/drivers/acpi/events/evrgnini.c b/drivers/acpi/events/evrgnini.c index d1809f4240a4..1cecd577b899 100644 --- a/drivers/acpi/events/evrgnini.c +++ b/drivers/acpi/events/evrgnini.c @@ -71,7 +71,7 @@ acpi_ev_system_memory_region_setup(acpi_handle handle, (union acpi_operand_object *)handle; struct acpi_mem_space_context *local_region_context; - ACPI_FUNCTION_TRACE("ev_system_memory_region_setup"); + ACPI_FUNCTION_TRACE(ev_system_memory_region_setup); if (function == ACPI_REGION_DEACTIVATE) { if (*region_context) { @@ -129,7 +129,7 @@ acpi_ev_io_space_region_setup(acpi_handle handle, u32 function, void *handler_context, void **region_context) { - ACPI_FUNCTION_TRACE("ev_io_space_region_setup"); + ACPI_FUNCTION_TRACE(ev_io_space_region_setup); if (function == ACPI_REGION_DEACTIVATE) { *region_context = NULL; @@ -172,7 +172,7 @@ acpi_ev_pci_config_region_setup(acpi_handle handle, (union acpi_operand_object *)handle; struct acpi_device_id object_hID; - ACPI_FUNCTION_TRACE("ev_pci_config_region_setup"); + ACPI_FUNCTION_TRACE(ev_pci_config_region_setup); handler_obj = region_obj->region.handler; if (!handler_obj) { @@ -248,7 +248,7 @@ acpi_ev_pci_config_region_setup(acpi_handle handle, } else { ACPI_EXCEPTION((AE_INFO, status, - "Could not install pci_config handler for Root Bridge %4.4s", + "Could not install PciConfig handler for Root Bridge %4.4s", acpi_ut_get_node_name (pci_root_node))); } @@ -350,7 +350,7 @@ acpi_ev_pci_bar_region_setup(acpi_handle handle, u32 function, void *handler_context, void **region_context) { - ACPI_FUNCTION_TRACE("ev_pci_bar_region_setup"); + ACPI_FUNCTION_TRACE(ev_pci_bar_region_setup); return_ACPI_STATUS(AE_OK); } @@ -377,7 +377,7 @@ acpi_ev_cmos_region_setup(acpi_handle handle, u32 function, void *handler_context, void **region_context) { - ACPI_FUNCTION_TRACE("ev_cmos_region_setup"); + ACPI_FUNCTION_TRACE(ev_cmos_region_setup); return_ACPI_STATUS(AE_OK); } @@ -402,7 +402,7 @@ acpi_ev_default_region_setup(acpi_handle handle, u32 function, void *handler_context, void **region_context) { - ACPI_FUNCTION_TRACE("ev_default_region_setup"); + ACPI_FUNCTION_TRACE(ev_default_region_setup); if (function == ACPI_REGION_DEACTIVATE) { *region_context = NULL; @@ -448,7 +448,7 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj, acpi_name *reg_name_ptr = (acpi_name *) METHOD_NAME__REG; union acpi_operand_object *region_obj2; - ACPI_FUNCTION_TRACE_U32("ev_initialize_region", acpi_ns_locked); + ACPI_FUNCTION_TRACE_U32(ev_initialize_region, acpi_ns_locked); if (!region_obj) { return_ACPI_STATUS(AE_BAD_PARAMETER); @@ -588,7 +588,7 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj, /* If we get here, there is no handler for this region */ ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, - "No handler for region_type %s(%X) (region_obj %p)\n", + "No handler for RegionType %s(%X) (RegionObj %p)\n", acpi_ut_get_region_name(space_id), space_id, region_obj)); diff --git a/drivers/acpi/events/evsci.c b/drivers/acpi/events/evsci.c index 9a622169008a..8106215ad554 100644 --- a/drivers/acpi/events/evsci.c +++ b/drivers/acpi/events/evsci.c @@ -69,7 +69,7 @@ static u32 ACPI_SYSTEM_XFACE acpi_ev_sci_xrupt_handler(void *context) struct acpi_gpe_xrupt_info *gpe_xrupt_list = context; u32 interrupt_handled = ACPI_INTERRUPT_NOT_HANDLED; - ACPI_FUNCTION_TRACE("ev_sci_xrupt_handler"); + ACPI_FUNCTION_TRACE(ev_sci_xrupt_handler); /* * We are guaranteed by the ACPI CA initialization/shutdown code that @@ -108,7 +108,7 @@ u32 ACPI_SYSTEM_XFACE acpi_ev_gpe_xrupt_handler(void *context) struct acpi_gpe_xrupt_info *gpe_xrupt_list = context; u32 interrupt_handled = ACPI_INTERRUPT_NOT_HANDLED; - ACPI_FUNCTION_TRACE("ev_gpe_xrupt_handler"); + ACPI_FUNCTION_TRACE(ev_gpe_xrupt_handler); /* * We are guaranteed by the ACPI CA initialization/shutdown code that @@ -140,7 +140,7 @@ u32 acpi_ev_install_sci_handler(void) { u32 status = AE_OK; - ACPI_FUNCTION_TRACE("ev_install_sci_handler"); + ACPI_FUNCTION_TRACE(ev_install_sci_handler); status = acpi_os_install_interrupt_handler((u32) acpi_gbl_FADT->sci_int, acpi_ev_sci_xrupt_handler, @@ -171,7 +171,7 @@ acpi_status acpi_ev_remove_sci_handler(void) { acpi_status status; - ACPI_FUNCTION_TRACE("ev_remove_sci_handler"); + ACPI_FUNCTION_TRACE(ev_remove_sci_handler); /* Just let the OS remove the handler and disable the level */ diff --git a/drivers/acpi/events/evxface.c b/drivers/acpi/events/evxface.c index 7d1cebc871f6..76c34a66e0e0 100644 --- a/drivers/acpi/events/evxface.c +++ b/drivers/acpi/events/evxface.c @@ -66,7 +66,7 @@ acpi_status acpi_install_exception_handler(acpi_exception_handler handler) { acpi_status status; - ACPI_FUNCTION_TRACE("acpi_install_exception_handler"); + ACPI_FUNCTION_TRACE(acpi_install_exception_handler); status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); if (ACPI_FAILURE(status)) { @@ -113,7 +113,7 @@ acpi_install_fixed_event_handler(u32 event, { acpi_status status; - ACPI_FUNCTION_TRACE("acpi_install_fixed_event_handler"); + ACPI_FUNCTION_TRACE(acpi_install_fixed_event_handler); /* Parameter validation */ @@ -179,7 +179,7 @@ acpi_remove_fixed_event_handler(u32 event, acpi_event_handler handler) { acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE("acpi_remove_fixed_event_handler"); + ACPI_FUNCTION_TRACE(acpi_remove_fixed_event_handler); /* Parameter validation */ @@ -243,7 +243,7 @@ acpi_install_notify_handler(acpi_handle device, struct acpi_namespace_node *node; acpi_status status; - ACPI_FUNCTION_TRACE("acpi_install_notify_handler"); + ACPI_FUNCTION_TRACE(acpi_install_notify_handler); /* Parameter validation */ @@ -408,7 +408,7 @@ acpi_remove_notify_handler(acpi_handle device, struct acpi_namespace_node *node; acpi_status status; - ACPI_FUNCTION_TRACE("acpi_remove_notify_handler"); + ACPI_FUNCTION_TRACE(acpi_remove_notify_handler); /* Parameter validation */ @@ -563,7 +563,7 @@ acpi_install_gpe_handler(acpi_handle gpe_device, acpi_status status; acpi_cpu_flags flags; - ACPI_FUNCTION_TRACE("acpi_install_gpe_handler"); + ACPI_FUNCTION_TRACE(acpi_install_gpe_handler); /* Parameter validation */ @@ -653,7 +653,7 @@ acpi_remove_gpe_handler(acpi_handle gpe_device, acpi_status status; acpi_cpu_flags flags; - ACPI_FUNCTION_TRACE("acpi_remove_gpe_handler"); + ACPI_FUNCTION_TRACE(acpi_remove_gpe_handler); /* Parameter validation */ diff --git a/drivers/acpi/events/evxfevnt.c b/drivers/acpi/events/evxfevnt.c index 4a36559fa816..7ebc2efac936 100644 --- a/drivers/acpi/events/evxfevnt.c +++ b/drivers/acpi/events/evxfevnt.c @@ -63,7 +63,7 @@ acpi_status acpi_enable(void) { acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE("acpi_enable"); + ACPI_FUNCTION_TRACE(acpi_enable); /* Make sure we have the FADT */ @@ -109,7 +109,7 @@ acpi_status acpi_disable(void) { acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE("acpi_disable"); + ACPI_FUNCTION_TRACE(acpi_disable); if (!acpi_gbl_FADT) { ACPI_WARNING((AE_INFO, "No FADT information present!")); @@ -155,7 +155,7 @@ acpi_status acpi_enable_event(u32 event, u32 flags) acpi_status status = AE_OK; u32 value; - ACPI_FUNCTION_TRACE("acpi_enable_event"); + ACPI_FUNCTION_TRACE(acpi_enable_event); /* Decode the Fixed Event */ @@ -213,7 +213,7 @@ acpi_status acpi_set_gpe_type(acpi_handle gpe_device, u32 gpe_number, u8 type) acpi_status status = AE_OK; struct acpi_gpe_event_info *gpe_event_info; - ACPI_FUNCTION_TRACE("acpi_set_gpe_type"); + ACPI_FUNCTION_TRACE(acpi_set_gpe_type); /* Ensure that we have a valid GPE number */ @@ -256,7 +256,7 @@ acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number, u32 flags) acpi_status status = AE_OK; struct acpi_gpe_event_info *gpe_event_info; - ACPI_FUNCTION_TRACE("acpi_enable_gpe"); + ACPI_FUNCTION_TRACE(acpi_enable_gpe); /* Use semaphore lock if not executing at interrupt level */ @@ -307,7 +307,7 @@ acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number, u32 flags) acpi_status status = AE_OK; struct acpi_gpe_event_info *gpe_event_info; - ACPI_FUNCTION_TRACE("acpi_disable_gpe"); + ACPI_FUNCTION_TRACE(acpi_disable_gpe); /* Use semaphore lock if not executing at interrupt level */ @@ -354,7 +354,7 @@ acpi_status acpi_disable_event(u32 event, u32 flags) acpi_status status = AE_OK; u32 value; - ACPI_FUNCTION_TRACE("acpi_disable_event"); + ACPI_FUNCTION_TRACE(acpi_disable_event); /* Decode the Fixed Event */ @@ -407,7 +407,7 @@ acpi_status acpi_clear_event(u32 event) { acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE("acpi_clear_event"); + ACPI_FUNCTION_TRACE(acpi_clear_event); /* Decode the Fixed Event */ @@ -446,7 +446,7 @@ acpi_status acpi_clear_gpe(acpi_handle gpe_device, u32 gpe_number, u32 flags) acpi_status status = AE_OK; struct acpi_gpe_event_info *gpe_event_info; - ACPI_FUNCTION_TRACE("acpi_clear_gpe"); + ACPI_FUNCTION_TRACE(acpi_clear_gpe); /* Use semaphore lock if not executing at interrupt level */ @@ -494,7 +494,7 @@ acpi_status acpi_get_event_status(u32 event, acpi_event_status * event_status) { acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE("acpi_get_event_status"); + ACPI_FUNCTION_TRACE(acpi_get_event_status); if (!event_status) { return_ACPI_STATUS(AE_BAD_PARAMETER); @@ -539,7 +539,7 @@ acpi_get_gpe_status(acpi_handle gpe_device, acpi_status status = AE_OK; struct acpi_gpe_event_info *gpe_event_info; - ACPI_FUNCTION_TRACE("acpi_get_gpe_status"); + ACPI_FUNCTION_TRACE(acpi_get_gpe_status); /* Use semaphore lock if not executing at interrupt level */ @@ -596,7 +596,7 @@ acpi_install_gpe_block(acpi_handle gpe_device, struct acpi_namespace_node *node; struct acpi_gpe_block_info *gpe_block; - ACPI_FUNCTION_TRACE("acpi_install_gpe_block"); + ACPI_FUNCTION_TRACE(acpi_install_gpe_block); if ((!gpe_device) || (!gpe_block_address) || (!register_count)) { return_ACPI_STATUS(AE_BAD_PARAMETER); @@ -684,7 +684,7 @@ acpi_status acpi_remove_gpe_block(acpi_handle gpe_device) acpi_status status; struct acpi_namespace_node *node; - ACPI_FUNCTION_TRACE("acpi_remove_gpe_block"); + ACPI_FUNCTION_TRACE(acpi_remove_gpe_block); if (!gpe_device) { return_ACPI_STATUS(AE_BAD_PARAMETER); diff --git a/drivers/acpi/events/evxfregn.c b/drivers/acpi/events/evxfregn.c index 63a070bb9d17..e8b86a0baad0 100644 --- a/drivers/acpi/events/evxfregn.c +++ b/drivers/acpi/events/evxfregn.c @@ -73,7 +73,7 @@ acpi_install_address_space_handler(acpi_handle device, struct acpi_namespace_node *node; acpi_status status; - ACPI_FUNCTION_TRACE("acpi_install_address_space_handler"); + ACPI_FUNCTION_TRACE(acpi_install_address_space_handler); /* Parameter validation */ @@ -139,7 +139,7 @@ acpi_remove_address_space_handler(acpi_handle device, struct acpi_namespace_node *node; acpi_status status; - ACPI_FUNCTION_TRACE("acpi_remove_address_space_handler"); + ACPI_FUNCTION_TRACE(acpi_remove_address_space_handler); /* Parameter validation */ @@ -228,7 +228,7 @@ acpi_remove_address_space_handler(acpi_handle device, /* The handler does not exist */ ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, - "Unable to remove address handler %p for %s(%X), dev_node %p, obj %p\n", + "Unable to remove address handler %p for %s(%X), DevNode %p, obj %p\n", handler, acpi_ut_get_region_name(space_id), space_id, node, obj_desc)); diff --git a/drivers/acpi/executer/exconfig.c b/drivers/acpi/executer/exconfig.c index e0deffb56790..9c46f3338640 100644 --- a/drivers/acpi/executer/exconfig.c +++ b/drivers/acpi/executer/exconfig.c @@ -82,7 +82,7 @@ acpi_ex_add_table(struct acpi_table_header *table, struct acpi_table_desc table_info; union acpi_operand_object *obj_desc; - ACPI_FUNCTION_TRACE("ex_add_table"); + ACPI_FUNCTION_TRACE(ex_add_table); /* Create an object to be the table handle */ @@ -100,7 +100,7 @@ acpi_ex_add_table(struct acpi_table_header *table, ACPI_MEMSET(&table_info, 0, sizeof(struct acpi_table_desc)); - table_info.type = ACPI_TABLE_SSDT; + table_info.type = ACPI_TABLE_ID_SSDT; table_info.pointer = table; table_info.length = (acpi_size) table->length; table_info.allocation = ACPI_MEM_ALLOCATED; @@ -162,7 +162,7 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state, struct acpi_namespace_node *parameter_node = NULL; union acpi_operand_object *ddb_handle; - ACPI_FUNCTION_TRACE("ex_load_table_op"); + ACPI_FUNCTION_TRACE(ex_load_table_op); #if 0 /* @@ -300,7 +300,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, struct acpi_table_header table_header; u32 i; - ACPI_FUNCTION_TRACE("ex_load_op"); + ACPI_FUNCTION_TRACE(ex_load_op); /* Object can be either an op_region or a Field */ @@ -411,12 +411,8 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, /* The table must be either an SSDT or a PSDT */ - if ((!ACPI_STRNCMP(table_ptr->signature, - acpi_gbl_table_data[ACPI_TABLE_PSDT].signature, - acpi_gbl_table_data[ACPI_TABLE_PSDT].sig_length)) && - (!ACPI_STRNCMP(table_ptr->signature, - acpi_gbl_table_data[ACPI_TABLE_SSDT].signature, - acpi_gbl_table_data[ACPI_TABLE_SSDT].sig_length))) { + if ((!ACPI_COMPARE_NAME(table_ptr->signature, PSDT_SIG)) && + (!ACPI_COMPARE_NAME(table_ptr->signature, SSDT_SIG))) { ACPI_ERROR((AE_INFO, "Table has invalid signature [%4.4s], must be SSDT or PSDT", table_ptr->signature)); @@ -470,7 +466,7 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle) union acpi_operand_object *table_desc = ddb_handle; struct acpi_table_desc *table_info; - ACPI_FUNCTION_TRACE("ex_unload_table"); + ACPI_FUNCTION_TRACE(ex_unload_table); /* * Validate the handle diff --git a/drivers/acpi/executer/exconvrt.c b/drivers/acpi/executer/exconvrt.c index a2c93c9ba07c..b732e399b1ef 100644 --- a/drivers/acpi/executer/exconvrt.c +++ b/drivers/acpi/executer/exconvrt.c @@ -79,7 +79,7 @@ acpi_ex_convert_to_integer(union acpi_operand_object *obj_desc, u32 count; acpi_status status; - ACPI_FUNCTION_TRACE_PTR("ex_convert_to_integer", obj_desc); + ACPI_FUNCTION_TRACE_PTR(ex_convert_to_integer, obj_desc); switch (ACPI_GET_OBJECT_TYPE(obj_desc)) { case ACPI_TYPE_INTEGER: @@ -199,7 +199,7 @@ acpi_ex_convert_to_buffer(union acpi_operand_object *obj_desc, union acpi_operand_object *return_desc; u8 *new_buf; - ACPI_FUNCTION_TRACE_PTR("ex_convert_to_buffer", obj_desc); + ACPI_FUNCTION_TRACE_PTR(ex_convert_to_buffer, obj_desc); switch (ACPI_GET_OBJECT_TYPE(obj_desc)) { case ACPI_TYPE_BUFFER: @@ -402,7 +402,7 @@ acpi_ex_convert_to_string(union acpi_operand_object * obj_desc, u16 base = 16; u8 separator = ','; - ACPI_FUNCTION_TRACE_PTR("ex_convert_to_string", obj_desc); + ACPI_FUNCTION_TRACE_PTR(ex_convert_to_string, obj_desc); switch (ACPI_GET_OBJECT_TYPE(obj_desc)) { case ACPI_TYPE_STRING: @@ -569,7 +569,7 @@ acpi_ex_convert_to_target_type(acpi_object_type destination_type, { acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE("ex_convert_to_target_type"); + ACPI_FUNCTION_TRACE(ex_convert_to_target_type); /* Default behavior */ @@ -659,7 +659,7 @@ acpi_ex_convert_to_target_type(acpi_object_type destination_type, default: ACPI_ERROR((AE_INFO, - "Unknown Target type ID 0x%X aml_opcode %X dest_type %s", + "Unknown Target type ID 0x%X AmlOpcode %X DestType %s", GET_CURRENT_ARG_TYPE(walk_state->op_info-> runtime_args), walk_state->opcode, diff --git a/drivers/acpi/executer/excreate.c b/drivers/acpi/executer/excreate.c index 763e132da4c6..106dc7219df7 100644 --- a/drivers/acpi/executer/excreate.c +++ b/drivers/acpi/executer/excreate.c @@ -69,7 +69,7 @@ acpi_status acpi_ex_create_alias(struct acpi_walk_state *walk_state) struct acpi_namespace_node *alias_node; acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE("ex_create_alias"); + ACPI_FUNCTION_TRACE(ex_create_alias); /* Get the source/alias operands (both namespace nodes) */ @@ -164,7 +164,7 @@ acpi_status acpi_ex_create_event(struct acpi_walk_state *walk_state) acpi_status status; union acpi_operand_object *obj_desc; - ACPI_FUNCTION_TRACE("ex_create_event"); + ACPI_FUNCTION_TRACE(ex_create_event); obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_EVENT); if (!obj_desc) { @@ -216,7 +216,7 @@ acpi_status acpi_ex_create_mutex(struct acpi_walk_state *walk_state) acpi_status status = AE_OK; union acpi_operand_object *obj_desc; - ACPI_FUNCTION_TRACE_PTR("ex_create_mutex", ACPI_WALK_OPERANDS); + ACPI_FUNCTION_TRACE_PTR(ex_create_mutex, ACPI_WALK_OPERANDS); /* Create the new mutex object */ @@ -281,7 +281,7 @@ acpi_ex_create_region(u8 * aml_start, struct acpi_namespace_node *node; union acpi_operand_object *region_obj2; - ACPI_FUNCTION_TRACE("ex_create_region"); + ACPI_FUNCTION_TRACE(ex_create_region); /* Get the Namespace Node */ @@ -301,7 +301,7 @@ acpi_ex_create_region(u8 * aml_start, */ if ((region_space >= ACPI_NUM_PREDEFINED_REGIONS) && (region_space < ACPI_USER_REGION_BEGIN)) { - ACPI_ERROR((AE_INFO, "Invalid address_space type %X", + ACPI_ERROR((AE_INFO, "Invalid AddressSpace type %X", region_space)); return_ACPI_STATUS(AE_AML_INVALID_SPACE_ID); } @@ -365,7 +365,7 @@ acpi_status acpi_ex_create_table_region(struct acpi_walk_state *walk_state) struct acpi_table_header *table; union acpi_operand_object *region_obj2; - ACPI_FUNCTION_TRACE("ex_create_table_region"); + ACPI_FUNCTION_TRACE(ex_create_table_region); /* Get the Node from the object stack */ @@ -453,7 +453,7 @@ acpi_status acpi_ex_create_processor(struct acpi_walk_state *walk_state) union acpi_operand_object *obj_desc; acpi_status status; - ACPI_FUNCTION_TRACE_PTR("ex_create_processor", walk_state); + ACPI_FUNCTION_TRACE_PTR(ex_create_processor, walk_state); /* Create the processor object */ @@ -500,7 +500,7 @@ acpi_status acpi_ex_create_power_resource(struct acpi_walk_state *walk_state) acpi_status status; union acpi_operand_object *obj_desc; - ACPI_FUNCTION_TRACE_PTR("ex_create_power_resource", walk_state); + ACPI_FUNCTION_TRACE_PTR(ex_create_power_resource, walk_state); /* Create the power resource object */ @@ -550,7 +550,7 @@ acpi_ex_create_method(u8 * aml_start, acpi_status status; u8 method_flags; - ACPI_FUNCTION_TRACE_PTR("ex_create_method", walk_state); + ACPI_FUNCTION_TRACE_PTR(ex_create_method, walk_state); /* Create a new method object */ diff --git a/drivers/acpi/executer/exdump.c b/drivers/acpi/executer/exdump.c index 1dfebf9e7074..7b9718e976bf 100644 --- a/drivers/acpi/executer/exdump.c +++ b/drivers/acpi/executer/exdump.c @@ -123,7 +123,7 @@ static struct acpi_exdump_info acpi_ex_dump_event[2] = { static struct acpi_exdump_info acpi_ex_dump_method[8] = { {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_method), NULL}, - {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.param_count), "param_count"}, + {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.param_count), "ParamCount"}, {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.concurrency), "Concurrency"}, {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(method.semaphore), "Semaphore"}, {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.owner_id), "Owner Id"}, @@ -332,7 +332,7 @@ acpi_ex_dump_object(union acpi_operand_object *obj_desc, if (!info) { acpi_os_printf - ("ex_dump_object: Display not implemented for object type %s\n", + ("ExDumpObject: Display not implemented for object type %s\n", acpi_ut_get_object_type_name(obj_desc)); return; } @@ -456,7 +456,7 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth) u32 length; u32 index; - ACPI_FUNCTION_NAME("ex_dump_operand") + ACPI_FUNCTION_NAME(ex_dump_operand) if (! ((ACPI_LV_EXEC & acpi_dbg_level) @@ -525,7 +525,7 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth) case AML_REF_OF_OP: - acpi_os_printf("Reference: (ref_of) %p\n", + acpi_os_printf("Reference: (RefOf) %p\n", obj_desc->reference.object); break; @@ -614,7 +614,7 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth) case ACPI_TYPE_PACKAGE: - acpi_os_printf("Package [Len %X] element_array %p\n", + acpi_os_printf("Package [Len %X] ElementArray %p\n", obj_desc->package.count, obj_desc->package.elements); @@ -666,13 +666,13 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth) case ACPI_TYPE_LOCAL_BANK_FIELD: - acpi_os_printf("bank_field\n"); + acpi_os_printf("BankField\n"); break; case ACPI_TYPE_LOCAL_REGION_FIELD: acpi_os_printf - ("region_field: Bits=%X acc_width=%X Lock=%X Update=%X at byte=%X bit=%X of below:\n", + ("RegionField: Bits=%X AccWidth=%X Lock=%X Update=%X at byte=%X bit=%X of below:\n", obj_desc->field.bit_length, obj_desc->field.access_byte_width, obj_desc->field.field_flags & AML_FIELD_LOCK_RULE_MASK, @@ -685,12 +685,12 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth) case ACPI_TYPE_LOCAL_INDEX_FIELD: - acpi_os_printf("index_field\n"); + acpi_os_printf("IndexField\n"); break; case ACPI_TYPE_BUFFER_FIELD: - acpi_os_printf("buffer_field: %X bits at byte %X bit %X of\n", + acpi_os_printf("BufferField: %X bits at byte %X bit %X of\n", obj_desc->buffer_field.bit_length, obj_desc->buffer_field.base_byte_offset, obj_desc->buffer_field.start_field_bit_offset); @@ -781,7 +781,7 @@ acpi_ex_dump_operands(union acpi_operand_object **operands, { acpi_native_uint i; - ACPI_FUNCTION_NAME("ex_dump_operands"); + ACPI_FUNCTION_NAME(ex_dump_operands); if (!ident) { ident = "?"; @@ -1021,7 +1021,7 @@ acpi_ex_dump_package_obj(union acpi_operand_object *obj_desc, void acpi_ex_dump_object_descriptor(union acpi_operand_object *obj_desc, u32 flags) { - ACPI_FUNCTION_TRACE("ex_dump_object_descriptor"); + ACPI_FUNCTION_TRACE(ex_dump_object_descriptor); if (!obj_desc) { return_VOID; @@ -1050,7 +1050,7 @@ acpi_ex_dump_object_descriptor(union acpi_operand_object *obj_desc, u32 flags) if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) != ACPI_DESC_TYPE_OPERAND) { acpi_os_printf - ("ex_dump_object_descriptor: %p is not an ACPI operand object: [%s]\n", + ("ExDumpObjectDescriptor: %p is not an ACPI operand object: [%s]\n", obj_desc, acpi_ut_get_descriptor_name(obj_desc)); return_VOID; } diff --git a/drivers/acpi/executer/exfield.c b/drivers/acpi/executer/exfield.c index 36c265a00c26..9ea9c3a67ca9 100644 --- a/drivers/acpi/executer/exfield.c +++ b/drivers/acpi/executer/exfield.c @@ -73,7 +73,7 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state, void *buffer; u8 locked; - ACPI_FUNCTION_TRACE_PTR("ex_read_data_from_field", obj_desc); + ACPI_FUNCTION_TRACE_PTR(ex_read_data_from_field, obj_desc); /* Parameter validation */ @@ -164,11 +164,11 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state, } ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, - "field_read [TO]: Obj %p, Type %X, Buf %p, byte_len %X\n", + "FieldRead [TO]: Obj %p, Type %X, Buf %p, ByteLen %X\n", obj_desc, ACPI_GET_OBJECT_TYPE(obj_desc), buffer, (u32) length)); ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, - "field_read [FROM]: bit_len %X, bit_off %X, byte_off %X\n", + "FieldRead [FROM]: BitLen %X, BitOff %X, ByteOff %X\n", obj_desc->common_field.bit_length, obj_desc->common_field.start_field_bit_offset, obj_desc->common_field.base_byte_offset)); @@ -220,7 +220,7 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, u8 locked; union acpi_operand_object *buffer_desc; - ACPI_FUNCTION_TRACE_PTR("ex_write_data_to_field", obj_desc); + ACPI_FUNCTION_TRACE_PTR(ex_write_data_to_field, obj_desc); /* Parameter validation */ @@ -349,14 +349,14 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, } ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, - "field_write [FROM]: Obj %p (%s:%X), Buf %p, byte_len %X\n", + "FieldWrite [FROM]: Obj %p (%s:%X), Buf %p, ByteLen %X\n", source_desc, acpi_ut_get_type_name(ACPI_GET_OBJECT_TYPE (source_desc)), ACPI_GET_OBJECT_TYPE(source_desc), buffer, length)); ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, - "field_write [TO]: Obj %p (%s:%X), bit_len %X, bit_off %X, byte_off %X\n", + "FieldWrite [TO]: Obj %p (%s:%X), BitLen %X, BitOff %X, ByteOff %X\n", obj_desc, acpi_ut_get_type_name(ACPI_GET_OBJECT_TYPE(obj_desc)), ACPI_GET_OBJECT_TYPE(obj_desc), diff --git a/drivers/acpi/executer/exfldio.c b/drivers/acpi/executer/exfldio.c index d5a4b2627c19..ca9925c0d011 100644 --- a/drivers/acpi/executer/exfldio.c +++ b/drivers/acpi/executer/exfldio.c @@ -87,7 +87,7 @@ acpi_ex_setup_region(union acpi_operand_object *obj_desc, acpi_status status = AE_OK; union acpi_operand_object *rgn_desc; - ACPI_FUNCTION_TRACE_U32("ex_setup_region", field_datum_byte_offset); + ACPI_FUNCTION_TRACE_U32(ex_setup_region, field_datum_byte_offset); rgn_desc = obj_desc->common_field.region_obj; @@ -112,6 +112,16 @@ acpi_ex_setup_region(union acpi_operand_object *obj_desc, } } + /* Exit if Address/Length have been disallowed by the host OS */ + + if (rgn_desc->common.flags & AOPOBJ_INVALID) { + return_ACPI_STATUS(AE_AML_ILLEGAL_ADDRESS); + } + + /* + * Exit now for SMBus address space, it has a non-linear address space + * and the request cannot be directly validated + */ if (rgn_desc->region.space_id == ACPI_ADR_SPACE_SMBUS) { /* SMBus has a non-linear address space */ @@ -218,7 +228,7 @@ acpi_ex_access_region(union acpi_operand_object *obj_desc, union acpi_operand_object *rgn_desc; acpi_physical_address address; - ACPI_FUNCTION_TRACE("ex_access_region"); + ACPI_FUNCTION_TRACE(ex_access_region); /* * Ensure that the region operands are fully evaluated and verify @@ -247,7 +257,7 @@ acpi_ex_access_region(union acpi_operand_object *obj_desc, } ACPI_DEBUG_PRINT_RAW((ACPI_DB_BFIELD, - " Region [%s:%X], Width %X, byte_base %X, Offset %X at %8.8X%8.8X\n", + " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %8.8X%8.8X\n", acpi_ut_get_region_name(rgn_desc->region. space_id), rgn_desc->region.space_id, @@ -353,7 +363,7 @@ acpi_ex_field_datum_io(union acpi_operand_object *obj_desc, acpi_status status; acpi_integer local_value; - ACPI_FUNCTION_TRACE_U32("ex_field_datum_io", field_datum_byte_offset); + ACPI_FUNCTION_TRACE_U32(ex_field_datum_io, field_datum_byte_offset); if (read_write == ACPI_READ) { if (!value) { @@ -488,7 +498,7 @@ acpi_ex_field_datum_io(union acpi_operand_object *obj_desc, } ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, - "I/O to Data Register: value_ptr %p\n", + "I/O to Data Register: ValuePtr %p\n", value)); if (read_write == ACPI_READ) { @@ -561,7 +571,7 @@ acpi_ex_write_with_update_rule(union acpi_operand_object *obj_desc, acpi_integer merged_value; acpi_integer current_value; - ACPI_FUNCTION_TRACE_U32("ex_write_with_update_rule", mask); + ACPI_FUNCTION_TRACE_U32(ex_write_with_update_rule, mask); /* Start with the new bits */ @@ -617,7 +627,7 @@ acpi_ex_write_with_update_rule(union acpi_operand_object *obj_desc, default: ACPI_ERROR((AE_INFO, - "Unknown update_rule value: %X", + "Unknown UpdateRule value: %X", (obj_desc->common_field. field_flags & AML_FIELD_UPDATE_RULE_MASK))); @@ -626,7 +636,7 @@ acpi_ex_write_with_update_rule(union acpi_operand_object *obj_desc, } ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, - "Mask %8.8X%8.8X, datum_offset %X, Width %X, Value %8.8X%8.8X, merged_value %8.8X%8.8X\n", + "Mask %8.8X%8.8X, DatumOffset %X, Width %X, Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n", ACPI_FORMAT_UINT64(mask), field_datum_byte_offset, obj_desc->common_field.access_byte_width, @@ -669,7 +679,7 @@ acpi_ex_extract_from_field(union acpi_operand_object *obj_desc, u32 field_datum_count; u32 i; - ACPI_FUNCTION_TRACE("ex_extract_from_field"); + ACPI_FUNCTION_TRACE(ex_extract_from_field); /* Validate target buffer and clear it */ @@ -784,7 +794,7 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc, u32 field_datum_count; u32 i; - ACPI_FUNCTION_TRACE("ex_insert_into_field"); + ACPI_FUNCTION_TRACE(ex_insert_into_field); /* Validate input buffer */ diff --git a/drivers/acpi/executer/exmisc.c b/drivers/acpi/executer/exmisc.c index 74f2c1a9bdaf..794d9b8de956 100644 --- a/drivers/acpi/executer/exmisc.c +++ b/drivers/acpi/executer/exmisc.c @@ -72,7 +72,7 @@ acpi_ex_get_object_reference(union acpi_operand_object *obj_desc, union acpi_operand_object *reference_obj; union acpi_operand_object *referenced_obj; - ACPI_FUNCTION_TRACE_PTR("ex_get_object_reference", obj_desc); + ACPI_FUNCTION_TRACE_PTR(ex_get_object_reference, obj_desc); *return_desc = NULL; @@ -168,7 +168,7 @@ acpi_ex_concat_template(union acpi_operand_object *operand0, acpi_size length1; acpi_size new_length; - ACPI_FUNCTION_TRACE("ex_concat_template"); + ACPI_FUNCTION_TRACE(ex_concat_template); /* * Find the end_tag descriptor in each resource template. @@ -250,7 +250,7 @@ acpi_ex_do_concatenate(union acpi_operand_object *operand0, char *new_buf; acpi_status status; - ACPI_FUNCTION_TRACE("ex_do_concatenate"); + ACPI_FUNCTION_TRACE(ex_do_concatenate); /* * Convert the second operand if necessary. The first operand @@ -489,7 +489,7 @@ acpi_ex_do_logical_numeric_op(u16 opcode, acpi_status status = AE_OK; u8 local_result = FALSE; - ACPI_FUNCTION_TRACE("ex_do_logical_numeric_op"); + ACPI_FUNCTION_TRACE(ex_do_logical_numeric_op); switch (opcode) { case AML_LAND_OP: /* LAnd (Integer0, Integer1) */ @@ -557,7 +557,7 @@ acpi_ex_do_logical_op(u16 opcode, u8 local_result = FALSE; int compare; - ACPI_FUNCTION_TRACE("ex_do_logical_op"); + ACPI_FUNCTION_TRACE(ex_do_logical_op); /* * Convert the second operand if necessary. The first operand diff --git a/drivers/acpi/executer/exmutex.c b/drivers/acpi/executer/exmutex.c index eaee1de5e90d..93098d68cadf 100644 --- a/drivers/acpi/executer/exmutex.c +++ b/drivers/acpi/executer/exmutex.c @@ -61,7 +61,7 @@ acpi_ex_link_mutex(union acpi_operand_object *obj_desc, * * RETURN: None * - * DESCRIPTION: Remove a mutex from the "acquired_mutex" list + * DESCRIPTION: Remove a mutex from the "AcquiredMutex" list * ******************************************************************************/ @@ -95,7 +95,7 @@ void acpi_ex_unlink_mutex(union acpi_operand_object *obj_desc) * * RETURN: None * - * DESCRIPTION: Add a mutex to the "acquired_mutex" list for this walk + * DESCRIPTION: Add a mutex to the "AcquiredMutex" list for this walk * ******************************************************************************/ @@ -144,7 +144,7 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc, { acpi_status status; - ACPI_FUNCTION_TRACE_PTR("ex_acquire_mutex", obj_desc); + ACPI_FUNCTION_TRACE_PTR(ex_acquire_mutex, obj_desc); if (!obj_desc) { return_ACPI_STATUS(AE_BAD_PARAMETER); @@ -165,7 +165,7 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc, */ if (walk_state->thread->current_sync_level > obj_desc->mutex.sync_level) { ACPI_ERROR((AE_INFO, - "Cannot acquire Mutex [%4.4s], incorrect sync_level", + "Cannot acquire Mutex [%4.4s], incorrect SyncLevel", acpi_ut_get_node_name(obj_desc->mutex.node))); return_ACPI_STATUS(AE_AML_MUTEX_ORDER); } @@ -234,7 +234,7 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, { acpi_status status; - ACPI_FUNCTION_TRACE("ex_release_mutex"); + ACPI_FUNCTION_TRACE(ex_release_mutex); if (!obj_desc) { return_ACPI_STATUS(AE_BAD_PARAMETER); @@ -279,7 +279,7 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, */ if (obj_desc->mutex.sync_level > walk_state->thread->current_sync_level) { ACPI_ERROR((AE_INFO, - "Cannot release Mutex [%4.4s], incorrect sync_level", + "Cannot release Mutex [%4.4s], incorrect SyncLevel", acpi_ut_get_node_name(obj_desc->mutex.node))); return_ACPI_STATUS(AE_AML_MUTEX_ORDER); } diff --git a/drivers/acpi/executer/exnames.c b/drivers/acpi/executer/exnames.c index 085b18f8dd00..d3d70364626c 100644 --- a/drivers/acpi/executer/exnames.c +++ b/drivers/acpi/executer/exnames.c @@ -77,7 +77,7 @@ static char *acpi_ex_allocate_name_string(u32 prefix_count, u32 num_name_segs) char *name_string; u32 size_needed; - ACPI_FUNCTION_TRACE("ex_allocate_name_string"); + ACPI_FUNCTION_TRACE(ex_allocate_name_string); /* * Allow room for all \ and ^ prefixes, all segments and a multi_name_prefix. @@ -162,7 +162,7 @@ static acpi_status acpi_ex_name_segment(u8 ** in_aml_address, char *name_string) u32 index; char char_buf[5]; - ACPI_FUNCTION_TRACE("ex_name_segment"); + ACPI_FUNCTION_TRACE(ex_name_segment); /* * If first character is a digit, then we know that we aren't looking at a @@ -253,7 +253,7 @@ acpi_ex_get_name_string(acpi_object_type data_type, u32 prefix_count = 0; u8 has_prefix = FALSE; - ACPI_FUNCTION_TRACE_PTR("ex_get_name_string", aml_address); + ACPI_FUNCTION_TRACE_PTR(ex_get_name_string, aml_address); if (ACPI_TYPE_LOCAL_REGION_FIELD == data_type || ACPI_TYPE_LOCAL_BANK_FIELD == data_type || @@ -277,7 +277,7 @@ acpi_ex_get_name_string(acpi_object_type data_type, case AML_ROOT_PREFIX: ACPI_DEBUG_PRINT((ACPI_DB_LOAD, - "root_prefix(\\) at %p\n", + "RootPrefix(\\) at %p\n", aml_address)); /* @@ -295,7 +295,7 @@ acpi_ex_get_name_string(acpi_object_type data_type, do { ACPI_DEBUG_PRINT((ACPI_DB_LOAD, - "parent_prefix (^) at %p\n", + "ParentPrefix (^) at %p\n", aml_address)); aml_address++; @@ -319,7 +319,7 @@ acpi_ex_get_name_string(acpi_object_type data_type, case AML_DUAL_NAME_PREFIX: ACPI_DEBUG_PRINT((ACPI_DB_LOAD, - "dual_name_prefix at %p\n", + "DualNamePrefix at %p\n", aml_address)); aml_address++; @@ -346,7 +346,7 @@ acpi_ex_get_name_string(acpi_object_type data_type, case AML_MULTI_NAME_PREFIX_OP: ACPI_DEBUG_PRINT((ACPI_DB_LOAD, - "multi_name_prefix at %p\n", + "MultiNamePrefix at %p\n", aml_address)); /* Fetch count of segments remaining in name path */ @@ -382,7 +382,7 @@ acpi_ex_get_name_string(acpi_object_type data_type, if (prefix_count == ACPI_UINT32_MAX) { ACPI_DEBUG_PRINT((ACPI_DB_EXEC, - "name_seg is \"\\\" followed by NULL\n")); + "NameSeg is \"\\\" followed by NULL\n")); } /* Consume the NULL byte */ diff --git a/drivers/acpi/executer/exoparg1.c b/drivers/acpi/executer/exoparg1.c index d00f766246f3..05b89c5878eb 100644 --- a/drivers/acpi/executer/exoparg1.c +++ b/drivers/acpi/executer/exoparg1.c @@ -89,7 +89,7 @@ acpi_status acpi_ex_opcode_0A_0T_1R(struct acpi_walk_state *walk_state) acpi_status status = AE_OK; union acpi_operand_object *return_desc = NULL; - ACPI_FUNCTION_TRACE_STR("ex_opcode_0A_0T_1R", + ACPI_FUNCTION_TRACE_STR(ex_opcode_0A_0T_1R, acpi_ps_get_opcode_name(walk_state->opcode)); /* Examine the AML opcode */ @@ -150,7 +150,7 @@ acpi_status acpi_ex_opcode_1A_0T_0R(struct acpi_walk_state *walk_state) union acpi_operand_object **operand = &walk_state->operands[0]; acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE_STR("ex_opcode_1A_0T_0R", + ACPI_FUNCTION_TRACE_STR(ex_opcode_1A_0T_0R, acpi_ps_get_opcode_name(walk_state->opcode)); /* Examine the AML opcode */ @@ -216,7 +216,7 @@ acpi_status acpi_ex_opcode_1A_1T_0R(struct acpi_walk_state *walk_state) acpi_status status = AE_OK; union acpi_operand_object **operand = &walk_state->operands[0]; - ACPI_FUNCTION_TRACE_STR("ex_opcode_1A_1T_0R", + ACPI_FUNCTION_TRACE_STR(ex_opcode_1A_1T_0R, acpi_ps_get_opcode_name(walk_state->opcode)); /* Examine the AML opcode */ @@ -264,7 +264,7 @@ acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state) acpi_integer power_of_ten; acpi_integer digit; - ACPI_FUNCTION_TRACE_STR("ex_opcode_1A_1T_1R", + ACPI_FUNCTION_TRACE_STR(ex_opcode_1A_1T_1R, acpi_ps_get_opcode_name(walk_state->opcode)); /* Examine the AML opcode */ @@ -590,7 +590,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state) u32 type; acpi_integer value; - ACPI_FUNCTION_TRACE_STR("ex_opcode_1A_0T_1R", + ACPI_FUNCTION_TRACE_STR(ex_opcode_1A_0T_1R, acpi_ps_get_opcode_name(walk_state->opcode)); /* Examine the AML opcode */ @@ -975,7 +975,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state) default: ACPI_ERROR((AE_INFO, - "Unknown Index target_type %X in obj %p", + "Unknown Index TargetType %X in obj %p", operand[0]->reference. target_type, operand[0])); status = AE_AML_OPERAND_TYPE; diff --git a/drivers/acpi/executer/exoparg2.c b/drivers/acpi/executer/exoparg2.c index 690e43db0abe..7d2cbc113160 100644 --- a/drivers/acpi/executer/exoparg2.c +++ b/drivers/acpi/executer/exoparg2.c @@ -92,7 +92,7 @@ acpi_status acpi_ex_opcode_2A_0T_0R(struct acpi_walk_state *walk_state) u32 value; acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE_STR("ex_opcode_2A_0T_0R", + ACPI_FUNCTION_TRACE_STR(ex_opcode_2A_0T_0R, acpi_ps_get_opcode_name(walk_state->opcode)); /* Examine the opcode */ @@ -121,7 +121,7 @@ acpi_status acpi_ex_opcode_2A_0T_0R(struct acpi_walk_state *walk_state) #ifdef ACPI_GPE_NOTIFY_CHECK /* * GPE method wake/notify check. Here, we want to ensure that we - * don't receive any "device_wake" Notifies from a GPE _Lxx or _Exx + * don't receive any "DeviceWake" Notifies from a GPE _Lxx or _Exx * GPE method during system runtime. If we do, the GPE is marked * as "wake-only" and disabled. * @@ -186,7 +186,7 @@ acpi_status acpi_ex_opcode_2A_2T_1R(struct acpi_walk_state *walk_state) union acpi_operand_object *return_desc2 = NULL; acpi_status status; - ACPI_FUNCTION_TRACE_STR("ex_opcode_2A_2T_1R", + ACPI_FUNCTION_TRACE_STR(ex_opcode_2A_2T_1R, acpi_ps_get_opcode_name(walk_state->opcode)); /* Execute the opcode */ @@ -283,7 +283,7 @@ acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state) acpi_status status = AE_OK; acpi_size length; - ACPI_FUNCTION_TRACE_STR("ex_opcode_2A_1T_1R", + ACPI_FUNCTION_TRACE_STR(ex_opcode_2A_1T_1R, acpi_ps_get_opcode_name(walk_state->opcode)); /* Execute the opcode */ @@ -514,7 +514,7 @@ acpi_status acpi_ex_opcode_2A_0T_1R(struct acpi_walk_state *walk_state) acpi_status status = AE_OK; u8 logical_result = FALSE; - ACPI_FUNCTION_TRACE_STR("ex_opcode_2A_0T_1R", + ACPI_FUNCTION_TRACE_STR(ex_opcode_2A_0T_1R, acpi_ps_get_opcode_name(walk_state->opcode)); /* Create the internal return object */ diff --git a/drivers/acpi/executer/exoparg3.c b/drivers/acpi/executer/exoparg3.c index 4897e6c3431f..e2d945dfd509 100644 --- a/drivers/acpi/executer/exoparg3.c +++ b/drivers/acpi/executer/exoparg3.c @@ -88,14 +88,14 @@ acpi_status acpi_ex_opcode_3A_0T_0R(struct acpi_walk_state *walk_state) struct acpi_signal_fatal_info *fatal; acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE_STR("ex_opcode_3A_0T_0R", + ACPI_FUNCTION_TRACE_STR(ex_opcode_3A_0T_0R, acpi_ps_get_opcode_name(walk_state->opcode)); switch (walk_state->opcode) { case AML_FATAL_OP: /* Fatal (fatal_type fatal_code fatal_arg) */ ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "fatal_op: Type %X Code %X Arg %X <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n", + "FatalOp: Type %X Code %X Arg %X <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n", (u32) operand[0]->integer.value, (u32) operand[1]->integer.value, (u32) operand[2]->integer.value)); @@ -150,7 +150,7 @@ acpi_status acpi_ex_opcode_3A_1T_1R(struct acpi_walk_state *walk_state) acpi_integer index; acpi_size length; - ACPI_FUNCTION_TRACE_STR("ex_opcode_3A_1T_1R", + ACPI_FUNCTION_TRACE_STR(ex_opcode_3A_1T_1R, acpi_ps_get_opcode_name(walk_state->opcode)); switch (walk_state->opcode) { diff --git a/drivers/acpi/executer/exoparg6.c b/drivers/acpi/executer/exoparg6.c index 33e4fb1addce..f0c0ba6eb408 100644 --- a/drivers/acpi/executer/exoparg6.c +++ b/drivers/acpi/executer/exoparg6.c @@ -220,7 +220,7 @@ acpi_status acpi_ex_opcode_6A_0T_1R(struct acpi_walk_state * walk_state) acpi_integer index; union acpi_operand_object *this_element; - ACPI_FUNCTION_TRACE_STR("ex_opcode_6A_0T_1R", + ACPI_FUNCTION_TRACE_STR(ex_opcode_6A_0T_1R, acpi_ps_get_opcode_name(walk_state->opcode)); switch (walk_state->opcode) { diff --git a/drivers/acpi/executer/exprep.c b/drivers/acpi/executer/exprep.c index 916234bf811c..44d064f427b9 100644 --- a/drivers/acpi/executer/exprep.c +++ b/drivers/acpi/executer/exprep.c @@ -97,7 +97,7 @@ acpi_ex_generate_access(u32 field_bit_offset, u32 minimum_accesses = 0xFFFFFFFF; u32 accesses; - ACPI_FUNCTION_TRACE("ex_generate_access"); + ACPI_FUNCTION_TRACE(ex_generate_access); /* Round Field start offset and length to "minimal" byte boundaries */ @@ -146,7 +146,7 @@ acpi_ex_generate_access(u32 field_bit_offset, accesses = field_end_offset - field_start_offset; ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, - "access_width %d end is within region\n", + "AccessWidth %d end is within region\n", access_byte_width)); ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, @@ -173,7 +173,7 @@ acpi_ex_generate_access(u32 field_bit_offset, } } else { ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, - "access_width %d end is NOT within region\n", + "AccessWidth %d end is NOT within region\n", access_byte_width)); if (access_byte_width == 1) { ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, @@ -228,7 +228,7 @@ acpi_ex_decode_field_access(union acpi_operand_object *obj_desc, u32 byte_alignment; u32 bit_length; - ACPI_FUNCTION_TRACE("ex_decode_field_access"); + ACPI_FUNCTION_TRACE(ex_decode_field_access); access = (field_flags & AML_FIELD_ACCESS_TYPE_MASK); @@ -322,7 +322,7 @@ acpi_ex_prep_common_field_object(union acpi_operand_object *obj_desc, u32 byte_alignment; u32 nearest_byte_address; - ACPI_FUNCTION_TRACE("ex_prep_common_field_object"); + ACPI_FUNCTION_TRACE(ex_prep_common_field_object); /* * Note: the structure being initialized is the @@ -415,13 +415,13 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info) u32 type; acpi_status status; - ACPI_FUNCTION_TRACE("ex_prep_field_value"); + ACPI_FUNCTION_TRACE(ex_prep_field_value); /* Parameter validation */ if (info->field_type != ACPI_TYPE_LOCAL_INDEX_FIELD) { if (!info->region_node) { - ACPI_ERROR((AE_INFO, "Null region_node")); + ACPI_ERROR((AE_INFO, "Null RegionNode")); return_ACPI_STATUS(AE_AML_NO_OPERAND); } @@ -467,7 +467,7 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info) acpi_ut_add_reference(obj_desc->field.region_obj); ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, - "region_field: bit_off %X, Off %X, Gran %X, Region %p\n", + "RegionField: BitOff %X, Off %X, Gran %X, Region %p\n", obj_desc->field.start_field_bit_offset, obj_desc->field.base_byte_offset, obj_desc->field.access_byte_width, @@ -488,7 +488,7 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info) acpi_ut_add_reference(obj_desc->bank_field.bank_obj); ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, - "Bank Field: bit_off %X, Off %X, Gran %X, Region %p, bank_reg %p\n", + "Bank Field: BitOff %X, Off %X, Gran %X, Region %p, BankReg %p\n", obj_desc->bank_field.start_field_bit_offset, obj_desc->bank_field.base_byte_offset, obj_desc->field.access_byte_width, @@ -519,23 +519,29 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info) acpi_ut_add_reference(obj_desc->index_field.index_obj); /* - * February 2006: Changed to match MS behavior + * April 2006: Changed to match MS behavior * * The value written to the Index register is the byte offset of the - * target field. + * target field in units of the granularity of the index_field * * Previously, the value was calculated as an index in terms of the * width of the Data register, as below: * - * obj_desc->index_field.Value = (u32) - * (Info->field_bit_position / ACPI_MUL_8 ( - * obj_desc->Field.access_byte_width)); + * obj_desc->index_field.Value = (u32) + * (Info->field_bit_position / ACPI_MUL_8 ( + * obj_desc->Field.access_byte_width)); + * + * February 2006: Tried value as a byte offset: + * obj_desc->index_field.Value = (u32) + * ACPI_DIV_8 (Info->field_bit_position); */ obj_desc->index_field.value = - (u32) ACPI_DIV_8(info->field_bit_position); + (u32) ACPI_ROUND_DOWN(ACPI_DIV_8(info->field_bit_position), + obj_desc->index_field. + access_byte_width); ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, - "index_field: bit_off %X, Off %X, Value %X, Gran %X, Index %p, Data %p\n", + "IndexField: BitOff %X, Off %X, Value %X, Gran %X, Index %p, Data %p\n", obj_desc->index_field.start_field_bit_offset, obj_desc->index_field.base_byte_offset, obj_desc->index_field.value, @@ -557,7 +563,7 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info) acpi_ns_get_type(info->field_node)); ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, - "Set named_obj %p [%4.4s], obj_desc %p\n", + "Set NamedObj %p [%4.4s], ObjDesc %p\n", info->field_node, acpi_ut_get_node_name(info->field_node), obj_desc)); diff --git a/drivers/acpi/executer/exregion.c b/drivers/acpi/executer/exregion.c index fdeda7beae43..4fba452a5590 100644 --- a/drivers/acpi/executer/exregion.c +++ b/drivers/acpi/executer/exregion.c @@ -81,7 +81,7 @@ acpi_ex_system_memory_space_handler(u32 function, u32 remainder; #endif - ACPI_FUNCTION_TRACE("ex_system_memory_space_handler"); + ACPI_FUNCTION_TRACE(ex_system_memory_space_handler); /* Validate and translate the bit width */ @@ -103,7 +103,7 @@ acpi_ex_system_memory_space_handler(u32 function, break; default: - ACPI_ERROR((AE_INFO, "Invalid system_memory width %d", + ACPI_ERROR((AE_INFO, "Invalid SystemMemory width %d", bit_width)); return_ACPI_STATUS(AE_AML_OPERAND_VALUE); } @@ -284,7 +284,7 @@ acpi_ex_system_io_space_handler(u32 function, acpi_status status = AE_OK; u32 value32; - ACPI_FUNCTION_TRACE("ex_system_io_space_handler"); + ACPI_FUNCTION_TRACE(ex_system_io_space_handler); ACPI_DEBUG_PRINT((ACPI_DB_INFO, "System-IO (width %d) R/W %d Address=%8.8X%8.8X\n", @@ -343,7 +343,7 @@ acpi_ex_pci_config_space_handler(u32 function, struct acpi_pci_id *pci_id; u16 pci_register; - ACPI_FUNCTION_TRACE("ex_pci_config_space_handler"); + ACPI_FUNCTION_TRACE(ex_pci_config_space_handler); /* * The arguments to acpi_os(Read|Write)pci_configuration are: @@ -415,7 +415,7 @@ acpi_ex_cmos_space_handler(u32 function, { acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE("ex_cmos_space_handler"); + ACPI_FUNCTION_TRACE(ex_cmos_space_handler); return_ACPI_STATUS(status); } @@ -447,7 +447,7 @@ acpi_ex_pci_bar_space_handler(u32 function, { acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE("ex_pci_bar_space_handler"); + ACPI_FUNCTION_TRACE(ex_pci_bar_space_handler); return_ACPI_STATUS(status); } @@ -482,7 +482,7 @@ acpi_ex_data_table_space_handler(u32 function, u32 i; char *logical_addr_ptr; - ACPI_FUNCTION_TRACE("ex_data_table_space_handler"); + ACPI_FUNCTION_TRACE(ex_data_table_space_handler); logical_addr_ptr = ACPI_PHYSADDR_TO_PTR(address); diff --git a/drivers/acpi/executer/exresnte.c b/drivers/acpi/executer/exresnte.c index 417d914d9e19..f9b9f5008596 100644 --- a/drivers/acpi/executer/exresnte.c +++ b/drivers/acpi/executer/exresnte.c @@ -87,7 +87,7 @@ acpi_ex_resolve_node_to_value(struct acpi_namespace_node **object_ptr, struct acpi_namespace_node *node; acpi_object_type entry_type; - ACPI_FUNCTION_TRACE("ex_resolve_node_to_value"); + ACPI_FUNCTION_TRACE(ex_resolve_node_to_value); /* * The stack pointer points to a struct acpi_namespace_node (Node). Get the @@ -97,7 +97,7 @@ acpi_ex_resolve_node_to_value(struct acpi_namespace_node **object_ptr, source_desc = acpi_ns_get_attached_object(node); entry_type = acpi_ns_get_type((acpi_handle) node); - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Entry=%p source_desc=%p [%s]\n", + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Entry=%p SourceDesc=%p [%s]\n", node, source_desc, acpi_ut_get_type_name(entry_type))); @@ -202,7 +202,7 @@ acpi_ex_resolve_node_to_value(struct acpi_namespace_node **object_ptr, case ACPI_TYPE_LOCAL_INDEX_FIELD: ACPI_DEBUG_PRINT((ACPI_DB_EXEC, - "field_read Node=%p source_desc=%p Type=%X\n", + "FieldRead Node=%p SourceDesc=%p Type=%X\n", node, source_desc, entry_type)); status = diff --git a/drivers/acpi/executer/exresolv.c b/drivers/acpi/executer/exresolv.c index 22dabdd10604..006bba035d51 100644 --- a/drivers/acpi/executer/exresolv.c +++ b/drivers/acpi/executer/exresolv.c @@ -78,7 +78,7 @@ acpi_ex_resolve_to_value(union acpi_operand_object **stack_ptr, { acpi_status status; - ACPI_FUNCTION_TRACE_PTR("ex_resolve_to_value", stack_ptr); + ACPI_FUNCTION_TRACE_PTR(ex_resolve_to_value, stack_ptr); if (!stack_ptr || !*stack_ptr) { ACPI_ERROR((AE_INFO, "Internal - null pointer")); @@ -144,7 +144,7 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr, union acpi_operand_object *obj_desc; u16 opcode; - ACPI_FUNCTION_TRACE("ex_resolve_object_to_value"); + ACPI_FUNCTION_TRACE(ex_resolve_object_to_value); stack_desc = *stack_ptr; @@ -190,7 +190,7 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr, } ACPI_DEBUG_PRINT((ACPI_DB_EXEC, - "[Arg/Local %X] value_obj is %p\n", + "[Arg/Local %X] ValueObj is %p\n", stack_desc->reference.offset, obj_desc)); @@ -239,7 +239,7 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr, /* Invalid reference object */ ACPI_ERROR((AE_INFO, - "Unknown target_type %X in Index/Reference obj %p", + "Unknown TargetType %X in Index/Reference obj %p", stack_desc->reference.target_type, stack_desc)); status = AE_AML_INTERNAL; @@ -293,7 +293,7 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr, case ACPI_TYPE_LOCAL_INDEX_FIELD: ACPI_DEBUG_PRINT((ACPI_DB_EXEC, - "field_read source_desc=%p Type=%X\n", + "FieldRead SourceDesc=%p Type=%X\n", stack_desc, ACPI_GET_OBJECT_TYPE(stack_desc))); @@ -337,7 +337,7 @@ acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state, acpi_object_type type; acpi_status status; - ACPI_FUNCTION_TRACE("acpi_ex_resolve_multiple"); + ACPI_FUNCTION_TRACE(acpi_ex_resolve_multiple); /* Operand can be either a namespace node or an operand descriptor */ @@ -488,7 +488,7 @@ acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state, case AML_DEBUG_OP: - /* The Debug Object is of type "debug_object" */ + /* The Debug Object is of type "DebugObject" */ type = ACPI_TYPE_DEBUG_OBJECT; goto exit; diff --git a/drivers/acpi/executer/exresop.c b/drivers/acpi/executer/exresop.c index 42b9089dccc0..4c93d0972333 100644 --- a/drivers/acpi/executer/exresop.c +++ b/drivers/acpi/executer/exresop.c @@ -144,7 +144,7 @@ acpi_ex_resolve_operands(u16 opcode, acpi_object_type type_needed; u16 target_op = 0; - ACPI_FUNCTION_TRACE_U32("ex_resolve_operands", opcode); + ACPI_FUNCTION_TRACE_U32(ex_resolve_operands, opcode); op_info = acpi_ps_get_opcode_info(opcode); if (op_info->class == AML_CLASS_UNKNOWN) { @@ -159,7 +159,7 @@ acpi_ex_resolve_operands(u16 opcode, } ACPI_DEBUG_PRINT((ACPI_DB_EXEC, - "Opcode %X [%s] required_operand_types=%8.8X\n", + "Opcode %X [%s] RequiredOperandTypes=%8.8X\n", opcode, op_info->name, arg_types)); /* @@ -249,7 +249,7 @@ acpi_ex_resolve_operands(u16 opcode, ACPI_DEBUG_ONLY_MEMBERS(ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, - "Operand is a Reference, ref_opcode [%s]\n", + "Operand is a Reference, RefOpcode [%s]\n", (acpi_ps_get_opcode_info (obj_desc-> reference. @@ -626,7 +626,7 @@ acpi_ex_resolve_operands(u16 opcode, default: ACPI_ERROR((AE_INFO, - "Needed [Region/region_field], found [%s] %p", + "Needed [Region/RegionField], found [%s] %p", acpi_ut_get_object_type_name (obj_desc), obj_desc)); diff --git a/drivers/acpi/executer/exstore.c b/drivers/acpi/executer/exstore.c index 287476f319f4..0456405ba019 100644 --- a/drivers/acpi/executer/exstore.c +++ b/drivers/acpi/executer/exstore.c @@ -82,7 +82,7 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc, { u32 i; - ACPI_FUNCTION_TRACE_PTR("ex_do_debug_object", source_desc); + ACPI_FUNCTION_TRACE_PTR(ex_do_debug_object, source_desc); ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "[ACPI Debug] %*s", level, " ")); @@ -245,7 +245,7 @@ acpi_ex_store(union acpi_operand_object *source_desc, acpi_status status = AE_OK; union acpi_operand_object *ref_desc = dest_desc; - ACPI_FUNCTION_TRACE_PTR("ex_store", dest_desc); + ACPI_FUNCTION_TRACE_PTR(ex_store, dest_desc); /* Validate parameters */ @@ -297,7 +297,7 @@ acpi_ex_store(union acpi_operand_object *source_desc, ACPI_DUMP_STACK_ENTRY(source_desc); ACPI_DUMP_STACK_ENTRY(dest_desc); - ACPI_DUMP_OPERANDS(&dest_desc, ACPI_IMODE_EXECUTE, "ex_store", + ACPI_DUMP_OPERANDS(&dest_desc, ACPI_IMODE_EXECUTE, "ExStore", 2, "Target is not a Reference or Constant object"); @@ -396,7 +396,7 @@ acpi_ex_store_object_to_index(union acpi_operand_object *source_desc, u8 value = 0; u32 i; - ACPI_FUNCTION_TRACE("ex_store_object_to_index"); + ACPI_FUNCTION_TRACE(ex_store_object_to_index); /* * Destination must be a reference pointer, and @@ -503,8 +503,7 @@ acpi_ex_store_object_to_index(union acpi_operand_object *source_desc, break; default: - ACPI_ERROR((AE_INFO, - "Target is not a Package or buffer_field")); + ACPI_ERROR((AE_INFO, "Target is not a Package or BufferField")); status = AE_AML_OPERAND_TYPE; break; } @@ -549,7 +548,7 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc, union acpi_operand_object *new_desc; acpi_object_type target_type; - ACPI_FUNCTION_TRACE_PTR("ex_store_object_to_node", source_desc); + ACPI_FUNCTION_TRACE_PTR(ex_store_object_to_node, source_desc); /* Get current type of the node, and object attached to Node */ diff --git a/drivers/acpi/executer/exstoren.c b/drivers/acpi/executer/exstoren.c index 969f9cbbbeeb..591aaf0e18b3 100644 --- a/drivers/acpi/executer/exstoren.c +++ b/drivers/acpi/executer/exstoren.c @@ -72,7 +72,7 @@ acpi_ex_resolve_object(union acpi_operand_object **source_desc_ptr, union acpi_operand_object *source_desc = *source_desc_ptr; acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE("ex_resolve_object"); + ACPI_FUNCTION_TRACE(ex_resolve_object); /* Ensure we have a Target that can be stored to */ @@ -201,7 +201,7 @@ acpi_ex_store_object_to_object(union acpi_operand_object *source_desc, union acpi_operand_object *actual_src_desc; acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE_PTR("ex_store_object_to_object", source_desc); + ACPI_FUNCTION_TRACE_PTR(ex_store_object_to_object, source_desc); actual_src_desc = source_desc; if (!dest_desc) { diff --git a/drivers/acpi/executer/exstorob.c b/drivers/acpi/executer/exstorob.c index db42461101e0..18925f5b313c 100644 --- a/drivers/acpi/executer/exstorob.c +++ b/drivers/acpi/executer/exstorob.c @@ -67,7 +67,7 @@ acpi_ex_store_buffer_to_buffer(union acpi_operand_object *source_desc, u32 length; u8 *buffer; - ACPI_FUNCTION_TRACE_PTR("ex_store_buffer_to_buffer", source_desc); + ACPI_FUNCTION_TRACE_PTR(ex_store_buffer_to_buffer, source_desc); /* We know that source_desc is a buffer by now */ @@ -158,7 +158,7 @@ acpi_ex_store_string_to_string(union acpi_operand_object *source_desc, u32 length; u8 *buffer; - ACPI_FUNCTION_TRACE_PTR("ex_store_string_to_string", source_desc); + ACPI_FUNCTION_TRACE_PTR(ex_store_string_to_string, source_desc); /* We know that source_desc is a string by now */ diff --git a/drivers/acpi/executer/exsystem.c b/drivers/acpi/executer/exsystem.c index 6a2e47a0e112..52beee3674a0 100644 --- a/drivers/acpi/executer/exsystem.c +++ b/drivers/acpi/executer/exsystem.c @@ -68,7 +68,7 @@ acpi_status acpi_ex_system_wait_semaphore(acpi_handle semaphore, u16 timeout) acpi_status status; acpi_status status2; - ACPI_FUNCTION_TRACE("ex_system_wait_semaphore"); + ACPI_FUNCTION_TRACE(ex_system_wait_semaphore); status = acpi_os_wait_semaphore(semaphore, 1, 0); if (ACPI_SUCCESS(status)) { @@ -193,7 +193,7 @@ acpi_ex_system_acquire_mutex(union acpi_operand_object * time_desc, { acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE_PTR("ex_system_acquire_mutex", obj_desc); + ACPI_FUNCTION_TRACE_PTR(ex_system_acquire_mutex, obj_desc); if (!obj_desc) { return_ACPI_STATUS(AE_BAD_PARAMETER); @@ -231,7 +231,7 @@ acpi_status acpi_ex_system_release_mutex(union acpi_operand_object *obj_desc) { acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE("ex_system_release_mutex"); + ACPI_FUNCTION_TRACE(ex_system_release_mutex); if (!obj_desc) { return_ACPI_STATUS(AE_BAD_PARAMETER); @@ -265,7 +265,7 @@ acpi_status acpi_ex_system_signal_event(union acpi_operand_object *obj_desc) { acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE("ex_system_signal_event"); + ACPI_FUNCTION_TRACE(ex_system_signal_event); if (obj_desc) { status = acpi_os_signal_semaphore(obj_desc->event.semaphore, 1); @@ -295,7 +295,7 @@ acpi_ex_system_wait_event(union acpi_operand_object *time_desc, { acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE("ex_system_wait_event"); + ACPI_FUNCTION_TRACE(ex_system_wait_event); if (obj_desc) { status = diff --git a/drivers/acpi/executer/exutils.c b/drivers/acpi/executer/exutils.c index 8543d1a0ed31..3ef8cd703e06 100644 --- a/drivers/acpi/executer/exutils.c +++ b/drivers/acpi/executer/exutils.c @@ -87,7 +87,7 @@ acpi_status acpi_ex_enter_interpreter(void) { acpi_status status; - ACPI_FUNCTION_TRACE("ex_enter_interpreter"); + ACPI_FUNCTION_TRACE(ex_enter_interpreter); status = acpi_ut_acquire_mutex(ACPI_MTX_EXECUTE); if (ACPI_FAILURE(status)) { @@ -123,7 +123,7 @@ void acpi_ex_exit_interpreter(void) { acpi_status status; - ACPI_FUNCTION_TRACE("ex_exit_interpreter"); + ACPI_FUNCTION_TRACE(ex_exit_interpreter); status = acpi_ut_release_mutex(ACPI_MTX_EXECUTE); if (ACPI_FAILURE(status)) { @@ -189,7 +189,7 @@ u8 acpi_ex_acquire_global_lock(u32 field_flags) u8 locked = FALSE; acpi_status status; - ACPI_FUNCTION_TRACE("ex_acquire_global_lock"); + ACPI_FUNCTION_TRACE(ex_acquire_global_lock); /* Only attempt lock if the always_lock bit is set */ @@ -226,7 +226,7 @@ void acpi_ex_release_global_lock(u8 locked_by_me) { acpi_status status; - ACPI_FUNCTION_TRACE("ex_release_global_lock"); + ACPI_FUNCTION_TRACE(ex_release_global_lock); /* Only attempt unlock if the caller locked it */ @@ -266,7 +266,7 @@ static u32 acpi_ex_digits_needed(acpi_integer value, u32 base) u32 num_digits; acpi_integer current_value; - ACPI_FUNCTION_TRACE("ex_digits_needed"); + ACPI_FUNCTION_TRACE(ex_digits_needed); /* acpi_integer is unsigned, so we don't worry about a '-' prefix */ diff --git a/drivers/acpi/hardware/hwacpi.c b/drivers/acpi/hardware/hwacpi.c index ea2f13271ff1..de50fab2a910 100644 --- a/drivers/acpi/hardware/hwacpi.c +++ b/drivers/acpi/hardware/hwacpi.c @@ -63,7 +63,7 @@ acpi_status acpi_hw_initialize(void) { acpi_status status; - ACPI_FUNCTION_TRACE("hw_initialize"); + ACPI_FUNCTION_TRACE(hw_initialize); /* We must have the ACPI tables by the time we get here */ @@ -100,7 +100,7 @@ acpi_status acpi_hw_set_mode(u32 mode) acpi_status status; u32 retry; - ACPI_FUNCTION_TRACE("hw_set_mode"); + ACPI_FUNCTION_TRACE(hw_set_mode); /* * ACPI 2.0 clarified that if SMI_CMD in FADT is zero, @@ -198,7 +198,7 @@ u32 acpi_hw_get_mode(void) acpi_status status; u32 value; - ACPI_FUNCTION_TRACE("hw_get_mode"); + ACPI_FUNCTION_TRACE(hw_get_mode); /* * ACPI 2.0 clarified that if SMI_CMD in FADT is zero, diff --git a/drivers/acpi/hardware/hwgpe.c b/drivers/acpi/hardware/hwgpe.c index 729b68eb3e35..608a3a60ee11 100644 --- a/drivers/acpi/hardware/hwgpe.c +++ b/drivers/acpi/hardware/hwgpe.c @@ -370,7 +370,7 @@ acpi_status acpi_hw_disable_all_gpes(void) { acpi_status status; - ACPI_FUNCTION_TRACE("hw_disable_all_gpes"); + ACPI_FUNCTION_TRACE(hw_disable_all_gpes); status = acpi_ev_walk_gpe_list(acpi_hw_disable_gpe_block); status = acpi_ev_walk_gpe_list(acpi_hw_clear_gpe_block); @@ -393,7 +393,7 @@ acpi_status acpi_hw_enable_all_runtime_gpes(void) { acpi_status status; - ACPI_FUNCTION_TRACE("hw_enable_all_runtime_gpes"); + ACPI_FUNCTION_TRACE(hw_enable_all_runtime_gpes); status = acpi_ev_walk_gpe_list(acpi_hw_enable_runtime_gpe_block); return_ACPI_STATUS(status); @@ -415,7 +415,7 @@ acpi_status acpi_hw_enable_all_wakeup_gpes(void) { acpi_status status; - ACPI_FUNCTION_TRACE("hw_enable_all_wakeup_gpes"); + ACPI_FUNCTION_TRACE(hw_enable_all_wakeup_gpes); status = acpi_ev_walk_gpe_list(acpi_hw_enable_wakeup_gpe_block); return_ACPI_STATUS(status); diff --git a/drivers/acpi/hardware/hwregs.c b/drivers/acpi/hardware/hwregs.c index 3d1f41c6bfe9..ec9f5a11a8b3 100644 --- a/drivers/acpi/hardware/hwregs.c +++ b/drivers/acpi/hardware/hwregs.c @@ -66,7 +66,7 @@ acpi_status acpi_hw_clear_acpi_status(u32 flags) { acpi_status status; - ACPI_FUNCTION_TRACE("hw_clear_acpi_status"); + ACPI_FUNCTION_TRACE(hw_clear_acpi_status); ACPI_DEBUG_PRINT((ACPI_DB_IO, "About to write %04X to %04X\n", ACPI_BITMASK_ALL_FIXED_STATUS, @@ -130,7 +130,7 @@ acpi_get_sleep_type_data(u8 sleep_state, u8 * sleep_type_a, u8 * sleep_type_b) struct acpi_parameter_info info; char *sleep_state_name; - ACPI_FUNCTION_TRACE("acpi_get_sleep_type_data"); + ACPI_FUNCTION_TRACE(acpi_get_sleep_type_data); /* Validate parameters */ @@ -148,7 +148,7 @@ acpi_get_sleep_type_data(u8 sleep_state, u8 * sleep_type_a, u8 * sleep_type_b) status = acpi_ns_evaluate_by_name(sleep_state_name, &info); if (ACPI_FAILURE(status)) { ACPI_DEBUG_PRINT((ACPI_DB_EXEC, - "%s while evaluating sleep_state [%s]\n", + "%s while evaluating SleepState [%s]\n", acpi_format_exception(status), sleep_state_name)); @@ -208,7 +208,7 @@ acpi_get_sleep_type_data(u8 sleep_state, u8 * sleep_type_a, u8 * sleep_type_b) if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, - "While evaluating sleep_state [%s], bad Sleep object %p type %s", + "While evaluating SleepState [%s], bad Sleep object %p type %s", sleep_state_name, info.return_object, acpi_ut_get_object_type_name(info. return_object))); @@ -236,7 +236,7 @@ struct acpi_bit_register_info *acpi_hw_get_bit_register_info(u32 register_id) ACPI_FUNCTION_ENTRY(); if (register_id > ACPI_BITREG_MAX) { - ACPI_ERROR((AE_INFO, "Invalid bit_register ID: %X", + ACPI_ERROR((AE_INFO, "Invalid BitRegister ID: %X", register_id)); return (NULL); } @@ -265,7 +265,7 @@ acpi_status acpi_get_register(u32 register_id, u32 * return_value, u32 flags) struct acpi_bit_register_info *bit_reg_info; acpi_status status; - ACPI_FUNCTION_TRACE("acpi_get_register"); + ACPI_FUNCTION_TRACE(acpi_get_register); /* Get the info structure corresponding to the requested ACPI Register */ @@ -331,13 +331,13 @@ acpi_status acpi_set_register(u32 register_id, u32 value, u32 flags) struct acpi_bit_register_info *bit_reg_info; acpi_status status; - ACPI_FUNCTION_TRACE_U32("acpi_set_register", register_id); + ACPI_FUNCTION_TRACE_U32(acpi_set_register, register_id); /* Get the info structure corresponding to the requested ACPI Register */ bit_reg_info = acpi_hw_get_bit_register_info(register_id); if (!bit_reg_info) { - ACPI_ERROR((AE_INFO, "Bad ACPI HW register_id: %X", + ACPI_ERROR((AE_INFO, "Bad ACPI HW RegisterId: %X", register_id)); return_ACPI_STATUS(AE_BAD_PARAMETER); } @@ -494,7 +494,7 @@ acpi_hw_register_read(u8 use_lock, u32 register_id, u32 * return_value) u32 value2 = 0; acpi_status status; - ACPI_FUNCTION_TRACE("hw_register_read"); + ACPI_FUNCTION_TRACE(hw_register_read); if (ACPI_MTX_LOCK == use_lock) { status = acpi_ut_acquire_mutex(ACPI_MTX_HARDWARE); @@ -607,7 +607,7 @@ acpi_status acpi_hw_register_write(u8 use_lock, u32 register_id, u32 value) { acpi_status status; - ACPI_FUNCTION_TRACE("hw_register_write"); + ACPI_FUNCTION_TRACE(hw_register_write); if (ACPI_MTX_LOCK == use_lock) { status = acpi_ut_acquire_mutex(ACPI_MTX_HARDWARE); @@ -729,7 +729,7 @@ acpi_hw_low_level_read(u32 width, u32 * value, struct acpi_generic_address *reg) u64 address; acpi_status status; - ACPI_FUNCTION_NAME("hw_low_level_read"); + ACPI_FUNCTION_NAME(hw_low_level_read); /* * Must have a valid pointer to a GAS structure, and @@ -801,7 +801,7 @@ acpi_hw_low_level_write(u32 width, u32 value, struct acpi_generic_address * reg) u64 address; acpi_status status; - ACPI_FUNCTION_NAME("hw_low_level_write"); + ACPI_FUNCTION_NAME(hw_low_level_write); /* * Must have a valid pointer to a GAS structure, and diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c index 685debafbb72..8bb43cae60c2 100644 --- a/drivers/acpi/hardware/hwsleep.c +++ b/drivers/acpi/hardware/hwsleep.c @@ -63,7 +63,7 @@ acpi_status acpi_set_firmware_waking_vector(acpi_physical_address physical_address) { - ACPI_FUNCTION_TRACE("acpi_set_firmware_waking_vector"); + ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector); /* Set the vector */ @@ -98,7 +98,7 @@ acpi_status acpi_get_firmware_waking_vector(acpi_physical_address * physical_address) { - ACPI_FUNCTION_TRACE("acpi_get_firmware_waking_vector"); + ACPI_FUNCTION_TRACE(acpi_get_firmware_waking_vector); if (!physical_address) { return_ACPI_STATUS(AE_BAD_PARAMETER); @@ -142,7 +142,7 @@ acpi_status acpi_enter_sleep_state_prep(u8 sleep_state) struct acpi_object_list arg_list; union acpi_object arg; - ACPI_FUNCTION_TRACE("acpi_enter_sleep_state_prep"); + ACPI_FUNCTION_TRACE(acpi_enter_sleep_state_prep); /* * _PSW methods could be run here to enable wake-on keyboard, LAN, etc. @@ -230,7 +230,7 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state) u32 in_value; acpi_status status; - ACPI_FUNCTION_TRACE("acpi_enter_sleep_state"); + ACPI_FUNCTION_TRACE(acpi_enter_sleep_state); if ((acpi_gbl_sleep_type_a > ACPI_SLEEP_TYPE_MAX) || (acpi_gbl_sleep_type_b > ACPI_SLEEP_TYPE_MAX)) { @@ -399,7 +399,7 @@ acpi_status asmlinkage acpi_enter_sleep_state_s4bios(void) u32 in_value; acpi_status status; - ACPI_FUNCTION_TRACE("acpi_enter_sleep_state_s4bios"); + ACPI_FUNCTION_TRACE(acpi_enter_sleep_state_s4bios); status = acpi_set_register(ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_DO_NOT_LOCK); @@ -468,7 +468,7 @@ acpi_status acpi_leave_sleep_state(u8 sleep_state) u32 PM1Acontrol; u32 PM1Bcontrol; - ACPI_FUNCTION_TRACE("acpi_leave_sleep_state"); + ACPI_FUNCTION_TRACE(acpi_leave_sleep_state); /* * Set SLP_TYPE and SLP_EN to state S0. diff --git a/drivers/acpi/hardware/hwtimer.c b/drivers/acpi/hardware/hwtimer.c index a559ac17b132..c4ec47c939fd 100644 --- a/drivers/acpi/hardware/hwtimer.c +++ b/drivers/acpi/hardware/hwtimer.c @@ -60,7 +60,7 @@ ACPI_MODULE_NAME("hwtimer") ******************************************************************************/ acpi_status acpi_get_timer_resolution(u32 * resolution) { - ACPI_FUNCTION_TRACE("acpi_get_timer_resolution"); + ACPI_FUNCTION_TRACE(acpi_get_timer_resolution); if (!resolution) { return_ACPI_STATUS(AE_BAD_PARAMETER); @@ -92,7 +92,7 @@ acpi_status acpi_get_timer(u32 * ticks) { acpi_status status; - ACPI_FUNCTION_TRACE("acpi_get_timer"); + ACPI_FUNCTION_TRACE(acpi_get_timer); if (!ticks) { return_ACPI_STATUS(AE_BAD_PARAMETER); @@ -140,7 +140,7 @@ acpi_get_timer_duration(u32 start_ticks, u32 end_ticks, u32 * time_elapsed) u32 delta_ticks; acpi_integer quotient; - ACPI_FUNCTION_TRACE("acpi_get_timer_duration"); + ACPI_FUNCTION_TRACE(acpi_get_timer_duration); if (!time_elapsed) { return_ACPI_STATUS(AE_BAD_PARAMETER); diff --git a/drivers/acpi/namespace/nsaccess.c b/drivers/acpi/namespace/nsaccess.c index d4914fda6a37..5e3f63a90fb4 100644 --- a/drivers/acpi/namespace/nsaccess.c +++ b/drivers/acpi/namespace/nsaccess.c @@ -70,7 +70,7 @@ acpi_status acpi_ns_root_initialize(void) union acpi_operand_object *obj_desc; acpi_string val = NULL; - ACPI_FUNCTION_TRACE("ns_root_initialize"); + ACPI_FUNCTION_TRACE(ns_root_initialize); status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { @@ -314,7 +314,7 @@ acpi_ns_lookup(union acpi_generic_state *scope_info, u32 local_flags = flags & ~(ACPI_NS_ERROR_IF_FOUND | ACPI_NS_SEARCH_PARENT); - ACPI_FUNCTION_TRACE("ns_lookup"); + ACPI_FUNCTION_TRACE(ns_lookup); if (!return_node) { return_ACPI_STATUS(AE_BAD_PARAMETER); @@ -615,7 +615,7 @@ acpi_ns_lookup(union acpi_generic_state *scope_info, /* Complain about a type mismatch */ ACPI_WARNING((AE_INFO, - "ns_lookup: Type mismatch on %4.4s (%s), searching for (%s)", + "NsLookup: Type mismatch on %4.4s (%s), searching for (%s)", ACPI_CAST_PTR(char, &simple_name), acpi_ut_get_type_name(this_node->type), acpi_ut_get_type_name diff --git a/drivers/acpi/namespace/nsalloc.c b/drivers/acpi/namespace/nsalloc.c index c92c03693a16..dc3f0739a46b 100644 --- a/drivers/acpi/namespace/nsalloc.c +++ b/drivers/acpi/namespace/nsalloc.c @@ -62,7 +62,7 @@ struct acpi_namespace_node *acpi_ns_create_node(u32 name) { struct acpi_namespace_node *node; - ACPI_FUNCTION_TRACE("ns_create_node"); + ACPI_FUNCTION_TRACE(ns_create_node); node = acpi_os_acquire_object(acpi_gbl_namespace_cache); if (!node) { @@ -94,7 +94,7 @@ void acpi_ns_delete_node(struct acpi_namespace_node *node) struct acpi_namespace_node *prev_node; struct acpi_namespace_node *next_node; - ACPI_FUNCTION_TRACE_PTR("ns_delete_node", node); + ACPI_FUNCTION_TRACE_PTR(ns_delete_node, node); parent_node = acpi_ns_get_parent_node(node); @@ -167,7 +167,7 @@ void acpi_ns_install_node(struct acpi_walk_state *walk_state, struct acpi_namesp acpi_owner_id owner_id = 0; struct acpi_namespace_node *child_node; - ACPI_FUNCTION_TRACE("ns_install_node"); + ACPI_FUNCTION_TRACE(ns_install_node); /* * Get the owner ID from the Walk state @@ -234,7 +234,7 @@ void acpi_ns_delete_children(struct acpi_namespace_node *parent_node) struct acpi_namespace_node *next_node; u8 flags; - ACPI_FUNCTION_TRACE_PTR("ns_delete_children", parent_node); + ACPI_FUNCTION_TRACE_PTR(ns_delete_children, parent_node); if (!parent_node) { return_VOID; @@ -313,7 +313,7 @@ void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node) struct acpi_namespace_node *child_node = NULL; u32 level = 1; - ACPI_FUNCTION_TRACE("ns_delete_namespace_subtree"); + ACPI_FUNCTION_TRACE(ns_delete_namespace_subtree); if (!parent_node) { return_VOID; @@ -395,7 +395,7 @@ void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id) u32 level; struct acpi_namespace_node *parent_node; - ACPI_FUNCTION_TRACE_U32("ns_delete_namespace_by_owner", owner_id); + ACPI_FUNCTION_TRACE_U32(ns_delete_namespace_by_owner, owner_id); if (owner_id == 0) { return_VOID; diff --git a/drivers/acpi/namespace/nsdump.c b/drivers/acpi/namespace/nsdump.c index 5662d2def62f..d72df66aa965 100644 --- a/drivers/acpi/namespace/nsdump.c +++ b/drivers/acpi/namespace/nsdump.c @@ -75,7 +75,7 @@ void acpi_ns_print_pathname(u32 num_segments, char *pathname) { acpi_native_uint i; - ACPI_FUNCTION_NAME("ns_print_pathname"); + ACPI_FUNCTION_NAME(ns_print_pathname); if (!(acpi_dbg_level & ACPI_LV_NAMES) || !(acpi_dbg_layer & ACPI_NAMESPACE)) { @@ -123,7 +123,7 @@ void acpi_ns_dump_pathname(acpi_handle handle, char *msg, u32 level, u32 component) { - ACPI_FUNCTION_TRACE("ns_dump_pathname"); + ACPI_FUNCTION_TRACE(ns_dump_pathname); /* Do this only if the requested debug level and component are enabled */ @@ -167,7 +167,7 @@ acpi_ns_dump_one_object(acpi_handle obj_handle, u32 dbg_level; u32 i; - ACPI_FUNCTION_NAME("ns_dump_one_object"); + ACPI_FUNCTION_NAME(ns_dump_one_object); /* Is output enabled? */ @@ -675,7 +675,7 @@ void acpi_ns_dump_tables(acpi_handle search_base, u32 max_depth) { acpi_handle search_handle = search_base; - ACPI_FUNCTION_TRACE("ns_dump_tables"); + ACPI_FUNCTION_TRACE(ns_dump_tables); if (!acpi_gbl_root_node) { /* diff --git a/drivers/acpi/namespace/nsdumpdv.c b/drivers/acpi/namespace/nsdumpdv.c index 2b311da01ef5..c6bf5d30fca3 100644 --- a/drivers/acpi/namespace/nsdumpdv.c +++ b/drivers/acpi/namespace/nsdumpdv.c @@ -74,7 +74,7 @@ acpi_ns_dump_one_device(acpi_handle obj_handle, acpi_status status; u32 i; - ACPI_FUNCTION_NAME("ns_dump_one_device"); + ACPI_FUNCTION_NAME(ns_dump_one_device); status = acpi_ns_dump_one_object(obj_handle, level, context, return_value); @@ -115,7 +115,7 @@ void acpi_ns_dump_root_devices(void) acpi_handle sys_bus_handle; acpi_status status; - ACPI_FUNCTION_NAME("ns_dump_root_devices"); + ACPI_FUNCTION_NAME(ns_dump_root_devices); /* Only dump the table if tracing is enabled */ diff --git a/drivers/acpi/namespace/nseval.c b/drivers/acpi/namespace/nseval.c index f5d8e71b82cc..4b054062b46a 100644 --- a/drivers/acpi/namespace/nseval.c +++ b/drivers/acpi/namespace/nseval.c @@ -85,7 +85,7 @@ acpi_ns_evaluate_relative(char *pathname, struct acpi_parameter_info *info) union acpi_generic_state *scope_info; char *internal_path = NULL; - ACPI_FUNCTION_TRACE("ns_evaluate_relative"); + ACPI_FUNCTION_TRACE(ns_evaluate_relative); /* * Must have a valid object handle @@ -182,7 +182,7 @@ acpi_ns_evaluate_by_name(char *pathname, struct acpi_parameter_info *info) acpi_status status; char *internal_path = NULL; - ACPI_FUNCTION_TRACE("ns_evaluate_by_name"); + ACPI_FUNCTION_TRACE(ns_evaluate_by_name); /* Build an internal name string for the method */ @@ -262,7 +262,7 @@ acpi_status acpi_ns_evaluate_by_handle(struct acpi_parameter_info *info) { acpi_status status; - ACPI_FUNCTION_TRACE("ns_evaluate_by_handle"); + ACPI_FUNCTION_TRACE(ns_evaluate_by_handle); /* Check if namespace has been initialized */ @@ -368,7 +368,7 @@ acpi_ns_execute_control_method(struct acpi_parameter_info *info) { acpi_status status; - ACPI_FUNCTION_TRACE("ns_execute_control_method"); + ACPI_FUNCTION_TRACE(ns_execute_control_method); /* Verify that there is a method associated with this object */ @@ -436,7 +436,7 @@ static acpi_status acpi_ns_get_object_value(struct acpi_parameter_info *info) acpi_status status = AE_OK; struct acpi_namespace_node *resolved_node = info->node; - ACPI_FUNCTION_TRACE("ns_get_object_value"); + ACPI_FUNCTION_TRACE(ns_get_object_value); /* * Objects require additional resolution steps (e.g., the Node may be a diff --git a/drivers/acpi/namespace/nsinit.c b/drivers/acpi/namespace/nsinit.c index 57b2537643c7..bf1d8dbc0b86 100644 --- a/drivers/acpi/namespace/nsinit.c +++ b/drivers/acpi/namespace/nsinit.c @@ -58,6 +58,10 @@ static acpi_status acpi_ns_init_one_device(acpi_handle obj_handle, u32 nesting_level, void *context, void **return_value); +static acpi_status +acpi_ns_find_ini_methods(acpi_handle obj_handle, + u32 nesting_level, void *context, void **return_value); + /******************************************************************************* * * FUNCTION: acpi_ns_initialize_objects @@ -76,7 +80,7 @@ acpi_status acpi_ns_initialize_objects(void) acpi_status status; struct acpi_init_walk_info info; - ACPI_FUNCTION_TRACE("ns_initialize_objects"); + ACPI_FUNCTION_TRACE(ns_initialize_objects); ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "**** Starting initialization of namespace objects ****\n")); @@ -93,7 +97,7 @@ acpi_status acpi_ns_initialize_objects(void) ACPI_UINT32_MAX, acpi_ns_init_one_object, &info, NULL); if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "During walk_namespace")); + ACPI_EXCEPTION((AE_INFO, status, "During WalkNamespace")); } ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, @@ -133,7 +137,7 @@ acpi_status acpi_ns_initialize_devices(void) acpi_status status; struct acpi_device_walk_info info; - ACPI_FUNCTION_TRACE("ns_initialize_devices"); + ACPI_FUNCTION_TRACE(ns_initialize_devices); /* Init counters */ @@ -142,28 +146,29 @@ acpi_status acpi_ns_initialize_devices(void) info.num_INI = 0; ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, - "Executing all Device _STA and_INI methods:")); + "Initializing Device/Processor/Thermal objects by executing _INI methods:")); + + /* Tree analysis: find all subtrees that contain _INI methods */ - status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); + status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, FALSE, + acpi_ns_find_ini_methods, &info, NULL); if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); + ACPI_EXCEPTION((AE_INFO, status, "During WalkNamespace")); } - /* Walk namespace for all objects */ + /* Walk namespace to execute all _INIs on present devices */ status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, TRUE, + ACPI_UINT32_MAX, FALSE, acpi_ns_init_one_device, &info, NULL); - - (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "During walk_namespace")); + ACPI_EXCEPTION((AE_INFO, status, "During WalkNamespace")); } ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, - "\n%hd Devices found - executed %hd _STA, %hd _INI methods\n", - info.device_count, info.num_STA, info.num_INI)); + "\nExecuted %hd _INI methods requiring %hd _STA executions (examined %hd objects)\n", + info.num_INI, info.num_STA, info.device_count)); return_ACPI_STATUS(status); } @@ -200,7 +205,7 @@ acpi_ns_init_one_object(acpi_handle obj_handle, (struct acpi_namespace_node *)obj_handle; union acpi_operand_object *obj_desc; - ACPI_FUNCTION_NAME("ns_init_one_object"); + ACPI_FUNCTION_NAME(ns_init_one_object); info->object_count++; @@ -309,6 +314,72 @@ acpi_ns_init_one_object(acpi_handle obj_handle, return (AE_OK); } +/******************************************************************************* + * + * FUNCTION: acpi_ns_find_ini_methods + * + * PARAMETERS: acpi_walk_callback + * + * RETURN: acpi_status + * + * DESCRIPTION: Called during namespace walk. Finds objects named _INI under + * device/processor/thermal objects, and marks the entire subtree + * with a SUBTREE_HAS_INI flag. This flag is used during the + * subsequent device initialization walk to avoid entire subtrees + * that do not contain an _INI. + * + ******************************************************************************/ + +static acpi_status +acpi_ns_find_ini_methods(acpi_handle obj_handle, + u32 nesting_level, void *context, void **return_value) +{ + struct acpi_device_walk_info *info = + ACPI_CAST_PTR(struct acpi_device_walk_info, context); + struct acpi_namespace_node *node; + struct acpi_namespace_node *parent_node; + + /* Keep count of device/processor/thermal objects */ + + node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_handle); + if ((node->type == ACPI_TYPE_DEVICE) || + (node->type == ACPI_TYPE_PROCESSOR) || + (node->type == ACPI_TYPE_THERMAL)) { + info->device_count++; + return (AE_OK); + } + + /* We are only looking for methods named _INI */ + + if (!ACPI_COMPARE_NAME(node->name.ascii, METHOD_NAME__INI)) { + return (AE_OK); + } + + /* + * The only _INI methods that we care about are those that are + * present under Device, Processor, and Thermal objects. + */ + parent_node = acpi_ns_get_parent_node(node); + switch (parent_node->type) { + case ACPI_TYPE_DEVICE: + case ACPI_TYPE_PROCESSOR: + case ACPI_TYPE_THERMAL: + + /* Mark parent and bubble up the INI present flag to the root */ + + while (parent_node) { + parent_node->flags |= ANOBJ_SUBTREE_HAS_INI; + parent_node = acpi_ns_get_parent_node(parent_node); + } + break; + + default: + break; + } + + return (AE_OK); +} + /******************************************************************************* * * FUNCTION: acpi_ns_init_one_device @@ -328,64 +399,49 @@ acpi_ns_init_one_device(acpi_handle obj_handle, u32 nesting_level, void *context, void **return_value) { struct acpi_device_walk_info *info = - (struct acpi_device_walk_info *)context; + ACPI_CAST_PTR(struct acpi_device_walk_info, context); struct acpi_parameter_info pinfo; u32 flags; acpi_status status; - struct acpi_namespace_node *ini_node; struct acpi_namespace_node *device_node; - ACPI_FUNCTION_TRACE("ns_init_one_device"); + ACPI_FUNCTION_TRACE(ns_init_one_device); - device_node = acpi_ns_map_handle_to_node(obj_handle); - if (!device_node) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } + /* We are interested in Devices, Processors and thermal_zones only */ - /* - * We will run _STA/_INI on Devices, Processors and thermal_zones only - */ + device_node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_handle); if ((device_node->type != ACPI_TYPE_DEVICE) && (device_node->type != ACPI_TYPE_PROCESSOR) && (device_node->type != ACPI_TYPE_THERMAL)) { return_ACPI_STATUS(AE_OK); } - if ((acpi_dbg_level <= ACPI_LV_ALL_EXCEPTIONS) && - (!(acpi_dbg_level & ACPI_LV_INFO))) { - ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, ".")); - } - - info->device_count++; - /* - * Check if the _INI method exists for this device - - * if _INI does not exist, there is no need to run _STA - * No _INI means device requires no initialization + * Because of an earlier namespace analysis, all subtrees that contain an + * _INI method are tagged. + * + * If this device subtree does not contain any _INI methods, we + * can exit now and stop traversing this entire subtree. */ - status = acpi_ns_search_node(*ACPI_CAST_PTR(u32, METHOD_NAME__INI), - device_node, ACPI_TYPE_METHOD, &ini_node); - if (ACPI_FAILURE(status)) { - - /* No _INI method found - move on to next device */ - - return_ACPI_STATUS(AE_OK); + if (!(device_node->flags & ANOBJ_SUBTREE_HAS_INI)) { + return_ACPI_STATUS(AE_CTRL_DEPTH); } /* - * Run _STA to determine if we can run _INI on the device - - * the device must be present before _INI can be run. - * However, _STA is not required - assume device present if no _STA + * Run _STA to determine if this device is present and functioning. We + * must know this information for two important reasons (from ACPI spec): + * + * 1) We can only run _INI if the device is present. + * 2) We must abort the device tree walk on this subtree if the device is + * not present and is not functional (we will not examine the children) + * + * The _STA method is not required to be present under the device, we + * assume the device is present if _STA does not exist. */ - ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname(ACPI_TYPE_METHOD, - device_node, - METHOD_NAME__STA)); + ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname + (ACPI_TYPE_METHOD, device_node, METHOD_NAME__STA)); - pinfo.node = device_node; - pinfo.parameters = NULL; - pinfo.parameter_type = ACPI_PARAM_ARGS; - - status = acpi_ut_execute_STA(pinfo.node, &flags); + status = acpi_ut_execute_STA(device_node, &flags); if (ACPI_FAILURE(status)) { /* Ignore error and move on to next device */ @@ -393,55 +449,108 @@ acpi_ns_init_one_device(acpi_handle obj_handle, return_ACPI_STATUS(AE_OK); } + /* + * Flags == -1 means that _STA was not found. In this case, we assume that + * the device is both present and functional. + * + * From the ACPI spec, description of _STA: + * + * "If a device object (including the processor object) does not have an + * _STA object, then OSPM assumes that all of the above bits are set (in + * other words, the device is present, ..., and functioning)" + */ if (flags != ACPI_UINT32_MAX) { info->num_STA++; } + /* + * Examine the PRESENT and FUNCTIONING status bits + * + * Note: ACPI spec does not seem to specify behavior for the present but + * not functioning case, so we assume functioning if present. + */ if (!(flags & ACPI_STA_DEVICE_PRESENT)) { - /* Don't look at children of a not present device */ - - return_ACPI_STATUS(AE_CTRL_DEPTH); + /* Device is not present, we must examine the Functioning bit */ + + if (flags & ACPI_STA_DEVICE_FUNCTIONING) { + /* + * Device is not present but is "functioning". In this case, + * we will not run _INI, but we continue to examine the children + * of this device. + * + * From the ACPI spec, description of _STA: (Note - no mention + * of whether to run _INI or not on the device in question) + * + * "_STA may return bit 0 clear (not present) with bit 3 set + * (device is functional). This case is used to indicate a valid + * device for which no device driver should be loaded (for example, + * a bridge device.) Children of this device may be present and + * valid. OSPM should continue enumeration below a device whose + * _STA returns this bit combination" + */ + return_ACPI_STATUS(AE_OK); + } else { + /* + * Device is not present and is not functioning. We must abort the + * walk of this subtree immediately -- don't look at the children + * of such a device. + * + * From the ACPI spec, description of _INI: + * + * "If the _STA method indicates that the device is not present, + * OSPM will not run the _INI and will not examine the children + * of the device for _INI methods" + */ + return_ACPI_STATUS(AE_CTRL_DEPTH); + } } /* - * The device is present and _INI exists. Run the _INI method. - * (We already have the _INI node from above) + * The device is present or is assumed present if no _STA exists. + * Run the _INI if it exists (not required to exist) + * + * Note: We know there is an _INI within this subtree, but it may not be + * under this particular device, it may be lower in the branch. */ - ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname(ACPI_TYPE_METHOD, - pinfo.node, - METHOD_NAME__INI)); + ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname + (ACPI_TYPE_METHOD, device_node, METHOD_NAME__INI)); - pinfo.node = ini_node; - status = acpi_ns_evaluate_by_handle(&pinfo); - if (ACPI_FAILURE(status)) { - - /* Ignore error and move on to next device */ - -#ifdef ACPI_DEBUG_OUTPUT - char *scope_name = acpi_ns_get_external_pathname(ini_node); + pinfo.node = device_node; + pinfo.parameters = NULL; + pinfo.parameter_type = ACPI_PARAM_ARGS; - ACPI_WARNING((AE_INFO, "%s._INI failed: %s", - scope_name, acpi_format_exception(status))); + status = acpi_ns_evaluate_relative(METHOD_NAME__INI, &pinfo); + if (ACPI_SUCCESS(status)) { - ACPI_FREE(scope_name); -#endif - } else { /* Delete any return object (especially if implicit_return is enabled) */ if (pinfo.return_object) { acpi_ut_remove_reference(pinfo.return_object); } - /* Count of successful INIs */ - info->num_INI++; + if ((acpi_dbg_level <= ACPI_LV_ALL_EXCEPTIONS) && + (!(acpi_dbg_level & ACPI_LV_INFO))) { + ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, ".")); + } } +#ifdef ACPI_DEBUG_OUTPUT + else if (status != AE_NOT_FOUND) { - if (acpi_gbl_init_handler) { + /* Ignore error and move on to next device */ + + char *scope_name = acpi_ns_get_external_pathname(pinfo.node); - /* External initialization handler is present, call it */ + ACPI_EXCEPTION((AE_INFO, status, "during %s._INI execution", + scope_name)); + ACPI_FREE(scope_name); + } +#endif + /* If an external initialization handler is present, call it */ + + if (acpi_gbl_init_handler) { status = acpi_gbl_init_handler(pinfo.node, ACPI_INIT_DEVICE_INI); } diff --git a/drivers/acpi/namespace/nsload.c b/drivers/acpi/namespace/nsload.c index 80acfd35f3ec..fe75d888e183 100644 --- a/drivers/acpi/namespace/nsload.c +++ b/drivers/acpi/namespace/nsload.c @@ -77,7 +77,7 @@ acpi_ns_load_table(struct acpi_table_desc *table_desc, { acpi_status status; - ACPI_FUNCTION_TRACE("ns_load_table"); + ACPI_FUNCTION_TRACE(ns_load_table); /* Check if table contains valid AML (must be DSDT, PSDT, SSDT, etc.) */ @@ -169,7 +169,7 @@ static acpi_status acpi_ns_load_table_by_type(acpi_table_type table_type) acpi_status status; struct acpi_table_desc *table_desc; - ACPI_FUNCTION_TRACE("ns_load_table_by_type"); + ACPI_FUNCTION_TRACE(ns_load_table_by_type); status = acpi_ut_acquire_mutex(ACPI_MTX_TABLES); if (ACPI_FAILURE(status)) { @@ -181,11 +181,11 @@ static acpi_status acpi_ns_load_table_by_type(acpi_table_type table_type) * DSDT (one), SSDT/PSDT (multiple) */ switch (table_type) { - case ACPI_TABLE_DSDT: + case ACPI_TABLE_ID_DSDT: ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Namespace load: DSDT\n")); - table_desc = acpi_gbl_table_lists[ACPI_TABLE_DSDT].next; + table_desc = acpi_gbl_table_lists[ACPI_TABLE_ID_DSDT].next; /* If table already loaded into namespace, just return */ @@ -201,8 +201,8 @@ static acpi_status acpi_ns_load_table_by_type(acpi_table_type table_type) } break; - case ACPI_TABLE_SSDT: - case ACPI_TABLE_PSDT: + case ACPI_TABLE_ID_SSDT: + case ACPI_TABLE_ID_PSDT: ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Namespace load: %d SSDT or PSDTs\n", @@ -259,7 +259,7 @@ acpi_status acpi_ns_load_namespace(void) { acpi_status status; - ACPI_FUNCTION_TRACE("acpi_load_name_space"); + ACPI_FUNCTION_TRACE(acpi_load_name_space); /* There must be at least a DSDT installed */ @@ -272,15 +272,15 @@ acpi_status acpi_ns_load_namespace(void) * Load the namespace. The DSDT is required, * but the SSDT and PSDT tables are optional. */ - status = acpi_ns_load_table_by_type(ACPI_TABLE_DSDT); + status = acpi_ns_load_table_by_type(ACPI_TABLE_ID_DSDT); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } /* Ignore exceptions from these */ - (void)acpi_ns_load_table_by_type(ACPI_TABLE_SSDT); - (void)acpi_ns_load_table_by_type(ACPI_TABLE_PSDT); + (void)acpi_ns_load_table_by_type(ACPI_TABLE_ID_SSDT); + (void)acpi_ns_load_table_by_type(ACPI_TABLE_ID_PSDT); ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, "ACPI Namespace successfully loaded at root %p\n", @@ -315,7 +315,7 @@ static acpi_status acpi_ns_delete_subtree(acpi_handle start_handle) acpi_handle dummy; u32 level; - ACPI_FUNCTION_TRACE("ns_delete_subtree"); + ACPI_FUNCTION_TRACE(ns_delete_subtree); parent_handle = start_handle; child_handle = NULL; @@ -395,7 +395,7 @@ acpi_status acpi_ns_unload_namespace(acpi_handle handle) { acpi_status status; - ACPI_FUNCTION_TRACE("ns_unload_name_space"); + ACPI_FUNCTION_TRACE(ns_unload_name_space); /* Parameter validation */ diff --git a/drivers/acpi/namespace/nsnames.c b/drivers/acpi/namespace/nsnames.c index ba812f43897f..97b8332c9746 100644 --- a/drivers/acpi/namespace/nsnames.c +++ b/drivers/acpi/namespace/nsnames.c @@ -132,7 +132,7 @@ char *acpi_ns_get_external_pathname(struct acpi_namespace_node *node) char *name_buffer; acpi_size size; - ACPI_FUNCTION_TRACE_PTR("ns_get_external_pathname", node); + ACPI_FUNCTION_TRACE_PTR(ns_get_external_pathname, node); /* Calculate required buffer size based on depth below root */ @@ -213,7 +213,7 @@ acpi_ns_handle_to_pathname(acpi_handle target_handle, struct acpi_namespace_node *node; acpi_size required_size; - ACPI_FUNCTION_TRACE_PTR("ns_handle_to_pathname", target_handle); + ACPI_FUNCTION_TRACE_PTR(ns_handle_to_pathname, target_handle); node = acpi_ns_map_handle_to_node(target_handle); if (!node) { diff --git a/drivers/acpi/namespace/nsobject.c b/drivers/acpi/namespace/nsobject.c index 39dc87b228fc..aabe8794b908 100644 --- a/drivers/acpi/namespace/nsobject.c +++ b/drivers/acpi/namespace/nsobject.c @@ -76,7 +76,7 @@ acpi_ns_attach_object(struct acpi_namespace_node *node, union acpi_operand_object *last_obj_desc; acpi_object_type object_type = ACPI_TYPE_ANY; - ACPI_FUNCTION_TRACE("ns_attach_object"); + ACPI_FUNCTION_TRACE(ns_attach_object); /* * Parameter validation @@ -85,7 +85,7 @@ acpi_ns_attach_object(struct acpi_namespace_node *node, /* Invalid handle */ - ACPI_ERROR((AE_INFO, "Null named_obj handle")); + ACPI_ERROR((AE_INFO, "Null NamedObj handle")); return_ACPI_STATUS(AE_BAD_PARAMETER); } @@ -111,7 +111,7 @@ acpi_ns_attach_object(struct acpi_namespace_node *node, if (node->object == object) { ACPI_DEBUG_PRINT((ACPI_DB_EXEC, - "Obj %p already installed in name_obj %p\n", + "Obj %p already installed in NameObj %p\n", object, node)); return_ACPI_STATUS(AE_OK); @@ -204,7 +204,7 @@ void acpi_ns_detach_object(struct acpi_namespace_node *node) { union acpi_operand_object *obj_desc; - ACPI_FUNCTION_TRACE("ns_detach_object"); + ACPI_FUNCTION_TRACE(ns_detach_object); obj_desc = node->object; @@ -255,7 +255,7 @@ union acpi_operand_object *acpi_ns_get_attached_object(struct acpi_namespace_node *node) { - ACPI_FUNCTION_TRACE_PTR("ns_get_attached_object", node); + ACPI_FUNCTION_TRACE_PTR(ns_get_attached_object, node); if (!node) { ACPI_WARNING((AE_INFO, "Null Node ptr")); @@ -290,7 +290,7 @@ union acpi_operand_object *acpi_ns_get_secondary_object(union acpi_operand_object *obj_desc) { - ACPI_FUNCTION_TRACE_PTR("ns_get_secondary_object", obj_desc); + ACPI_FUNCTION_TRACE_PTR(ns_get_secondary_object, obj_desc); if ((!obj_desc) || (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_LOCAL_DATA) || diff --git a/drivers/acpi/namespace/nsparse.c b/drivers/acpi/namespace/nsparse.c index 64daf3028dea..155505a4ef69 100644 --- a/drivers/acpi/namespace/nsparse.c +++ b/drivers/acpi/namespace/nsparse.c @@ -68,7 +68,7 @@ acpi_ns_one_complete_parse(u8 pass_number, struct acpi_table_desc *table_desc) acpi_status status; struct acpi_walk_state *walk_state; - ACPI_FUNCTION_TRACE("ns_one_complete_parse"); + ACPI_FUNCTION_TRACE(ns_one_complete_parse); /* Create and init a Root Node */ @@ -124,7 +124,7 @@ acpi_ns_parse_table(struct acpi_table_desc *table_desc, { acpi_status status; - ACPI_FUNCTION_TRACE("ns_parse_table"); + ACPI_FUNCTION_TRACE(ns_parse_table); /* * AML Parse, pass 1 diff --git a/drivers/acpi/namespace/nssearch.c b/drivers/acpi/namespace/nssearch.c index 51adec5a23d6..34ac512a2d5e 100644 --- a/drivers/acpi/namespace/nssearch.c +++ b/drivers/acpi/namespace/nssearch.c @@ -89,7 +89,7 @@ acpi_ns_search_node(u32 target_name, { struct acpi_namespace_node *next_node; - ACPI_FUNCTION_TRACE("ns_search_node"); + ACPI_FUNCTION_TRACE(ns_search_node); #ifdef ACPI_DEBUG_OUTPUT if (ACPI_LV_NAMES & acpi_dbg_level) { @@ -203,7 +203,7 @@ acpi_ns_search_parent_tree(u32 target_name, acpi_status status; struct acpi_namespace_node *parent_node; - ACPI_FUNCTION_TRACE("ns_search_parent_tree"); + ACPI_FUNCTION_TRACE(ns_search_parent_tree); parent_node = acpi_ns_get_parent_node(node); @@ -293,13 +293,13 @@ acpi_ns_search_and_enter(u32 target_name, acpi_status status; struct acpi_namespace_node *new_node; - ACPI_FUNCTION_TRACE("ns_search_and_enter"); + ACPI_FUNCTION_TRACE(ns_search_and_enter); /* Parameter validation */ if (!node || !target_name || !return_node) { ACPI_ERROR((AE_INFO, - "Null param: Node %p Name %X return_node %p", + "Null param: Node %p Name %X ReturnNode %p", node, target_name, return_node)); return_ACPI_STATUS(AE_BAD_PARAMETER); } diff --git a/drivers/acpi/namespace/nsutils.c b/drivers/acpi/namespace/nsutils.c index 9fa38ffc2e6e..d1d55032b455 100644 --- a/drivers/acpi/namespace/nsutils.c +++ b/drivers/acpi/namespace/nsutils.c @@ -241,7 +241,7 @@ static u8 acpi_ns_valid_path_separator(char sep) acpi_object_type acpi_ns_get_type(struct acpi_namespace_node * node) { - ACPI_FUNCTION_TRACE("ns_get_type"); + ACPI_FUNCTION_TRACE(ns_get_type); if (!node) { ACPI_WARNING((AE_INFO, "Null Node parameter")); @@ -266,7 +266,7 @@ acpi_object_type acpi_ns_get_type(struct acpi_namespace_node * node) u32 acpi_ns_local(acpi_object_type type) { - ACPI_FUNCTION_TRACE("ns_local"); + ACPI_FUNCTION_TRACE(ns_local); if (!acpi_ut_valid_object_type(type)) { @@ -366,7 +366,7 @@ acpi_status acpi_ns_build_internal_name(struct acpi_namestring_info *info) char *result = NULL; acpi_native_uint i; - ACPI_FUNCTION_TRACE("ns_build_internal_name"); + ACPI_FUNCTION_TRACE(ns_build_internal_name); /* Setup the correct prefixes, counts, and pointers */ @@ -477,7 +477,7 @@ acpi_status acpi_ns_internalize_name(char *external_name, char **converted_name) struct acpi_namestring_info info; acpi_status status; - ACPI_FUNCTION_TRACE("ns_internalize_name"); + ACPI_FUNCTION_TRACE(ns_internalize_name); if ((!external_name) || (*external_name == 0) || (!converted_name)) { return_ACPI_STATUS(AE_BAD_PARAMETER); @@ -537,7 +537,7 @@ acpi_ns_externalize_name(u32 internal_name_length, acpi_native_uint i = 0; acpi_native_uint j = 0; - ACPI_FUNCTION_TRACE("ns_externalize_name"); + ACPI_FUNCTION_TRACE(ns_externalize_name); if (!internal_name_length || !internal_name || !converted_name) { return_ACPI_STATUS(AE_BAD_PARAMETER); @@ -756,7 +756,7 @@ void acpi_ns_terminate(void) { union acpi_operand_object *obj_desc; - ACPI_FUNCTION_TRACE("ns_terminate"); + ACPI_FUNCTION_TRACE(ns_terminate); /* * 1) Free the entire namespace -- all nodes and objects @@ -796,7 +796,7 @@ void acpi_ns_terminate(void) u32 acpi_ns_opens_scope(acpi_object_type type) { - ACPI_FUNCTION_TRACE_STR("ns_opens_scope", acpi_ut_get_type_name(type)); + ACPI_FUNCTION_TRACE_STR(ns_opens_scope, acpi_ut_get_type_name(type)); if (!acpi_ut_valid_object_type(type)) { @@ -840,7 +840,7 @@ acpi_ns_get_node_by_path(char *pathname, acpi_status status; char *internal_path = NULL; - ACPI_FUNCTION_TRACE_PTR("ns_get_node_by_path", pathname); + ACPI_FUNCTION_TRACE_PTR(ns_get_node_by_path, pathname); if (pathname) { @@ -966,7 +966,7 @@ acpi_name acpi_ns_find_parent_name(struct acpi_namespace_node * child_node) { struct acpi_namespace_node *parent_node; - ACPI_FUNCTION_TRACE("ns_find_parent_name"); + ACPI_FUNCTION_TRACE(ns_find_parent_name); if (child_node) { diff --git a/drivers/acpi/namespace/nswalk.c b/drivers/acpi/namespace/nswalk.c index 6bbc734bfee2..c8f6bef16ed0 100644 --- a/drivers/acpi/namespace/nswalk.c +++ b/drivers/acpi/namespace/nswalk.c @@ -164,7 +164,7 @@ acpi_ns_walk_namespace(acpi_object_type type, acpi_object_type child_type; u32 level; - ACPI_FUNCTION_TRACE("ns_walk_namespace"); + ACPI_FUNCTION_TRACE(ns_walk_namespace); /* Special case for the namespace Root Node */ diff --git a/drivers/acpi/namespace/nsxfeval.c b/drivers/acpi/namespace/nsxfeval.c index 7cdedc96a40a..998b29611b19 100644 --- a/drivers/acpi/namespace/nsxfeval.c +++ b/drivers/acpi/namespace/nsxfeval.c @@ -80,7 +80,7 @@ acpi_evaluate_object_typed(acpi_handle handle, acpi_status status; u8 must_free = FALSE; - ACPI_FUNCTION_TRACE("acpi_evaluate_object_typed"); + ACPI_FUNCTION_TRACE(acpi_evaluate_object_typed); /* Return buffer must be valid */ @@ -175,7 +175,7 @@ acpi_evaluate_object(acpi_handle handle, acpi_size buffer_space_needed; u32 i; - ACPI_FUNCTION_TRACE("acpi_evaluate_object"); + ACPI_FUNCTION_TRACE(acpi_evaluate_object); info.node = handle; info.parameters = NULL; @@ -395,7 +395,7 @@ acpi_walk_namespace(acpi_object_type type, { acpi_status status; - ACPI_FUNCTION_TRACE("acpi_walk_namespace"); + ACPI_FUNCTION_TRACE(acpi_walk_namespace); /* Parameter validation */ @@ -553,7 +553,7 @@ acpi_get_devices(char *HID, acpi_status status; struct acpi_get_devices_info info; - ACPI_FUNCTION_TRACE("acpi_get_devices"); + ACPI_FUNCTION_TRACE(acpi_get_devices); /* Parameter validation */ diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 006b31a56559..109c3f8ae7df 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -1042,12 +1042,12 @@ void acpi_os_release_lock(acpi_handle handle, acpi_cpu_flags flags) * * FUNCTION: acpi_os_create_cache * - * PARAMETERS: CacheName - Ascii name for the cache - * ObjectSize - Size of each cached object - * MaxDepth - Maximum depth of the cache (in objects) - * ReturnCache - Where the new cache object is returned + * PARAMETERS: name - Ascii name for the cache + * size - Size of each cached object + * depth - Maximum depth of the cache (in objects) + * cache - Where the new cache object is returned * - * RETURN: Status + * RETURN: status * * DESCRIPTION: Create a cache object * @@ -1057,7 +1057,10 @@ acpi_status acpi_os_create_cache(char *name, u16 size, u16 depth, acpi_cache_t ** cache) { *cache = kmem_cache_create(name, size, 0, 0, NULL, NULL); - return AE_OK; + if (cache == NULL) + return AE_ERROR; + else + return AE_OK; } /******************************************************************************* @@ -1137,4 +1140,52 @@ void *acpi_os_acquire_object(acpi_cache_t * cache) return object; } +/****************************************************************************** + * + * FUNCTION: acpi_os_validate_interface + * + * PARAMETERS: interface - Requested interface to be validated + * + * RETURN: AE_OK if interface is supported, AE_SUPPORT otherwise + * + * DESCRIPTION: Match an interface string to the interfaces supported by the + * host. Strings originate from an AML call to the _OSI method. + * + *****************************************************************************/ + +acpi_status +acpi_os_validate_interface (char *interface) +{ + + return AE_SUPPORT; +} + + +/****************************************************************************** + * + * FUNCTION: acpi_os_validate_address + * + * PARAMETERS: space_id - ACPI space ID + * address - Physical address + * length - Address length + * + * RETURN: AE_OK if address/length is valid for the space_id. Otherwise, + * should return AE_AML_ILLEGAL_ADDRESS. + * + * DESCRIPTION: Validate a system address via the host OS. Used to validate + * the addresses accessed by AML operation regions. + * + *****************************************************************************/ + +acpi_status +acpi_os_validate_address ( + u8 space_id, + acpi_physical_address address, + acpi_size length) +{ + + return AE_OK; +} + + #endif diff --git a/drivers/acpi/parser/psargs.c b/drivers/acpi/parser/psargs.c index 1c5934fe1853..bf88e076c3e9 100644 --- a/drivers/acpi/parser/psargs.c +++ b/drivers/acpi/parser/psargs.c @@ -79,7 +79,7 @@ acpi_ps_get_next_package_length(struct acpi_parse_state *parser_state) acpi_native_uint byte_count; u8 byte_zero_mask = 0x3F; /* Default [0:5] */ - ACPI_FUNCTION_TRACE("ps_get_next_package_length"); + ACPI_FUNCTION_TRACE(ps_get_next_package_length); /* * Byte 0 bits [6:7] contain the number of additional bytes @@ -128,7 +128,7 @@ u8 *acpi_ps_get_next_package_end(struct acpi_parse_state *parser_state) u8 *start = parser_state->aml; u32 package_length; - ACPI_FUNCTION_TRACE("ps_get_next_package_end"); + ACPI_FUNCTION_TRACE(ps_get_next_package_end); /* Function below updates parser_state->Aml */ @@ -157,7 +157,7 @@ char *acpi_ps_get_next_namestring(struct acpi_parse_state *parser_state) u8 *start = parser_state->aml; u8 *end = parser_state->aml; - ACPI_FUNCTION_TRACE("ps_get_next_namestring"); + ACPI_FUNCTION_TRACE(ps_get_next_namestring); /* Point past any namestring prefix characters (backslash or carat) */ @@ -237,7 +237,7 @@ acpi_ps_get_next_namepath(struct acpi_walk_state *walk_state, struct acpi_namespace_node *node; union acpi_generic_state scope_info; - ACPI_FUNCTION_TRACE("ps_get_next_namepath"); + ACPI_FUNCTION_TRACE(ps_get_next_namepath); path = acpi_ps_get_next_namestring(parser_state); acpi_ps_init_op(arg, AML_INT_NAMEPATH_OP); @@ -391,7 +391,7 @@ acpi_ps_get_next_simple_arg(struct acpi_parse_state *parser_state, u16 opcode; u8 *aml = parser_state->aml; - ACPI_FUNCTION_TRACE_U32("ps_get_next_simple_arg", arg_type); + ACPI_FUNCTION_TRACE_U32(ps_get_next_simple_arg, arg_type); switch (arg_type) { case ARGP_BYTEDATA: @@ -456,7 +456,7 @@ acpi_ps_get_next_simple_arg(struct acpi_parse_state *parser_state, default: - ACPI_ERROR((AE_INFO, "Invalid arg_type %X", arg_type)); + ACPI_ERROR((AE_INFO, "Invalid ArgType %X", arg_type)); return_VOID; } @@ -487,7 +487,7 @@ static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state u16 opcode; u32 name; - ACPI_FUNCTION_TRACE("ps_get_next_field"); + ACPI_FUNCTION_TRACE(ps_get_next_field); /* Determine field type */ @@ -593,7 +593,7 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state, u32 subop; acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE_PTR("ps_get_next_arg", parser_state); + ACPI_FUNCTION_TRACE_PTR(ps_get_next_arg, parser_state); switch (arg_type) { case ARGP_BYTEDATA: @@ -718,7 +718,7 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state, default: - ACPI_ERROR((AE_INFO, "Invalid arg_type: %X", arg_type)); + ACPI_ERROR((AE_INFO, "Invalid ArgType: %X", arg_type)); status = AE_AML_OPERAND_TYPE; break; } diff --git a/drivers/acpi/parser/psloop.c b/drivers/acpi/parser/psloop.c index 3a29ce680370..e1541db3753a 100644 --- a/drivers/acpi/parser/psloop.c +++ b/drivers/acpi/parser/psloop.c @@ -83,7 +83,7 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) struct acpi_parse_state *parser_state; u8 *aml_op_start = NULL; - ACPI_FUNCTION_TRACE_PTR("ps_parse_loop", walk_state); + ACPI_FUNCTION_TRACE_PTR(ps_parse_loop, walk_state); if (walk_state->descending_callback == NULL) { return_ACPI_STATUS(AE_BAD_PARAMETER); @@ -129,7 +129,7 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) } ACPI_EXCEPTION((AE_INFO, status, - "get_predicate Failed")); + "GetPredicate Failed")); return_ACPI_STATUS(status); } @@ -375,7 +375,7 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) if (walk_state->op_info) { ACPI_DEBUG_PRINT((ACPI_DB_PARSE, - "Opcode %4.4X [%s] Op %p Aml %p aml_offset %5.5X\n", + "Opcode %4.4X [%s] Op %p Aml %p AmlOffset %5.5X\n", (u32) op->common.aml_opcode, walk_state->op_info->name, op, parser_state->aml, diff --git a/drivers/acpi/parser/psopcode.c b/drivers/acpi/parser/psopcode.c index 9eb8d0663886..4bd25e32769f 100644 --- a/drivers/acpi/parser/psopcode.c +++ b/drivers/acpi/parser/psopcode.c @@ -725,7 +725,7 @@ static const u8 acpi_gbl_long_op_index[NUM_EXTENDED_OPCODE] = { const struct acpi_opcode_info *acpi_ps_get_opcode_info(u16 opcode) { - ACPI_FUNCTION_NAME("ps_get_opcode_info"); + ACPI_FUNCTION_NAME(ps_get_opcode_info); /* * Detect normal 8-bit opcode or extended 16-bit opcode @@ -781,7 +781,7 @@ char *acpi_ps_get_opcode_name(u16 opcode) return (op->name); #else - return ("AE_NOT_CONFIGURED"); + return ("OpcodeName unavailable"); #endif } diff --git a/drivers/acpi/parser/psparse.c b/drivers/acpi/parser/psparse.c index 83d8916bc1af..796f6b719929 100644 --- a/drivers/acpi/parser/psparse.c +++ b/drivers/acpi/parser/psparse.c @@ -138,7 +138,7 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state, const struct acpi_opcode_info *parent_info; union acpi_parse_object *replacement_op = NULL; - ACPI_FUNCTION_TRACE_PTR("ps_complete_this_op", op); + ACPI_FUNCTION_TRACE_PTR(ps_complete_this_op, op); /* Check for null Op, can happen if AML code is corrupt */ @@ -333,7 +333,7 @@ acpi_ps_next_parse_state(struct acpi_walk_state *walk_state, struct acpi_parse_state *parser_state = &walk_state->parser_state; acpi_status status = AE_CTRL_PENDING; - ACPI_FUNCTION_TRACE_PTR("ps_next_parse_state", op); + ACPI_FUNCTION_TRACE_PTR(ps_next_parse_state, op); switch (callback_status) { case AE_CTRL_TERMINATE: @@ -453,10 +453,10 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state) struct acpi_thread_state *prev_walk_list = acpi_gbl_current_walk_list; struct acpi_walk_state *previous_walk_state; - ACPI_FUNCTION_TRACE("ps_parse_aml"); + ACPI_FUNCTION_TRACE(ps_parse_aml); ACPI_DEBUG_PRINT((ACPI_DB_PARSE, - "Entered with walk_state=%p Aml=%p size=%X\n", + "Entered with WalkState=%p Aml=%p size=%X\n", walk_state, walk_state->parser_state.aml, walk_state->parser_state.aml_size)); @@ -555,21 +555,9 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state) */ if (((walk_state->parse_flags & ACPI_PARSE_MODE_MASK) == ACPI_PARSE_EXECUTE) || (ACPI_FAILURE(status))) { - if (walk_state->method_desc) { - - /* Decrement the thread count on the method parse tree */ - - if (walk_state->method_desc->method. - thread_count) { - walk_state->method_desc->method. - thread_count--; - } else { - ACPI_ERROR((AE_INFO, - "Invalid zero thread count in method")); - } - } - - acpi_ds_terminate_control_method(walk_state); + acpi_ds_terminate_control_method(walk_state-> + method_desc, + walk_state); } /* Delete this walk state and all linked control states */ @@ -578,7 +566,7 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state) previous_walk_state = walk_state; ACPI_DEBUG_PRINT((ACPI_DB_PARSE, - "return_value=%p, implicit_value=%p State=%p\n", + "ReturnValue=%p, ImplicitValue=%p State=%p\n", walk_state->return_desc, walk_state->implicit_return_obj, walk_state)); diff --git a/drivers/acpi/parser/psscope.c b/drivers/acpi/parser/psscope.c index 424ab1c20da5..a3e0314de24d 100644 --- a/drivers/acpi/parser/psscope.c +++ b/drivers/acpi/parser/psscope.c @@ -106,7 +106,7 @@ acpi_ps_init_scope(struct acpi_parse_state * parser_state, { union acpi_generic_state *scope; - ACPI_FUNCTION_TRACE_PTR("ps_init_scope", root_op); + ACPI_FUNCTION_TRACE_PTR(ps_init_scope, root_op); scope = acpi_ut_create_generic_state(); if (!scope) { @@ -147,7 +147,7 @@ acpi_ps_push_scope(struct acpi_parse_state *parser_state, { union acpi_generic_state *scope; - ACPI_FUNCTION_TRACE_PTR("ps_push_scope", op); + ACPI_FUNCTION_TRACE_PTR(ps_push_scope, op); scope = acpi_ut_create_generic_state(); if (!scope) { @@ -200,7 +200,7 @@ acpi_ps_pop_scope(struct acpi_parse_state *parser_state, { union acpi_generic_state *scope = parser_state->scope; - ACPI_FUNCTION_TRACE("ps_pop_scope"); + ACPI_FUNCTION_TRACE(ps_pop_scope); /* Only pop the scope if there is in fact a next scope */ @@ -247,7 +247,7 @@ void acpi_ps_cleanup_scope(struct acpi_parse_state *parser_state) { union acpi_generic_state *scope; - ACPI_FUNCTION_TRACE_PTR("ps_cleanup_scope", parser_state); + ACPI_FUNCTION_TRACE_PTR(ps_cleanup_scope, parser_state); if (!parser_state) { return_VOID; diff --git a/drivers/acpi/parser/psutils.c b/drivers/acpi/parser/psutils.c index 43e3190583e3..182474ae8ce9 100644 --- a/drivers/acpi/parser/psutils.c +++ b/drivers/acpi/parser/psutils.c @@ -172,7 +172,7 @@ union acpi_parse_object *acpi_ps_alloc_op(u16 opcode) void acpi_ps_free_op(union acpi_parse_object *op) { - ACPI_FUNCTION_NAME("ps_free_op"); + ACPI_FUNCTION_NAME(ps_free_op); if (op->common.aml_opcode == AML_INT_RETURN_VALUE_OP) { ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "Free retval op: %p\n", diff --git a/drivers/acpi/parser/pswalk.c b/drivers/acpi/parser/pswalk.c index 3d08b8c6db41..a84a547a0f1b 100644 --- a/drivers/acpi/parser/pswalk.c +++ b/drivers/acpi/parser/pswalk.c @@ -64,7 +64,7 @@ void acpi_ps_delete_parse_tree(union acpi_parse_object *subtree_root) union acpi_parse_object *next = NULL; union acpi_parse_object *parent = NULL; - ACPI_FUNCTION_TRACE_PTR("ps_delete_parse_tree", subtree_root); + ACPI_FUNCTION_TRACE_PTR(ps_delete_parse_tree, subtree_root); /* Visit all nodes in the subtree */ diff --git a/drivers/acpi/parser/psxface.c b/drivers/acpi/parser/psxface.c index e09a820ee294..6b1411f1087d 100644 --- a/drivers/acpi/parser/psxface.c +++ b/drivers/acpi/parser/psxface.c @@ -216,7 +216,7 @@ acpi_status acpi_ps_execute_method(struct acpi_parameter_info *info) { acpi_status status; - ACPI_FUNCTION_TRACE("ps_execute_method"); + ACPI_FUNCTION_TRACE(ps_execute_method); /* Validate the Info and method Node */ @@ -286,8 +286,7 @@ acpi_status acpi_ps_execute_method(struct acpi_parameter_info *info) * a control exception code */ if (info->return_object) { - ACPI_DEBUG_PRINT((ACPI_DB_PARSE, - "Method returned obj_desc=%p\n", + ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "Method returned ObjDesc=%p\n", info->return_object)); ACPI_DUMP_STACK_ENTRY(info->return_object); @@ -350,7 +349,7 @@ static acpi_status acpi_ps_execute_pass(struct acpi_parameter_info *info) union acpi_parse_object *op; struct acpi_walk_state *walk_state; - ACPI_FUNCTION_TRACE("ps_execute_pass"); + ACPI_FUNCTION_TRACE(ps_execute_pass); /* Create and init a Root Node */ diff --git a/drivers/acpi/resources/rscalc.c b/drivers/acpi/resources/rscalc.c index dd5caa2c8fdd..a573ad5d41db 100644 --- a/drivers/acpi/resources/rscalc.c +++ b/drivers/acpi/resources/rscalc.c @@ -190,7 +190,7 @@ acpi_rs_get_aml_length(struct acpi_resource * resource, acpi_size * size_needed) acpi_size aml_size_needed = 0; acpi_rs_length total_size; - ACPI_FUNCTION_TRACE("rs_get_aml_length"); + ACPI_FUNCTION_TRACE(rs_get_aml_length); /* Traverse entire list of internal resource descriptors */ @@ -345,7 +345,7 @@ acpi_rs_get_list_length(u8 * aml_buffer, u8 resource_index; u8 minimum_aml_resource_length; - ACPI_FUNCTION_TRACE("rs_get_list_length"); + ACPI_FUNCTION_TRACE(rs_get_list_length); *size_needed = 0; end_aml = aml_buffer + aml_buffer_length; @@ -456,7 +456,7 @@ acpi_rs_get_list_length(u8 * aml_buffer, *size_needed += buffer_size; ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, - "Type %.2X, aml_length %.2X internal_length %.2X\n", + "Type %.2X, AmlLength %.2X InternalLength %.2X\n", acpi_ut_get_resource_type(aml_buffer), acpi_ut_get_descriptor_length(aml_buffer), buffer_size)); @@ -503,7 +503,7 @@ acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object, u8 name_found; u32 table_index; - ACPI_FUNCTION_TRACE("rs_get_pci_routing_table_length"); + ACPI_FUNCTION_TRACE(rs_get_pci_routing_table_length); number_of_elements = package_object->package.count; diff --git a/drivers/acpi/resources/rscreate.c b/drivers/acpi/resources/rscreate.c index 01488cfc9bae..4c322daaf885 100644 --- a/drivers/acpi/resources/rscreate.c +++ b/drivers/acpi/resources/rscreate.c @@ -77,9 +77,9 @@ acpi_rs_create_resource_list(union acpi_operand_object *aml_buffer, u32 aml_buffer_length; void *resource; - ACPI_FUNCTION_TRACE("rs_create_resource_list"); + ACPI_FUNCTION_TRACE(rs_create_resource_list); - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "aml_buffer = %p\n", aml_buffer)); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "AmlBuffer = %p\n", aml_buffer)); /* Params already validated, so we don't re-validate here */ @@ -93,7 +93,7 @@ acpi_rs_create_resource_list(union acpi_operand_object *aml_buffer, status = acpi_rs_get_list_length(aml_start, aml_buffer_length, &list_size_needed); - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Status=%X list_size_needed=%X\n", + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Status=%X ListSizeNeeded=%X\n", status, (u32) list_size_needed)); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); @@ -116,7 +116,7 @@ acpi_rs_create_resource_list(union acpi_operand_object *aml_buffer, return_ACPI_STATUS(status); } - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "output_buffer %p Length %X\n", + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "OutputBuffer %p Length %X\n", output_buffer->pointer, (u32) output_buffer->length)); return_ACPI_STATUS(AE_OK); } @@ -158,7 +158,7 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object, acpi_status status; struct acpi_buffer path_buffer; - ACPI_FUNCTION_TRACE("rs_create_pci_routing_table"); + ACPI_FUNCTION_TRACE(rs_create_pci_routing_table); /* Params already validated, so we don't re-validate here */ @@ -170,7 +170,7 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object, return_ACPI_STATUS(status); } - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "buffer_size_needed = %X\n", + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "BufferSizeNeeded = %X\n", (u32) buffer_size_needed)); /* Validate/Allocate/Clear caller buffer */ @@ -344,7 +344,7 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object, user_prt->source_index = (u32) obj_desc->integer.value; } else { ACPI_ERROR((AE_INFO, - "(PRT[%X].source_index) Need Integer, found %s", + "(PRT[%X].SourceIndex) Need Integer, found %s", index, acpi_ut_get_object_type_name(obj_desc))); return_ACPI_STATUS(AE_BAD_DATA); @@ -355,7 +355,7 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object, top_object_list++; } - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "output_buffer %p Length %X\n", + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "OutputBuffer %p Length %X\n", output_buffer->pointer, (u32) output_buffer->length)); return_ACPI_STATUS(AE_OK); } @@ -385,9 +385,9 @@ acpi_rs_create_aml_resources(struct acpi_resource *linked_list_buffer, acpi_status status; acpi_size aml_size_needed = 0; - ACPI_FUNCTION_TRACE("rs_create_aml_resources"); + ACPI_FUNCTION_TRACE(rs_create_aml_resources); - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "linked_list_buffer = %p\n", + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "LinkedListBuffer = %p\n", linked_list_buffer)); /* @@ -398,7 +398,7 @@ acpi_rs_create_aml_resources(struct acpi_resource *linked_list_buffer, */ status = acpi_rs_get_aml_length(linked_list_buffer, &aml_size_needed); - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "aml_size_needed=%X, %s\n", + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "AmlSizeNeeded=%X, %s\n", (u32) aml_size_needed, acpi_format_exception(status))); if (ACPI_FAILURE(status)) { @@ -422,7 +422,7 @@ acpi_rs_create_aml_resources(struct acpi_resource *linked_list_buffer, return_ACPI_STATUS(status); } - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "output_buffer %p Length %X\n", + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "OutputBuffer %p Length %X\n", output_buffer->pointer, (u32) output_buffer->length)); return_ACPI_STATUS(AE_OK); } diff --git a/drivers/acpi/resources/rsdump.c b/drivers/acpi/resources/rsdump.c index e7de061cf883..9c99a723a860 100644 --- a/drivers/acpi/resources/rsdump.c +++ b/drivers/acpi/resources/rsdump.c @@ -91,11 +91,11 @@ acpi_rs_dump_descriptor(void *resource, struct acpi_rsdump_info *table); struct acpi_rsdump_info acpi_rs_dump_irq[6] = { {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_irq), "IRQ", NULL}, {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(irq.triggering), "Triggering", - acpi_gbl_HEdecode}, + acpi_gbl_he_decode}, {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(irq.polarity), "Polarity", - acpi_gbl_LLdecode}, + acpi_gbl_ll_decode}, {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(irq.sharable), "Sharing", - acpi_gbl_SHRdecode}, + acpi_gbl_shr_decode}, {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(irq.interrupt_count), "Interrupt Count", NULL}, {ACPI_RSD_SHORTLIST, ACPI_RSD_OFFSET(irq.interrupts[0]), @@ -105,11 +105,11 @@ struct acpi_rsdump_info acpi_rs_dump_irq[6] = { struct acpi_rsdump_info acpi_rs_dump_dma[6] = { {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_dma), "DMA", NULL}, {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(dma.type), "Speed", - acpi_gbl_TYPdecode}, + acpi_gbl_typ_decode}, {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(dma.bus_master), "Mastering", - acpi_gbl_BMdecode}, + acpi_gbl_bm_decode}, {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(dma.transfer), "Transfer Type", - acpi_gbl_SIZdecode}, + acpi_gbl_siz_decode}, {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(dma.channel_count), "Channel Count", NULL}, {ACPI_RSD_SHORTLIST, ACPI_RSD_OFFSET(dma.channels[0]), "Channel List", @@ -158,7 +158,7 @@ struct acpi_rsdump_info acpi_rs_dump_vendor[3] = { }; struct acpi_rsdump_info acpi_rs_dump_end_tag[1] = { - {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_end_tag), "end_tag", + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_end_tag), "EndTag", NULL} }; @@ -166,7 +166,7 @@ struct acpi_rsdump_info acpi_rs_dump_memory24[6] = { {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_memory24), "24-Bit Memory Range", NULL}, {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(memory24.write_protect), - "Write Protect", acpi_gbl_RWdecode}, + "Write Protect", acpi_gbl_rw_decode}, {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(memory24.minimum), "Address Minimum", NULL}, {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(memory24.maximum), "Address Maximum", @@ -181,7 +181,7 @@ struct acpi_rsdump_info acpi_rs_dump_memory32[6] = { {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_memory32), "32-Bit Memory Range", NULL}, {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(memory32.write_protect), - "Write Protect", acpi_gbl_RWdecode}, + "Write Protect", acpi_gbl_rw_decode}, {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(memory32.minimum), "Address Minimum", NULL}, {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(memory32.maximum), "Address Maximum", @@ -196,7 +196,7 @@ struct acpi_rsdump_info acpi_rs_dump_fixed_memory32[4] = { {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_fixed_memory32), "32-Bit Fixed Memory Range", NULL}, {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(fixed_memory32.write_protect), - "Write Protect", acpi_gbl_RWdecode}, + "Write Protect", acpi_gbl_rw_decode}, {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(fixed_memory32.address), "Address", NULL}, {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(fixed_memory32.address_length), @@ -278,11 +278,11 @@ struct acpi_rsdump_info acpi_rs_dump_ext_irq[8] = { {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(extended_irq.producer_consumer), "Type", acpi_gbl_consume_decode}, {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(extended_irq.triggering), - "Triggering", acpi_gbl_HEdecode}, + "Triggering", acpi_gbl_he_decode}, {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(extended_irq.polarity), "Polarity", - acpi_gbl_LLdecode}, + acpi_gbl_ll_decode}, {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(extended_irq.sharable), "Sharing", - acpi_gbl_SHRdecode}, + acpi_gbl_shr_decode}, {ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(extended_irq.resource_source), NULL, NULL}, {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(extended_irq.interrupt_count), @@ -314,7 +314,7 @@ static struct acpi_rsdump_info acpi_rs_dump_general_flags[5] = { {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.producer_consumer), "Consumer/Producer", acpi_gbl_consume_decode}, {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.decode), "Address Decode", - acpi_gbl_DECdecode}, + acpi_gbl_dec_decode}, {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.min_address_fixed), "Min Relocatability", acpi_gbl_min_decode}, {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.max_address_fixed), @@ -325,24 +325,24 @@ static struct acpi_rsdump_info acpi_rs_dump_memory_flags[5] = { {ACPI_RSD_LITERAL, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_memory_flags), "Resource Type", (void *)"Memory Range"}, {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.info.mem.write_protect), - "Write Protect", acpi_gbl_RWdecode}, + "Write Protect", acpi_gbl_rw_decode}, {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(address.info.mem.caching), - "Caching", acpi_gbl_MEMdecode}, + "Caching", acpi_gbl_mem_decode}, {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(address.info.mem.range_type), - "Range Type", acpi_gbl_MTPdecode}, + "Range Type", acpi_gbl_mtp_decode}, {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.info.mem.translation), - "Translation", acpi_gbl_TTPdecode} + "Translation", acpi_gbl_ttp_decode} }; static struct acpi_rsdump_info acpi_rs_dump_io_flags[4] = { {ACPI_RSD_LITERAL, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_io_flags), "Resource Type", (void *)"I/O Range"}, {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(address.info.io.range_type), - "Range Type", acpi_gbl_RNGdecode}, + "Range Type", acpi_gbl_rng_decode}, {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.info.io.translation), - "Translation", acpi_gbl_TTPdecode}, + "Translation", acpi_gbl_ttp_decode}, {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.info.io.translation_type), - "Translation Type", acpi_gbl_TRSdecode} + "Translation Type", acpi_gbl_trs_decode} }; /* diff --git a/drivers/acpi/resources/rslist.c b/drivers/acpi/resources/rslist.c index 1b2d1e717e74..29423ce030ca 100644 --- a/drivers/acpi/resources/rslist.c +++ b/drivers/acpi/resources/rslist.c @@ -71,7 +71,7 @@ acpi_rs_convert_aml_to_resources(u8 * aml, struct acpi_resource *resource; acpi_status status; - ACPI_FUNCTION_TRACE("rs_convert_aml_to_resources"); + ACPI_FUNCTION_TRACE(rs_convert_aml_to_resources); /* * Check that the input buffer and all subsequent pointers into it @@ -99,7 +99,7 @@ acpi_rs_convert_aml_to_resources(u8 * aml, } ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, - "Type %.2X, aml_length %.2X internal_length %.2X\n", + "Type %.2X, AmlLength %.2X InternalLength %.2X\n", acpi_ut_get_resource_type(aml), length, resource->length)); @@ -136,7 +136,7 @@ acpi_rs_convert_resources_to_aml(struct acpi_resource *resource, u8 *end_aml = output_buffer + aml_size_needed; acpi_status status; - ACPI_FUNCTION_TRACE("rs_convert_resources_to_aml"); + ACPI_FUNCTION_TRACE(rs_convert_resources_to_aml); /* Walk the resource descriptor list, convert each descriptor */ diff --git a/drivers/acpi/resources/rsmisc.c b/drivers/acpi/resources/rsmisc.c index 6a731f4028d4..faf6e106b785 100644 --- a/drivers/acpi/resources/rsmisc.c +++ b/drivers/acpi/resources/rsmisc.c @@ -81,7 +81,7 @@ acpi_rs_convert_aml_to_resource(struct acpi_resource *resource, u16 item_count = 0; u16 temp16 = 0; - ACPI_FUNCTION_TRACE("rs_convert_aml_to_resource"); + ACPI_FUNCTION_TRACE(rs_convert_aml_to_resource); if (((acpi_native_uint) resource) & 0x3) { @@ -332,7 +332,7 @@ acpi_rs_convert_resource_to_aml(struct acpi_resource *resource, u16 temp16 = 0; u16 item_count = 0; - ACPI_FUNCTION_TRACE("rs_convert_resource_to_aml"); + ACPI_FUNCTION_TRACE(rs_convert_resource_to_aml); /* * First table entry must be ACPI_RSC_INITxxx and must contain the diff --git a/drivers/acpi/resources/rsutils.c b/drivers/acpi/resources/rsutils.c index 9bcf0b637d22..aa98eebc9b78 100644 --- a/drivers/acpi/resources/rsutils.c +++ b/drivers/acpi/resources/rsutils.c @@ -461,7 +461,7 @@ acpi_rs_get_prt_method_data(acpi_handle handle, struct acpi_buffer * ret_buffer) union acpi_operand_object *obj_desc; acpi_status status; - ACPI_FUNCTION_TRACE("rs_get_prt_method_data"); + ACPI_FUNCTION_TRACE(rs_get_prt_method_data); /* Parameters guaranteed valid by caller */ @@ -509,7 +509,7 @@ acpi_rs_get_crs_method_data(acpi_handle handle, struct acpi_buffer *ret_buffer) union acpi_operand_object *obj_desc; acpi_status status; - ACPI_FUNCTION_TRACE("rs_get_crs_method_data"); + ACPI_FUNCTION_TRACE(rs_get_crs_method_data); /* Parameters guaranteed valid by caller */ @@ -559,7 +559,7 @@ acpi_rs_get_prs_method_data(acpi_handle handle, struct acpi_buffer *ret_buffer) union acpi_operand_object *obj_desc; acpi_status status; - ACPI_FUNCTION_TRACE("rs_get_prs_method_data"); + ACPI_FUNCTION_TRACE(rs_get_prs_method_data); /* Parameters guaranteed valid by caller */ @@ -611,7 +611,7 @@ acpi_rs_get_method_data(acpi_handle handle, union acpi_operand_object *obj_desc; acpi_status status; - ACPI_FUNCTION_TRACE("rs_get_method_data"); + ACPI_FUNCTION_TRACE(rs_get_method_data); /* Parameters guaranteed valid by caller */ @@ -662,7 +662,7 @@ acpi_rs_set_srs_method_data(acpi_handle handle, struct acpi_buffer *in_buffer) acpi_status status; struct acpi_buffer buffer; - ACPI_FUNCTION_TRACE("rs_set_srs_method_data"); + ACPI_FUNCTION_TRACE(rs_set_srs_method_data); /* Parameters guaranteed valid by caller */ diff --git a/drivers/acpi/resources/rsxface.c b/drivers/acpi/resources/rsxface.c index 1d00d285a5a3..8c1628c12cc8 100644 --- a/drivers/acpi/resources/rsxface.c +++ b/drivers/acpi/resources/rsxface.c @@ -95,7 +95,7 @@ acpi_get_irq_routing_table(acpi_handle device_handle, { acpi_status status; - ACPI_FUNCTION_TRACE("acpi_get_irq_routing_table "); + ACPI_FUNCTION_TRACE(acpi_get_irq_routing_table); /* * Must have a valid handle and buffer, So we have to have a handle @@ -147,7 +147,7 @@ acpi_get_current_resources(acpi_handle device_handle, { acpi_status status; - ACPI_FUNCTION_TRACE("acpi_get_current_resources"); + ACPI_FUNCTION_TRACE(acpi_get_current_resources); /* * Must have a valid handle and buffer, So we have to have a handle @@ -197,7 +197,7 @@ acpi_get_possible_resources(acpi_handle device_handle, { acpi_status status; - ACPI_FUNCTION_TRACE("acpi_get_possible_resources"); + ACPI_FUNCTION_TRACE(acpi_get_possible_resources); /* * Must have a valid handle and buffer, So we have to have a handle @@ -249,13 +249,13 @@ acpi_walk_resources(acpi_handle device_handle, struct acpi_resource *resource; struct acpi_resource *resource_end; - ACPI_FUNCTION_TRACE("acpi_walk_resources"); + ACPI_FUNCTION_TRACE(acpi_walk_resources); /* Parameter validation */ if (!device_handle || !user_function || !name || - (ACPI_STRNCMP(name, METHOD_NAME__CRS, sizeof(METHOD_NAME__CRS)) && - ACPI_STRNCMP(name, METHOD_NAME__PRS, sizeof(METHOD_NAME__PRS)))) { + (!ACPI_COMPARE_NAME(name, METHOD_NAME__CRS) && + !ACPI_COMPARE_NAME(name, METHOD_NAME__PRS))) { return_ACPI_STATUS(AE_BAD_PARAMETER); } @@ -339,7 +339,7 @@ acpi_set_current_resources(acpi_handle device_handle, { acpi_status status; - ACPI_FUNCTION_TRACE("acpi_set_current_resources"); + ACPI_FUNCTION_TRACE(acpi_set_current_resources); /* Must have a valid handle and buffer */ diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c index 1943bec18848..a934ac42178d 100644 --- a/drivers/acpi/system.c +++ b/drivers/acpi/system.c @@ -82,7 +82,7 @@ acpi_system_read_dsdt(struct file *file, ACPI_FUNCTION_TRACE("acpi_system_read_dsdt"); - status = acpi_get_table(ACPI_TABLE_DSDT, 1, &dsdt); + status = acpi_get_table(ACPI_TABLE_ID_DSDT, 1, &dsdt); if (ACPI_FAILURE(status)) return_VALUE(-ENODEV); @@ -110,7 +110,7 @@ acpi_system_read_fadt(struct file *file, ACPI_FUNCTION_TRACE("acpi_system_read_fadt"); - status = acpi_get_table(ACPI_TABLE_FADT, 1, &fadt); + status = acpi_get_table(ACPI_TABLE_ID_FADT, 1, &fadt); if (ACPI_FAILURE(status)) return_VALUE(-ENODEV); diff --git a/drivers/acpi/tables/tbconvrt.c b/drivers/acpi/tables/tbconvrt.c index a913a927d321..d697fcb35d52 100644 --- a/drivers/acpi/tables/tbconvrt.c +++ b/drivers/acpi/tables/tbconvrt.c @@ -492,7 +492,7 @@ acpi_status acpi_tb_convert_table_fadt(void) struct fadt_descriptor *local_fadt; struct acpi_table_desc *table_desc; - ACPI_FUNCTION_TRACE("tb_convert_table_fadt"); + ACPI_FUNCTION_TRACE(tb_convert_table_fadt); /* * acpi_gbl_FADT is valid. Validate the FADT length. The table must be @@ -541,7 +541,7 @@ acpi_status acpi_tb_convert_table_fadt(void) /* Free the original table */ - table_desc = acpi_gbl_table_lists[ACPI_TABLE_FADT].next; + table_desc = acpi_gbl_table_lists[ACPI_TABLE_ID_FADT].next; acpi_tb_delete_single_table(table_desc); /* Install the new table */ @@ -579,7 +579,7 @@ acpi_status acpi_tb_convert_table_fadt(void) acpi_status acpi_tb_build_common_facs(struct acpi_table_desc *table_info) { - ACPI_FUNCTION_TRACE("tb_build_common_facs"); + ACPI_FUNCTION_TRACE(tb_build_common_facs); /* Absolute minimum length is 24, but the ACPI spec says 64 */ diff --git a/drivers/acpi/tables/tbget.c b/drivers/acpi/tables/tbget.c index b7bd20b9a75e..3a4f46ca3884 100644 --- a/drivers/acpi/tables/tbget.c +++ b/drivers/acpi/tables/tbget.c @@ -78,7 +78,7 @@ acpi_tb_get_table(struct acpi_pointer *address, acpi_status status; struct acpi_table_header header; - ACPI_FUNCTION_TRACE("tb_get_table"); + ACPI_FUNCTION_TRACE(tb_get_table); /* Get the header in order to get signature and table size */ @@ -124,7 +124,7 @@ acpi_tb_get_table_header(struct acpi_pointer *address, acpi_status status = AE_OK; struct acpi_table_header *header = NULL; - ACPI_FUNCTION_TRACE("tb_get_table_header"); + ACPI_FUNCTION_TRACE(tb_get_table_header); /* * Flags contains the current processor mode (Virtual or Physical @@ -202,7 +202,7 @@ acpi_tb_get_table_body(struct acpi_pointer *address, { acpi_status status; - ACPI_FUNCTION_TRACE("tb_get_table_body"); + ACPI_FUNCTION_TRACE(tb_get_table_body); if (!table_info || !address) { return_ACPI_STATUS(AE_BAD_PARAMETER); @@ -246,7 +246,7 @@ acpi_tb_table_override(struct acpi_table_header *header, acpi_status status; struct acpi_pointer address; - ACPI_FUNCTION_TRACE("tb_table_override"); + ACPI_FUNCTION_TRACE(tb_table_override); /* * The OSL will examine the header and decide whether to override this @@ -318,7 +318,7 @@ acpi_tb_get_this_table(struct acpi_pointer *address, u8 allocation; acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE("tb_get_this_table"); + ACPI_FUNCTION_TRACE(tb_get_this_table); /* * Flags contains the current processor mode (Virtual or Physical @@ -383,7 +383,7 @@ acpi_tb_get_this_table(struct acpi_pointer *address, * Validate checksum for _most_ tables, * even the ones whose signature we don't recognize */ - if (table_info->type != ACPI_TABLE_FACS) { + if (table_info->type != ACPI_TABLE_ID_FACS) { status = acpi_tb_verify_table_checksum(full_table); #if (!ACPI_CHECKSUM_ABORT) @@ -433,13 +433,13 @@ acpi_tb_get_table_ptr(acpi_table_type table_type, struct acpi_table_desc *table_desc; u32 i; - ACPI_FUNCTION_TRACE("tb_get_table_ptr"); + ACPI_FUNCTION_TRACE(tb_get_table_ptr); if (!acpi_gbl_DSDT) { return_ACPI_STATUS(AE_NO_ACPI_TABLES); } - if (table_type > ACPI_TABLE_MAX) { + if (table_type > ACPI_TABLE_ID_MAX) { return_ACPI_STATUS(AE_BAD_PARAMETER); } diff --git a/drivers/acpi/tables/tbgetall.c b/drivers/acpi/tables/tbgetall.c index b4ec61d7cf06..ad982112e4c6 100644 --- a/drivers/acpi/tables/tbgetall.c +++ b/drivers/acpi/tables/tbgetall.c @@ -77,7 +77,7 @@ acpi_tb_get_primary_table(struct acpi_pointer *address, acpi_status status; struct acpi_table_header header; - ACPI_FUNCTION_TRACE("tb_get_primary_table"); + ACPI_FUNCTION_TRACE(tb_get_primary_table); /* Ignore a NULL address in the RSDT */ @@ -140,7 +140,7 @@ acpi_tb_get_secondary_table(struct acpi_pointer *address, acpi_status status; struct acpi_table_header header; - ACPI_FUNCTION_TRACE_STR("tb_get_secondary_table", signature); + ACPI_FUNCTION_TRACE_STR(tb_get_secondary_table, signature); /* Get the header in order to match the signature */ @@ -151,7 +151,7 @@ acpi_tb_get_secondary_table(struct acpi_pointer *address, /* Signature must match request */ - if (ACPI_STRNCMP(header.signature, signature, ACPI_NAME_SIZE)) { + if (!ACPI_COMPARE_NAME(header.signature, signature)) { ACPI_ERROR((AE_INFO, "Incorrect table signature - wanted [%s] found [%4.4s]", signature, header.signature)); @@ -207,7 +207,7 @@ acpi_status acpi_tb_get_required_tables(void) struct acpi_table_desc table_info; struct acpi_pointer address; - ACPI_FUNCTION_TRACE("tb_get_required_tables"); + ACPI_FUNCTION_TRACE(tb_get_required_tables); ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%d ACPI tables in RSDT\n", acpi_gbl_rsdt_table_count)); @@ -306,6 +306,6 @@ acpi_status acpi_tb_get_required_tables(void) /* Always delete the RSDP mapping, we are done with it */ - acpi_tb_delete_tables_by_type(ACPI_TABLE_RSDP); + acpi_tb_delete_tables_by_type(ACPI_TABLE_ID_RSDP); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/tables/tbinstal.c b/drivers/acpi/tables/tbinstal.c index ce57a195577a..7ca2df75bb11 100644 --- a/drivers/acpi/tables/tbinstal.c +++ b/drivers/acpi/tables/tbinstal.c @@ -73,11 +73,11 @@ acpi_tb_match_signature(char *signature, { acpi_native_uint i; - ACPI_FUNCTION_TRACE("tb_match_signature"); + ACPI_FUNCTION_TRACE(tb_match_signature); /* Search for a signature match among the known table types */ - for (i = 0; i < NUM_ACPI_TABLE_TYPES; i++) { + for (i = 0; i < (ACPI_TABLE_ID_MAX + 1); i++) { if (!(acpi_gbl_table_data[i].flags & search_type)) { continue; } @@ -123,7 +123,7 @@ acpi_status acpi_tb_install_table(struct acpi_table_desc *table_info) { acpi_status status; - ACPI_FUNCTION_TRACE("tb_install_table"); + ACPI_FUNCTION_TRACE(tb_install_table); /* Lock tables while installing */ @@ -188,7 +188,7 @@ acpi_tb_recognize_table(struct acpi_table_desc *table_info, u8 search_type) struct acpi_table_header *table_header; acpi_status status; - ACPI_FUNCTION_TRACE("tb_recognize_table"); + ACPI_FUNCTION_TRACE(tb_recognize_table); /* Ensure that we have a valid table pointer */ @@ -219,7 +219,6 @@ acpi_tb_recognize_table(struct acpi_table_desc *table_info, u8 search_type) /* Return the table type and length via the info struct */ table_info->length = (acpi_size) table_header->length; - return_ACPI_STATUS(status); } @@ -244,7 +243,7 @@ acpi_tb_init_table_descriptor(acpi_table_type table_type, struct acpi_table_desc *table_desc; acpi_status status; - ACPI_FUNCTION_TRACE_U32("tb_init_table_descriptor", table_type); + ACPI_FUNCTION_TRACE_U32(tb_init_table_descriptor, table_type); /* Allocate a descriptor for this table */ @@ -313,15 +312,14 @@ acpi_tb_init_table_descriptor(acpi_table_type table_type, /* Finish initialization of the table descriptor */ + table_desc->loaded_into_namespace = FALSE; table_desc->type = (u8) table_type; table_desc->pointer = table_info->pointer; table_desc->length = table_info->length; table_desc->allocation = table_info->allocation; table_desc->aml_start = (u8 *) (table_desc->pointer + 1), - table_desc->aml_length = (u32) (table_desc->length - - (u32) sizeof(struct - acpi_table_header)); - table_desc->loaded_into_namespace = FALSE; + table_desc->aml_length = (u32) + (table_desc->length - (u32) sizeof(struct acpi_table_header)); /* * Set the appropriate global pointer (if there is one) to point to the @@ -336,7 +334,6 @@ acpi_tb_init_table_descriptor(acpi_table_type table_type, table_info->owner_id = table_desc->owner_id; table_info->installed_desc = table_desc; - return_ACPI_STATUS(AE_OK); } @@ -360,7 +357,7 @@ void acpi_tb_delete_all_tables(void) * Free memory allocated for ACPI tables * Memory can either be mapped or allocated */ - for (type = 0; type < NUM_ACPI_TABLE_TYPES; type++) { + for (type = 0; type < (ACPI_TABLE_ID_MAX + 1); type++) { acpi_tb_delete_tables_by_type(type); } } @@ -384,9 +381,9 @@ void acpi_tb_delete_tables_by_type(acpi_table_type type) u32 count; u32 i; - ACPI_FUNCTION_TRACE_U32("tb_delete_tables_by_type", type); + ACPI_FUNCTION_TRACE_U32(tb_delete_tables_by_type, type); - if (type > ACPI_TABLE_MAX) { + if (type > ACPI_TABLE_ID_MAX) { return_VOID; } @@ -397,28 +394,28 @@ void acpi_tb_delete_tables_by_type(acpi_table_type type) /* Clear the appropriate "typed" global table pointer */ switch (type) { - case ACPI_TABLE_RSDP: + case ACPI_TABLE_ID_RSDP: acpi_gbl_RSDP = NULL; break; - case ACPI_TABLE_DSDT: + case ACPI_TABLE_ID_DSDT: acpi_gbl_DSDT = NULL; break; - case ACPI_TABLE_FADT: + case ACPI_TABLE_ID_FADT: acpi_gbl_FADT = NULL; break; - case ACPI_TABLE_FACS: + case ACPI_TABLE_ID_FACS: acpi_gbl_FACS = NULL; break; - case ACPI_TABLE_XSDT: + case ACPI_TABLE_ID_XSDT: acpi_gbl_XSDT = NULL; break; - case ACPI_TABLE_SSDT: - case ACPI_TABLE_PSDT: + case ACPI_TABLE_ID_SSDT: + case ACPI_TABLE_ID_PSDT: default: break; } @@ -504,7 +501,7 @@ struct acpi_table_desc *acpi_tb_uninstall_table(struct acpi_table_desc { struct acpi_table_desc *next_desc; - ACPI_FUNCTION_TRACE_PTR("tb_uninstall_table", table_desc); + ACPI_FUNCTION_TRACE_PTR(tb_uninstall_table, table_desc); if (!table_desc) { return_PTR(NULL); diff --git a/drivers/acpi/tables/tbrsdt.c b/drivers/acpi/tables/tbrsdt.c index 9e0ebe625ed9..9e226438a3f6 100644 --- a/drivers/acpi/tables/tbrsdt.c +++ b/drivers/acpi/tables/tbrsdt.c @@ -64,7 +64,7 @@ acpi_status acpi_tb_verify_rsdp(struct acpi_pointer *address) acpi_status status; struct rsdp_descriptor *rsdp; - ACPI_FUNCTION_TRACE("tb_verify_rsdp"); + ACPI_FUNCTION_TRACE(tb_verify_rsdp); switch (address->pointer_type) { case ACPI_LOGICAL_POINTER: @@ -103,7 +103,7 @@ acpi_status acpi_tb_verify_rsdp(struct acpi_pointer *address) /* Save the table pointers and allocation info */ - status = acpi_tb_init_table_descriptor(ACPI_TABLE_RSDP, &table_info); + status = acpi_tb_init_table_descriptor(ACPI_TABLE_ID_RSDP, &table_info); if (ACPI_FAILURE(status)) { goto cleanup; } @@ -174,22 +174,19 @@ void acpi_tb_get_rsdt_address(struct acpi_pointer *out_address) acpi_status acpi_tb_validate_rsdt(struct acpi_table_header *table_ptr) { - int no_match; + char *signature; ACPI_FUNCTION_ENTRY(); - /* - * Search for appropriate signature, RSDT or XSDT - */ + /* Search for appropriate signature, RSDT or XSDT */ + if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) { - no_match = ACPI_STRNCMP((char *)table_ptr, RSDT_SIG, - sizeof(RSDT_SIG) - 1); + signature = RSDT_SIG; } else { - no_match = ACPI_STRNCMP((char *)table_ptr, XSDT_SIG, - sizeof(XSDT_SIG) - 1); + signature = XSDT_SIG; } - if (no_match) { + if (!ACPI_COMPARE_NAME(table_ptr->signature, signature)) { /* Invalid RSDT or XSDT signature */ @@ -235,13 +232,13 @@ acpi_status acpi_tb_get_table_rsdt(void) acpi_status status; struct acpi_pointer address; - ACPI_FUNCTION_TRACE("tb_get_table_rsdt"); + ACPI_FUNCTION_TRACE(tb_get_table_rsdt); /* Get the RSDT/XSDT via the RSDP */ acpi_tb_get_rsdt_address(&address); - table_info.type = ACPI_TABLE_XSDT; + table_info.type = ACPI_TABLE_ID_XSDT; status = acpi_tb_get_table(&address, &table_info); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, @@ -275,7 +272,7 @@ acpi_status acpi_tb_get_table_rsdt(void) /* Save the table pointers and allocation info */ - status = acpi_tb_init_table_descriptor(ACPI_TABLE_XSDT, &table_info); + status = acpi_tb_init_table_descriptor(ACPI_TABLE_ID_XSDT, &table_info); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } diff --git a/drivers/acpi/tables/tbutils.c b/drivers/acpi/tables/tbutils.c index f8d28ae8811d..5f1440376514 100644 --- a/drivers/acpi/tables/tbutils.c +++ b/drivers/acpi/tables/tbutils.c @@ -71,7 +71,7 @@ acpi_status acpi_tb_is_table_installed(struct acpi_table_desc *new_table_desc) { struct acpi_table_desc *table_desc; - ACPI_FUNCTION_TRACE("tb_is_table_installed"); + ACPI_FUNCTION_TRACE(tb_is_table_installed); /* Get the list descriptor and first table descriptor */ @@ -100,7 +100,7 @@ acpi_status acpi_tb_is_table_installed(struct acpi_table_desc *new_table_desc) /* Match: this table is already installed */ ACPI_DEBUG_PRINT((ACPI_DB_TABLES, - "Table [%4.4s] already installed: Rev %X oem_table_id [%8.8s]\n", + "Table [%4.4s] already installed: Rev %X OemTableId [%8.8s]\n", new_table_desc->pointer->signature, new_table_desc->pointer->revision, new_table_desc->pointer-> @@ -288,7 +288,7 @@ acpi_tb_verify_table_checksum(struct acpi_table_header *table_header) { u8 checksum; - ACPI_FUNCTION_TRACE("tb_verify_table_checksum"); + ACPI_FUNCTION_TRACE(tb_verify_table_checksum); /* Compute the checksum on the table */ @@ -329,7 +329,7 @@ acpi_tb_handle_to_object(u16 table_id, u32 i; struct acpi_table_desc *table_desc; - ACPI_FUNCTION_NAME("tb_handle_to_object"); + ACPI_FUNCTION_NAME(tb_handle_to_object); for (i = 0; i < ACPI_TABLE_MAX; i++) { table_desc = acpi_gbl_table_lists[i].next; @@ -343,7 +343,7 @@ acpi_tb_handle_to_object(u16 table_id, } } - ACPI_ERROR((AE_INFO, "table_id=%X does not exist", table_id)); + ACPI_ERROR((AE_INFO, "TableId=%X does not exist", table_id)); return (AE_BAD_PARAMETER); } #endif diff --git a/drivers/acpi/tables/tbxface.c b/drivers/acpi/tables/tbxface.c index 53c627e401bf..4e91f2984815 100644 --- a/drivers/acpi/tables/tbxface.c +++ b/drivers/acpi/tables/tbxface.c @@ -66,7 +66,7 @@ acpi_status acpi_load_tables(void) struct acpi_pointer rsdp_address; acpi_status status; - ACPI_FUNCTION_TRACE("acpi_load_tables"); + ACPI_FUNCTION_TRACE(acpi_load_tables); /* Get the RSDP */ @@ -145,7 +145,7 @@ acpi_status acpi_load_table(struct acpi_table_header *table_ptr) struct acpi_table_desc table_info; struct acpi_pointer address; - ACPI_FUNCTION_TRACE("acpi_load_table"); + ACPI_FUNCTION_TRACE(acpi_load_table); if (!table_ptr) { return_ACPI_STATUS(AE_BAD_PARAMETER); @@ -188,12 +188,12 @@ acpi_status acpi_load_table(struct acpi_table_header *table_ptr) /* Convert the table to common format if necessary */ switch (table_info.type) { - case ACPI_TABLE_FADT: + case ACPI_TABLE_ID_FADT: status = acpi_tb_convert_table_fadt(); break; - case ACPI_TABLE_FACS: + case ACPI_TABLE_ID_FACS: status = acpi_tb_build_common_facs(&table_info); break; @@ -234,11 +234,11 @@ acpi_status acpi_unload_table(acpi_table_type table_type) { struct acpi_table_desc *table_desc; - ACPI_FUNCTION_TRACE("acpi_unload_table"); + ACPI_FUNCTION_TRACE(acpi_unload_table); /* Parameter validation */ - if (table_type > ACPI_TABLE_MAX) { + if (table_type > ACPI_TABLE_ID_MAX) { return_ACPI_STATUS(AE_BAD_PARAMETER); } @@ -292,16 +292,16 @@ acpi_get_table_header(acpi_table_type table_type, struct acpi_table_header *tbl_ptr; acpi_status status; - ACPI_FUNCTION_TRACE("acpi_get_table_header"); + ACPI_FUNCTION_TRACE(acpi_get_table_header); if ((instance == 0) || - (table_type == ACPI_TABLE_RSDP) || (!out_table_header)) { + (table_type == ACPI_TABLE_ID_RSDP) || (!out_table_header)) { return_ACPI_STATUS(AE_BAD_PARAMETER); } /* Check the table type and instance */ - if ((table_type > ACPI_TABLE_MAX) || + if ((table_type > ACPI_TABLE_ID_MAX) || (ACPI_IS_SINGLE_TABLE(acpi_gbl_table_data[table_type].flags) && instance > 1)) { return_ACPI_STATUS(AE_BAD_PARAMETER); @@ -361,7 +361,7 @@ acpi_get_table(acpi_table_type table_type, acpi_status status; acpi_size table_length; - ACPI_FUNCTION_TRACE("acpi_get_table"); + ACPI_FUNCTION_TRACE(acpi_get_table); /* Parameter validation */ @@ -376,7 +376,7 @@ acpi_get_table(acpi_table_type table_type, /* Check the table type and instance */ - if ((table_type > ACPI_TABLE_MAX) || + if ((table_type > ACPI_TABLE_ID_MAX) || (ACPI_IS_SINGLE_TABLE(acpi_gbl_table_data[table_type].flags) && instance > 1)) { return_ACPI_STATUS(AE_BAD_PARAMETER); @@ -399,7 +399,7 @@ acpi_get_table(acpi_table_type table_type, /* Get the table length */ - if (table_type == ACPI_TABLE_RSDP) { + if (table_type == ACPI_TABLE_ID_RSDP) { /* RSD PTR is the only "table" without a header */ diff --git a/drivers/acpi/tables/tbxfroot.c b/drivers/acpi/tables/tbxfroot.c index 550284f5d1ed..3107e741d510 100644 --- a/drivers/acpi/tables/tbxfroot.c +++ b/drivers/acpi/tables/tbxfroot.c @@ -119,7 +119,7 @@ acpi_tb_find_table(char *signature, acpi_status status; struct acpi_table_header *table; - ACPI_FUNCTION_TRACE("tb_find_table"); + ACPI_FUNCTION_TRACE(tb_find_table); /* Validate string lengths */ @@ -129,7 +129,7 @@ acpi_tb_find_table(char *signature, return_ACPI_STATUS(AE_AML_STRING_LIMIT); } - if (!ACPI_STRNCMP(signature, DSDT_SIG, ACPI_NAME_SIZE)) { + if (ACPI_COMPARE_NAME(signature, DSDT_SIG)) { /* * The DSDT pointer is contained in the FADT, not the RSDT. * This code should suffice, because the only code that would perform @@ -154,10 +154,12 @@ acpi_tb_find_table(char *signature, /* Check oem_id and oem_table_id */ - if ((oem_id[0] && ACPI_STRNCMP(oem_id, table->oem_id, - sizeof(table->oem_id))) || - (oem_table_id[0] && ACPI_STRNCMP(oem_table_id, table->oem_table_id, - sizeof(table->oem_table_id)))) { + if ((oem_id[0] && + ACPI_STRNCMP(oem_id, table->oem_id, + sizeof(table->oem_id))) || + (oem_table_id[0] && + ACPI_STRNCMP(oem_table_id, table->oem_table_id, + sizeof(table->oem_table_id)))) { return_ACPI_STATUS(AE_AML_NAME_NOT_FOUND); } @@ -201,7 +203,7 @@ acpi_get_firmware_table(acpi_string signature, u32 i; u32 j; - ACPI_FUNCTION_TRACE("acpi_get_firmware_table"); + ACPI_FUNCTION_TRACE(acpi_get_firmware_table); /* * Ensure that at least the table manager is initialized. We don't @@ -325,7 +327,7 @@ acpi_get_firmware_table(acpi_string signature, /* Compare table signatures and table instance */ - if (!ACPI_STRNCMP(header->signature, signature, ACPI_NAME_SIZE)) { + if (ACPI_COMPARE_NAME(header->signature, signature)) { /* An instance of the table was found */ @@ -388,7 +390,7 @@ acpi_status acpi_find_root_pointer(u32 flags, struct acpi_pointer *rsdp_address) struct acpi_table_desc table_info; acpi_status status; - ACPI_FUNCTION_TRACE("acpi_find_root_pointer"); + ACPI_FUNCTION_TRACE(acpi_find_root_pointer); /* Get the RSDP */ @@ -425,7 +427,7 @@ static u8 *acpi_tb_scan_memory_for_rsdp(u8 * start_address, u32 length) u8 *mem_rover; u8 *end_address; - ACPI_FUNCTION_TRACE("tb_scan_memory_for_rsdp"); + ACPI_FUNCTION_TRACE(tb_scan_memory_for_rsdp); end_address = start_address + length; @@ -490,7 +492,7 @@ acpi_tb_find_rsdp(struct acpi_table_desc *table_info, u32 flags) u32 physical_address; acpi_status status; - ACPI_FUNCTION_TRACE("tb_find_rsdp"); + ACPI_FUNCTION_TRACE(tb_find_rsdp); /* * Scan supports either logical addressing or physical addressing diff --git a/drivers/acpi/utilities/utalloc.c b/drivers/acpi/utilities/utalloc.c index 3b29aecaaca5..65a7c2ed9aa1 100644 --- a/drivers/acpi/utilities/utalloc.c +++ b/drivers/acpi/utilities/utalloc.c @@ -108,7 +108,7 @@ acpi_status acpi_ut_create_caches(void) } status = - acpi_os_create_cache("Acpi-parse_ext", + acpi_os_create_cache("Acpi-ParseExt", sizeof(struct acpi_parse_obj_named), ACPI_MAX_EXTPARSE_CACHE_DEPTH, &acpi_gbl_ps_node_ext_cache); @@ -289,7 +289,7 @@ void *acpi_ut_allocate(acpi_size size, u32 component, char *module, u32 line) { void *allocation; - ACPI_FUNCTION_TRACE_U32("ut_allocate", size); + ACPI_FUNCTION_TRACE_U32(ut_allocate, size); /* Check for an inadvertent size of zero bytes */ diff --git a/drivers/acpi/utilities/utcache.c b/drivers/acpi/utilities/utcache.c index 593b08ccd6bf..56270a30718a 100644 --- a/drivers/acpi/utilities/utcache.c +++ b/drivers/acpi/utilities/utcache.c @@ -244,7 +244,7 @@ void *acpi_os_acquire_object(struct acpi_memory_list *cache) acpi_status status; void *object; - ACPI_FUNCTION_NAME("os_acquire_object"); + ACPI_FUNCTION_NAME(os_acquire_object); if (!cache) { return (NULL); diff --git a/drivers/acpi/utilities/utcopy.c b/drivers/acpi/utilities/utcopy.c index 371cddc0d574..5e1a80d1bc36 100644 --- a/drivers/acpi/utilities/utcopy.c +++ b/drivers/acpi/utilities/utcopy.c @@ -109,7 +109,7 @@ acpi_ut_copy_isimple_to_esimple(union acpi_operand_object *internal_object, { acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE("ut_copy_isimple_to_esimple"); + ACPI_FUNCTION_TRACE(ut_copy_isimple_to_esimple); *buffer_space_used = 0; @@ -325,7 +325,7 @@ acpi_ut_copy_ipackage_to_epackage(union acpi_operand_object *internal_object, acpi_status status; struct acpi_pkg_info info; - ACPI_FUNCTION_TRACE("ut_copy_ipackage_to_epackage"); + ACPI_FUNCTION_TRACE(ut_copy_ipackage_to_epackage); /* * First package at head of the buffer @@ -383,7 +383,7 @@ acpi_ut_copy_iobject_to_eobject(union acpi_operand_object *internal_object, { acpi_status status; - ACPI_FUNCTION_TRACE("ut_copy_iobject_to_eobject"); + ACPI_FUNCTION_TRACE(ut_copy_iobject_to_eobject); if (ACPI_GET_OBJECT_TYPE(internal_object) == ACPI_TYPE_PACKAGE) { /* @@ -442,7 +442,7 @@ acpi_ut_copy_esimple_to_isimple(union acpi_object *external_object, { union acpi_operand_object *internal_object; - ACPI_FUNCTION_TRACE("ut_copy_esimple_to_isimple"); + ACPI_FUNCTION_TRACE(ut_copy_esimple_to_isimple); /* * Simple types supported are: String, Buffer, Integer @@ -552,7 +552,7 @@ acpi_ut_copy_epackage_to_ipackage(union acpi_operand_object *internal_object, union acpi_operand_object *this_internal_obj; union acpi_object *this_external_obj; - ACPI_FUNCTION_TRACE("ut_copy_epackage_to_ipackage"); + ACPI_FUNCTION_TRACE(ut_copy_epackage_to_ipackage); /* * First package at head of the buffer @@ -600,7 +600,7 @@ acpi_ut_copy_eobject_to_iobject(union acpi_object *external_object, { acpi_status status; - ACPI_FUNCTION_TRACE("ut_copy_eobject_to_iobject"); + ACPI_FUNCTION_TRACE(ut_copy_eobject_to_iobject); if (external_object->type == ACPI_TYPE_PACKAGE) { /* @@ -854,7 +854,7 @@ acpi_ut_copy_ipackage_to_ipackage(union acpi_operand_object *source_obj, { acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE("ut_copy_ipackage_to_ipackage"); + ACPI_FUNCTION_TRACE(ut_copy_ipackage_to_ipackage); dest_obj->common.type = ACPI_GET_OBJECT_TYPE(source_obj); dest_obj->common.flags = source_obj->common.flags; @@ -910,7 +910,7 @@ acpi_ut_copy_iobject_to_iobject(union acpi_operand_object *source_desc, { acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE("ut_copy_iobject_to_iobject"); + ACPI_FUNCTION_TRACE(ut_copy_iobject_to_iobject); /* Create the top level object */ diff --git a/drivers/acpi/utilities/utdelete.c b/drivers/acpi/utilities/utdelete.c index b4e34a2f81f7..0bb4b59b2804 100644 --- a/drivers/acpi/utilities/utdelete.c +++ b/drivers/acpi/utilities/utdelete.c @@ -76,7 +76,7 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object) union acpi_operand_object *second_desc; union acpi_operand_object *next_desc; - ACPI_FUNCTION_TRACE_PTR("ut_delete_internal_obj", object); + ACPI_FUNCTION_TRACE_PTR(ut_delete_internal_obj, object); if (!object) { return_VOID; @@ -276,7 +276,7 @@ void acpi_ut_delete_internal_object_list(union acpi_operand_object **obj_list) { union acpi_operand_object **internal_obj; - ACPI_FUNCTION_TRACE("ut_delete_internal_object_list"); + ACPI_FUNCTION_TRACE(ut_delete_internal_object_list); /* Walk the null-terminated internal list */ @@ -309,7 +309,7 @@ acpi_ut_update_ref_count(union acpi_operand_object *object, u32 action) u16 count; u16 new_count; - ACPI_FUNCTION_NAME("ut_update_ref_count"); + ACPI_FUNCTION_NAME(ut_update_ref_count); if (!object) { return; @@ -425,7 +425,7 @@ acpi_ut_update_object_reference(union acpi_operand_object * object, u16 action) union acpi_generic_state *state; acpi_native_uint i; - ACPI_FUNCTION_TRACE_PTR("ut_update_object_reference", object); + ACPI_FUNCTION_TRACE_PTR(ut_update_object_reference, object); while (object) { @@ -570,7 +570,7 @@ acpi_ut_update_object_reference(union acpi_operand_object * object, u16 action) void acpi_ut_add_reference(union acpi_operand_object *object) { - ACPI_FUNCTION_TRACE_PTR("ut_add_reference", object); + ACPI_FUNCTION_TRACE_PTR(ut_add_reference, object); /* Ensure that we have a valid object */ @@ -603,7 +603,7 @@ void acpi_ut_add_reference(union acpi_operand_object *object) void acpi_ut_remove_reference(union acpi_operand_object *object) { - ACPI_FUNCTION_TRACE_PTR("ut_remove_reference", object); + ACPI_FUNCTION_TRACE_PTR(ut_remove_reference, object); /* * Allow a NULL pointer to be passed in, just ignore it. This saves diff --git a/drivers/acpi/utilities/uteval.c b/drivers/acpi/utilities/uteval.c index 68b9eff4b326..444d3a502c46 100644 --- a/drivers/acpi/utilities/uteval.c +++ b/drivers/acpi/utilities/uteval.c @@ -56,6 +56,34 @@ static acpi_status acpi_ut_translate_one_cid(union acpi_operand_object *obj_desc, struct acpi_compatible_id *one_cid); +/* + * Strings supported by the _OSI predefined (internal) method. + */ +static const char *acpi_interfaces_supported[] = { + /* Operating System Vendor Strings */ + + "Linux", + "Windows 2000", + "Windows 2001", + "Windows 2001 SP0", + "Windows 2001 SP1", + "Windows 2001 SP2", + "Windows 2001 SP3", + "Windows 2001 SP4", + "Windows 2001.1", + "Windows 2001.1 SP1", /* Added 03/2006 */ + "Windows 2006", /* Added 03/2006 */ + + /* Feature Group Strings */ + + "Extended Address Space Descriptor" + /* + * All "optional" feature group strings (features that are implemented + * by the host) should be implemented in the host version of + * acpi_os_validate_interface and should not be added here. + */ +}; + /******************************************************************************* * * FUNCTION: acpi_ut_osi_implementation @@ -64,18 +92,18 @@ acpi_ut_translate_one_cid(union acpi_operand_object *obj_desc, * * RETURN: Status * - * DESCRIPTION: Implementation of _OSI predefined control method - * Supported = _OSI (String) + * DESCRIPTION: Implementation of the _OSI predefined control method * ******************************************************************************/ acpi_status acpi_ut_osi_implementation(struct acpi_walk_state *walk_state) { + acpi_status status; union acpi_operand_object *string_desc; union acpi_operand_object *return_desc; acpi_native_uint i; - ACPI_FUNCTION_TRACE("ut_osi_implementation"); + ACPI_FUNCTION_TRACE(ut_osi_implementation); /* Validate the string input argument */ @@ -84,29 +112,47 @@ acpi_status acpi_ut_osi_implementation(struct acpi_walk_state *walk_state) return_ACPI_STATUS(AE_TYPE); } - /* Create a return object (Default value = 0) */ + /* Create a return object */ return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); if (!return_desc) { return_ACPI_STATUS(AE_NO_MEMORY); } - /* Compare input string to table of supported strings */ + /* Default return value is SUPPORTED */ - for (i = 0; i < ACPI_NUM_OSI_STRINGS; i++) { - if (!ACPI_STRCMP(string_desc->string.pointer, - ACPI_CAST_PTR(char, - acpi_gbl_valid_osi_strings[i]))) - { + return_desc->integer.value = ACPI_UINT32_MAX; + walk_state->return_desc = return_desc; + + /* Compare input string to static table of supported interfaces */ - /* This string is supported */ + for (i = 0; i < ACPI_ARRAY_LENGTH(acpi_interfaces_supported); i++) { + if (!ACPI_STRCMP + (string_desc->string.pointer, + acpi_interfaces_supported[i])) { - return_desc->integer.value = 0xFFFFFFFF; - break; + /* The interface is supported */ + + return_ACPI_STATUS(AE_CTRL_TERMINATE); } } - walk_state->return_desc = return_desc; + /* + * Did not match the string in the static table, call the host OSL to + * check for a match with one of the optional strings (such as + * "Module Device", "3.0 Thermal Model", etc.) + */ + status = acpi_os_validate_interface(string_desc->string.pointer); + if (ACPI_SUCCESS(status)) { + + /* The interface is supported */ + + return_ACPI_STATUS(AE_CTRL_TERMINATE); + } + + /* The interface is not supported */ + + return_desc->integer.value = 0; return_ACPI_STATUS(AE_CTRL_TERMINATE); } @@ -139,7 +185,7 @@ acpi_ut_evaluate_object(struct acpi_namespace_node *prefix_node, acpi_status status; u32 return_btype; - ACPI_FUNCTION_TRACE("ut_evaluate_object"); + ACPI_FUNCTION_TRACE(ut_evaluate_object); info.node = prefix_node; info.parameters = NULL; @@ -258,7 +304,7 @@ acpi_ut_evaluate_numeric_object(char *object_name, union acpi_operand_object *obj_desc; acpi_status status; - ACPI_FUNCTION_TRACE("ut_evaluate_numeric_object"); + ACPI_FUNCTION_TRACE(ut_evaluate_numeric_object); status = acpi_ut_evaluate_object(device_node, object_name, ACPI_BTYPE_INTEGER, &obj_desc); @@ -334,7 +380,7 @@ acpi_ut_execute_HID(struct acpi_namespace_node *device_node, union acpi_operand_object *obj_desc; acpi_status status; - ACPI_FUNCTION_TRACE("ut_execute_HID"); + ACPI_FUNCTION_TRACE(ut_execute_HID); status = acpi_ut_evaluate_object(device_node, METHOD_NAME__HID, ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING, @@ -438,7 +484,7 @@ acpi_ut_execute_CID(struct acpi_namespace_node * device_node, struct acpi_compatible_id_list *cid_list; acpi_native_uint i; - ACPI_FUNCTION_TRACE("ut_execute_CID"); + ACPI_FUNCTION_TRACE(ut_execute_CID); /* Evaluate the _CID method for this device */ @@ -536,7 +582,7 @@ acpi_ut_execute_UID(struct acpi_namespace_node *device_node, union acpi_operand_object *obj_desc; acpi_status status; - ACPI_FUNCTION_TRACE("ut_execute_UID"); + ACPI_FUNCTION_TRACE(ut_execute_UID); status = acpi_ut_evaluate_object(device_node, METHOD_NAME__UID, ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING, @@ -586,7 +632,7 @@ acpi_ut_execute_STA(struct acpi_namespace_node *device_node, u32 * flags) union acpi_operand_object *obj_desc; acpi_status status; - ACPI_FUNCTION_TRACE("ut_execute_STA"); + ACPI_FUNCTION_TRACE(ut_execute_STA); status = acpi_ut_evaluate_object(device_node, METHOD_NAME__STA, ACPI_BTYPE_INTEGER, &obj_desc); @@ -636,7 +682,7 @@ acpi_ut_execute_sxds(struct acpi_namespace_node *device_node, u8 * highest) acpi_status status; u32 i; - ACPI_FUNCTION_TRACE("ut_execute_Sxds"); + ACPI_FUNCTION_TRACE(ut_execute_sxds); for (i = 0; i < 4; i++) { highest[i] = 0xFF; diff --git a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c index e8ae417c9848..e666c71be0bf 100644 --- a/drivers/acpi/utilities/utglobal.c +++ b/drivers/acpi/utilities/utglobal.c @@ -181,30 +181,6 @@ const char *acpi_gbl_highest_dstate_names[4] = { "_S4D" }; -/* - * Strings supported by the _OSI predefined (internal) method. - * When adding strings, be sure to update ACPI_NUM_OSI_STRINGS. - */ -const char *acpi_gbl_valid_osi_strings[ACPI_NUM_OSI_STRINGS] = { - /* Operating System Vendor Strings */ - - "Linux", - "Windows 2000", - "Windows 2001", - "Windows 2001 SP0", - "Windows 2001 SP1", - "Windows 2001 SP2", - "Windows 2001 SP3", - "Windows 2001 SP4", - "Windows 2001.1", - "Windows 2001.1 SP1", /* Added 03/2006 */ - "Windows 2006", /* Added 03/2006 */ - - /* Feature Group Strings */ - - "Extended Address Space Descriptor" -}; - /******************************************************************************* * * Namespace globals @@ -317,9 +293,9 @@ char acpi_ut_hex_to_ascii_char(acpi_integer integer, u32 position) * ******************************************************************************/ -struct acpi_table_list acpi_gbl_table_lists[NUM_ACPI_TABLE_TYPES]; +struct acpi_table_list acpi_gbl_table_lists[ACPI_TABLE_ID_MAX + 1]; -struct acpi_table_support acpi_gbl_table_data[NUM_ACPI_TABLE_TYPES] = { +struct acpi_table_support acpi_gbl_table_data[ACPI_TABLE_ID_MAX + 1] = { /*********** Name, Signature, Global typed pointer Signature size, Type How many allowed?, Contains valid AML? */ /* RSDP 0 */ {RSDP_NAME, RSDP_SIG, NULL, sizeof(RSDP_SIG) - 1, @@ -483,9 +459,9 @@ char *acpi_ut_get_region_name(u8 space_id) { if (space_id >= ACPI_USER_REGION_BEGIN) { - return ("user_defined_region"); + return ("UserDefinedRegion"); } else if (space_id >= ACPI_NUM_PREDEFINED_REGIONS) { - return ("invalid_space_id"); + return ("InvalidSpaceId"); } return (ACPI_CAST_PTR(char, acpi_gbl_region_types[space_id])); @@ -519,7 +495,7 @@ char *acpi_ut_get_event_name(u32 event_id) { if (event_id > ACPI_EVENT_MAX) { - return ("invalid_event_iD"); + return ("InvalidEventID"); } return (ACPI_CAST_PTR(char, acpi_gbl_event_types[event_id])); @@ -774,7 +750,7 @@ void acpi_ut_init_globals(void) acpi_status status; u32 i; - ACPI_FUNCTION_TRACE("ut_init_globals"); + ACPI_FUNCTION_TRACE(ut_init_globals); /* Create all memory caches */ @@ -785,7 +761,7 @@ void acpi_ut_init_globals(void) /* ACPI table structure */ - for (i = 0; i < NUM_ACPI_TABLE_TYPES; i++) { + for (i = 0; i < (ACPI_TABLE_ID_MAX + 1); i++) { acpi_gbl_table_lists[i].next = NULL; acpi_gbl_table_lists[i].count = 0; } diff --git a/drivers/acpi/utilities/utinit.c b/drivers/acpi/utilities/utinit.c index 7538b165b6e5..c65747d3c880 100644 --- a/drivers/acpi/utilities/utinit.c +++ b/drivers/acpi/utilities/utinit.c @@ -176,7 +176,7 @@ static void acpi_ut_terminate(void) struct acpi_gpe_xrupt_info *gpe_xrupt_info; struct acpi_gpe_xrupt_info *next_gpe_xrupt_info; - ACPI_FUNCTION_TRACE("ut_terminate"); + ACPI_FUNCTION_TRACE(ut_terminate); /* Free global tables, etc. */ /* Free global GPE blocks and related info structures */ @@ -216,7 +216,7 @@ static void acpi_ut_terminate(void) void acpi_ut_subsystem_shutdown(void) { - ACPI_FUNCTION_TRACE("ut_subsystem_shutdown"); + ACPI_FUNCTION_TRACE(ut_subsystem_shutdown); /* Just exit if subsystem is already shutdown */ diff --git a/drivers/acpi/utilities/utmath.c b/drivers/acpi/utilities/utmath.c index 4a3360484e72..19d74bedce27 100644 --- a/drivers/acpi/utilities/utmath.c +++ b/drivers/acpi/utilities/utmath.c @@ -77,7 +77,7 @@ acpi_ut_short_divide(acpi_integer dividend, union uint64_overlay quotient; u32 remainder32; - ACPI_FUNCTION_TRACE("ut_short_divide"); + ACPI_FUNCTION_TRACE(ut_short_divide); /* Always check for a zero divisor */ @@ -139,7 +139,7 @@ acpi_ut_divide(acpi_integer in_dividend, union uint64_overlay partial2; union uint64_overlay partial3; - ACPI_FUNCTION_TRACE("ut_divide"); + ACPI_FUNCTION_TRACE(ut_divide); /* Always check for a zero divisor */ @@ -261,7 +261,7 @@ acpi_ut_short_divide(acpi_integer in_dividend, acpi_integer * out_quotient, u32 * out_remainder) { - ACPI_FUNCTION_TRACE("ut_short_divide"); + ACPI_FUNCTION_TRACE(ut_short_divide); /* Always check for a zero divisor */ @@ -287,7 +287,7 @@ acpi_ut_divide(acpi_integer in_dividend, acpi_integer in_divisor, acpi_integer * out_quotient, acpi_integer * out_remainder) { - ACPI_FUNCTION_TRACE("ut_divide"); + ACPI_FUNCTION_TRACE(ut_divide); /* Always check for a zero divisor */ diff --git a/drivers/acpi/utilities/utmisc.c b/drivers/acpi/utilities/utmisc.c index 4623d7e215d3..874467117cec 100644 --- a/drivers/acpi/utilities/utmisc.c +++ b/drivers/acpi/utilities/utmisc.c @@ -95,7 +95,7 @@ acpi_status acpi_ut_allocate_owner_id(acpi_owner_id * owner_id) acpi_native_uint k; acpi_status status; - ACPI_FUNCTION_TRACE("ut_allocate_owner_id"); + ACPI_FUNCTION_TRACE(ut_allocate_owner_id); /* Guard against multiple allocations of ID to the same location */ @@ -152,7 +152,7 @@ acpi_status acpi_ut_allocate_owner_id(acpi_owner_id * owner_id) (acpi_owner_id) ((k + 1) + ACPI_MUL_32(j)); ACPI_DEBUG_PRINT((ACPI_DB_VALUES, - "Allocated owner_id: %2.2X\n", + "Allocated OwnerId: %2.2X\n", (unsigned int)*owner_id)); goto exit; } @@ -173,7 +173,7 @@ acpi_status acpi_ut_allocate_owner_id(acpi_owner_id * owner_id) */ status = AE_OWNER_ID_LIMIT; ACPI_ERROR((AE_INFO, - "Could not allocate new owner_id (255 max), AE_OWNER_ID_LIMIT")); + "Could not allocate new OwnerId (255 max), AE_OWNER_ID_LIMIT")); exit: (void)acpi_ut_release_mutex(ACPI_MTX_CACHES); @@ -201,7 +201,7 @@ void acpi_ut_release_owner_id(acpi_owner_id * owner_id_ptr) acpi_native_uint index; u32 bit; - ACPI_FUNCTION_TRACE_U32("ut_release_owner_id", owner_id); + ACPI_FUNCTION_TRACE_U32(ut_release_owner_id, owner_id); /* Always clear the input owner_id (zero is an invalid ID) */ @@ -210,7 +210,7 @@ void acpi_ut_release_owner_id(acpi_owner_id * owner_id_ptr) /* Zero is not a valid owner_iD */ if (owner_id == 0) { - ACPI_ERROR((AE_INFO, "Invalid owner_id: %2.2X", owner_id)); + ACPI_ERROR((AE_INFO, "Invalid OwnerId: %2.2X", owner_id)); return_VOID; } @@ -236,7 +236,7 @@ void acpi_ut_release_owner_id(acpi_owner_id * owner_id_ptr) acpi_gbl_owner_id_mask[index] ^= bit; } else { ACPI_ERROR((AE_INFO, - "Release of non-allocated owner_id: %2.2X", + "Release of non-allocated OwnerId: %2.2X", owner_id + 1)); } @@ -618,7 +618,7 @@ acpi_ut_strtoul64(char *string, u32 base, acpi_integer * ret_integer) acpi_integer return_value = 0; acpi_integer quotient; - ACPI_FUNCTION_TRACE("ut_stroul64"); + ACPI_FUNCTION_TRACE(ut_stroul64); if ((!string) || !(*string)) { goto error_exit; @@ -794,7 +794,7 @@ acpi_ut_walk_package_tree(union acpi_operand_object * source_object, u32 this_index; union acpi_operand_object *this_source_obj; - ACPI_FUNCTION_TRACE("ut_walk_package_tree"); + ACPI_FUNCTION_TRACE(ut_walk_package_tree); state = acpi_ut_create_pkg_state(source_object, target_object, 0); if (!state) { diff --git a/drivers/acpi/utilities/utmutex.c b/drivers/acpi/utilities/utmutex.c index 0ac6700a45f8..b851f7be5d58 100644 --- a/drivers/acpi/utilities/utmutex.c +++ b/drivers/acpi/utilities/utmutex.c @@ -68,7 +68,7 @@ acpi_status acpi_ut_mutex_initialize(void) u32 i; acpi_status status; - ACPI_FUNCTION_TRACE("ut_mutex_initialize"); + ACPI_FUNCTION_TRACE(ut_mutex_initialize); /* * Create each of the predefined mutex objects @@ -100,7 +100,7 @@ void acpi_ut_mutex_terminate(void) { u32 i; - ACPI_FUNCTION_TRACE("ut_mutex_terminate"); + ACPI_FUNCTION_TRACE(ut_mutex_terminate); /* * Delete each predefined mutex object @@ -129,7 +129,7 @@ static acpi_status acpi_ut_create_mutex(acpi_mutex_handle mutex_id) { acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE_U32("ut_create_mutex", mutex_id); + ACPI_FUNCTION_TRACE_U32(ut_create_mutex, mutex_id); if (mutex_id > MAX_MUTEX) { return_ACPI_STATUS(AE_BAD_PARAMETER); @@ -163,7 +163,7 @@ static acpi_status acpi_ut_delete_mutex(acpi_mutex_handle mutex_id) { acpi_status status; - ACPI_FUNCTION_TRACE_U32("ut_delete_mutex", mutex_id); + ACPI_FUNCTION_TRACE_U32(ut_delete_mutex, mutex_id); if (mutex_id > MAX_MUTEX) { return_ACPI_STATUS(AE_BAD_PARAMETER); @@ -194,7 +194,7 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id) acpi_status status; acpi_thread_id this_thread_id; - ACPI_FUNCTION_NAME("ut_acquire_mutex"); + ACPI_FUNCTION_NAME(ut_acquire_mutex); if (mutex_id > MAX_MUTEX) { return (AE_BAD_PARAMETER); @@ -277,7 +277,7 @@ acpi_status acpi_ut_release_mutex(acpi_mutex_handle mutex_id) acpi_status status; acpi_thread_id this_thread_id; - ACPI_FUNCTION_NAME("ut_release_mutex"); + ACPI_FUNCTION_NAME(ut_release_mutex); this_thread_id = acpi_os_get_thread_id(); ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, diff --git a/drivers/acpi/utilities/utobject.c b/drivers/acpi/utilities/utobject.c index 8e3dcbd23f5d..ba7d8ac702df 100644 --- a/drivers/acpi/utilities/utobject.c +++ b/drivers/acpi/utilities/utobject.c @@ -92,7 +92,7 @@ union acpi_operand_object *acpi_ut_create_internal_object_dbg(char *module_name, union acpi_operand_object *object; union acpi_operand_object *second_object; - ACPI_FUNCTION_TRACE_STR("ut_create_internal_object_dbg", + ACPI_FUNCTION_TRACE_STR(ut_create_internal_object_dbg, acpi_ut_get_type_name(type)); /* Allocate the raw object descriptor */ @@ -161,7 +161,7 @@ union acpi_operand_object *acpi_ut_create_buffer_object(acpi_size buffer_size) union acpi_operand_object *buffer_desc; u8 *buffer = NULL; - ACPI_FUNCTION_TRACE_U32("ut_create_buffer_object", buffer_size); + ACPI_FUNCTION_TRACE_U32(ut_create_buffer_object, buffer_size); /* Create a new Buffer object */ @@ -215,7 +215,7 @@ union acpi_operand_object *acpi_ut_create_string_object(acpi_size string_size) union acpi_operand_object *string_desc; char *string; - ACPI_FUNCTION_TRACE_U32("ut_create_string_object", string_size); + ACPI_FUNCTION_TRACE_U32(ut_create_string_object, string_size); /* Create a new String object */ @@ -261,7 +261,7 @@ union acpi_operand_object *acpi_ut_create_string_object(acpi_size string_size) u8 acpi_ut_valid_internal_object(void *object) { - ACPI_FUNCTION_NAME("ut_valid_internal_object"); + ACPI_FUNCTION_NAME(ut_valid_internal_object); /* Check for a null pointer */ @@ -309,7 +309,7 @@ void *acpi_ut_allocate_object_desc_dbg(char *module_name, { union acpi_operand_object *object; - ACPI_FUNCTION_TRACE("ut_allocate_object_desc_dbg"); + ACPI_FUNCTION_TRACE(ut_allocate_object_desc_dbg); object = acpi_os_acquire_object(acpi_gbl_operand_cache); if (!object) { @@ -344,7 +344,7 @@ void *acpi_ut_allocate_object_desc_dbg(char *module_name, void acpi_ut_delete_object_desc(union acpi_operand_object *object) { - ACPI_FUNCTION_TRACE_PTR("ut_delete_object_desc", object); + ACPI_FUNCTION_TRACE_PTR(ut_delete_object_desc, object); /* Object must be an union acpi_operand_object */ @@ -383,7 +383,7 @@ acpi_ut_get_simple_object_size(union acpi_operand_object *internal_object, acpi_size length; acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE_PTR("ut_get_simple_object_size", internal_object); + ACPI_FUNCTION_TRACE_PTR(ut_get_simple_object_size, internal_object); /* * Handle a null object (Could be a uninitialized package @@ -562,7 +562,7 @@ acpi_ut_get_package_object_size(union acpi_operand_object *internal_object, acpi_status status; struct acpi_pkg_info info; - ACPI_FUNCTION_TRACE_PTR("ut_get_package_object_size", internal_object); + ACPI_FUNCTION_TRACE_PTR(ut_get_package_object_size, internal_object); info.length = 0; info.object_space = 0; diff --git a/drivers/acpi/utilities/utresrc.c b/drivers/acpi/utilities/utresrc.c index 1e680794c6df..5a2de92831d3 100644 --- a/drivers/acpi/utilities/utresrc.c +++ b/drivers/acpi/utilities/utresrc.c @@ -45,113 +45,113 @@ #include #define _COMPONENT ACPI_UTILITIES -ACPI_MODULE_NAME("utmisc") +ACPI_MODULE_NAME("utresrc") #if defined(ACPI_DISASSEMBLER) || defined (ACPI_DEBUGGER) /* * Strings used to decode resource descriptors. * Used by both the disasssembler and the debugger resource dump routines */ -const char *acpi_gbl_BMdecode[2] = { - "not_bus_master", - "bus_master" +const char *acpi_gbl_bm_decode[] = { + "NotBusMaster", + "BusMaster" }; -const char *acpi_gbl_config_decode[4] = { +const char *acpi_gbl_config_decode[] = { "0 - Good Configuration", "1 - Acceptable Configuration", "2 - Suboptimal Configuration", "3 - ***Invalid Configuration***", }; -const char *acpi_gbl_consume_decode[2] = { - "resource_producer", - "resource_consumer" +const char *acpi_gbl_consume_decode[] = { + "ResourceProducer", + "ResourceConsumer" }; -const char *acpi_gbl_DECdecode[2] = { - "pos_decode", - "sub_decode" +const char *acpi_gbl_dec_decode[] = { + "PosDecode", + "SubDecode" }; -const char *acpi_gbl_HEdecode[2] = { +const char *acpi_gbl_he_decode[] = { "Level", "Edge" }; -const char *acpi_gbl_io_decode[2] = { +const char *acpi_gbl_io_decode[] = { "Decode10", "Decode16" }; -const char *acpi_gbl_LLdecode[2] = { - "active_high", - "active_low" +const char *acpi_gbl_ll_decode[] = { + "ActiveHigh", + "ActiveLow" }; -const char *acpi_gbl_max_decode[2] = { - "max_not_fixed", - "max_fixed" +const char *acpi_gbl_max_decode[] = { + "MaxNotFixed", + "MaxFixed" }; -const char *acpi_gbl_MEMdecode[4] = { - "non_cacheable", +const char *acpi_gbl_mem_decode[] = { + "NonCacheable", "Cacheable", - "write_combining", + "WriteCombining", "Prefetchable" }; -const char *acpi_gbl_min_decode[2] = { - "min_not_fixed", - "min_fixed" +const char *acpi_gbl_min_decode[] = { + "MinNotFixed", + "MinFixed" }; -const char *acpi_gbl_MTPdecode[4] = { - "address_range_memory", - "address_range_reserved", - "address_range_aCPI", - "address_range_nVS" +const char *acpi_gbl_mtp_decode[] = { + "AddressRangeMemory", + "AddressRangeReserved", + "AddressRangeACPI", + "AddressRangeNVS" }; -const char *acpi_gbl_RNGdecode[4] = { - "invalid_ranges", - "non_iSAonly_ranges", - "ISAonly_ranges", - "entire_range" +const char *acpi_gbl_rng_decode[] = { + "InvalidRanges", + "NonISAOnlyRanges", + "ISAOnlyRanges", + "EntireRange" }; -const char *acpi_gbl_RWdecode[2] = { - "read_only", - "read_write" +const char *acpi_gbl_rw_decode[] = { + "ReadOnly", + "ReadWrite" }; -const char *acpi_gbl_SHRdecode[2] = { +const char *acpi_gbl_shr_decode[] = { "Exclusive", "Shared" }; -const char *acpi_gbl_SIZdecode[4] = { +const char *acpi_gbl_siz_decode[] = { "Transfer8", "Transfer8_16", "Transfer16", - "invalid_size" + "InvalidSize" }; -const char *acpi_gbl_TRSdecode[2] = { - "dense_translation", - "sparse_translation" +const char *acpi_gbl_trs_decode[] = { + "DenseTranslation", + "SparseTranslation" }; -const char *acpi_gbl_TTPdecode[2] = { - "type_static", - "type_translation" +const char *acpi_gbl_ttp_decode[] = { + "TypeStatic", + "TypeTranslation" }; -const char *acpi_gbl_TYPdecode[4] = { +const char *acpi_gbl_typ_decode[] = { "Compatibility", - "type_a", - "type_b", - "type_f" + "TypeA", + "TypeB", + "TypeF" }; #endif @@ -266,7 +266,7 @@ acpi_ut_walk_aml_resources(u8 * aml, u32 length; u32 offset = 0; - ACPI_FUNCTION_TRACE("ut_walk_aml_resources"); + ACPI_FUNCTION_TRACE(ut_walk_aml_resources); /* The absolute minimum resource template is one end_tag descriptor */ @@ -597,7 +597,7 @@ acpi_ut_get_resource_end_tag(union acpi_operand_object * obj_desc, { acpi_status status; - ACPI_FUNCTION_TRACE("ut_get_resource_end_tag"); + ACPI_FUNCTION_TRACE(ut_get_resource_end_tag); /* Allow a buffer length of zero */ diff --git a/drivers/acpi/utilities/utstate.c b/drivers/acpi/utilities/utstate.c index aec5034cd978..0f5c5bb5deff 100644 --- a/drivers/acpi/utilities/utstate.c +++ b/drivers/acpi/utilities/utstate.c @@ -96,7 +96,7 @@ void acpi_ut_push_generic_state(union acpi_generic_state **list_head, union acpi_generic_state *state) { - ACPI_FUNCTION_TRACE("ut_push_generic_state"); + ACPI_FUNCTION_TRACE(ut_push_generic_state); /* Push the state object onto the front of the list (stack) */ @@ -123,7 +123,7 @@ union acpi_generic_state *acpi_ut_pop_generic_state(union acpi_generic_state { union acpi_generic_state *state; - ACPI_FUNCTION_TRACE("ut_pop_generic_state"); + ACPI_FUNCTION_TRACE(ut_pop_generic_state); /* Remove the state object at the head of the list (stack) */ @@ -185,7 +185,7 @@ struct acpi_thread_state *acpi_ut_create_thread_state(void) { union acpi_generic_state *state; - ACPI_FUNCTION_TRACE("ut_create_thread_state"); + ACPI_FUNCTION_TRACE(ut_create_thread_state); /* Create the generic state object */ @@ -222,7 +222,7 @@ union acpi_generic_state *acpi_ut_create_update_state(union acpi_operand_object { union acpi_generic_state *state; - ACPI_FUNCTION_TRACE_PTR("ut_create_update_state", object); + ACPI_FUNCTION_TRACE_PTR(ut_create_update_state, object); /* Create the generic state object */ @@ -259,7 +259,7 @@ union acpi_generic_state *acpi_ut_create_pkg_state(void *internal_object, { union acpi_generic_state *state; - ACPI_FUNCTION_TRACE_PTR("ut_create_pkg_state", internal_object); + ACPI_FUNCTION_TRACE_PTR(ut_create_pkg_state, internal_object); /* Create the generic state object */ @@ -296,7 +296,7 @@ union acpi_generic_state *acpi_ut_create_control_state(void) { union acpi_generic_state *state; - ACPI_FUNCTION_TRACE("ut_create_control_state"); + ACPI_FUNCTION_TRACE(ut_create_control_state); /* Create the generic state object */ @@ -328,7 +328,7 @@ union acpi_generic_state *acpi_ut_create_control_state(void) void acpi_ut_delete_generic_state(union acpi_generic_state *state) { - ACPI_FUNCTION_TRACE("ut_delete_generic_state"); + ACPI_FUNCTION_TRACE(ut_delete_generic_state); /* Ignore null state */ diff --git a/drivers/acpi/utilities/utxface.c b/drivers/acpi/utilities/utxface.c index ac90048a8a5b..3538f69c82a1 100644 --- a/drivers/acpi/utilities/utxface.c +++ b/drivers/acpi/utilities/utxface.c @@ -65,7 +65,7 @@ acpi_status acpi_initialize_subsystem(void) { acpi_status status; - ACPI_FUNCTION_TRACE("acpi_initialize_subsystem"); + ACPI_FUNCTION_TRACE(acpi_initialize_subsystem); ACPI_DEBUG_EXEC(acpi_ut_init_stack_ptr_trace()); @@ -125,7 +125,7 @@ acpi_status acpi_enable_subsystem(u32 flags) { acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE("acpi_enable_subsystem"); + ACPI_FUNCTION_TRACE(acpi_enable_subsystem); /* * We must initialize the hardware before we can enable ACPI. @@ -151,7 +151,7 @@ acpi_status acpi_enable_subsystem(u32 flags) status = acpi_enable(); if (ACPI_FAILURE(status)) { - ACPI_WARNING((AE_INFO, "acpi_enable failed")); + ACPI_WARNING((AE_INFO, "AcpiEnable failed")); return_ACPI_STATUS(status); } } @@ -246,7 +246,7 @@ acpi_status acpi_initialize_objects(u32 flags) { acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE("acpi_initialize_objects"); + ACPI_FUNCTION_TRACE(acpi_initialize_objects); /* * Run all _REG methods @@ -257,7 +257,7 @@ acpi_status acpi_initialize_objects(u32 flags) */ if (!(flags & ACPI_NO_ADDRESS_SPACE_INIT)) { ACPI_DEBUG_PRINT((ACPI_DB_EXEC, - "[Init] Executing _REG op_region methods\n")); + "[Init] Executing _REG OpRegion methods\n")); status = acpi_ev_initialize_op_regions(); if (ACPI_FAILURE(status)) { @@ -322,7 +322,7 @@ acpi_status acpi_terminate(void) { acpi_status status; - ACPI_FUNCTION_TRACE("acpi_terminate"); + ACPI_FUNCTION_TRACE(acpi_terminate); /* Terminate the AML Debugger if present */ @@ -400,7 +400,7 @@ acpi_status acpi_get_system_info(struct acpi_buffer * out_buffer) acpi_status status; u32 i; - ACPI_FUNCTION_TRACE("acpi_get_system_info"); + ACPI_FUNCTION_TRACE(acpi_get_system_info); /* Parameter validation */ @@ -451,8 +451,8 @@ acpi_status acpi_get_system_info(struct acpi_buffer * out_buffer) /* Current status of the ACPI tables, per table type */ - info_ptr->num_table_types = NUM_ACPI_TABLE_TYPES; - for (i = 0; i < NUM_ACPI_TABLE_TYPES; i++) { + info_ptr->num_table_types = ACPI_TABLE_ID_MAX + 1; + for (i = 0; i < (ACPI_TABLE_ID_MAX + 1); i++) { info_ptr->table_info[i].count = acpi_gbl_table_lists[i].count; } @@ -507,7 +507,7 @@ ACPI_EXPORT_SYMBOL(acpi_install_initialization_handler) ****************************************************************************/ acpi_status acpi_purge_cached_objects(void) { - ACPI_FUNCTION_TRACE("acpi_purge_cached_objects"); + ACPI_FUNCTION_TRACE(acpi_purge_cached_objects); (void)acpi_os_purge_cache(acpi_gbl_state_cache); (void)acpi_os_purge_cache(acpi_gbl_operand_cache); diff --git a/include/acpi/acconfig.h b/include/acpi/acconfig.h index b6bba7db52d9..11e72e6cdc01 100644 --- a/include/acpi/acconfig.h +++ b/include/acpi/acconfig.h @@ -63,7 +63,7 @@ /* Current ACPICA subsystem version in YYYYMMDD format */ -#define ACPI_CA_VERSION 0x20060331 +#define ACPI_CA_VERSION 0x20060421 /* * OS name, used for the _OS object. The _OS object is essentially obsolete, @@ -171,13 +171,15 @@ #define ACPI_MAX_ADDRESS_SPACE 255 /* Array sizes. Used for range checking also */ +#define ACPI_MAX_MATCH_OPCODE 5 +#if 0 #define ACPI_NUM_ACCESS_TYPES 6 #define ACPI_NUM_UPDATE_RULES 3 #define ACPI_NUM_LOCK_RULES 2 -#define ACPI_NUM_MATCH_OPS 6 -#define ACPI_NUM_OPCODES 256 #define ACPI_NUM_FIELD_NAMES 2 +#define ACPI_NUM_OPCODES 256 +#endif /* RSDP checksums */ @@ -188,10 +190,6 @@ #define ACPI_SMBUS_BUFFER_SIZE 34 -/* Number of strings associated with the _OSI reserved method */ - -#define ACPI_NUM_OSI_STRINGS 12 - /****************************************************************************** * * ACPI AML Debugger diff --git a/include/acpi/acdisasm.h b/include/acpi/acdisasm.h index 70b52ffa969e..6f2556582f05 100644 --- a/include/acpi/acdisasm.h +++ b/include/acpi/acdisasm.h @@ -124,12 +124,12 @@ struct acpi_resource_tag { /* Strings used for decoding flags to ASL keywords */ -extern const char *acpi_gbl_word_decode[4]; -extern const char *acpi_gbl_irq_decode[2]; -extern const char *acpi_gbl_lock_rule[ACPI_NUM_LOCK_RULES]; -extern const char *acpi_gbl_access_types[ACPI_NUM_ACCESS_TYPES]; -extern const char *acpi_gbl_update_rules[ACPI_NUM_UPDATE_RULES]; -extern const char *acpi_gbl_match_ops[ACPI_NUM_MATCH_OPS]; +extern const char *acpi_gbl_word_decode[]; +extern const char *acpi_gbl_irq_decode[]; +extern const char *acpi_gbl_lock_rule[]; +extern const char *acpi_gbl_access_types[]; +extern const char *acpi_gbl_update_rules[]; +extern const char *acpi_gbl_match_ops[]; extern struct acpi_dmtable_info acpi_dm_table_info_asf0[]; extern struct acpi_dmtable_info acpi_dm_table_info_asf1[]; diff --git a/include/acpi/acdispat.h b/include/acpi/acdispat.h index c41a926ff317..fcf03eb41374 100644 --- a/include/acpi/acdispat.h +++ b/include/acpi/acdispat.h @@ -194,7 +194,9 @@ acpi_status acpi_ds_restart_control_method(struct acpi_walk_state *walk_state, union acpi_operand_object *return_desc); -void acpi_ds_terminate_control_method(struct acpi_walk_state *walk_state); +void +acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, + struct acpi_walk_state *walk_state); acpi_status acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node, diff --git a/include/acpi/acexcep.h b/include/acpi/acexcep.h index dc768aa580e4..797ca1ea5214 100644 --- a/include/acpi/acexcep.h +++ b/include/acpi/acexcep.h @@ -160,8 +160,9 @@ #define AE_AML_BAD_RESOURCE_VALUE (acpi_status) (0x001F | AE_CODE_AML) #define AE_AML_CIRCULAR_REFERENCE (acpi_status) (0x0020 | AE_CODE_AML) #define AE_AML_BAD_RESOURCE_LENGTH (acpi_status) (0x0021 | AE_CODE_AML) +#define AE_AML_ILLEGAL_ADDRESS (acpi_status) (0x0022 | AE_CODE_AML) -#define AE_CODE_AML_MAX 0x0021 +#define AE_CODE_AML_MAX 0x0022 /* * Internal exceptions used for control @@ -275,7 +276,8 @@ char const *acpi_gbl_exception_names_aml[] = { "AE_AML_NO_RESOURCE_END_TAG", "AE_AML_BAD_RESOURCE_VALUE", "AE_AML_CIRCULAR_REFERENCE", - "AE_AML_BAD_RESOURCE_LENGTH" + "AE_AML_BAD_RESOURCE_LENGTH", + "AE_AML_ILLEGAL_ADDRESS" }; char const *acpi_gbl_exception_names_ctrl[] = { diff --git a/include/acpi/acglobal.h b/include/acpi/acglobal.h index 17c5b462676e..5f2daf402ee1 100644 --- a/include/acpi/acglobal.h +++ b/include/acpi/acglobal.h @@ -115,7 +115,7 @@ ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_enable_interpreter_slack, FALSE); * Automatically serialize ALL control methods? Default is FALSE, meaning * to use the Serialized/not_serialized method flags on a per method basis. * Only change this if the ASL code is poorly written and cannot handle - * reentrancy even though methods are marked "not_serialized". + * reentrancy even though methods are marked "NotSerialized". */ ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_all_methods_serialized, FALSE); @@ -178,8 +178,8 @@ ACPI_EXTERN u8 acpi_gbl_integer_nybble_width; /* * ACPI Table info arrays */ -extern struct acpi_table_list acpi_gbl_table_lists[NUM_ACPI_TABLE_TYPES]; -extern struct acpi_table_support acpi_gbl_table_data[NUM_ACPI_TABLE_TYPES]; +extern struct acpi_table_list acpi_gbl_table_lists[ACPI_TABLE_ID_MAX + 1]; +extern struct acpi_table_support acpi_gbl_table_data[ACPI_TABLE_ID_MAX + 1]; /* * Predefined mutex objects. This array contains the @@ -246,7 +246,6 @@ extern const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT]; extern const char *acpi_gbl_highest_dstate_names[4]; extern const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES]; extern const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS]; -extern const char *acpi_gbl_valid_osi_strings[ACPI_NUM_OSI_STRINGS]; /***************************************************************************** * diff --git a/include/acpi/aclocal.h b/include/acpi/aclocal.h index 99785bae59b3..06a9bd0a9ce9 100644 --- a/include/acpi/aclocal.h +++ b/include/acpi/aclocal.h @@ -105,14 +105,14 @@ static char *acpi_gbl_mutex_names[] = { "ACPI_MTX_Parser", "ACPI_MTX_Dispatcher", "ACPI_MTX_Tables", - "ACPI_MTX_op_regions", + "ACPI_MTX_OpRegions", "ACPI_MTX_Namespace", "ACPI_MTX_Events", "ACPI_MTX_Hardware", "ACPI_MTX_Caches", "ACPI_MTX_Memory", - "ACPI_MTX_debug_cmd_complete", - "ACPI_MTX_debug_cmd_ready", + "ACPI_MTX_DebugCmdComplete", + "ACPI_MTX_DebugCmdReady", }; #endif @@ -205,9 +205,12 @@ struct acpi_namespace_node { #define ANOBJ_DATA_WIDTH_32 0x02 /* Parent table uses 32-bit math */ #define ANOBJ_METHOD_ARG 0x04 /* Node is a method argument */ #define ANOBJ_METHOD_LOCAL 0x08 /* Node is a method local */ +#define ANOBJ_SUBTREE_HAS_INI 0x10 /* Used to optimize device initialization */ + #define ANOBJ_METHOD_NO_RETVal 0x10 /* i_aSL only: Method has no return value */ #define ANOBJ_METHOD_SOME_NO_RETVal 0x20 /* i_aSL only: Method has at least one return value */ #define ANOBJ_IS_BIT_OFFSet 0x40 /* i_aSL only: Reference is a bit offset */ +#define ANOBJ_IS_REFERENCed 0x80 /* i_aSL only: Object was referenced */ /* * ACPI Table Descriptor. One per ACPI table diff --git a/include/acpi/acmacros.h b/include/acpi/acmacros.h index 60ceed4c81bf..b7547aba91b9 100644 --- a/include/acpi/acmacros.h +++ b/include/acpi/acmacros.h @@ -56,6 +56,10 @@ #define ACPI_CLEAR_BIT(target,bit) ((target) &= ~(bit)) #define ACPI_MIN(a,b) (((a)<(b))?(a):(b)) +/* Size calculation */ + +#define ACPI_ARRAY_LENGTH(x) (sizeof(x) / sizeof((x)[0])) + #if ACPI_MACHINE_WIDTH == 16 /* @@ -143,7 +147,7 @@ #ifndef ACPI_MISALIGNMENT_NOT_SUPPORTED #define ACPI_COMPARE_NAME(a,b) (*ACPI_CAST_PTR (u32,(a)) == *ACPI_CAST_PTR (u32,(b))) #else -#define ACPI_COMPARE_NAME(a,b) (!ACPI_STRNCMP (ACPI_CAST_PTR (char,(a)), ACPI_CAST_PTR (char,(b)), 4)) +#define ACPI_COMPARE_NAME(a,b) (!ACPI_STRNCMP (ACPI_CAST_PTR (char,(a)), ACPI_CAST_PTR (char,(b)), ACPI_NAME_SIZE)) #endif /* @@ -522,12 +526,12 @@ #define ACPI_GET_FUNCTION_NAME _acpi_function_name /* * The Name parameter should be the procedure name as a quoted string. - * This is declared as a local string ("my_function_name") so that it can + * This is declared as a local string ("MyFunctionName") so that it can * be also used by the function exit macros below. * Note: (const char) is used to be compatible with the debug interfaces * and macros such as __FUNCTION__. */ -#define ACPI_FUNCTION_NAME(name) const char *_acpi_function_name = name; +#define ACPI_FUNCTION_NAME(name) const char *_acpi_function_name = #name; #else /* Compiler supports __FUNCTION__ (or equivalent) -- Ignore this macro */ @@ -551,7 +555,7 @@ * WARNING: These macros include a return statement. This is usually considered * bad form, but having a separate exit macro is very ugly and difficult to maintain. * One of the FUNCTION_TRACE macros above must be used in conjunction with these macros - * so that "_acpi_function_name" is defined. + * so that "_AcpiFunctionName" is defined. * * Note: the DO_WHILE0 macro is used to prevent some compilers from complaining * about these constructs. diff --git a/include/acpi/acobject.h b/include/acpi/acobject.h index d9442d346b9b..1747d94084d8 100644 --- a/include/acpi/acobject.h +++ b/include/acpi/acobject.h @@ -89,6 +89,7 @@ #define AOPOBJ_OBJECT_INITIALIZED 0x08 #define AOPOBJ_SETUP_COMPLETE 0x10 #define AOPOBJ_SINGLE_DATUM 0x20 +#define AOPOBJ_INVALID 0x40 /* Used if host OS won't allow an op_region address */ /****************************************************************************** * @@ -248,7 +249,7 @@ struct acpi_object_bank_field { struct acpi_object_index_field { ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO /* - * No "region_obj" pointer needed since the Index and Data registers + * No "RegionObj" pointer needed since the Index and Data registers * are each field definitions unto themselves. */ union acpi_operand_object *index_obj; /* Index register */ diff --git a/include/acpi/acoutput.h b/include/acpi/acoutput.h index 621fe23bb4fb..8d5039d0b430 100644 --- a/include/acpi/acoutput.h +++ b/include/acpi/acoutput.h @@ -50,7 +50,7 @@ * component basis and a per-exception-type basis. */ -/* Component IDs are used in the global "debug_layer" */ +/* Component IDs are used in the global "DebugLayer" */ #define ACPI_UTILITIES 0x00000001 #define ACPI_HARDWARE 0x00000002 @@ -121,7 +121,7 @@ #define ACPI_LV_INTERRUPTS 0x08000000 #define ACPI_LV_VERBOSITY3 0x0F000000 | ACPI_LV_VERBOSITY2 -/* Exceptionally verbose output -- also used in the global "debug_level" */ +/* Exceptionally verbose output -- also used in the global "DebugLevel" */ #define ACPI_LV_AML_DISASSEMBLE 0x10000000 #define ACPI_LV_VERBOSE_INFO 0x20000000 @@ -135,7 +135,7 @@ */ #define ACPI_DEBUG_LEVEL(dl) (u32) dl,ACPI_DEBUG_PARAMETERS -/* Exception level -- used in the global "debug_level" */ +/* Exception level -- used in the global "DebugLevel" */ #define ACPI_DB_INIT ACPI_DEBUG_LEVEL (ACPI_LV_INIT) #define ACPI_DB_DEBUG_OBJECT ACPI_DEBUG_LEVEL (ACPI_LV_DEBUG_OBJECT) @@ -150,7 +150,7 @@ #define ACPI_DB_ERROR ACPI_DEBUG_LEVEL (ACPI_LV_ERROR) #define ACPI_DB_WARN ACPI_DEBUG_LEVEL (ACPI_LV_WARN) -/* Trace level -- also used in the global "debug_level" */ +/* Trace level -- also used in the global "DebugLevel" */ #define ACPI_DB_INIT_NAMES ACPI_DEBUG_LEVEL (ACPI_LV_INIT_NAMES) #define ACPI_DB_THREADS ACPI_DEBUG_LEVEL (ACPI_LV_THREADS) diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h index 42307d948c1b..a5264fac696e 100644 --- a/include/acpi/acpiosxf.h +++ b/include/acpi/acpiosxf.h @@ -212,6 +212,13 @@ acpi_os_derive_pci_id(acpi_handle rhandle, /* * Miscellaneous */ + +acpi_status acpi_os_validate_interface(char *interface); + +acpi_status +acpi_os_validate_address(u8 space_id, + acpi_physical_address address, acpi_size length); + u8 acpi_os_readable(void *pointer, acpi_size length); #ifdef ACPI_FUTURE_USAGE diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index 091dd2567172..6d4e743a753b 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -490,15 +490,15 @@ typedef u64 acpi_integer; */ typedef u32 acpi_table_type; -#define ACPI_TABLE_RSDP (acpi_table_type) 0 -#define ACPI_TABLE_DSDT (acpi_table_type) 1 -#define ACPI_TABLE_FADT (acpi_table_type) 2 -#define ACPI_TABLE_FACS (acpi_table_type) 3 -#define ACPI_TABLE_PSDT (acpi_table_type) 4 -#define ACPI_TABLE_SSDT (acpi_table_type) 5 -#define ACPI_TABLE_XSDT (acpi_table_type) 6 -#define ACPI_TABLE_MAX 6 -#define NUM_ACPI_TABLE_TYPES (ACPI_TABLE_MAX+1) +#define ACPI_TABLE_ID_RSDP (acpi_table_type) 0 +#define ACPI_TABLE_ID_DSDT (acpi_table_type) 1 +#define ACPI_TABLE_ID_FADT (acpi_table_type) 2 +#define ACPI_TABLE_ID_FACS (acpi_table_type) 3 +#define ACPI_TABLE_ID_PSDT (acpi_table_type) 4 +#define ACPI_TABLE_ID_SSDT (acpi_table_type) 5 +#define ACPI_TABLE_ID_XSDT (acpi_table_type) 6 +#define ACPI_TABLE_ID_MAX 6 +#define ACPI_NUM_TABLE_TYPES (ACPI_TABLE_ID_MAX+1) /* * Types associated with ACPI names and objects. The first group of @@ -829,7 +829,7 @@ struct acpi_system_info { u32 debug_level; u32 debug_layer; u32 num_table_types; - struct acpi_table_info table_info[NUM_ACPI_TABLE_TYPES]; + struct acpi_table_info table_info[ACPI_TABLE_ID_MAX + 1]; }; /* @@ -924,7 +924,8 @@ struct acpi_compatible_id_list { #define ACPI_STA_DEVICE_PRESENT 0x01 #define ACPI_STA_DEVICE_ENABLED 0x02 #define ACPI_STA_DEVICE_UI 0x04 -#define ACPI_STA_DEVICE_OK 0x08 +#define ACPI_STA_DEVICE_FUNCTIONING 0x08 +#define ACPI_STA_DEVICE_OK 0x08 /* Synonym */ #define ACPI_STA_BATTERY_PRESENT 0x10 #define ACPI_COMMON_OBJ_INFO \ diff --git a/include/acpi/acutils.h b/include/acpi/acutils.h index 115b0cbc370f..ba039ea1a057 100644 --- a/include/acpi/acutils.h +++ b/include/acpi/acutils.h @@ -50,24 +50,24 @@ extern const u8 acpi_gbl_resource_aml_sizes[]; #if defined(ACPI_DISASSEMBLER) || defined (ACPI_DEBUGGER) -extern const char *acpi_gbl_BMdecode[2]; -extern const char *acpi_gbl_config_decode[4]; -extern const char *acpi_gbl_consume_decode[2]; -extern const char *acpi_gbl_DECdecode[2]; -extern const char *acpi_gbl_HEdecode[2]; -extern const char *acpi_gbl_io_decode[2]; -extern const char *acpi_gbl_LLdecode[2]; -extern const char *acpi_gbl_max_decode[2]; -extern const char *acpi_gbl_MEMdecode[4]; -extern const char *acpi_gbl_min_decode[2]; -extern const char *acpi_gbl_MTPdecode[4]; -extern const char *acpi_gbl_RNGdecode[4]; -extern const char *acpi_gbl_RWdecode[2]; -extern const char *acpi_gbl_SHRdecode[2]; -extern const char *acpi_gbl_SIZdecode[4]; -extern const char *acpi_gbl_TRSdecode[2]; -extern const char *acpi_gbl_TTPdecode[2]; -extern const char *acpi_gbl_TYPdecode[4]; +extern const char *acpi_gbl_bm_decode[]; +extern const char *acpi_gbl_config_decode[]; +extern const char *acpi_gbl_consume_decode[]; +extern const char *acpi_gbl_dec_decode[]; +extern const char *acpi_gbl_he_decode[]; +extern const char *acpi_gbl_io_decode[]; +extern const char *acpi_gbl_ll_decode[]; +extern const char *acpi_gbl_max_decode[]; +extern const char *acpi_gbl_mem_decode[]; +extern const char *acpi_gbl_min_decode[]; +extern const char *acpi_gbl_mtp_decode[]; +extern const char *acpi_gbl_rng_decode[]; +extern const char *acpi_gbl_rw_decode[]; +extern const char *acpi_gbl_shr_decode[]; +extern const char *acpi_gbl_siz_decode[]; +extern const char *acpi_gbl_trs_decode[]; +extern const char *acpi_gbl_ttp_decode[]; +extern const char *acpi_gbl_typ_decode[]; #endif /* Types for Resource descriptor entries */ @@ -81,7 +81,7 @@ typedef acpi_status(*acpi_walk_aml_callback) (u8 * aml, u32 length, u32 offset, - u8 resource_index, void *context); + u8 resource_index, void **context); typedef acpi_status(*acpi_pkg_callback) (u8 object_type, diff --git a/include/acpi/platform/acenv.h b/include/acpi/platform/acenv.h index fd189d425c78..453a469fd397 100644 --- a/include/acpi/platform/acenv.h +++ b/include/acpi/platform/acenv.h @@ -49,16 +49,18 @@ */ #ifdef ACPI_LIBRARY +/* + * Note: The non-debug version of the acpi_library does not contain any + * debug support, for minimimal size. The debug version uses ACPI_FULL_DEBUG + */ #define ACPI_USE_LOCAL_CACHE #endif -#ifdef ACPI_DUMP_APP -#ifndef MSDOS +#ifdef ACPI_ASL_COMPILER #define ACPI_DEBUG_OUTPUT -#endif #define ACPI_APPLICATION #define ACPI_DISASSEMBLER -#define ACPI_NO_METHOD_EXECUTION +#define ACPI_CONSTANT_EVAL_ONLY #define ACPI_LARGE_NAMESPACE_NODE #define ACPI_DATA_TABLE_DISASSEMBLY #endif @@ -66,19 +68,20 @@ #ifdef ACPI_EXEC_APP #undef DEBUGGER_THREADING #define DEBUGGER_THREADING DEBUGGER_SINGLE_THREADED -#define ACPI_DEBUG_OUTPUT +#define ACPI_FULL_DEBUG #define ACPI_APPLICATION #define ACPI_DEBUGGER -#define ACPI_DISASSEMBLER #define ACPI_MUTEX_DEBUG #define ACPI_DBG_TRACK_ALLOCATIONS #endif -#ifdef ACPI_ASL_COMPILER +#ifdef ACPI_DASM_APP +#ifndef MSDOS #define ACPI_DEBUG_OUTPUT +#endif #define ACPI_APPLICATION #define ACPI_DISASSEMBLER -#define ACPI_CONSTANT_EVAL_ONLY +#define ACPI_NO_METHOD_EXECUTION #define ACPI_LARGE_NAMESPACE_NODE #define ACPI_DATA_TABLE_DISASSEMBLY #endif @@ -88,6 +91,12 @@ #define ACPI_USE_LOCAL_CACHE #endif +#ifdef ACPI_FULL_DEBUG +#define ACPI_DEBUGGER +#define ACPI_DEBUG_OUTPUT +#define ACPI_DISASSEMBLER +#endif + /* * Environment configuration. The purpose of this file is to interface to the * local generation environment. -- cgit v1.2.3 From 958dd242b691f64ab4632b4903dbb1e16fee8269 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Fri, 12 May 2006 17:12:00 -0400 Subject: ACPI: ACPICA 20060512 Replaced the acpi_os_queue_for_execution() with a new interface named acpi_os_execute(). The major difference is that the new interface does not have a Priority parameter, this appeared to be useless and has been replaced by a Type parameter. The Type tells the OS what type of execution is being requested, such as global lock handler, notify handler, GPE handler, etc. This allows the host to queue and execute the request as appropriate for the request type, possibly using different work queues and different priorities for the various request types. This enables fixes for multithreading deadlock problems such as http://bugzilla.kernel.org/show_bug.cgi?id=5534 (Alexey Starikovskiy and Bob Moore) Fixed a possible memory leak associated with the support for the so-called "implicit return" ACPI extension. Reported by FreeBSD (Fiodor Suietov) http://bugzilla.kernel.org/show_bug.cgi?id=6514 Fixed a problem with the Load() operator where a table load from an operation region could overwrite an internal table buffer by up to 7 bytes and cause alignment faults on IPF systems. (With assistance from Luming Yu) Signed-off-by: Bob Moore Signed-off-by: Len Brown --- drivers/acpi/dispatcher/dsmethod.c | 23 +++++++++++++++------ drivers/acpi/dispatcher/dsmthdat.c | 6 +++--- drivers/acpi/dispatcher/dswload.c | 41 +++++++++++++++++++++++++++++++++----- drivers/acpi/events/evgpe.c | 8 ++++---- drivers/acpi/events/evmisc.c | 10 ++++------ drivers/acpi/events/evregion.c | 7 ++++--- drivers/acpi/executer/exconfig.c | 17 +++++++++++----- drivers/acpi/executer/exstorob.c | 2 +- drivers/acpi/namespace/nsaccess.c | 8 ++++---- drivers/acpi/namespace/nssearch.c | 7 ++++++- drivers/acpi/resources/rscalc.c | 4 ++-- drivers/acpi/resources/rscreate.c | 2 +- drivers/acpi/resources/rsutils.c | 5 +++-- drivers/acpi/tables/tbrsdt.c | 6 ++---- drivers/acpi/tables/tbxfroot.c | 16 +++++++-------- drivers/acpi/utilities/utglobal.c | 8 -------- include/acpi/acconfig.h | 2 +- include/acpi/acdisasm.h | 8 +++++++- include/acpi/acevents.h | 2 +- include/acpi/acglobal.h | 8 -------- include/acpi/aclocal.h | 14 ++++++++----- include/acpi/acmacros.h | 10 +++++----- include/acpi/acnamesp.h | 1 + include/acpi/acpiosxf.h | 19 +++++++++++------- include/acpi/actbl.h | 6 +++--- include/acpi/actypes.h | 6 +++--- include/acpi/amlcode.h | 6 ++++-- include/acpi/amlresrc.h | 19 ++++++++---------- 28 files changed, 161 insertions(+), 110 deletions(-) (limited to 'include') diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c index 651f2b68531b..e348db0e541e 100644 --- a/drivers/acpi/dispatcher/dsmethod.c +++ b/drivers/acpi/dispatcher/dsmethod.c @@ -385,6 +385,7 @@ acpi_ds_restart_control_method(struct acpi_walk_state *walk_state, union acpi_operand_object *return_desc) { acpi_status status; + int same_as_implicit_return; ACPI_FUNCTION_TRACE_PTR(ds_restart_control_method, walk_state); @@ -402,6 +403,11 @@ acpi_ds_restart_control_method(struct acpi_walk_state *walk_state, if (return_desc) { + /* Is the implicit return object the same as the return desc? */ + + same_as_implicit_return = + (walk_state->implicit_return_obj == return_desc); + /* Are we actually going to use the return value? */ if (walk_state->return_used) { @@ -422,18 +428,23 @@ acpi_ds_restart_control_method(struct acpi_walk_state *walk_state, } /* - * The following code is the - * optional support for a so-called "implicit return". Some AML code - * assumes that the last value of the method is "implicitly" returned - * to the caller. Just save the last result as the return value. + * The following code is the optional support for the so-called + * "implicit return". Some AML code assumes that the last value of the + * method is "implicitly" returned to the caller, in the absence of an + * explicit return value. + * + * Just save the last result of the method as the return value. + * * NOTE: this is optional because the ASL language does not actually * support this behavior. */ else if (!acpi_ds_do_implicit_return - (return_desc, walk_state, FALSE)) { + (return_desc, walk_state, FALSE) + || same_as_implicit_return) { /* * Delete the return value if it will not be used by the - * calling method + * calling method or remove one reference if the explicit return + * is the same as the implicit return value. */ acpi_ut_remove_reference(return_desc); } diff --git a/drivers/acpi/dispatcher/dsmthdat.c b/drivers/acpi/dispatcher/dsmthdat.c index b47c54fad86d..459160ff9058 100644 --- a/drivers/acpi/dispatcher/dsmthdat.c +++ b/drivers/acpi/dispatcher/dsmthdat.c @@ -336,7 +336,7 @@ acpi_ds_method_data_set_value(u16 opcode, * Increment ref count so object can't be deleted while installed. * NOTE: We do not copy the object in order to preserve the call by * reference semantics of ACPI Control Method invocation. - * (See ACPI specification 2.0_c) + * (See ACPI Specification 2.0_c) */ acpi_ut_add_reference(object); @@ -351,7 +351,7 @@ acpi_ds_method_data_set_value(u16 opcode, * FUNCTION: acpi_ds_method_data_get_value * * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP - * Index - which local_var or argument to get + * Index - Which local_var or argument to get * walk_state - Current walk state object * dest_desc - Where Arg or Local value is returned * @@ -459,7 +459,7 @@ acpi_ds_method_data_get_value(u16 opcode, * FUNCTION: acpi_ds_method_data_delete_value * * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP - * Index - which local_var or argument to delete + * Index - Which local_var or argument to delete * walk_state - Current walk state object * * RETURN: None diff --git a/drivers/acpi/dispatcher/dswload.c b/drivers/acpi/dispatcher/dswload.c index a8deb700cf33..35074399c617 100644 --- a/drivers/acpi/dispatcher/dswload.c +++ b/drivers/acpi/dispatcher/dswload.c @@ -178,12 +178,12 @@ acpi_ds_load1_begin_op(struct acpi_walk_state * walk_state, * Target of Scope() not found. Generate an External for it, and * insert the name into the namespace. */ - acpi_dm_add_to_external_list(path); + acpi_dm_add_to_external_list(path, ACPI_TYPE_DEVICE, 0); status = acpi_ns_lookup(walk_state->scope_info, path, object_type, ACPI_IMODE_LOAD_PASS1, ACPI_NS_SEARCH_PARENT, walk_state, - &(node)); + &node); } #endif if (ACPI_FAILURE(status)) { @@ -301,10 +301,41 @@ acpi_ds_load1_begin_op(struct acpi_walk_state * walk_state, status = acpi_ns_lookup(walk_state->scope_info, path, object_type, ACPI_IMODE_LOAD_PASS1, flags, walk_state, - &(node)); + &node); if (ACPI_FAILURE(status)) { - ACPI_ERROR_NAMESPACE(path, status); - return_ACPI_STATUS(status); + if (status == AE_ALREADY_EXISTS) { + + /* The name already exists in this scope */ + + if (node->flags & ANOBJ_IS_EXTERNAL) { + /* + * Allow one create on an object or segment that was + * previously declared External + */ + node->flags &= ~ANOBJ_IS_EXTERNAL; + node->type = (u8) object_type; + + /* Just retyped a node, probably will need to open a scope */ + + if (acpi_ns_opens_scope(object_type)) { + status = + acpi_ds_scope_stack_push + (node, object_type, + walk_state); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS + (status); + } + } + status = AE_OK; + } + } + + if (ACPI_FAILURE(status)) { + + ACPI_ERROR_NAMESPACE(path, status); + return_ACPI_STATUS(status); + } } break; } diff --git a/drivers/acpi/events/evgpe.c b/drivers/acpi/events/evgpe.c index 25fd12a29a29..aa179dc78011 100644 --- a/drivers/acpi/events/evgpe.c +++ b/drivers/acpi/events/evgpe.c @@ -489,7 +489,7 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list) * RETURN: None * * DESCRIPTION: Perform the actual execution of a GPE control method. This - * function is called from an invocation of acpi_os_queue_for_execution + * function is called from an invocation of acpi_os_exece * (and therefore does NOT execute at interrupt level) so that * the control method itself is not executed in the context of * an interrupt handler. @@ -674,9 +674,9 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number) * Execute the method associated with the GPE * NOTE: Level-triggered GPEs are cleared after the method completes. */ - status = acpi_os_queue_for_execution(OSD_PRIORITY_GPE, - acpi_ev_asynch_execute_gpe_method, - gpe_event_info); + status = acpi_os_execute(OSL_GPE_HANDLER, + acpi_ev_asynch_execute_gpe_method, + gpe_event_info); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Unable to queue handler for GPE[%2X] - event disabled", diff --git a/drivers/acpi/events/evmisc.c b/drivers/acpi/events/evmisc.c index 97e05481aa7c..24e0b8d36f31 100644 --- a/drivers/acpi/events/evmisc.c +++ b/drivers/acpi/events/evmisc.c @@ -191,9 +191,8 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node, notify_info->notify.value = (u16) notify_value; notify_info->notify.handler_obj = handler_obj; - status = acpi_os_queue_for_execution(OSD_PRIORITY_HIGH, - acpi_ev_notify_dispatch, - notify_info); + status = acpi_os_execute(OSL_NOTIFY_HANDLER, + acpi_ev_notify_dispatch, notify_info); if (ACPI_FAILURE(status)) { acpi_ut_delete_generic_state(notify_info); } @@ -346,9 +345,8 @@ static u32 acpi_ev_global_lock_handler(void *context) /* Run the Global Lock thread which will signal all waiting threads */ - status = acpi_os_queue_for_execution(OSD_PRIORITY_HIGH, - acpi_ev_global_lock_thread, - context); + status = acpi_os_execute(OSL_GLOBAL_LOCK_HANDLER, + acpi_ev_global_lock_thread, context); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Could not queue Global Lock thread")); diff --git a/drivers/acpi/events/evregion.c b/drivers/acpi/events/evregion.c index eb29e96f053c..edf9d2e1dff9 100644 --- a/drivers/acpi/events/evregion.c +++ b/drivers/acpi/events/evregion.c @@ -261,7 +261,8 @@ acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function) * Function - Read or Write operation * Address - Where in the space to read or write * bit_width - Field width in bits (8, 16, 32, or 64) - * Value - Pointer to in or out value + * Value - Pointer to in or out value, must be + * full 64-bit acpi_integer * * RETURN: Status * @@ -274,7 +275,7 @@ acpi_status acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, u32 function, acpi_physical_address address, - u32 bit_width, void *value) + u32 bit_width, acpi_integer * value) { acpi_status status; acpi_status status2; @@ -1007,7 +1008,7 @@ acpi_ev_execute_reg_methods(struct acpi_namespace_node *node, * * PARAMETERS: walk_namespace callback * - * DESCRIPTION: Run _REg method for region objects of the requested space_iD + * DESCRIPTION: Run _REG method for region objects of the requested space_iD * ******************************************************************************/ diff --git a/drivers/acpi/executer/exconfig.c b/drivers/acpi/executer/exconfig.c index 9c46f3338640..9ae3cb55979b 100644 --- a/drivers/acpi/executer/exconfig.c +++ b/drivers/acpi/executer/exconfig.c @@ -298,6 +298,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, struct acpi_table_header *table_ptr = NULL; acpi_physical_address address; struct acpi_table_header table_header; + acpi_integer temp; u32 i; ACPI_FUNCTION_TRACE(ex_load_op); @@ -326,7 +327,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, address = obj_desc->region.address; - /* Get the table length from the table header */ + /* Get part of the table header to get the table length */ table_header.length = 0; for (i = 0; i < 8; i++) { @@ -334,11 +335,14 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, acpi_ev_address_space_dispatch(obj_desc, ACPI_READ, (acpi_physical_address) (i + address), 8, - ((u8 *) & - table_header) + i); + &temp); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } + + /* Get the one valid byte of the returned 64-bit value */ + + ACPI_CAST_PTR(u8, &table_header)[i] = (u8) temp; } /* Sanity check the table length */ @@ -361,11 +365,14 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, acpi_ev_address_space_dispatch(obj_desc, ACPI_READ, (acpi_physical_address) (i + address), 8, - ((u8 *) table_ptr + - i)); + &temp); if (ACPI_FAILURE(status)) { goto cleanup; } + + /* Get the one valid byte of the returned 64-bit value */ + + ACPI_CAST_PTR(u8, table_ptr)[i] = (u8) temp; } break; diff --git a/drivers/acpi/executer/exstorob.c b/drivers/acpi/executer/exstorob.c index 18925f5b313c..99ebe5adfcda 100644 --- a/drivers/acpi/executer/exstorob.c +++ b/drivers/acpi/executer/exstorob.c @@ -103,7 +103,7 @@ acpi_ex_store_buffer_to_buffer(union acpi_operand_object *source_desc, * NOTE: ACPI versions up to 3.0 specified that the buffer must be * truncated if the string is smaller than the buffer. However, "other" * implementations of ACPI never did this and thus became the defacto - * standard. ACPi 3.0_a changes this behavior such that the buffer + * standard. ACPI 3.0_a changes this behavior such that the buffer * is no longer truncated. */ diff --git a/drivers/acpi/namespace/nsaccess.c b/drivers/acpi/namespace/nsaccess.c index 5e3f63a90fb4..ba8ad569188f 100644 --- a/drivers/acpi/namespace/nsaccess.c +++ b/drivers/acpi/namespace/nsaccess.c @@ -157,7 +157,7 @@ acpi_status acpi_ns_root_initialize(void) #if defined (ACPI_ASL_COMPILER) - /* save the parameter count for the i_aSL compiler */ + /* Save the parameter count for the i_aSL compiler */ new_node->value = obj_desc->method.param_count; #else @@ -311,8 +311,7 @@ acpi_ns_lookup(union acpi_generic_state *scope_info, acpi_object_type type_to_check_for; acpi_object_type this_search_type; u32 search_parent_flag = ACPI_NS_SEARCH_PARENT; - u32 local_flags = flags & ~(ACPI_NS_ERROR_IF_FOUND | - ACPI_NS_SEARCH_PARENT); + u32 local_flags; ACPI_FUNCTION_TRACE(ns_lookup); @@ -320,8 +319,9 @@ acpi_ns_lookup(union acpi_generic_state *scope_info, return_ACPI_STATUS(AE_BAD_PARAMETER); } - acpi_gbl_ns_lookup_count++; + local_flags = flags & ~(ACPI_NS_ERROR_IF_FOUND | ACPI_NS_SEARCH_PARENT); *return_node = ACPI_ENTRY_NOT_FOUND; + acpi_gbl_ns_lookup_count++; if (!acpi_gbl_root_node) { return_ACPI_STATUS(AE_NO_NAMESPACE); diff --git a/drivers/acpi/namespace/nssearch.c b/drivers/acpi/namespace/nssearch.c index 34ac512a2d5e..d2473476afa5 100644 --- a/drivers/acpi/namespace/nssearch.c +++ b/drivers/acpi/namespace/nssearch.c @@ -299,7 +299,7 @@ acpi_ns_search_and_enter(u32 target_name, if (!node || !target_name || !return_node) { ACPI_ERROR((AE_INFO, - "Null param: Node %p Name %X ReturnNode %p", + "Null parameter: Node %p Name %X ReturnNode %p", node, target_name, return_node)); return_ACPI_STATUS(AE_BAD_PARAMETER); } @@ -385,6 +385,11 @@ acpi_ns_search_and_enter(u32 target_name, if (!new_node) { return_ACPI_STATUS(AE_NO_MEMORY); } +#ifdef ACPI_ASL_COMPILER + if (flags & ACPI_NS_EXTERNAL) { + new_node->flags |= ANOBJ_IS_EXTERNAL; + } +#endif /* Install the new object into the parent's list of children */ diff --git a/drivers/acpi/resources/rscalc.c b/drivers/acpi/resources/rscalc.c index a573ad5d41db..cf87b0230026 100644 --- a/drivers/acpi/resources/rscalc.c +++ b/drivers/acpi/resources/rscalc.c @@ -451,7 +451,7 @@ acpi_rs_get_list_length(u8 * aml_buffer, */ buffer_size = acpi_gbl_resource_struct_sizes[resource_index] + extra_struct_bytes; - buffer_size = ACPI_ROUND_UP_TO_NATIVE_WORD(buffer_size); + buffer_size = (u32) ACPI_ROUND_UP_TO_NATIVE_WORD(buffer_size); *size_needed += buffer_size; @@ -579,7 +579,7 @@ acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object, /* Round up the size since each element must be aligned */ - temp_size_needed = ACPI_ROUND_UP_to_64_bIT(temp_size_needed); + temp_size_needed = ACPI_ROUND_UP_TO_64BIT(temp_size_needed); /* Point to the next union acpi_operand_object */ diff --git a/drivers/acpi/resources/rscreate.c b/drivers/acpi/resources/rscreate.c index 4c322daaf885..008058acdd39 100644 --- a/drivers/acpi/resources/rscreate.c +++ b/drivers/acpi/resources/rscreate.c @@ -335,7 +335,7 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object, /* Now align the current length */ user_prt->length = - (u32) ACPI_ROUND_UP_to_64_bIT(user_prt->length); + (u32) ACPI_ROUND_UP_TO_64BIT(user_prt->length); /* 4) Fourth subobject: Dereference the PRT.source_index */ diff --git a/drivers/acpi/resources/rsutils.c b/drivers/acpi/resources/rsutils.c index aa98eebc9b78..0e493f2fec4d 100644 --- a/drivers/acpi/resources/rsutils.c +++ b/drivers/acpi/resources/rsutils.c @@ -354,6 +354,7 @@ acpi_rs_get_resource_source(acpi_rs_length resource_length, * Zero the entire area of the buffer. */ total_length = + (u32) ACPI_STRLEN(ACPI_CAST_PTR(char, &aml_resource_source[1])) + 1; total_length = (u32) ACPI_ROUND_UP_TO_NATIVE_WORD(total_length); @@ -528,7 +529,7 @@ acpi_rs_get_crs_method_data(acpi_handle handle, struct acpi_buffer *ret_buffer) */ status = acpi_rs_create_resource_list(obj_desc, ret_buffer); - /* on exit, we must delete the object returned by evaluate_object */ + /* On exit, we must delete the object returned by evaluate_object */ acpi_ut_remove_reference(obj_desc); return_ACPI_STATUS(status); @@ -578,7 +579,7 @@ acpi_rs_get_prs_method_data(acpi_handle handle, struct acpi_buffer *ret_buffer) */ status = acpi_rs_create_resource_list(obj_desc, ret_buffer); - /* on exit, we must delete the object returned by evaluate_object */ + /* On exit, we must delete the object returned by evaluate_object */ acpi_ut_remove_reference(obj_desc); return_ACPI_STATUS(status); diff --git a/drivers/acpi/tables/tbrsdt.c b/drivers/acpi/tables/tbrsdt.c index 9e226438a3f6..494965229fa2 100644 --- a/drivers/acpi/tables/tbrsdt.c +++ b/drivers/acpi/tables/tbrsdt.c @@ -196,10 +196,8 @@ acpi_status acpi_tb_validate_rsdt(struct acpi_table_header *table_ptr) ACPI_DUMP_BUFFER(acpi_gbl_RSDP, 20); ACPI_ERROR((AE_INFO, - "RSDT/XSDT signature at %X (%p) is invalid", - acpi_gbl_RSDP->rsdt_physical_address, - (void *)(acpi_native_uint) acpi_gbl_RSDP-> - rsdt_physical_address)); + "RSDT/XSDT signature at %X is invalid", + acpi_gbl_RSDP->rsdt_physical_address)); if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) { ACPI_ERROR((AE_INFO, "Looking for RSDT")); diff --git a/drivers/acpi/tables/tbxfroot.c b/drivers/acpi/tables/tbxfroot.c index 3107e741d510..da2648bbdbc0 100644 --- a/drivers/acpi/tables/tbxfroot.c +++ b/drivers/acpi/tables/tbxfroot.c @@ -472,10 +472,10 @@ static u8 *acpi_tb_scan_memory_for_rsdp(u8 * start_address, u32 length) * * RETURN: Status, RSDP physical address * - * DESCRIPTION: search lower 1_mbyte of memory for the root system descriptor + * DESCRIPTION: Search lower 1_mbyte of memory for the root system descriptor * pointer structure. If it is found, set *RSDP to point to it. * - * NOTE1: The RSDp must be either in the first 1_k of the Extended + * NOTE1: The RSDP must be either in the first 1_k of the Extended * BIOS Data Area or between E0000 and FFFFF (From ACPI Spec.) * Only a 32-bit physical address is necessary. * @@ -525,7 +525,7 @@ acpi_tb_find_rsdp(struct acpi_table_desc *table_info, u32 flags) if (physical_address > 0x400) { /* - * 1b) Search EBDA paragraphs (EBDa is required to be a + * 1b) Search EBDA paragraphs (EBDA is required to be a * minimum of 1_k length) */ status = acpi_os_map_memory((acpi_physical_address) @@ -550,7 +550,7 @@ acpi_tb_find_rsdp(struct acpi_table_desc *table_info, u32 flags) /* Return the physical address */ physical_address += - ACPI_PTR_DIFF(mem_rover, table_ptr); + (u32) ACPI_PTR_DIFF(mem_rover, table_ptr); table_info->physical_address = (acpi_physical_address) physical_address; @@ -584,9 +584,9 @@ acpi_tb_find_rsdp(struct acpi_table_desc *table_info, u32 flags) /* Return the physical address */ - physical_address = - ACPI_HI_RSDP_WINDOW_BASE + ACPI_PTR_DIFF(mem_rover, - table_ptr); + physical_address = (u32) + (ACPI_HI_RSDP_WINDOW_BASE + + ACPI_PTR_DIFF(mem_rover, table_ptr)); table_info->physical_address = (acpi_physical_address) physical_address; @@ -607,7 +607,7 @@ acpi_tb_find_rsdp(struct acpi_table_desc *table_info, u32 flags) if (physical_address > 0x400) { /* - * 1b) Search EBDA paragraphs (EBDa is required to be a minimum of + * 1b) Search EBDA paragraphs (EBDA is required to be a minimum of * 1_k length) */ mem_rover = diff --git a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c index e666c71be0bf..9450f9b5bfb2 100644 --- a/drivers/acpi/utilities/utglobal.c +++ b/drivers/acpi/utilities/utglobal.c @@ -443,7 +443,6 @@ struct acpi_fixed_event_info acpi_gbl_fixed_event_info[ACPI_NUM_FIXED_EVENTS] = /* Region type decoding */ const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS] = { -/*! [Begin] no source code translation (keep these ASL Keywords as-is) */ "SystemMemory", "SystemIO", "PCI_Config", @@ -452,7 +451,6 @@ const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS] = { "CMOS", "PCIBARTarget", "DataTable" -/*! [End] no source code translation !*/ }; char *acpi_ut_get_region_name(u8 space_id) @@ -482,13 +480,11 @@ char *acpi_ut_get_region_name(u8 space_id) /* Event type decoding */ static const char *acpi_gbl_event_types[ACPI_NUM_FIXED_EVENTS] = { -/*! [Begin] no source code translation (keep these strings as-is) */ "PM_Timer", "GlobalLock", "PowerButton", "SleepButton", "RealTimeClock", -/*! [End] no source code translation !*/ }; char *acpi_ut_get_event_name(u32 event_id) @@ -526,7 +522,6 @@ static const char acpi_gbl_bad_type[] = "UNDEFINED"; /* Printable names of the ACPI object types */ static const char *acpi_gbl_ns_type_names[] = { -/*! [Begin] no source code translation (keep these strings as-is) */ /* 00 */ "Untyped", /* 01 */ "Integer", /* 02 */ "String", @@ -558,7 +553,6 @@ static const char *acpi_gbl_ns_type_names[] = { /* 28 */ "Extra", /* 29 */ "Data", /* 30 */ "Invalid" -/*! [End] no source code translation !*/ }; char *acpi_ut_get_type_name(acpi_object_type type) @@ -641,7 +635,6 @@ char *acpi_ut_get_node_name(void *object) /* Printable names of object descriptor types */ static const char *acpi_gbl_desc_type_names[] = { -/*! [Begin] no source code translation (keep these ASL Keywords as-is) */ /* 00 */ "Invalid", /* 01 */ "Cached", /* 02 */ "State-Generic", @@ -658,7 +651,6 @@ static const char *acpi_gbl_desc_type_names[] = { /* 13 */ "Parser", /* 14 */ "Operand", /* 15 */ "Node" -/*! [End] no source code translation !*/ }; char *acpi_ut_get_descriptor_name(void *object) diff --git a/include/acpi/acconfig.h b/include/acpi/acconfig.h index 11e72e6cdc01..0177ed3dc807 100644 --- a/include/acpi/acconfig.h +++ b/include/acpi/acconfig.h @@ -63,7 +63,7 @@ /* Current ACPICA subsystem version in YYYYMMDD format */ -#define ACPI_CA_VERSION 0x20060421 +#define ACPI_CA_VERSION 0x20060512 /* * OS name, used for the _OS object. The _OS object is essentially obsolete, diff --git a/include/acpi/acdisasm.h b/include/acpi/acdisasm.h index 6f2556582f05..9a7d6921f534 100644 --- a/include/acpi/acdisasm.h +++ b/include/acpi/acdisasm.h @@ -54,7 +54,11 @@ struct acpi_external_list { char *path; + char *internal_path; struct acpi_external_list *next; + u32 value; + u16 length; + u8 type; }; extern struct acpi_external_list *acpi_gbl_external_list; @@ -108,6 +112,8 @@ struct acpi_dmtable_data { struct acpi_op_walk_info { u32 level; + u32 last_level; + u32 count; u32 bit_offset; u32 flags; struct acpi_walk_state *walk_state; @@ -390,7 +396,7 @@ acpi_dm_vendor_small_descriptor(union aml_resource *resource, /* * dmutils */ -void acpi_dm_add_to_external_list(char *path); +void acpi_dm_add_to_external_list(char *path, u8 type, u32 value); /* * dmrestag diff --git a/include/acpi/acevents.h b/include/acpi/acevents.h index 272bd0480ec7..234142828e1a 100644 --- a/include/acpi/acevents.h +++ b/include/acpi/acevents.h @@ -138,7 +138,7 @@ acpi_status acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, u32 function, acpi_physical_address address, - u32 bit_width, void *value); + u32 bit_width, acpi_integer * value); acpi_status acpi_ev_attach_region(union acpi_operand_object *handler_obj, diff --git a/include/acpi/acglobal.h b/include/acpi/acglobal.h index 5f2daf402ee1..9297f293b2c0 100644 --- a/include/acpi/acglobal.h +++ b/include/acpi/acglobal.h @@ -290,14 +290,6 @@ ACPI_EXTERN struct acpi_thread_state *acpi_gbl_current_walk_list; ACPI_EXTERN u8 acpi_gbl_cm_single_step; -/***************************************************************************** - * - * Parser globals - * - ****************************************************************************/ - -ACPI_EXTERN union acpi_parse_object *acpi_gbl_parsed_namespace_root; - /***************************************************************************** * * Hardware globals diff --git a/include/acpi/aclocal.h b/include/acpi/aclocal.h index 06a9bd0a9ce9..98c697e3c486 100644 --- a/include/acpi/aclocal.h +++ b/include/acpi/aclocal.h @@ -207,10 +207,11 @@ struct acpi_namespace_node { #define ANOBJ_METHOD_LOCAL 0x08 /* Node is a method local */ #define ANOBJ_SUBTREE_HAS_INI 0x10 /* Used to optimize device initialization */ -#define ANOBJ_METHOD_NO_RETVal 0x10 /* i_aSL only: Method has no return value */ -#define ANOBJ_METHOD_SOME_NO_RETVal 0x20 /* i_aSL only: Method has at least one return value */ -#define ANOBJ_IS_BIT_OFFSet 0x40 /* i_aSL only: Reference is a bit offset */ -#define ANOBJ_IS_REFERENCed 0x80 /* i_aSL only: Object was referenced */ +#define ANOBJ_IS_EXTERNAL 0x08 /* i_aSL only: This object created via External() */ +#define ANOBJ_METHOD_NO_RETVAL 0x10 /* i_aSL only: Method has no return value */ +#define ANOBJ_METHOD_SOME_NO_RETVAL 0x20 /* i_aSL only: Method has at least one return value */ +#define ANOBJ_IS_BIT_OFFSET 0x40 /* i_aSL only: Reference is a bit offset */ +#define ANOBJ_IS_REFERENCED 0x80 /* i_aSL only: Object was referenced */ /* * ACPI Table Descriptor. One per ACPI table @@ -595,6 +596,9 @@ union acpi_parse_value { #define ACPI_DASM_UNICODE 0x03 #define ACPI_DASM_EISAID 0x04 #define ACPI_DASM_MATCHOP 0x05 +#define ACPI_DASM_LNOT_PREFIX 0x06 +#define ACPI_DASM_LNOT_SUFFIX 0x07 +#define ACPI_DASM_IGNORE 0x08 /* * Generic operation (for example: If, While, Store) @@ -613,7 +617,7 @@ struct acpi_parse_obj_named { u32 name; /* 4-byte name or zero if no name */ }; -/* this version is used by the i_aSL compiler only */ +/* This version is used by the i_aSL compiler only */ #define ACPI_MAX_PARSEOP_NAME 20 diff --git a/include/acpi/acmacros.h b/include/acpi/acmacros.h index b7547aba91b9..38f9aa4bef00 100644 --- a/include/acpi/acmacros.h +++ b/include/acpi/acmacros.h @@ -103,7 +103,7 @@ * printf() format helpers */ -/* Split 64-bit integer into two 32-bit values. Use with %8.8X%8.8X */ +/* Split 64-bit integer into two 32-bit values. Use with %8.8_x%8.8_x */ #define ACPI_FORMAT_UINT64(i) ACPI_HIDWORD(i),ACPI_LODWORD(i) @@ -359,12 +359,12 @@ /* Note: sizeof(acpi_native_uint) evaluates to either 2, 4, or 8 */ -#define ACPI_ROUND_DOWN_to_32_bIT(a) ACPI_ROUND_DOWN(a,4) -#define ACPI_ROUND_DOWN_to_64_bIT(a) ACPI_ROUND_DOWN(a,8) +#define ACPI_ROUND_DOWN_TO_32BIT(a) ACPI_ROUND_DOWN(a,4) +#define ACPI_ROUND_DOWN_TO_64BIT(a) ACPI_ROUND_DOWN(a,8) #define ACPI_ROUND_DOWN_TO_NATIVE_WORD(a) ACPI_ROUND_DOWN(a,sizeof(acpi_native_uint)) -#define ACPI_ROUND_UP_to_32_bIT(a) ACPI_ROUND_UP(a,4) -#define ACPI_ROUND_UP_to_64_bIT(a) ACPI_ROUND_UP(a,8) +#define ACPI_ROUND_UP_TO_32BIT(a) ACPI_ROUND_UP(a,4) +#define ACPI_ROUND_UP_TO_64BIT(a) ACPI_ROUND_UP(a,8) #define ACPI_ROUND_UP_TO_NATIVE_WORD(a) ACPI_ROUND_UP(a,sizeof(acpi_native_uint)) #define ACPI_ROUND_BITS_UP_TO_BYTES(a) ACPI_DIV_8((a) + 7) diff --git a/include/acpi/acnamesp.h b/include/acpi/acnamesp.h index 132d64af24fe..2ef8540c0fba 100644 --- a/include/acpi/acnamesp.h +++ b/include/acpi/acnamesp.h @@ -64,6 +64,7 @@ #define ACPI_NS_NO_PEER_SEARCH 0x04 #define ACPI_NS_ERROR_IF_FOUND 0x08 #define ACPI_NS_PREFIX_IS_SCOPE 0x10 +#define ACPI_NS_EXTERNAL 0x20 #define ACPI_NS_WALK_UNLOCK TRUE #define ACPI_NS_WALK_NO_UNLOCK FALSE diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h index a5264fac696e..982e7ea177e3 100644 --- a/include/acpi/acpiosxf.h +++ b/include/acpi/acpiosxf.h @@ -50,12 +50,17 @@ #include "platform/acenv.h" #include "actypes.h" -/* Priorities for acpi_os_queue_for_execution */ +/* Types for acpi_os_execute */ -#define OSD_PRIORITY_GPE 1 -#define OSD_PRIORITY_HIGH 2 -#define OSD_PRIORITY_MED 3 -#define OSD_PRIORITY_LO 4 +typedef enum { + OSL_GLOBAL_LOCK_HANDLER, + OSL_NOTIFY_HANDLER, + OSL_GPE_HANDLER, + OSL_DEBUGGER_THREAD, + OSL_EC_POLL_HANDLER, + OSL_EC_BURST_HANDLER, + +} acpi_execute_type; #define ACPI_NO_UNIT_LIMIT ((u32) -1) #define ACPI_MUTEX_SEM 1 @@ -164,8 +169,8 @@ acpi_os_remove_interrupt_handler(u32 gsi, acpi_osd_handler service_routine); acpi_thread_id acpi_os_get_thread_id(void); acpi_status -acpi_os_queue_for_execution(u32 priority, - acpi_osd_exec_callback function, void *context); +acpi_os_execute(acpi_execute_type type, + acpi_osd_exec_callback function, void *context); void acpi_os_wait_events_complete(void *context); diff --git a/include/acpi/actbl.h b/include/acpi/actbl.h index e1a40135f707..b125ceed9cb7 100644 --- a/include/acpi/actbl.h +++ b/include/acpi/actbl.h @@ -206,8 +206,8 @@ struct acpi_common_facs { u32 V1_pm_tmr_blk; /* Port address of Power Mgt Timer Ctrl Reg Blk */ \ u32 V1_gpe0_blk; /* Port addr of General Purpose acpi_event 0 Reg Blk */ \ u32 V1_gpe1_blk; /* Port addr of General Purpose acpi_event 1 Reg Blk */ \ - u8 pm1_evt_len; /* Byte length of ports at pm1_x_evt_blk */ \ - u8 pm1_cnt_len; /* Byte length of ports at pm1_x_cnt_blk */ \ + u8 pm1_evt_len; /* Byte Length of ports at pm1_x_evt_blk */ \ + u8 pm1_cnt_len; /* Byte Length of ports at pm1_x_cnt_blk */ \ u8 pm2_cnt_len; /* Byte Length of ports at pm2_cnt_blk */ \ u8 pm_tm_len; /* Byte Length of ports at pm_tm_blk */ \ u8 gpe0_blk_len; /* Byte Length of ports at gpe0_blk */ \ @@ -252,7 +252,7 @@ struct fadt_descriptor { u8 S4rtc_sts_valid:1; /* 16: Contents of RTC_STS valid after S4 wake (ACPI 3.0) */ u8 remote_power_on_capable:1; /* 17: System is compatible with remote power on (ACPI 3.0) */ u8 force_apic_cluster_model:1; /* 18: All local APICs must use cluster model (ACPI 3.0) */ - u8 force_apic_physical_destination_mode:1; /* 19: all local x_aPICs must use physical dest mode (ACPI 3.0) */ + u8 force_apic_physical_destination_mode:1; /* 19: All local x_aPICs must use physical dest mode (ACPI 3.0) */ u8:4; /* 20-23: Reserved, must be zero */ u8 reserved3; /* 24-31: Reserved, must be zero */ diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index 6d4e743a753b..77cf1236b05a 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -971,7 +971,7 @@ struct acpi_mem_space_context { * Definitions for Resource Attributes */ typedef u16 acpi_rs_length; /* Resource Length field is fixed at 16 bits */ -typedef u32 acpi_rsdesc_size; /* Max Resource Descriptor size is (length+3) = (64_k-1)+3 */ +typedef u32 acpi_rsdesc_size; /* Max Resource Descriptor size is (Length+3) = (64_k-1)+3 */ /* * Memory Attributes @@ -986,8 +986,8 @@ typedef u32 acpi_rsdesc_size; /* Max Resource Descriptor size is (length+3) = (6 /* * IO Attributes - * The ISA Io ranges are: n000-n0_ffh, n400-n4_ffh, n800-n8_ffh, n_c00-n_cFFh. - * The non-ISA Io ranges are: n100-n3_ffh, n500-n7_ffh, n900-n_bFfh, n_cd0-n_fFFh. + * The ISA IO ranges are: n000-n0_fFh, n400-n4_fFh, n800-n8_fFh, n_c00-n_cFFh. + * The non-ISA IO ranges are: n100-n3_fFh, n500-n7_fFh, n900-n_bFFh, n_cd0-n_fFFh. */ #define ACPI_NON_ISA_ONLY_RANGES (u8) 0x01 #define ACPI_ISA_ONLY_RANGES (u8) 0x02 diff --git a/include/acpi/amlcode.h b/include/acpi/amlcode.h index 37964a59aef8..cf18426a87b1 100644 --- a/include/acpi/amlcode.h +++ b/include/acpi/amlcode.h @@ -180,8 +180,10 @@ #define AML_BANK_FIELD_OP (u16) 0x5b87 #define AML_DATA_REGION_OP (u16) 0x5b88 /* ACPI 2.0 */ -/* Bogus opcodes (they are actually two separate opcodes) */ - +/* + * Combination opcodes (actually two one-byte opcodes) + * Used by the disassembler and i_aSL compiler + */ #define AML_LGREATEREQUAL_OP (u16) 0x9295 #define AML_LLESSEQUAL_OP (u16) 0x9294 #define AML_LNOTEQUAL_OP (u16) 0x9293 diff --git a/include/acpi/amlresrc.h b/include/acpi/amlresrc.h index 64736860bdd5..be03818af9d1 100644 --- a/include/acpi/amlresrc.h +++ b/include/acpi/amlresrc.h @@ -47,8 +47,6 @@ #ifndef __AMLRESRC_H #define __AMLRESRC_H -/*! [Begin] no source code translation */ - /* * Resource descriptor tags, as defined in the ACPI specification. * Used to symbolically reference fields within a descriptor. @@ -65,12 +63,12 @@ #define ACPI_RESTAG_DMATYPE "_TYP" /* Compatible(0), A(1), B(2), F(3) */ #define ACPI_RESTAG_GRANULARITY "_GRA" #define ACPI_RESTAG_INTERRUPT "_INT" -#define ACPI_RESTAG_INTERRUPTLEVEL "_LL_" /* ActiveLo(1), ActiveHi(0) */ -#define ACPI_RESTAG_INTERRUPTSHARE "_SHR" /* Shareable(1), NoShare(0) */ +#define ACPI_RESTAG_INTERRUPTLEVEL "_LL_" /* active_lo(1), active_hi(0) */ +#define ACPI_RESTAG_INTERRUPTSHARE "_SHR" /* Shareable(1), no_share(0) */ #define ACPI_RESTAG_INTERRUPTTYPE "_HE_" /* Edge(1), Level(0) */ #define ACPI_RESTAG_LENGTH "_LEN" #define ACPI_RESTAG_MEMATTRIBUTES "_MTP" /* Memory(0), Reserved(1), ACPI(2), NVS(3) */ -#define ACPI_RESTAG_MEMTYPE "_MEM" /* NonCache(0), Cacheable(1) Cache+combine(2), Cache+prefetch(3) */ +#define ACPI_RESTAG_MEMTYPE "_MEM" /* non_cache(0), Cacheable(1) Cache+combine(2), Cache+prefetch(3) */ #define ACPI_RESTAG_MAXADDR "_MAX" #define ACPI_RESTAG_MINADDR "_MIN" #define ACPI_RESTAG_MAXTYPE "_MAF" @@ -78,12 +76,11 @@ #define ACPI_RESTAG_REGISTERBITOFFSET "_RBO" #define ACPI_RESTAG_REGISTERBITWIDTH "_RBW" #define ACPI_RESTAG_RANGETYPE "_RNG" -#define ACPI_RESTAG_READWRITETYPE "_RW_" /* ReadOnly(0), Writeable (1) */ +#define ACPI_RESTAG_READWRITETYPE "_RW_" /* read_only(0), Writeable (1) */ #define ACPI_RESTAG_TRANSLATION "_TRA" #define ACPI_RESTAG_TRANSTYPE "_TRS" /* Sparse(1), Dense(0) */ #define ACPI_RESTAG_TYPE "_TTP" /* Translation(1), Static (0) */ -#define ACPI_RESTAG_XFERTYPE "_SIZ" /* 8(0), 8And16(1), 16(2) */ -/*! [End] no source code translation !*/ +#define ACPI_RESTAG_XFERTYPE "_SIZ" /* 8(0), 8_and16(1), 16(2) */ /* Default sizes for "small" resource descriptors */ @@ -306,9 +303,9 @@ union aml_resource { /* Utility overlays */ struct aml_resource_address address; - u32 u32_item; - u16 u16_item; - u8 U8item; + u32 dword_item; + u16 word_item; + u8 byte_item; }; #endif -- cgit v1.2.3 From 4119532c95547821dbe72d6916dfa1b2148475b3 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Fri, 26 May 2006 16:36:00 -0400 Subject: ACPI: ACPICA 20060526 Restructured, flattened, and simplified the internal interfaces for namespace object evaluation - resulting in smaller code, less CPU stack use, and fewer interfaces. (With assistance from Mikhail Kouzmich) Fixed a problem with the CopyObject operator where the first parameter was not typed correctly for the parser, interpreter, compiler, and disassembler. Caused various errors and unexpected behavior. Fixed a problem where a ShiftLeft or ShiftRight of more than 64 bits produced incorrect results with some C compilers. Since the behavior of C compilers when the shift value is larger than the datatype width is apparently not well defined, the interpreter now detects this condition and simply returns zero as expected in all such cases. (BZ 395) Fixed problem reports (Valery Podrezov) integrated: - Update String-to-Integer conversion to match ACPI 3.0A spec http://bugzilla.kernel.org/show_bug.cgi?id=5329 Allow interpreter to handle nested method declarations http://bugzilla.kernel.org/show_bug.cgi?id=5361 Fixed problem reports (Fiodor Suietov) integrated: - acpi_terminate() doesn't free debug memory allocation list objects (BZ 355) - After Core Subsystem shutdown, acpi_subsystem_status() returns AE_OK (BZ 356) - acpi_os_unmap_memory() for RSDP can be invoked inconsistently (BZ 357) - Resource Manager should return AE_TYPE for non-device objects (BZ 358) - Incomplete cleanup branch in AcpiNsEvaluateRelative (BZ 359) - Use acpi_os_free() instead of ACPI_FREE in acpi_rs_set_srs_method_data (BZ 360) - Incomplete cleanup branch in acpi_ps_parse_aml (BZ 361) - Incomplete cleanup branch in acpi_ds_delete_walk_state (BZ 362) - acpi_get_table_header returns AE_NO_ACPI_TABLES until DSDT is loaded (BZ 365) - Status of the Global Initialization Handler call not used (BZ 366) - Incorrect object parameter to Global Initialization Handler (BZ 367) Signed-off-by: Bob Moore Signed-off-by: Len Brown --- drivers/acpi/dispatcher/dsmethod.c | 20 +- drivers/acpi/dispatcher/dswexec.c | 2 +- drivers/acpi/dispatcher/dswstate.c | 5 +- drivers/acpi/events/evgpe.c | 39 ++- drivers/acpi/events/evmisc.c | 18 +- drivers/acpi/events/evregion.c | 65 +++-- drivers/acpi/events/evrgnini.c | 5 +- drivers/acpi/executer/exconfig.c | 10 +- drivers/acpi/executer/exfldio.c | 24 +- drivers/acpi/executer/exmisc.c | 14 ++ drivers/acpi/executer/exoparg1.c | 18 +- drivers/acpi/executer/exregion.c | 15 +- drivers/acpi/hardware/hwregs.c | 51 ++-- drivers/acpi/namespace/nsaccess.c | 6 +- drivers/acpi/namespace/nseval.c | 485 +++++++++---------------------------- drivers/acpi/namespace/nsinit.c | 57 +++-- drivers/acpi/namespace/nssearch.c | 82 ++++--- drivers/acpi/namespace/nsutils.c | 63 +++-- drivers/acpi/namespace/nsxfeval.c | 119 +++++---- drivers/acpi/namespace/nsxfname.c | 5 +- drivers/acpi/parser/psparse.c | 1 + drivers/acpi/parser/psxface.c | 37 +-- drivers/acpi/resources/rsutils.c | 95 ++++---- drivers/acpi/resources/rsxface.c | 368 ++++++++++++++++------------ drivers/acpi/tables/tbget.c | 40 +-- drivers/acpi/tables/tbrsdt.c | 11 +- drivers/acpi/utilities/utalloc.c | 51 ++-- drivers/acpi/utilities/utdelete.c | 24 +- drivers/acpi/utilities/uteval.c | 45 ++-- drivers/acpi/utilities/utinit.c | 8 +- drivers/acpi/utilities/utmisc.c | 109 ++++++--- include/acpi/acconfig.h | 2 +- include/acpi/acdispat.h | 2 +- include/acpi/acnamesp.h | 22 +- include/acpi/acopcode.h | 2 +- include/acpi/acparser.h | 2 +- include/acpi/acpiosxf.h | 11 +- include/acpi/acresrc.h | 15 +- include/acpi/acstruct.h | 90 ++++--- 39 files changed, 981 insertions(+), 1057 deletions(-) (limited to 'include') diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c index e348db0e541e..21f059986273 100644 --- a/drivers/acpi/dispatcher/dsmethod.c +++ b/drivers/acpi/dispatcher/dsmethod.c @@ -231,7 +231,7 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread, struct acpi_namespace_node *method_node; struct acpi_walk_state *next_walk_state = NULL; union acpi_operand_object *obj_desc; - struct acpi_parameter_info info; + struct acpi_evaluate_info *info; u32 i; ACPI_FUNCTION_TRACE_PTR(ds_call_control_method, this_walk_state); @@ -319,12 +319,24 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread, */ this_walk_state->operands[this_walk_state->num_operands] = NULL; - info.parameters = &this_walk_state->operands[0]; - info.parameter_type = ACPI_PARAM_ARGS; + /* + * Allocate and initialize the evaluation information block + * TBD: this is somewhat inefficient, should change interface to + * ds_init_aml_walk. For now, keeps this struct off the CPU stack + */ + info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info)); + if (!info) { + return_ACPI_STATUS(AE_NO_MEMORY); + } + + info->parameters = &this_walk_state->operands[0]; + info->parameter_type = ACPI_PARAM_ARGS; status = acpi_ds_init_aml_walk(next_walk_state, NULL, method_node, obj_desc->method.aml_start, - obj_desc->method.aml_length, &info, 3); + obj_desc->method.aml_length, info, 3); + + ACPI_FREE(info); if (ACPI_FAILURE(status)) { goto cleanup; } diff --git a/drivers/acpi/dispatcher/dswexec.c b/drivers/acpi/dispatcher/dswexec.c index 8afb20384e96..3acbd9145d72 100644 --- a/drivers/acpi/dispatcher/dswexec.c +++ b/drivers/acpi/dispatcher/dswexec.c @@ -295,7 +295,7 @@ acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state, case AML_CLASS_NAMED_OBJECT: - if (walk_state->walk_type == ACPI_WALK_METHOD) { + if (walk_state->walk_type & ACPI_WALK_METHOD) { /* * Found a named object declaration during method execution; * we must enter this object into the namespace. The created diff --git a/drivers/acpi/dispatcher/dswstate.c b/drivers/acpi/dispatcher/dswstate.c index 82c1e219bf15..7817e5522679 100644 --- a/drivers/acpi/dispatcher/dswstate.c +++ b/drivers/acpi/dispatcher/dswstate.c @@ -703,7 +703,7 @@ acpi_ds_init_aml_walk(struct acpi_walk_state *walk_state, struct acpi_namespace_node *method_node, u8 * aml_start, u32 aml_length, - struct acpi_parameter_info *info, u8 pass_number) + struct acpi_evaluate_info *info, u8 pass_number) { acpi_status status; struct acpi_parse_state *parser_state = &walk_state->parser_state; @@ -825,9 +825,12 @@ void acpi_ds_delete_walk_state(struct acpi_walk_state *walk_state) return; } + /* There should not be any open scopes */ + if (walk_state->parser_state.scope) { ACPI_ERROR((AE_INFO, "%p walk still has a scope list", walk_state)); + acpi_ps_cleanup_scope(&walk_state->parser_state); } /* Always must free any linked control states */ diff --git a/drivers/acpi/events/evgpe.c b/drivers/acpi/events/evgpe.c index aa179dc78011..23fe53ba7375 100644 --- a/drivers/acpi/events/evgpe.c +++ b/drivers/acpi/events/evgpe.c @@ -488,9 +488,9 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list) * * RETURN: None * - * DESCRIPTION: Perform the actual execution of a GPE control method. This - * function is called from an invocation of acpi_os_exece - * (and therefore does NOT execute at interrupt level) so that + * DESCRIPTION: Perform the actual execution of a GPE control method. This + * function is called from an invocation of acpi_os_execute and + * therefore does NOT execute at interrupt level - so that * the control method itself is not executed in the context of * an interrupt handler. * @@ -502,7 +502,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) u32 gpe_number = 0; acpi_status status; struct acpi_gpe_event_info local_gpe_event_info; - struct acpi_parameter_info info; + struct acpi_evaluate_info *info; ACPI_FUNCTION_TRACE(ev_asynch_execute_gpe_method); @@ -540,16 +540,29 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) */ if ((local_gpe_event_info.flags & ACPI_GPE_DISPATCH_MASK) == ACPI_GPE_DISPATCH_METHOD) { - /* - * Invoke the GPE Method (_Lxx, _Exx) i.e., evaluate the _Lxx/_Exx - * control method that corresponds to this GPE - */ - info.node = local_gpe_event_info.dispatch.method_node; - info.parameters = - ACPI_CAST_PTR(union acpi_operand_object *, gpe_event_info); - info.parameter_type = ACPI_PARAM_GPE; - status = acpi_ns_evaluate_by_handle(&info); + /* Allocate the evaluation information block */ + + info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info)); + if (!info) { + status = AE_NO_MEMORY; + } else { + /* + * Invoke the GPE Method (_Lxx, _Exx) i.e., evaluate the _Lxx/_Exx + * control method that corresponds to this GPE + */ + info->prefix_node = + local_gpe_event_info.dispatch.method_node; + info->parameters = + ACPI_CAST_PTR(union acpi_operand_object *, + gpe_event_info); + info->parameter_type = ACPI_PARAM_GPE; + info->flags = ACPI_IGNORE_RETURN_VALUE; + + status = acpi_ns_evaluate(info); + ACPI_FREE(info); + } + if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "While evaluating method [%4.4s] for GPE[%2X]", diff --git a/drivers/acpi/events/evmisc.c b/drivers/acpi/events/evmisc.c index 24e0b8d36f31..6eef4efddcf6 100644 --- a/drivers/acpi/events/evmisc.c +++ b/drivers/acpi/events/evmisc.c @@ -49,12 +49,13 @@ #define _COMPONENT ACPI_EVENTS ACPI_MODULE_NAME("evmisc") +/* Names for Notify() values, used for debug output */ #ifdef ACPI_DEBUG_OUTPUT static const char *acpi_notify_value_names[] = { "Bus Check", "Device Check", "Device Wake", - "Eject request", + "Eject Request", "Device Check Light", "Frequency Mismatch", "Bus Mode Mismatch", @@ -191,8 +192,9 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node, notify_info->notify.value = (u16) notify_value; notify_info->notify.handler_obj = handler_obj; - status = acpi_os_execute(OSL_NOTIFY_HANDLER, - acpi_ev_notify_dispatch, notify_info); + status = + acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_notify_dispatch, + notify_info); if (ACPI_FAILURE(status)) { acpi_ut_delete_generic_state(notify_info); } @@ -345,8 +347,9 @@ static u32 acpi_ev_global_lock_handler(void *context) /* Run the Global Lock thread which will signal all waiting threads */ - status = acpi_os_execute(OSL_GLOBAL_LOCK_HANDLER, - acpi_ev_global_lock_thread, context); + status = + acpi_os_execute(OSL_GLOBAL_LOCK_HANDLER, + acpi_ev_global_lock_thread, context); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Could not queue Global Lock thread")); @@ -462,8 +465,9 @@ acpi_status acpi_ev_acquire_global_lock(u16 timeout) * Acquire the global lock semaphore first. * Since this wait will block, we must release the interpreter */ - status = acpi_ex_system_wait_semaphore(acpi_gbl_global_lock_semaphore, - timeout); + status = + acpi_ex_system_wait_semaphore(acpi_gbl_global_lock_semaphore, + timeout); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/events/evregion.c b/drivers/acpi/events/evregion.c index edf9d2e1dff9..094a17e4c86d 100644 --- a/drivers/acpi/events/evregion.c +++ b/drivers/acpi/events/evregion.c @@ -193,8 +193,8 @@ acpi_status acpi_ev_initialize_op_regions(void) acpi_status acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function) { - struct acpi_parameter_info info; - union acpi_operand_object *params[3]; + struct acpi_evaluate_info *info; + union acpi_operand_object *args[3]; union acpi_operand_object *region_obj2; acpi_status status; @@ -209,47 +209,60 @@ acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function) return_ACPI_STATUS(AE_OK); } + /* Allocate and initialize the evaluation information block */ + + info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info)); + if (!info) { + return_ACPI_STATUS(AE_NO_MEMORY); + } + + info->prefix_node = region_obj2->extra.method_REG; + info->pathname = NULL; + info->parameters = args; + info->parameter_type = ACPI_PARAM_ARGS; + info->flags = ACPI_IGNORE_RETURN_VALUE; + /* * The _REG method has two arguments: * - * Arg0, Integer: Operation region space ID - * Same value as region_obj->Region.space_id - * Arg1, Integer: connection status - * 1 for connecting the handler, - * 0 for disconnecting the handler - * Passed as a parameter + * Arg0 - Integer: + * Operation region space ID Same value as region_obj->Region.space_id + * + * Arg1 - Integer: + * connection status 1 for connecting the handler, 0 for disconnecting + * the handler (Passed as a parameter) */ - params[0] = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); - if (!params[0]) { - return_ACPI_STATUS(AE_NO_MEMORY); + args[0] = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); + if (!args[0]) { + status = AE_NO_MEMORY; + goto cleanup1; } - params[1] = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); - if (!params[1]) { + args[1] = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); + if (!args[1]) { status = AE_NO_MEMORY; - goto cleanup; + goto cleanup2; } /* Setup the parameter objects */ - params[0]->integer.value = region_obj->region.space_id; - params[1]->integer.value = function; - params[2] = NULL; - - info.node = region_obj2->extra.method_REG; - info.parameters = params; - info.parameter_type = ACPI_PARAM_ARGS; + args[0]->integer.value = region_obj->region.space_id; + args[1]->integer.value = function; + args[2] = NULL; /* Execute the method, no return value */ ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname - (ACPI_TYPE_METHOD, info.node, NULL)); - status = acpi_ns_evaluate_by_handle(&info); + (ACPI_TYPE_METHOD, info->prefix_node, NULL)); + + status = acpi_ns_evaluate(info); + acpi_ut_remove_reference(args[1]); - acpi_ut_remove_reference(params[1]); + cleanup2: + acpi_ut_remove_reference(args[0]); - cleanup: - acpi_ut_remove_reference(params[0]); + cleanup1: + ACPI_FREE(info); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/events/evrgnini.c b/drivers/acpi/events/evrgnini.c index 1cecd577b899..5b3c7a85eb9a 100644 --- a/drivers/acpi/events/evrgnini.c +++ b/drivers/acpi/events/evrgnini.c @@ -475,8 +475,9 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj, /* Find any "_REG" method associated with this region definition */ - status = acpi_ns_search_node(*reg_name_ptr, node, - ACPI_TYPE_METHOD, &method_node); + status = + acpi_ns_search_one_scope(*reg_name_ptr, node, ACPI_TYPE_METHOD, + &method_node); if (ACPI_SUCCESS(status)) { /* * The _REG method is optional and there can be only one per region diff --git a/drivers/acpi/executer/exconfig.c b/drivers/acpi/executer/exconfig.c index 9ae3cb55979b..823352435e08 100644 --- a/drivers/acpi/executer/exconfig.c +++ b/drivers/acpi/executer/exconfig.c @@ -214,9 +214,8 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state, * location within the namespace where the table will be loaded. */ status = - acpi_ns_get_node_by_path(operand[3]->string.pointer, - start_node, ACPI_NS_SEARCH_PARENT, - &parent_node); + acpi_ns_get_node(start_node, operand[3]->string.pointer, + ACPI_NS_SEARCH_PARENT, &parent_node); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -237,9 +236,8 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state, /* Find the node referenced by the parameter_path_string */ status = - acpi_ns_get_node_by_path(operand[4]->string.pointer, - start_node, ACPI_NS_SEARCH_PARENT, - ¶meter_node); + acpi_ns_get_node(start_node, operand[4]->string.pointer, + ACPI_NS_SEARCH_PARENT, ¶meter_node); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } diff --git a/drivers/acpi/executer/exfldio.c b/drivers/acpi/executer/exfldio.c index ca9925c0d011..3b7c4352ec57 100644 --- a/drivers/acpi/executer/exfldio.c +++ b/drivers/acpi/executer/exfldio.c @@ -145,10 +145,10 @@ acpi_ex_setup_region(union acpi_operand_object *obj_desc, * length of one field datum (access width) must fit within the region. * (Region length is specified in bytes) */ - if (rgn_desc->region.length < (obj_desc->common_field.base_byte_offset + - field_datum_byte_offset + - obj_desc->common_field. - access_byte_width)) { + if (rgn_desc->region.length < + (obj_desc->common_field.base_byte_offset + + field_datum_byte_offset + + obj_desc->common_field.access_byte_width)) { if (acpi_gbl_enable_interpreter_slack) { /* * Slack mode only: We will go ahead and allow access to this @@ -811,13 +811,15 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc, mask = ACPI_MASK_BITS_BELOW(obj_desc->common_field.start_field_bit_offset); - datum_count = - ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length, - obj_desc->common_field.access_bit_width); - field_datum_count = - ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length + - obj_desc->common_field.start_field_bit_offset, - obj_desc->common_field.access_bit_width); + + datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length, + obj_desc->common_field.access_bit_width); + + field_datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length + + obj_desc->common_field. + start_field_bit_offset, + obj_desc->common_field. + access_bit_width); /* Get initial Datum from the input buffer */ diff --git a/drivers/acpi/executer/exmisc.c b/drivers/acpi/executer/exmisc.c index 794d9b8de956..bd98aab017cf 100644 --- a/drivers/acpi/executer/exmisc.c +++ b/drivers/acpi/executer/exmisc.c @@ -445,10 +445,24 @@ acpi_ex_do_math_op(u16 opcode, acpi_integer integer0, acpi_integer integer1) case AML_SHIFT_LEFT_OP: /* shift_left (Operand, shift_count, Result) */ + /* + * We need to check if the shiftcount is larger than the integer bit + * width since the behavior of this is not well-defined in the C language. + */ + if (integer1 >= acpi_gbl_integer_bit_width) { + return (0); + } return (integer0 << integer1); case AML_SHIFT_RIGHT_OP: /* shift_right (Operand, shift_count, Result) */ + /* + * We need to check if the shiftcount is larger than the integer bit + * width since the behavior of this is not well-defined in the C language. + */ + if (integer1 >= acpi_gbl_integer_bit_width) { + return (0); + } return (integer0 >> integer1); case AML_SUBTRACT_OP: /* Subtract (Integer0, Integer1, Result) */ diff --git a/drivers/acpi/executer/exoparg1.c b/drivers/acpi/executer/exoparg1.c index 05b89c5878eb..8284c52875be 100644 --- a/drivers/acpi/executer/exoparg1.c +++ b/drivers/acpi/executer/exoparg1.c @@ -874,16 +874,14 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state) * Field, so we need to resolve the node to a value. */ status = - acpi_ns_get_node_by_path(operand[0]->string. - pointer, - walk_state-> - scope_info->scope. - node, - ACPI_NS_SEARCH_PARENT, - ACPI_CAST_INDIRECT_PTR - (struct - acpi_namespace_node, - &return_desc)); + acpi_ns_get_node(walk_state->scope_info-> + scope.node, + operand[0]->string.pointer, + ACPI_NS_SEARCH_PARENT, + ACPI_CAST_INDIRECT_PTR + (struct + acpi_namespace_node, + &return_desc)); if (ACPI_FAILURE(status)) { goto cleanup; } diff --git a/drivers/acpi/executer/exregion.c b/drivers/acpi/executer/exregion.c index 4fba452a5590..3cc97ba48b36 100644 --- a/drivers/acpi/executer/exregion.c +++ b/drivers/acpi/executer/exregion.c @@ -477,23 +477,16 @@ acpi_ex_data_table_space_handler(u32 function, acpi_integer * value, void *handler_context, void *region_context) { - acpi_status status = AE_OK; - u32 byte_width = ACPI_DIV_8(bit_width); - u32 i; - char *logical_addr_ptr; - ACPI_FUNCTION_TRACE(ex_data_table_space_handler); - logical_addr_ptr = ACPI_PHYSADDR_TO_PTR(address); - /* Perform the memory read or write */ switch (function) { case ACPI_READ: - for (i = 0; i < byte_width; i++) { - ((char *)value)[i] = logical_addr_ptr[i]; - } + ACPI_MEMCPY(ACPI_CAST_PTR(char, value), + ACPI_PHYSADDR_TO_PTR(address), + ACPI_DIV_8(bit_width)); break; case ACPI_WRITE: @@ -502,5 +495,5 @@ acpi_ex_data_table_space_handler(u32 function, return_ACPI_STATUS(AE_SUPPORT); } - return_ACPI_STATUS(status); + return_ACPI_STATUS(AE_OK); } diff --git a/drivers/acpi/hardware/hwregs.c b/drivers/acpi/hardware/hwregs.c index ec9f5a11a8b3..5a3aa8dd8cb7 100644 --- a/drivers/acpi/hardware/hwregs.c +++ b/drivers/acpi/hardware/hwregs.c @@ -127,8 +127,7 @@ acpi_status acpi_get_sleep_type_data(u8 sleep_state, u8 * sleep_type_a, u8 * sleep_type_b) { acpi_status status = AE_OK; - struct acpi_parameter_info info; - char *sleep_state_name; + struct acpi_evaluate_info *info; ACPI_FUNCTION_TRACE(acpi_get_sleep_type_data); @@ -138,34 +137,39 @@ acpi_get_sleep_type_data(u8 sleep_state, u8 * sleep_type_a, u8 * sleep_type_b) return_ACPI_STATUS(AE_BAD_PARAMETER); } - /* Evaluate the namespace object containing the values for this state */ + /* Allocate the evaluation information block */ + + info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info)); + if (!info) { + return_ACPI_STATUS(AE_NO_MEMORY); + } - info.parameters = NULL; - info.return_object = NULL; - sleep_state_name = + info->pathname = ACPI_CAST_PTR(char, acpi_gbl_sleep_state_names[sleep_state]); - status = acpi_ns_evaluate_by_name(sleep_state_name, &info); + /* Evaluate the namespace object containing the values for this state */ + + status = acpi_ns_evaluate(info); if (ACPI_FAILURE(status)) { ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%s while evaluating SleepState [%s]\n", acpi_format_exception(status), - sleep_state_name)); + info->pathname)); - return_ACPI_STATUS(status); + goto cleanup; } /* Must have a return object */ - if (!info.return_object) { + if (!info->return_object) { ACPI_ERROR((AE_INFO, "No Sleep State object returned from [%s]", - sleep_state_name)); + info->pathname)); status = AE_NOT_EXIST; } /* It must be of type Package */ - else if (ACPI_GET_OBJECT_TYPE(info.return_object) != ACPI_TYPE_PACKAGE) { + else if (ACPI_GET_OBJECT_TYPE(info->return_object) != ACPI_TYPE_PACKAGE) { ACPI_ERROR((AE_INFO, "Sleep State return object is not a Package")); status = AE_AML_OPERAND_TYPE; @@ -178,7 +182,7 @@ acpi_get_sleep_type_data(u8 sleep_state, u8 * sleep_type_a, u8 * sleep_type_b) * by BIOS vendors seems to be to have 2 or more elements, at least * one per sleep type (A/B). */ - else if (info.return_object->package.count < 2) { + else if (info->return_object->package.count < 2) { ACPI_ERROR((AE_INFO, "Sleep State return package does not have at least two elements")); status = AE_AML_NO_OPERAND; @@ -186,35 +190,38 @@ acpi_get_sleep_type_data(u8 sleep_state, u8 * sleep_type_a, u8 * sleep_type_b) /* The first two elements must both be of type Integer */ - else if ((ACPI_GET_OBJECT_TYPE(info.return_object->package.elements[0]) + else if ((ACPI_GET_OBJECT_TYPE(info->return_object->package.elements[0]) != ACPI_TYPE_INTEGER) || - (ACPI_GET_OBJECT_TYPE(info.return_object->package.elements[1]) + (ACPI_GET_OBJECT_TYPE(info->return_object->package.elements[1]) != ACPI_TYPE_INTEGER)) { ACPI_ERROR((AE_INFO, "Sleep State return package elements are not both Integers (%s, %s)", - acpi_ut_get_object_type_name(info.return_object-> + acpi_ut_get_object_type_name(info->return_object-> package.elements[0]), - acpi_ut_get_object_type_name(info.return_object-> + acpi_ut_get_object_type_name(info->return_object-> package.elements[1]))); status = AE_AML_OPERAND_TYPE; } else { /* Valid _Sx_ package size, type, and value */ *sleep_type_a = (u8) - (info.return_object->package.elements[0])->integer.value; + (info->return_object->package.elements[0])->integer.value; *sleep_type_b = (u8) - (info.return_object->package.elements[1])->integer.value; + (info->return_object->package.elements[1])->integer.value; } if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "While evaluating SleepState [%s], bad Sleep object %p type %s", - sleep_state_name, info.return_object, - acpi_ut_get_object_type_name(info. + info->pathname, info->return_object, + acpi_ut_get_object_type_name(info-> return_object))); } - acpi_ut_remove_reference(info.return_object); + acpi_ut_remove_reference(info->return_object); + + cleanup: + ACPI_FREE(info); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/namespace/nsaccess.c b/drivers/acpi/namespace/nsaccess.c index ba8ad569188f..48fadade52e2 100644 --- a/drivers/acpi/namespace/nsaccess.c +++ b/drivers/acpi/namespace/nsaccess.c @@ -259,10 +259,8 @@ acpi_status acpi_ns_root_initialize(void) /* Save a handle to "_GPE", it is always present */ if (ACPI_SUCCESS(status)) { - status = - acpi_ns_get_node_by_path("\\_GPE", NULL, - ACPI_NS_NO_UPSEARCH, - &acpi_gbl_fadt_gpe_device); + status = acpi_ns_get_node(NULL, "\\_GPE", ACPI_NS_NO_UPSEARCH, + &acpi_gbl_fadt_gpe_device); } return_ACPI_STATUS(status); diff --git a/drivers/acpi/namespace/nseval.c b/drivers/acpi/namespace/nseval.c index 4b054062b46a..4b0a4a8c9843 100644 --- a/drivers/acpi/namespace/nseval.c +++ b/drivers/acpi/namespace/nseval.c @@ -1,7 +1,6 @@ /******************************************************************************* * - * Module Name: nseval - Object evaluation interfaces -- includes control - * method lookup and execution. + * Module Name: nseval - Object evaluation, includes control method execution * ******************************************************************************/ @@ -50,196 +49,14 @@ #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nseval") -/* Local prototypes */ -static acpi_status -acpi_ns_execute_control_method(struct acpi_parameter_info *info); - -static acpi_status acpi_ns_get_object_value(struct acpi_parameter_info *info); - -/******************************************************************************* - * - * FUNCTION: acpi_ns_evaluate_relative - * - * PARAMETERS: Pathname - Name of method to execute, If NULL, the - * handle is the object to execute - * Info - Method info block, contains: - * return_object - Where to put method's return value (if - * any). If NULL, no value is returned. - * Params - List of parameters to pass to the method, - * terminated by NULL. Params itself may be - * NULL if no parameters are being passed. - * - * RETURN: Status - * - * DESCRIPTION: Evaluate the object or find and execute the requested method - * - * MUTEX: Locks Namespace - * - ******************************************************************************/ - -acpi_status -acpi_ns_evaluate_relative(char *pathname, struct acpi_parameter_info *info) -{ - acpi_status status; - struct acpi_namespace_node *node = NULL; - union acpi_generic_state *scope_info; - char *internal_path = NULL; - - ACPI_FUNCTION_TRACE(ns_evaluate_relative); - - /* - * Must have a valid object handle - */ - if (!info || !info->node) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - /* Build an internal name string for the method */ - - status = acpi_ns_internalize_name(pathname, &internal_path); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - scope_info = acpi_ut_create_generic_state(); - if (!scope_info) { - goto cleanup1; - } - - /* Get the prefix handle and Node */ - - status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE(status)) { - goto cleanup; - } - - info->node = acpi_ns_map_handle_to_node(info->node); - if (!info->node) { - (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); - status = AE_BAD_PARAMETER; - goto cleanup; - } - - /* Lookup the name in the namespace */ - - scope_info->scope.node = info->node; - status = acpi_ns_lookup(scope_info, internal_path, ACPI_TYPE_ANY, - ACPI_IMODE_EXECUTE, ACPI_NS_NO_UPSEARCH, NULL, - &node); - - (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); - - if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Object [%s] not found [%s]\n", - pathname, acpi_format_exception(status))); - goto cleanup; - } - - /* - * Now that we have a handle to the object, we can attempt to evaluate it. - */ - ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "%s [%p] Value %p\n", - pathname, node, acpi_ns_get_attached_object(node))); - - info->node = node; - status = acpi_ns_evaluate_by_handle(info); - - ACPI_DEBUG_PRINT((ACPI_DB_NAMES, - "*** Completed eval of object %s ***\n", pathname)); - - cleanup: - acpi_ut_delete_generic_state(scope_info); - - cleanup1: - ACPI_FREE(internal_path); - return_ACPI_STATUS(status); -} - -/******************************************************************************* - * - * FUNCTION: acpi_ns_evaluate_by_name - * - * PARAMETERS: Pathname - Fully qualified pathname to the object - * Info - Method info block, contains: - * return_object - Where to put method's return value (if - * any). If NULL, no value is returned. - * Params - List of parameters to pass to the method, - * terminated by NULL. Params itself may be - * NULL if no parameters are being passed. - * - * RETURN: Status - * - * DESCRIPTION: Evaluate the object or rind and execute the requested method - * passing the given parameters - * - * MUTEX: Locks Namespace - * - ******************************************************************************/ - -acpi_status -acpi_ns_evaluate_by_name(char *pathname, struct acpi_parameter_info *info) -{ - acpi_status status; - char *internal_path = NULL; - - ACPI_FUNCTION_TRACE(ns_evaluate_by_name); - - /* Build an internal name string for the method */ - - status = acpi_ns_internalize_name(pathname, &internal_path); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE(status)) { - goto cleanup; - } - - /* Lookup the name in the namespace */ - - status = acpi_ns_lookup(NULL, internal_path, ACPI_TYPE_ANY, - ACPI_IMODE_EXECUTE, ACPI_NS_NO_UPSEARCH, NULL, - &info->node); - - (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); - - if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT((ACPI_DB_NAMES, - "Object at [%s] was not found, status=%.4X\n", - pathname, status)); - goto cleanup; - } - - /* - * Now that we have a handle to the object, we can attempt to evaluate it. - */ - ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "%s [%p] Value %p\n", - pathname, info->node, - acpi_ns_get_attached_object(info->node))); - - status = acpi_ns_evaluate_by_handle(info); - - ACPI_DEBUG_PRINT((ACPI_DB_NAMES, - "*** Completed eval of object %s ***\n", pathname)); - - cleanup: - - /* Cleanup */ - - if (internal_path) { - ACPI_FREE(internal_path); - } - - return_ACPI_STATUS(status); -} - /******************************************************************************* * - * FUNCTION: acpi_ns_evaluate_by_handle + * FUNCTION: acpi_ns_evaluate * - * PARAMETERS: Info - Method info block, contains: - * Node - Method/Object Node to execute + * PARAMETERS: Info - Evaluation info block, contains: + * prefix_node - Prefix or Method/Object Node to execute + * Pathname - Name of method to execute, If NULL, the + * Node is the object to execute * Parameters - List of parameters to pass to the method, * terminated by NULL. Params itself may be * NULL if no parameters are being passed. @@ -248,29 +65,21 @@ acpi_ns_evaluate_by_name(char *pathname, struct acpi_parameter_info *info) * parameter_type - Type of Parameter list * return_object - Where to put method's return value (if * any). If NULL, no value is returned. + * Flags - ACPI_IGNORE_RETURN_VALUE to delete return * * RETURN: Status * - * DESCRIPTION: Evaluate object or execute the requested method passing the - * given parameters + * DESCRIPTION: Execute a control method or return the current value of an + * ACPI namespace object. * - * MUTEX: Locks Namespace + * MUTEX: Locks interpreter * ******************************************************************************/ - -acpi_status acpi_ns_evaluate_by_handle(struct acpi_parameter_info *info) +acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info) { acpi_status status; - ACPI_FUNCTION_TRACE(ns_evaluate_by_handle); - - /* Check if namespace has been initialized */ - - if (!acpi_gbl_root_node) { - return_ACPI_STATUS(AE_NO_NAMESPACE); - } - - /* Parameter Validation */ + ACPI_FUNCTION_TRACE(ns_evaluate); if (!info) { return_ACPI_STATUS(AE_BAD_PARAMETER); @@ -280,203 +89,120 @@ acpi_status acpi_ns_evaluate_by_handle(struct acpi_parameter_info *info) info->return_object = NULL; - /* Get the prefix handle and Node */ - - status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); + /* + * Get the actual namespace node for the target object. Handles these cases: + * + * 1) Null node, Pathname (absolute path) + * 2) Node, Pathname (path relative to Node) + * 3) Node, Null Pathname + */ + status = acpi_ns_get_node(info->prefix_node, info->pathname, + ACPI_NS_NO_UPSEARCH, &info->resolved_node); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } - info->node = acpi_ns_map_handle_to_node(info->node); - if (!info->node) { - (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - /* * For a method alias, we must grab the actual method node so that proper * scoping context will be established before execution. */ - if (acpi_ns_get_type(info->node) == ACPI_TYPE_LOCAL_METHOD_ALIAS) { - info->node = + if (acpi_ns_get_type(info->resolved_node) == + ACPI_TYPE_LOCAL_METHOD_ALIAS) { + info->resolved_node = ACPI_CAST_PTR(struct acpi_namespace_node, - info->node->object); + info->resolved_node->object); } + ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "%s [%p] Value %p\n", info->pathname, + info->resolved_node, + acpi_ns_get_attached_object(info->resolved_node))); + /* * Two major cases here: - * 1) The object is an actual control method -- execute it. - * 2) The object is not a method -- just return it's current value * - * In both cases, the namespace is unlocked by the acpi_ns* procedure + * 1) The object is a control method -- execute it + * 2) The object is not a method -- just return it's current value */ - if (acpi_ns_get_type(info->node) == ACPI_TYPE_METHOD) { + if (acpi_ns_get_type(info->resolved_node) == ACPI_TYPE_METHOD) { /* - * Case 1) We have an actual control method to execute + * 1) Object is a control method - execute it */ - status = acpi_ns_execute_control_method(info); - } else { - /* - * Case 2) Object is NOT a method, just return its current value - */ - status = acpi_ns_get_object_value(info); - } - - /* - * Check if there is a return value on the stack that must be dealt with - */ - if (status == AE_CTRL_RETURN_VALUE) { - - /* Map AE_CTRL_RETURN_VALUE to AE_OK, we are done with it */ - - status = AE_OK; - } - - /* - * Namespace was unlocked by the handling acpi_ns* function, so we - * just return - */ - return_ACPI_STATUS(status); -} - -/******************************************************************************* - * - * FUNCTION: acpi_ns_execute_control_method - * - * PARAMETERS: Info - Method info block, contains: - * Node - Method Node to execute - * obj_desc - Method object - * Parameters - List of parameters to pass to the method, - * terminated by NULL. Params itself may be - * NULL if no parameters are being passed. - * return_object - Where to put method's return value (if - * any). If NULL, no value is returned. - * parameter_type - Type of Parameter list - * return_object - Where to put method's return value (if - * any). If NULL, no value is returned. - * - * RETURN: Status - * - * DESCRIPTION: Execute the requested method passing the given parameters - * - * MUTEX: Assumes namespace is locked - * - ******************************************************************************/ - -static acpi_status -acpi_ns_execute_control_method(struct acpi_parameter_info *info) -{ - acpi_status status; - - ACPI_FUNCTION_TRACE(ns_execute_control_method); - - /* Verify that there is a method associated with this object */ - - info->obj_desc = acpi_ns_get_attached_object(info->node); - if (!info->obj_desc) { - ACPI_ERROR((AE_INFO, "No attached method object")); - (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); - return_ACPI_STATUS(AE_NULL_OBJECT); - } - - ACPI_DUMP_PATHNAME(info->node, "Execute Method:", - ACPI_LV_INFO, _COMPONENT); - - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Method at AML address %p Length %X\n", - info->obj_desc->method.aml_start + 1, - info->obj_desc->method.aml_length - 1)); - - /* - * Unlock the namespace before execution. This allows namespace access - * via the external Acpi* interfaces while a method is being executed. - * However, any namespace deletion must acquire both the namespace and - * interpreter locks to ensure that no thread is using the portion of the - * namespace that is being deleted. - */ - status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } + /* Verify that there is a method object associated with this node */ - /* - * Execute the method via the interpreter. The interpreter is locked - * here before calling into the AML parser - */ - status = acpi_ex_enter_interpreter(); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } + info->obj_desc = + acpi_ns_get_attached_object(info->resolved_node); + if (!info->obj_desc) { + ACPI_ERROR((AE_INFO, + "Control method has no attached sub-object")); + return_ACPI_STATUS(AE_NULL_OBJECT); + } - status = acpi_ps_execute_method(info); - acpi_ex_exit_interpreter(); + ACPI_DUMP_PATHNAME(info->resolved_node, "Execute Method:", + ACPI_LV_INFO, _COMPONENT); - return_ACPI_STATUS(status); -} + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, + "Method at AML address %p Length %X\n", + info->obj_desc->method.aml_start + 1, + info->obj_desc->method.aml_length - 1)); -/******************************************************************************* - * - * FUNCTION: acpi_ns_get_object_value - * - * PARAMETERS: Info - Method info block, contains: - * Node - Object's NS node - * return_object - Where to put object value (if - * any). If NULL, no value is returned. - * - * RETURN: Status - * - * DESCRIPTION: Return the current value of the object - * - * MUTEX: Assumes namespace is locked, leaves namespace unlocked - * - ******************************************************************************/ + /* + * Any namespace deletion must acquire both the namespace and + * interpreter locks to ensure that no thread is using the portion of + * the namespace that is being deleted. + * + * Execute the method via the interpreter. The interpreter is locked + * here before calling into the AML parser + */ + status = acpi_ex_enter_interpreter(); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } -static acpi_status acpi_ns_get_object_value(struct acpi_parameter_info *info) -{ - acpi_status status = AE_OK; - struct acpi_namespace_node *resolved_node = info->node; + status = acpi_ps_execute_method(info); + acpi_ex_exit_interpreter(); + } else { + /* + * 2) Object is not a method, return its current value + */ - ACPI_FUNCTION_TRACE(ns_get_object_value); + /* + * Objects require additional resolution steps (e.g., the Node may be + * a field that must be read, etc.) -- we can't just grab the object + * out of the node. + * + * Use resolve_node_to_value() to get the associated value. + * + * NOTE: we can get away with passing in NULL for a walk state because + * resolved_node is guaranteed to not be a reference to either a method + * local or a method argument (because this interface is never called + * from a running method.) + * + * Even though we do not directly invoke the interpreter for object + * resolution, we must lock it because we could access an opregion. + * The opregion access code assumes that the interpreter is locked. + */ + status = acpi_ex_enter_interpreter(); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } - /* - * Objects require additional resolution steps (e.g., the Node may be a - * field that must be read, etc.) -- we can't just grab the object out of - * the node. - */ + /* Function has a strange interface */ - /* - * Use resolve_node_to_value() to get the associated value. This call always - * deletes obj_desc (allocated above). - * - * NOTE: we can get away with passing in NULL for a walk state because - * obj_desc is guaranteed to not be a reference to either a method local or - * a method argument (because this interface can only be called from the - * acpi_evaluate external interface, never called from a running method.) - * - * Even though we do not directly invoke the interpreter for this, we must - * enter it because we could access an opregion. The opregion access code - * assumes that the interpreter is locked. - * - * We must release the namespace lock before entering the intepreter. - */ - status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } + status = + acpi_ex_resolve_node_to_value(&info->resolved_node, NULL); + acpi_ex_exit_interpreter(); - status = acpi_ex_enter_interpreter(); - if (ACPI_SUCCESS(status)) { - status = acpi_ex_resolve_node_to_value(&resolved_node, NULL); /* * If acpi_ex_resolve_node_to_value() succeeded, the return value was placed * in resolved_node. */ - acpi_ex_exit_interpreter(); - if (ACPI_SUCCESS(status)) { status = AE_CTRL_RETURN_VALUE; - info->return_object = ACPI_CAST_PTR - (union acpi_operand_object, resolved_node); + info->return_object = + ACPI_CAST_PTR(union acpi_operand_object, + info->resolved_node); + ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Returning object %p [%s]\n", info->return_object, @@ -485,7 +211,30 @@ static acpi_status acpi_ns_get_object_value(struct acpi_parameter_info *info) } } - /* Namespace is unlocked */ + /* + * Check if there is a return value that must be dealt with + */ + if (status == AE_CTRL_RETURN_VALUE) { + + /* If caller does not want the return value, delete it */ + if (info->flags & ACPI_IGNORE_RETURN_VALUE) { + acpi_ut_remove_reference(info->return_object); + info->return_object = NULL; + } + + /* Map AE_CTRL_RETURN_VALUE to AE_OK, we are done with it */ + + status = AE_OK; + } + + ACPI_DEBUG_PRINT((ACPI_DB_NAMES, + "*** Completed evaluation of object %s ***\n", + info->pathname)); + + /* + * Namespace was unlocked by the handling acpi_ns* function, so we + * just return + */ return_ACPI_STATUS(status); } diff --git a/drivers/acpi/namespace/nsinit.c b/drivers/acpi/namespace/nsinit.c index bf1d8dbc0b86..1c9ca6e05314 100644 --- a/drivers/acpi/namespace/nsinit.c +++ b/drivers/acpi/namespace/nsinit.c @@ -154,7 +154,16 @@ acpi_status acpi_ns_initialize_devices(void) ACPI_UINT32_MAX, FALSE, acpi_ns_find_ini_methods, &info, NULL); if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "During WalkNamespace")); + goto error_exit; + } + + /* Allocate the evaluation information block */ + + info.evaluate_info = + ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info)); + if (!info.evaluate_info) { + status = AE_NO_MEMORY; + goto error_exit; } /* Walk namespace to execute all _INIs on present devices */ @@ -162,8 +171,10 @@ acpi_status acpi_ns_initialize_devices(void) status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, FALSE, acpi_ns_init_one_device, &info, NULL); + + ACPI_FREE(info.evaluate_info); if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "During WalkNamespace")); + goto error_exit; } ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, @@ -171,6 +182,10 @@ acpi_status acpi_ns_initialize_devices(void) info.num_INI, info.num_STA, info.device_count)); return_ACPI_STATUS(status); + + error_exit: + ACPI_EXCEPTION((AE_INFO, status, "During device initialization")); + return_ACPI_STATUS(status); } /******************************************************************************* @@ -398,9 +413,9 @@ static acpi_status acpi_ns_init_one_device(acpi_handle obj_handle, u32 nesting_level, void *context, void **return_value) { - struct acpi_device_walk_info *info = + struct acpi_device_walk_info *walk_info = ACPI_CAST_PTR(struct acpi_device_walk_info, context); - struct acpi_parameter_info pinfo; + struct acpi_evaluate_info *info = walk_info->evaluate_info; u32 flags; acpi_status status; struct acpi_namespace_node *device_node; @@ -460,7 +475,7 @@ acpi_ns_init_one_device(acpi_handle obj_handle, * other words, the device is present, ..., and functioning)" */ if (flags != ACPI_UINT32_MAX) { - info->num_STA++; + walk_info->num_STA++; } /* @@ -516,20 +531,16 @@ acpi_ns_init_one_device(acpi_handle obj_handle, ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname (ACPI_TYPE_METHOD, device_node, METHOD_NAME__INI)); - pinfo.node = device_node; - pinfo.parameters = NULL; - pinfo.parameter_type = ACPI_PARAM_ARGS; + info->prefix_node = device_node; + info->pathname = METHOD_NAME__INI; + info->parameters = NULL; + info->parameter_type = ACPI_PARAM_ARGS; + info->flags = ACPI_IGNORE_RETURN_VALUE; - status = acpi_ns_evaluate_relative(METHOD_NAME__INI, &pinfo); + status = acpi_ns_evaluate(info); if (ACPI_SUCCESS(status)) { + walk_info->num_INI++; - /* Delete any return object (especially if implicit_return is enabled) */ - - if (pinfo.return_object) { - acpi_ut_remove_reference(pinfo.return_object); - } - - info->num_INI++; if ((acpi_dbg_level <= ACPI_LV_ALL_EXCEPTIONS) && (!(acpi_dbg_level & ACPI_LV_INFO))) { ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, ".")); @@ -540,20 +551,24 @@ acpi_ns_init_one_device(acpi_handle obj_handle, /* Ignore error and move on to next device */ - char *scope_name = acpi_ns_get_external_pathname(pinfo.node); + char *scope_name = + acpi_ns_get_external_pathname(info->resolved_node); ACPI_EXCEPTION((AE_INFO, status, "during %s._INI execution", scope_name)); ACPI_FREE(scope_name); + status = AE_OK; } #endif - /* If an external initialization handler is present, call it */ - + /* + * The _INI method has been run if present; call the Global Initialization + * Handler for this device. + */ if (acpi_gbl_init_handler) { status = - acpi_gbl_init_handler(pinfo.node, ACPI_INIT_DEVICE_INI); + acpi_gbl_init_handler(device_node, ACPI_INIT_DEVICE_INI); } - return_ACPI_STATUS(AE_OK); + return_ACPI_STATUS(status); } diff --git a/drivers/acpi/namespace/nssearch.c b/drivers/acpi/namespace/nssearch.c index d2473476afa5..500e2bbcfaf7 100644 --- a/drivers/acpi/namespace/nssearch.c +++ b/drivers/acpi/namespace/nssearch.c @@ -56,16 +56,16 @@ acpi_ns_search_parent_tree(u32 target_name, /******************************************************************************* * - * FUNCTION: acpi_ns_search_node + * FUNCTION: acpi_ns_search_one_scope * * PARAMETERS: target_name - Ascii ACPI name to search for - * Node - Starting node where search will begin + * parent_node - Starting node where search will begin * Type - Object type to match * return_node - Where the matched Named obj is returned * * RETURN: Status * - * DESCRIPTION: Search a single level of the namespace. Performs a + * DESCRIPTION: Search a single level of the namespace. Performs a * simple search of the specified level, and does not add * entries or search parents. * @@ -75,32 +75,37 @@ acpi_ns_search_parent_tree(u32 target_name, * * All namespace searching is linear in this implementation, but * could be easily modified to support any improved search - * algorithm. However, the linear search was chosen for simplicity + * algorithm. However, the linear search was chosen for simplicity * and because the trees are small and the other interpreter * execution overhead is relatively high. * + * Note: CPU execution analysis has shown that the AML interpreter spends + * a very small percentage of its time searching the namespace. Therefore, + * the linear search seems to be sufficient, as there would seem to be + * little value in improving the search. + * ******************************************************************************/ acpi_status -acpi_ns_search_node(u32 target_name, - struct acpi_namespace_node *node, - acpi_object_type type, - struct acpi_namespace_node **return_node) +acpi_ns_search_one_scope(u32 target_name, + struct acpi_namespace_node *parent_node, + acpi_object_type type, + struct acpi_namespace_node **return_node) { - struct acpi_namespace_node *next_node; + struct acpi_namespace_node *node; - ACPI_FUNCTION_TRACE(ns_search_node); + ACPI_FUNCTION_TRACE(ns_search_one_scope); #ifdef ACPI_DEBUG_OUTPUT if (ACPI_LV_NAMES & acpi_dbg_level) { char *scope_name; - scope_name = acpi_ns_get_external_pathname(node); + scope_name = acpi_ns_get_external_pathname(parent_node); if (scope_name) { ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Searching %s (%p) For [%4.4s] (%s)\n", - scope_name, node, ACPI_CAST_PTR(char, - &target_name), + scope_name, parent_node, + ACPI_CAST_PTR(char, &target_name), acpi_ut_get_type_name(type))); ACPI_FREE(scope_name); @@ -112,20 +117,20 @@ acpi_ns_search_node(u32 target_name, * Search for name at this namespace level, which is to say that we * must search for the name among the children of this object */ - next_node = node->child; - while (next_node) { + node = parent_node->child; + while (node) { /* Check for match against the name */ - if (next_node->name.integer == target_name) { + if (node->name.integer == target_name) { /* Resolve a control method alias if any */ - if (acpi_ns_get_type(next_node) == + if (acpi_ns_get_type(node) == ACPI_TYPE_LOCAL_METHOD_ALIAS) { - next_node = + node = ACPI_CAST_PTR(struct acpi_namespace_node, - next_node->object); + node->object); } /* Found matching entry */ @@ -133,12 +138,12 @@ acpi_ns_search_node(u32 target_name, ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Name [%4.4s] (%s) %p found in scope [%4.4s] %p\n", ACPI_CAST_PTR(char, &target_name), - acpi_ut_get_type_name(next_node-> - type), - next_node, - acpi_ut_get_node_name(node), node)); + acpi_ut_get_type_name(node->type), + node, + acpi_ut_get_node_name(parent_node), + parent_node)); - *return_node = next_node; + *return_node = node; return_ACPI_STATUS(AE_OK); } @@ -146,7 +151,7 @@ acpi_ns_search_node(u32 target_name, * The last entry in the list points back to the parent, * so a flag is used to indicate the end-of-list */ - if (next_node->flags & ANOBJ_END_OF_PEER_LIST) { + if (node->flags & ANOBJ_END_OF_PEER_LIST) { /* Searched entire list, we are done */ @@ -155,7 +160,7 @@ acpi_ns_search_node(u32 target_name, /* Didn't match name, move on to the next peer object */ - next_node = next_node->peer; + node = node->peer; } /* Searched entire namespace level, not found */ @@ -164,7 +169,8 @@ acpi_ns_search_node(u32 target_name, "Name [%4.4s] (%s) not found in search in scope [%4.4s] %p first child %p\n", ACPI_CAST_PTR(char, &target_name), acpi_ut_get_type_name(type), - acpi_ut_get_node_name(node), node, node->child)); + acpi_ut_get_node_name(parent_node), parent_node, + parent_node->child)); return_ACPI_STATUS(AE_NOT_FOUND); } @@ -181,14 +187,14 @@ acpi_ns_search_node(u32 target_name, * RETURN: Status * * DESCRIPTION: Called when a name has not been found in the current namespace - * level. Before adding it or giving up, ACPI scope rules require + * level. Before adding it or giving up, ACPI scope rules require * searching enclosing scopes in cases identified by acpi_ns_local(). * * "A name is located by finding the matching name in the current * name space, and then in the parent name space. If the parent * name space does not contain the name, the search continues * recursively until either the name is found or the name space - * does not have a parent (the root of the name space). This + * does not have a parent (the root of the name space). This * indicates that the name is not found" (From ACPI Specification, * section 5.3) * @@ -237,11 +243,12 @@ acpi_ns_search_parent_tree(u32 target_name, */ while (parent_node) { /* - * Search parent scope. Use TYPE_ANY because we don't care about the + * Search parent scope. Use TYPE_ANY because we don't care about the * object type at this point, we only care about the existence of - * the actual name we are searching for. Typechecking comes later. + * the actual name we are searching for. Typechecking comes later. */ - status = acpi_ns_search_node(target_name, parent_node, + status = + acpi_ns_search_one_scope(target_name, parent_node, ACPI_TYPE_ANY, return_node); if (ACPI_SUCCESS(status)) { return_ACPI_STATUS(status); @@ -273,7 +280,7 @@ acpi_ns_search_parent_tree(u32 target_name, * RETURN: Status * * DESCRIPTION: Search for a name segment in a single namespace level, - * optionally adding it if it is not found. If the passed + * optionally adding it if it is not found. If the passed * Type is not Any and the type previously stored in the * entry was Any (i.e. unknown), update the stored type. * @@ -332,7 +339,7 @@ acpi_ns_search_and_enter(u32 target_name, /* Try to find the name in the namespace level specified by the caller */ *return_node = ACPI_ENTRY_NOT_FOUND; - status = acpi_ns_search_node(target_name, node, type, return_node); + status = acpi_ns_search_one_scope(target_name, node, type, return_node); if (status != AE_NOT_FOUND) { /* * If we found it AND the request specifies that a find is an error, @@ -348,10 +355,10 @@ acpi_ns_search_and_enter(u32 target_name, } /* - * The name was not found. If we are NOT performing the first pass + * The name was not found. If we are NOT performing the first pass * (name entry) of loading the namespace, search the parent tree (all the * way to the root if necessary.) We don't want to perform the parent - * search when the namespace is actually being loaded. We want to perform + * search when the namespace is actually being loaded. We want to perform * the search when namespace references are being resolved (load pass 2) * and during the execution phase. */ @@ -386,6 +393,9 @@ acpi_ns_search_and_enter(u32 target_name, return_ACPI_STATUS(AE_NO_MEMORY); } #ifdef ACPI_ASL_COMPILER + /* + * Node is an object defined by an External() statement + */ if (flags & ACPI_NS_EXTERNAL) { new_node->flags |= ANOBJ_IS_EXTERNAL; } diff --git a/drivers/acpi/namespace/nsutils.c b/drivers/acpi/namespace/nsutils.c index d1d55032b455..aa4e799d9a8c 100644 --- a/drivers/acpi/namespace/nsutils.c +++ b/drivers/acpi/namespace/nsutils.c @@ -142,8 +142,9 @@ acpi_ns_report_method_error(char *module_name, acpi_os_printf("ACPI Error (%s-%04d): ", module_name, line_number); if (path) { - status = acpi_ns_get_node_by_path(path, prefix_node, - ACPI_NS_NO_UPSEARCH, &node); + status = + acpi_ns_get_node(prefix_node, path, ACPI_NS_NO_UPSEARCH, + &node); if (ACPI_FAILURE(status)) { acpi_os_printf("[Could not get node by pathname]"); } @@ -685,13 +686,9 @@ struct acpi_namespace_node *acpi_ns_map_handle_to_node(acpi_handle handle) ACPI_FUNCTION_ENTRY(); /* - * Simple implementation. + * Simple implementation */ - if (!handle) { - return (NULL); - } - - if (handle == ACPI_ROOT_OBJECT) { + if ((!handle) || (handle == ACPI_ROOT_OBJECT)) { return (acpi_gbl_root_node); } @@ -701,7 +698,7 @@ struct acpi_namespace_node *acpi_ns_map_handle_to_node(acpi_handle handle) return (NULL); } - return ((struct acpi_namespace_node *)handle); + return (ACPI_CAST_PTR(struct acpi_namespace_node, handle)); } /******************************************************************************* @@ -811,12 +808,12 @@ u32 acpi_ns_opens_scope(acpi_object_type type) /******************************************************************************* * - * FUNCTION: acpi_ns_get_node_by_path + * FUNCTION: acpi_ns_get_node * * PARAMETERS: *Pathname - Name to be found, in external (ASL) format. The * \ (backslash) and ^ (carat) prefixes, and the * . (period) to separate segments are supported. - * start_node - Root of subtree to be searched, or NS_ALL for the + * prefix_node - Root of subtree to be searched, or NS_ALL for the * root of the name space. If Name is fully * qualified (first s8 is '\'), the passed value * of Scope will not be accessed. @@ -832,24 +829,29 @@ u32 acpi_ns_opens_scope(acpi_object_type type) ******************************************************************************/ acpi_status -acpi_ns_get_node_by_path(char *pathname, - struct acpi_namespace_node *start_node, - u32 flags, struct acpi_namespace_node **return_node) +acpi_ns_get_node(struct acpi_namespace_node *prefix_node, + char *pathname, + u32 flags, struct acpi_namespace_node **return_node) { union acpi_generic_state scope_info; acpi_status status; - char *internal_path = NULL; + char *internal_path; - ACPI_FUNCTION_TRACE_PTR(ns_get_node_by_path, pathname); + ACPI_FUNCTION_TRACE_PTR(ns_get_node, pathname); - if (pathname) { + if (!pathname) { + *return_node = prefix_node; + if (!prefix_node) { + *return_node = acpi_gbl_root_node; + } + return_ACPI_STATUS(AE_OK); + } - /* Convert path to internal representation */ + /* Convert path to internal representation */ - status = acpi_ns_internalize_name(pathname, &internal_path); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } + status = acpi_ns_internalize_name(pathname, &internal_path); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); } /* Must lock namespace during lookup */ @@ -861,26 +863,23 @@ acpi_ns_get_node_by_path(char *pathname, /* Setup lookup scope (search starting point) */ - scope_info.scope.node = start_node; + scope_info.scope.node = prefix_node; /* Lookup the name in the namespace */ - status = acpi_ns_lookup(&scope_info, internal_path, - ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, - (flags | ACPI_NS_DONT_OPEN_SCOPE), - NULL, return_node); + status = acpi_ns_lookup(&scope_info, internal_path, ACPI_TYPE_ANY, + ACPI_IMODE_EXECUTE, + (flags | ACPI_NS_DONT_OPEN_SCOPE), NULL, + return_node); if (ACPI_FAILURE(status)) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s, %s\n", - internal_path, - acpi_format_exception(status))); + pathname, acpi_format_exception(status))); } (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); cleanup: - if (internal_path) { - ACPI_FREE(internal_path); - } + ACPI_FREE(internal_path); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/namespace/nsxfeval.c b/drivers/acpi/namespace/nsxfeval.c index 998b29611b19..6d9bd45af30a 100644 --- a/drivers/acpi/namespace/nsxfeval.c +++ b/drivers/acpi/namespace/nsxfeval.c @@ -171,51 +171,61 @@ acpi_evaluate_object(acpi_handle handle, { acpi_status status; acpi_status status2; - struct acpi_parameter_info info; + struct acpi_evaluate_info *info; acpi_size buffer_space_needed; u32 i; ACPI_FUNCTION_TRACE(acpi_evaluate_object); - info.node = handle; - info.parameters = NULL; - info.return_object = NULL; - info.parameter_type = ACPI_PARAM_ARGS; + /* Allocate and initialize the evaluation information block */ + + info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info)); + if (!info) { + return_ACPI_STATUS(AE_NO_MEMORY); + } + + info->pathname = pathname; + info->parameter_type = ACPI_PARAM_ARGS; + + /* Convert and validate the device handle */ + + info->prefix_node = acpi_ns_map_handle_to_node(handle); + if (!info->prefix_node) { + status = AE_BAD_PARAMETER; + goto cleanup; + } /* - * If there are parameters to be passed to the object - * (which must be a control method), the external objects - * must be converted to internal objects + * If there are parameters to be passed to a control method, the external + * objects must all be converted to internal objects */ if (external_params && external_params->count) { /* * Allocate a new parameter block for the internal objects * Add 1 to count to allow for null terminated internal list */ - info.parameters = ACPI_ALLOCATE_ZEROED(((acpi_size) - external_params->count + - 1) * sizeof(void *)); - if (!info.parameters) { - return_ACPI_STATUS(AE_NO_MEMORY); + info->parameters = ACPI_ALLOCATE_ZEROED(((acpi_size) + external_params-> + count + + 1) * sizeof(void *)); + if (!info->parameters) { + status = AE_NO_MEMORY; + goto cleanup; } - /* - * Convert each external object in the list to an - * internal object - */ + /* Convert each external object in the list to an internal object */ + for (i = 0; i < external_params->count; i++) { status = acpi_ut_copy_eobject_to_iobject(&external_params-> pointer[i], - &info. + &info-> parameters[i]); if (ACPI_FAILURE(status)) { - acpi_ut_delete_internal_object_list(info. - parameters); - return_ACPI_STATUS(status); + goto cleanup; } } - info.parameters[external_params->count] = NULL; + info->parameters[external_params->count] = NULL; } /* @@ -228,12 +238,13 @@ acpi_evaluate_object(acpi_handle handle, /* The path is fully qualified, just evaluate by name */ - status = acpi_ns_evaluate_by_name(pathname, &info); + info->prefix_node = NULL; + status = acpi_ns_evaluate(info); } else if (!handle) { /* - * A handle is optional iff a fully qualified pathname - * is specified. Since we've already handled fully - * qualified names above, this is an error + * A handle is optional iff a fully qualified pathname is specified. + * Since we've already handled fully qualified names above, this is + * an error */ if (!pathname) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, @@ -246,22 +257,9 @@ acpi_evaluate_object(acpi_handle handle, status = AE_BAD_PARAMETER; } else { - /* - * We get here if we have a handle -- and if we have a - * pathname it is relative. The handle will be validated - * in the lower procedures - */ - if (!pathname) { - /* - * The null pathname case means the handle is for - * the actual object to be evaluated - */ - status = acpi_ns_evaluate_by_handle(&info); - } else { - /* Both a Handle and a relative Pathname */ + /* We have a namespace a node and a possible relative path */ - status = acpi_ns_evaluate_relative(pathname, &info); - } + status = acpi_ns_evaluate(info); } /* @@ -269,10 +267,10 @@ acpi_evaluate_object(acpi_handle handle, * copy the return value to an external object. */ if (return_buffer) { - if (!info.return_object) { + if (!info->return_object) { return_buffer->length = 0; } else { - if (ACPI_GET_DESCRIPTOR_TYPE(info.return_object) == + if (ACPI_GET_DESCRIPTOR_TYPE(info->return_object) == ACPI_DESC_TYPE_NAMED) { /* * If we received a NS Node as a return object, this means that @@ -283,17 +281,16 @@ acpi_evaluate_object(acpi_handle handle, * support for various types at a later date if necessary. */ status = AE_TYPE; - info.return_object = NULL; /* No need to delete a NS Node */ + info->return_object = NULL; /* No need to delete a NS Node */ return_buffer->length = 0; } if (ACPI_SUCCESS(status)) { - /* - * Find out how large a buffer is needed - * to contain the returned object - */ + + /* Get the size of the returned object */ + status = - acpi_ut_get_object_size(info.return_object, + acpi_ut_get_object_size(info->return_object, &buffer_space_needed); if (ACPI_SUCCESS(status)) { @@ -319,7 +316,7 @@ acpi_evaluate_object(acpi_handle handle, status = acpi_ut_copy_iobject_to_eobject - (info.return_object, + (info->return_object, return_buffer); } } @@ -327,31 +324,33 @@ acpi_evaluate_object(acpi_handle handle, } } - if (info.return_object) { + if (info->return_object) { /* - * Delete the internal return object. NOTE: Interpreter - * must be locked to avoid race condition. + * Delete the internal return object. NOTE: Interpreter must be + * locked to avoid race condition. */ status2 = acpi_ex_enter_interpreter(); if (ACPI_SUCCESS(status2)) { - /* - * Delete the internal return object. (Or at least - * decrement the reference count by one) - */ - acpi_ut_remove_reference(info.return_object); + + /* Remove one reference on the return object (should delete it) */ + + acpi_ut_remove_reference(info->return_object); acpi_ex_exit_interpreter(); } } + cleanup: + /* Free the input parameter list (if we created one) */ - if (info.parameters) { + if (info->parameters) { /* Free the allocated parameter block */ - acpi_ut_delete_internal_object_list(info.parameters); + acpi_ut_delete_internal_object_list(info->parameters); } + ACPI_FREE(info); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/namespace/nsxfname.c b/drivers/acpi/namespace/nsxfname.c index 1303e2b062bb..978213a6c19f 100644 --- a/drivers/acpi/namespace/nsxfname.c +++ b/drivers/acpi/namespace/nsxfname.c @@ -112,9 +112,8 @@ acpi_get_handle(acpi_handle parent, /* * Find the Node and convert to a handle */ - status = - acpi_ns_get_node_by_path(pathname, prefix_node, ACPI_NS_NO_UPSEARCH, - &node); + status = acpi_ns_get_node(prefix_node, pathname, ACPI_NS_NO_UPSEARCH, + &node); *ret_handle = NULL; if (ACPI_SUCCESS(status)) { diff --git a/drivers/acpi/parser/psparse.c b/drivers/acpi/parser/psparse.c index 796f6b719929..7ee2f2e77525 100644 --- a/drivers/acpi/parser/psparse.c +++ b/drivers/acpi/parser/psparse.c @@ -464,6 +464,7 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state) thread = acpi_ut_create_thread_state(); if (!thread) { + acpi_ds_delete_walk_state(walk_state); return_ACPI_STATUS(AE_NO_MEMORY); } diff --git a/drivers/acpi/parser/psxface.c b/drivers/acpi/parser/psxface.c index 6b1411f1087d..5d996c1140af 100644 --- a/drivers/acpi/parser/psxface.c +++ b/drivers/acpi/parser/psxface.c @@ -50,14 +50,14 @@ ACPI_MODULE_NAME("psxface") /* Local Prototypes */ -static void acpi_ps_start_trace(struct acpi_parameter_info *info); +static void acpi_ps_start_trace(struct acpi_evaluate_info *info); -static void acpi_ps_stop_trace(struct acpi_parameter_info *info); +static void acpi_ps_stop_trace(struct acpi_evaluate_info *info); -static acpi_status acpi_ps_execute_pass(struct acpi_parameter_info *info); +static acpi_status acpi_ps_execute_pass(struct acpi_evaluate_info *info); static void -acpi_ps_update_parameter_list(struct acpi_parameter_info *info, u16 action); +acpi_ps_update_parameter_list(struct acpi_evaluate_info *info, u16 action); /******************************************************************************* * @@ -113,7 +113,7 @@ acpi_debug_trace(char *name, u32 debug_level, u32 debug_layer, u32 flags) * ******************************************************************************/ -static void acpi_ps_start_trace(struct acpi_parameter_info *info) +static void acpi_ps_start_trace(struct acpi_evaluate_info *info) { acpi_status status; @@ -125,7 +125,7 @@ static void acpi_ps_start_trace(struct acpi_parameter_info *info) } if ((!acpi_gbl_trace_method_name) || - (acpi_gbl_trace_method_name != info->node->name.integer)) { + (acpi_gbl_trace_method_name != info->resolved_node->name.integer)) { goto exit; } @@ -158,7 +158,7 @@ static void acpi_ps_start_trace(struct acpi_parameter_info *info) * ******************************************************************************/ -static void acpi_ps_stop_trace(struct acpi_parameter_info *info) +static void acpi_ps_stop_trace(struct acpi_evaluate_info *info) { acpi_status status; @@ -170,7 +170,7 @@ static void acpi_ps_stop_trace(struct acpi_parameter_info *info) } if ((!acpi_gbl_trace_method_name) || - (acpi_gbl_trace_method_name != info->node->name.integer)) { + (acpi_gbl_trace_method_name != info->resolved_node->name.integer)) { goto exit; } @@ -212,7 +212,7 @@ static void acpi_ps_stop_trace(struct acpi_parameter_info *info) * ******************************************************************************/ -acpi_status acpi_ps_execute_method(struct acpi_parameter_info *info) +acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info) { acpi_status status; @@ -220,14 +220,15 @@ acpi_status acpi_ps_execute_method(struct acpi_parameter_info *info) /* Validate the Info and method Node */ - if (!info || !info->node) { + if (!info || !info->resolved_node) { return_ACPI_STATUS(AE_NULL_ENTRY); } /* Init for new method, wait on concurrency semaphore */ status = - acpi_ds_begin_method_execution(info->node, info->obj_desc, NULL); + acpi_ds_begin_method_execution(info->resolved_node, info->obj_desc, + NULL); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -248,7 +249,7 @@ acpi_status acpi_ps_execute_method(struct acpi_parameter_info *info) */ ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "**** Begin Method Parse **** Entry=%p obj=%p\n", - info->node, info->obj_desc)); + info->resolved_node, info->obj_desc)); info->pass_number = 1; status = acpi_ps_execute_pass(info); @@ -261,7 +262,7 @@ acpi_status acpi_ps_execute_method(struct acpi_parameter_info *info) */ ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "**** Begin Method Execution **** Entry=%p obj=%p\n", - info->node, info->obj_desc)); + info->resolved_node, info->obj_desc)); info->pass_number = 3; status = acpi_ps_execute_pass(info); @@ -300,7 +301,7 @@ acpi_status acpi_ps_execute_method(struct acpi_parameter_info *info) * * FUNCTION: acpi_ps_update_parameter_list * - * PARAMETERS: Info - See struct acpi_parameter_info + * PARAMETERS: Info - See struct acpi_evaluate_info * (Used: parameter_type and Parameters) * Action - Add or Remove reference * @@ -311,7 +312,7 @@ acpi_status acpi_ps_execute_method(struct acpi_parameter_info *info) ******************************************************************************/ static void -acpi_ps_update_parameter_list(struct acpi_parameter_info *info, u16 action) +acpi_ps_update_parameter_list(struct acpi_evaluate_info *info, u16 action) { acpi_native_uint i; @@ -334,7 +335,7 @@ acpi_ps_update_parameter_list(struct acpi_parameter_info *info, u16 action) * * FUNCTION: acpi_ps_execute_pass * - * PARAMETERS: Info - See struct acpi_parameter_info + * PARAMETERS: Info - See struct acpi_evaluate_info * (Used: pass_number, Node, and obj_desc) * * RETURN: Status @@ -343,7 +344,7 @@ acpi_ps_update_parameter_list(struct acpi_parameter_info *info, u16 action) * ******************************************************************************/ -static acpi_status acpi_ps_execute_pass(struct acpi_parameter_info *info) +static acpi_status acpi_ps_execute_pass(struct acpi_evaluate_info *info) { acpi_status status; union acpi_parse_object *op; @@ -368,7 +369,7 @@ static acpi_status acpi_ps_execute_pass(struct acpi_parameter_info *info) goto cleanup; } - status = acpi_ds_init_aml_walk(walk_state, op, info->node, + status = acpi_ds_init_aml_walk(walk_state, op, info->resolved_node, info->obj_desc->method.aml_start, info->obj_desc->method.aml_length, info->pass_number == 1 ? NULL : info, diff --git a/drivers/acpi/resources/rsutils.c b/drivers/acpi/resources/rsutils.c index 0e493f2fec4d..a9cbee8e8b44 100644 --- a/drivers/acpi/resources/rsutils.c +++ b/drivers/acpi/resources/rsutils.c @@ -442,7 +442,7 @@ acpi_rs_set_resource_source(union aml_resource * aml, * * FUNCTION: acpi_rs_get_prt_method_data * - * PARAMETERS: Handle - Handle to the containing object + * PARAMETERS: Node - Device node * ret_buffer - Pointer to a buffer structure for the * results * @@ -457,7 +457,8 @@ acpi_rs_set_resource_source(union aml_resource * aml, ******************************************************************************/ acpi_status -acpi_rs_get_prt_method_data(acpi_handle handle, struct acpi_buffer * ret_buffer) +acpi_rs_get_prt_method_data(struct acpi_namespace_node * node, + struct acpi_buffer * ret_buffer) { union acpi_operand_object *obj_desc; acpi_status status; @@ -468,7 +469,7 @@ acpi_rs_get_prt_method_data(acpi_handle handle, struct acpi_buffer * ret_buffer) /* Execute the method, no parameters */ - status = acpi_ut_evaluate_object(handle, METHOD_NAME__PRT, + status = acpi_ut_evaluate_object(node, METHOD_NAME__PRT, ACPI_BTYPE_PACKAGE, &obj_desc); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); @@ -490,7 +491,7 @@ acpi_rs_get_prt_method_data(acpi_handle handle, struct acpi_buffer * ret_buffer) * * FUNCTION: acpi_rs_get_crs_method_data * - * PARAMETERS: Handle - Handle to the containing object + * PARAMETERS: Node - Device node * ret_buffer - Pointer to a buffer structure for the * results * @@ -505,7 +506,8 @@ acpi_rs_get_prt_method_data(acpi_handle handle, struct acpi_buffer * ret_buffer) ******************************************************************************/ acpi_status -acpi_rs_get_crs_method_data(acpi_handle handle, struct acpi_buffer *ret_buffer) +acpi_rs_get_crs_method_data(struct acpi_namespace_node *node, + struct acpi_buffer *ret_buffer) { union acpi_operand_object *obj_desc; acpi_status status; @@ -516,7 +518,7 @@ acpi_rs_get_crs_method_data(acpi_handle handle, struct acpi_buffer *ret_buffer) /* Execute the method, no parameters */ - status = acpi_ut_evaluate_object(handle, METHOD_NAME__CRS, + status = acpi_ut_evaluate_object(node, METHOD_NAME__CRS, ACPI_BTYPE_BUFFER, &obj_desc); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); @@ -539,7 +541,7 @@ acpi_rs_get_crs_method_data(acpi_handle handle, struct acpi_buffer *ret_buffer) * * FUNCTION: acpi_rs_get_prs_method_data * - * PARAMETERS: Handle - Handle to the containing object + * PARAMETERS: Node - Device node * ret_buffer - Pointer to a buffer structure for the * results * @@ -555,7 +557,8 @@ acpi_rs_get_crs_method_data(acpi_handle handle, struct acpi_buffer *ret_buffer) #ifdef ACPI_FUTURE_USAGE acpi_status -acpi_rs_get_prs_method_data(acpi_handle handle, struct acpi_buffer *ret_buffer) +acpi_rs_get_prs_method_data(struct acpi_namespace_node *node, + struct acpi_buffer *ret_buffer) { union acpi_operand_object *obj_desc; acpi_status status; @@ -566,7 +569,7 @@ acpi_rs_get_prs_method_data(acpi_handle handle, struct acpi_buffer *ret_buffer) /* Execute the method, no parameters */ - status = acpi_ut_evaluate_object(handle, METHOD_NAME__PRS, + status = acpi_ut_evaluate_object(node, METHOD_NAME__PRS, ACPI_BTYPE_BUFFER, &obj_desc); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); @@ -641,7 +644,7 @@ acpi_rs_get_method_data(acpi_handle handle, * * FUNCTION: acpi_rs_set_srs_method_data * - * PARAMETERS: Handle - Handle to the containing object + * PARAMETERS: Node - Device node * in_buffer - Pointer to a buffer structure of the * parameter * @@ -653,23 +656,37 @@ acpi_rs_get_method_data(acpi_handle handle, * If the function fails an appropriate status will be returned * and the contents of the callers buffer is undefined. * + * Note: Parameters guaranteed valid by caller + * ******************************************************************************/ acpi_status -acpi_rs_set_srs_method_data(acpi_handle handle, struct acpi_buffer *in_buffer) +acpi_rs_set_srs_method_data(struct acpi_namespace_node *node, + struct acpi_buffer *in_buffer) { - struct acpi_parameter_info info; - union acpi_operand_object *params[2]; + struct acpi_evaluate_info *info; + union acpi_operand_object *args[2]; acpi_status status; struct acpi_buffer buffer; ACPI_FUNCTION_TRACE(rs_set_srs_method_data); - /* Parameters guaranteed valid by caller */ + /* Allocate and initialize the evaluation information block */ + + info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info)); + if (!info) { + return_ACPI_STATUS(AE_NO_MEMORY); + } + + info->prefix_node = node; + info->pathname = METHOD_NAME__SRS; + info->parameters = args; + info->parameter_type = ACPI_PARAM_ARGS; + info->flags = ACPI_IGNORE_RETURN_VALUE; /* * The in_buffer parameter will point to a linked list of - * resource parameters. It needs to be formatted into a + * resource parameters. It needs to be formatted into a * byte stream to be sent in as an input parameter to _SRS * * Convert the linked list into a byte stream @@ -677,42 +694,36 @@ acpi_rs_set_srs_method_data(acpi_handle handle, struct acpi_buffer *in_buffer) buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; status = acpi_rs_create_aml_resources(in_buffer->pointer, &buffer); if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); + goto cleanup; } - /* Init the param object */ + /* Create and initialize the method parameter object */ - params[0] = acpi_ut_create_internal_object(ACPI_TYPE_BUFFER); - if (!params[0]) { - acpi_os_free(buffer.pointer); - return_ACPI_STATUS(AE_NO_MEMORY); + args[0] = acpi_ut_create_internal_object(ACPI_TYPE_BUFFER); + if (!args[0]) { + /* + * Must free the buffer allocated above (otherwise it is freed + * later) + */ + ACPI_FREE(buffer.pointer); + status = AE_NO_MEMORY; + goto cleanup; } - /* Set up the parameter object */ - - params[0]->buffer.length = (u32) buffer.length; - params[0]->buffer.pointer = buffer.pointer; - params[0]->common.flags = AOPOBJ_DATA_VALID; - params[1] = NULL; + args[0]->buffer.length = (u32) buffer.length; + args[0]->buffer.pointer = buffer.pointer; + args[0]->common.flags = AOPOBJ_DATA_VALID; + args[1] = NULL; - info.node = handle; - info.parameters = params; - info.parameter_type = ACPI_PARAM_ARGS; + /* Execute the method, no return value is expected */ - /* Execute the method, no return value */ + status = acpi_ns_evaluate(info); - status = acpi_ns_evaluate_relative(METHOD_NAME__SRS, &info); - if (ACPI_SUCCESS(status)) { - - /* Delete any return object (especially if implicit_return is enabled) */ - - if (info.return_object) { - acpi_ut_remove_reference(info.return_object); - } - } + /* Clean up and return the status from acpi_ns_evaluate */ - /* Clean up and return the status from acpi_ns_evaluate_relative */ + acpi_ut_remove_reference(args[0]); - acpi_ut_remove_reference(params[0]); + cleanup: + ACPI_FREE(info); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/resources/rsxface.c b/drivers/acpi/resources/rsxface.c index 8c1628c12cc8..1999e2ab7daa 100644 --- a/drivers/acpi/resources/rsxface.c +++ b/drivers/acpi/resources/rsxface.c @@ -43,6 +43,7 @@ #include #include +#include #define _COMPONENT ACPI_RESOURCES ACPI_MODULE_NAME("rsxface") @@ -66,19 +67,80 @@ ACPI_MODULE_NAME("rsxface") static acpi_status acpi_rs_match_vendor_resource(struct acpi_resource *resource, void *context); +static acpi_status +acpi_rs_validate_parameters(acpi_handle device_handle, + struct acpi_buffer *buffer, + struct acpi_namespace_node **return_node); + +/******************************************************************************* + * + * FUNCTION: acpi_rs_validate_parameters + * + * PARAMETERS: device_handle - Handle to a device + * Buffer - Pointer to a data buffer + * return_node - Pointer to where the device node is returned + * + * RETURN: Status + * + * DESCRIPTION: Common parameter validation for resource interfaces + * + ******************************************************************************/ + +static acpi_status +acpi_rs_validate_parameters(acpi_handle device_handle, + struct acpi_buffer *buffer, + struct acpi_namespace_node **return_node) +{ + acpi_status status; + struct acpi_namespace_node *node; + + ACPI_FUNCTION_TRACE(rs_validate_parameters); + + /* + * Must have a valid handle to an ACPI device + */ + if (!device_handle) { + return_ACPI_STATUS(AE_BAD_PARAMETER); + } + + node = acpi_ns_map_handle_to_node(device_handle); + if (!node) { + return_ACPI_STATUS(AE_BAD_PARAMETER); + } + + if (node->type != ACPI_TYPE_DEVICE) { + return_ACPI_STATUS(AE_TYPE); + } + + /* + * Validate the user buffer object + * + * if there is a non-zero buffer length we also need a valid pointer in + * the buffer. If it's a zero buffer length, we'll be returning the + * needed buffer size (later), so keep going. + */ + status = acpi_ut_validate_buffer(buffer); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + *return_node = node; + return_ACPI_STATUS(AE_OK); +} + /******************************************************************************* * * FUNCTION: acpi_get_irq_routing_table * - * PARAMETERS: device_handle - a handle to the Bus device we are querying - * ret_buffer - a pointer to a buffer to receive the + * PARAMETERS: device_handle - Handle to the Bus device we are querying + * ret_buffer - Pointer to a buffer to receive the * current resources for the device * * RETURN: Status * * DESCRIPTION: This function is called to get the IRQ routing table for a - * specific bus. The caller must first acquire a handle for the - * desired bus. The routine table is placed in the buffer pointed + * specific bus. The caller must first acquire a handle for the + * desired bus. The routine table is placed in the buffer pointed * to by the ret_buffer variable parameter. * * If the function fails an appropriate status will be returned @@ -94,25 +156,18 @@ acpi_get_irq_routing_table(acpi_handle device_handle, struct acpi_buffer *ret_buffer) { acpi_status status; + struct acpi_namespace_node *node; ACPI_FUNCTION_TRACE(acpi_get_irq_routing_table); - /* - * Must have a valid handle and buffer, So we have to have a handle - * and a return buffer structure, and if there is a non-zero buffer length - * we also need a valid pointer in the buffer. If it's a zero buffer length, - * we'll be returning the needed buffer size, so keep going. - */ - if (!device_handle) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } + /* Validate parameters then dispatch to internal routine */ - status = acpi_ut_validate_buffer(ret_buffer); + status = acpi_rs_validate_parameters(device_handle, ret_buffer, &node); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } - status = acpi_rs_get_prt_method_data(device_handle, ret_buffer); + status = acpi_rs_get_prt_method_data(node, ret_buffer); return_ACPI_STATUS(status); } @@ -122,16 +177,16 @@ ACPI_EXPORT_SYMBOL(acpi_get_irq_routing_table) * * FUNCTION: acpi_get_current_resources * - * PARAMETERS: device_handle - a handle to the device object for the + * PARAMETERS: device_handle - Handle to the device object for the * device we are querying - * ret_buffer - a pointer to a buffer to receive the + * ret_buffer - Pointer to a buffer to receive the * current resources for the device * * RETURN: Status * * DESCRIPTION: This function is called to get the current resources for a - * specific device. The caller must first acquire a handle for - * the desired device. The resource data is placed in the buffer + * specific device. The caller must first acquire a handle for + * the desired device. The resource data is placed in the buffer * pointed to by the ret_buffer variable parameter. * * If the function fails an appropriate status will be returned @@ -146,25 +201,18 @@ acpi_get_current_resources(acpi_handle device_handle, struct acpi_buffer *ret_buffer) { acpi_status status; + struct acpi_namespace_node *node; ACPI_FUNCTION_TRACE(acpi_get_current_resources); - /* - * Must have a valid handle and buffer, So we have to have a handle - * and a return buffer structure, and if there is a non-zero buffer length - * we also need a valid pointer in the buffer. If it's a zero buffer length, - * we'll be returning the needed buffer size, so keep going. - */ - if (!device_handle) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } + /* Validate parameters then dispatch to internal routine */ - status = acpi_ut_validate_buffer(ret_buffer); + status = acpi_rs_validate_parameters(device_handle, ret_buffer, &node); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } - status = acpi_rs_get_crs_method_data(device_handle, ret_buffer); + status = acpi_rs_get_crs_method_data(node, ret_buffer); return_ACPI_STATUS(status); } @@ -175,16 +223,16 @@ ACPI_EXPORT_SYMBOL(acpi_get_current_resources) * * FUNCTION: acpi_get_possible_resources * - * PARAMETERS: device_handle - a handle to the device object for the + * PARAMETERS: device_handle - Handle to the device object for the * device we are querying - * ret_buffer - a pointer to a buffer to receive the + * ret_buffer - Pointer to a buffer to receive the * resources for the device * * RETURN: Status * * DESCRIPTION: This function is called to get a list of the possible resources - * for a specific device. The caller must first acquire a handle - * for the desired device. The resource data is placed in the + * for a specific device. The caller must first acquire a handle + * for the desired device. The resource data is placed in the * buffer pointed to by the ret_buffer variable. * * If the function fails an appropriate status will be returned @@ -196,140 +244,38 @@ acpi_get_possible_resources(acpi_handle device_handle, struct acpi_buffer *ret_buffer) { acpi_status status; + struct acpi_namespace_node *node; ACPI_FUNCTION_TRACE(acpi_get_possible_resources); - /* - * Must have a valid handle and buffer, So we have to have a handle - * and a return buffer structure, and if there is a non-zero buffer length - * we also need a valid pointer in the buffer. If it's a zero buffer length, - * we'll be returning the needed buffer size, so keep going. - */ - if (!device_handle) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } + /* Validate parameters then dispatch to internal routine */ - status = acpi_ut_validate_buffer(ret_buffer); + status = acpi_rs_validate_parameters(device_handle, ret_buffer, &node); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } - status = acpi_rs_get_prs_method_data(device_handle, ret_buffer); + status = acpi_rs_get_prs_method_data(node, ret_buffer); return_ACPI_STATUS(status); } ACPI_EXPORT_SYMBOL(acpi_get_possible_resources) #endif /* ACPI_FUTURE_USAGE */ -/******************************************************************************* - * - * FUNCTION: acpi_walk_resources - * - * PARAMETERS: device_handle - Handle to the device object for the - * device we are querying - * Name - Method name of the resources we want - * (METHOD_NAME__CRS or METHOD_NAME__PRS) - * user_function - Called for each resource - * Context - Passed to user_function - * - * RETURN: Status - * - * DESCRIPTION: Retrieves the current or possible resource list for the - * specified device. The user_function is called once for - * each resource in the list. - * - ******************************************************************************/ -acpi_status -acpi_walk_resources(acpi_handle device_handle, - char *name, - acpi_walk_resource_callback user_function, void *context) -{ - acpi_status status; - struct acpi_buffer buffer; - struct acpi_resource *resource; - struct acpi_resource *resource_end; - - ACPI_FUNCTION_TRACE(acpi_walk_resources); - - /* Parameter validation */ - - if (!device_handle || !user_function || !name || - (!ACPI_COMPARE_NAME(name, METHOD_NAME__CRS) && - !ACPI_COMPARE_NAME(name, METHOD_NAME__PRS))) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - /* Get the _CRS or _PRS resource list */ - - buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; - status = acpi_rs_get_method_data(device_handle, name, &buffer); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* Buffer now contains the resource list */ - - resource = ACPI_CAST_PTR(struct acpi_resource, buffer.pointer); - resource_end = - ACPI_ADD_PTR(struct acpi_resource, buffer.pointer, buffer.length); - - /* Walk the resource list until the end_tag is found (or buffer end) */ - - while (resource < resource_end) { - - /* Sanity check the resource */ - - if (resource->type > ACPI_RESOURCE_TYPE_MAX) { - status = AE_AML_INVALID_RESOURCE_TYPE; - break; - } - - /* Invoke the user function, abort on any error returned */ - - status = user_function(resource, context); - if (ACPI_FAILURE(status)) { - if (status == AE_CTRL_TERMINATE) { - - /* This is an OK termination by the user function */ - - status = AE_OK; - } - break; - } - - /* end_tag indicates end-of-list */ - - if (resource->type == ACPI_RESOURCE_TYPE_END_TAG) { - break; - } - - /* Get the next resource descriptor */ - - resource = - ACPI_ADD_PTR(struct acpi_resource, resource, - resource->length); - } - - ACPI_FREE(buffer.pointer); - return_ACPI_STATUS(status); -} - -ACPI_EXPORT_SYMBOL(acpi_walk_resources) - /******************************************************************************* * * FUNCTION: acpi_set_current_resources * - * PARAMETERS: device_handle - a handle to the device object for the - * device we are changing the resources of - * in_buffer - a pointer to a buffer containing the + * PARAMETERS: device_handle - Handle to the device object for the + * device we are setting resources + * in_buffer - Pointer to a buffer containing the * resources to be set for the device * * RETURN: Status * * DESCRIPTION: This function is called to set the current resources for a - * specific device. The caller must first acquire a handle for - * the desired device. The resource data is passed to the routine + * specific device. The caller must first acquire a handle for + * the desired device. The resource data is passed to the routine * the buffer pointed to by the in_buffer variable. * ******************************************************************************/ @@ -338,17 +284,24 @@ acpi_set_current_resources(acpi_handle device_handle, struct acpi_buffer *in_buffer) { acpi_status status; + struct acpi_namespace_node *node; ACPI_FUNCTION_TRACE(acpi_set_current_resources); - /* Must have a valid handle and buffer */ + /* Validate the buffer, don't allow zero length */ - if ((!device_handle) || - (!in_buffer) || (!in_buffer->pointer) || (!in_buffer->length)) { + if ((!in_buffer) || (!in_buffer->pointer) || (!in_buffer->length)) { return_ACPI_STATUS(AE_BAD_PARAMETER); } - status = acpi_rs_set_srs_method_data(device_handle, in_buffer); + /* Validate parameters then dispatch to internal routine */ + + status = acpi_rs_validate_parameters(device_handle, in_buffer, &node); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + status = acpi_rs_set_srs_method_data(node, in_buffer); return_ACPI_STATUS(status); } @@ -358,15 +311,14 @@ ACPI_EXPORT_SYMBOL(acpi_set_current_resources) * * FUNCTION: acpi_resource_to_address64 * - * PARAMETERS: Resource - Pointer to a resource - * Out - Pointer to the users's return - * buffer (a struct - * struct acpi_resource_address64) + * PARAMETERS: Resource - Pointer to a resource + * Out - Pointer to the users's return buffer + * (a struct acpi_resource_address64) * * RETURN: Status * * DESCRIPTION: If the resource is an address16, address32, or address64, - * copy it to the address64 return buffer. This saves the + * copy it to the address64 return buffer. This saves the * caller from having to duplicate code for different-sized * addresses. * @@ -418,12 +370,12 @@ ACPI_EXPORT_SYMBOL(acpi_resource_to_address64) * * FUNCTION: acpi_get_vendor_resource * - * PARAMETERS: device_handle - Handle for the parent device object - * Name - Method name for the parent resource - * (METHOD_NAME__CRS or METHOD_NAME__PRS) - * Uuid - Pointer to the UUID to be matched. - * includes both subtype and 16-byte UUID - * ret_buffer - Where the vendor resource is returned + * PARAMETERS: device_handle - Handle for the parent device object + * Name - Method name for the parent resource + * (METHOD_NAME__CRS or METHOD_NAME__PRS) + * Uuid - Pointer to the UUID to be matched. + * includes both subtype and 16-byte UUID + * ret_buffer - Where the vendor resource is returned * * RETURN: Status * @@ -525,3 +477,99 @@ acpi_rs_match_vendor_resource(struct acpi_resource *resource, void *context) } ACPI_EXPORT_SYMBOL(acpi_rs_match_vendor_resource) + +/******************************************************************************* + * + * FUNCTION: acpi_walk_resources + * + * PARAMETERS: device_handle - Handle to the device object for the + * device we are querying + * Name - Method name of the resources we want + * (METHOD_NAME__CRS or METHOD_NAME__PRS) + * user_function - Called for each resource + * Context - Passed to user_function + * + * RETURN: Status + * + * DESCRIPTION: Retrieves the current or possible resource list for the + * specified device. The user_function is called once for + * each resource in the list. + * + ******************************************************************************/ + +acpi_status +acpi_walk_resources(acpi_handle device_handle, + char *name, + acpi_walk_resource_callback user_function, void *context) +{ + acpi_status status; + struct acpi_buffer buffer; + struct acpi_resource *resource; + struct acpi_resource *resource_end; + + ACPI_FUNCTION_TRACE(acpi_walk_resources); + + /* Parameter validation */ + + if (!device_handle || !user_function || !name || + (!ACPI_COMPARE_NAME(name, METHOD_NAME__CRS) && + !ACPI_COMPARE_NAME(name, METHOD_NAME__PRS))) { + return_ACPI_STATUS(AE_BAD_PARAMETER); + } + + /* Get the _CRS or _PRS resource list */ + + buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; + status = acpi_rs_get_method_data(device_handle, name, &buffer); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + /* Buffer now contains the resource list */ + + resource = ACPI_CAST_PTR(struct acpi_resource, buffer.pointer); + resource_end = + ACPI_ADD_PTR(struct acpi_resource, buffer.pointer, buffer.length); + + /* Walk the resource list until the end_tag is found (or buffer end) */ + + while (resource < resource_end) { + + /* Sanity check the resource */ + + if (resource->type > ACPI_RESOURCE_TYPE_MAX) { + status = AE_AML_INVALID_RESOURCE_TYPE; + break; + } + + /* Invoke the user function, abort on any error returned */ + + status = user_function(resource, context); + if (ACPI_FAILURE(status)) { + if (status == AE_CTRL_TERMINATE) { + + /* This is an OK termination by the user function */ + + status = AE_OK; + } + break; + } + + /* end_tag indicates end-of-list */ + + if (resource->type == ACPI_RESOURCE_TYPE_END_TAG) { + break; + } + + /* Get the next resource descriptor */ + + resource = + ACPI_ADD_PTR(struct acpi_resource, resource, + resource->length); + } + + ACPI_FREE(buffer.pointer); + return_ACPI_STATUS(status); +} + +ACPI_EXPORT_SYMBOL(acpi_walk_resources) diff --git a/drivers/acpi/tables/tbget.c b/drivers/acpi/tables/tbget.c index 3a4f46ca3884..99eacceff563 100644 --- a/drivers/acpi/tables/tbget.c +++ b/drivers/acpi/tables/tbget.c @@ -417,7 +417,7 @@ acpi_tb_get_this_table(struct acpi_pointer *address, * * PARAMETERS: table_type - one of the defined table types * Instance - Which table of this type - * table_ptr_loc - pointer to location to place the pointer for + * return_table - pointer to location to place the pointer for * return * * RETURN: Status @@ -428,58 +428,34 @@ acpi_tb_get_this_table(struct acpi_pointer *address, acpi_status acpi_tb_get_table_ptr(acpi_table_type table_type, - u32 instance, struct acpi_table_header **table_ptr_loc) + u32 instance, struct acpi_table_header **return_table) { struct acpi_table_desc *table_desc; u32 i; ACPI_FUNCTION_TRACE(tb_get_table_ptr); - if (!acpi_gbl_DSDT) { - return_ACPI_STATUS(AE_NO_ACPI_TABLES); - } - if (table_type > ACPI_TABLE_ID_MAX) { return_ACPI_STATUS(AE_BAD_PARAMETER); } - /* - * For all table types (Single/Multiple), the first - * instance is always in the list head. - */ - if (instance == 1) { - - /* Get the first */ - - *table_ptr_loc = NULL; - if (acpi_gbl_table_lists[table_type].next) { - *table_ptr_loc = - acpi_gbl_table_lists[table_type].next->pointer; - } - return_ACPI_STATUS(AE_OK); - } - - /* Check for instance out of range */ + /* Check for instance out of range of the current table count */ if (instance > acpi_gbl_table_lists[table_type].count) { return_ACPI_STATUS(AE_NOT_EXIST); } - /* Walk the list to get the desired table - * Since the if (Instance == 1) check above checked for the - * first table, setting table_desc equal to the .Next member - * is actually pointing to the second table. Therefore, we - * need to walk from the 2nd table until we reach the Instance - * that the user is looking for and return its table pointer. + /* + * Walk the list to get the desired table + * Note: Instance is one-based */ table_desc = acpi_gbl_table_lists[table_type].next; - for (i = 2; i < instance; i++) { + for (i = 1; i < instance; i++) { table_desc = table_desc->next; } /* We are now pointing to the requested table's descriptor */ - *table_ptr_loc = table_desc->pointer; - + *return_table = table_desc->pointer; return_ACPI_STATUS(AE_OK); } diff --git a/drivers/acpi/tables/tbrsdt.c b/drivers/acpi/tables/tbrsdt.c index 494965229fa2..abcb08c2592a 100644 --- a/drivers/acpi/tables/tbrsdt.c +++ b/drivers/acpi/tables/tbrsdt.c @@ -78,7 +78,7 @@ acpi_status acpi_tb_verify_rsdp(struct acpi_pointer *address) */ status = acpi_os_map_memory(address->pointer.physical, sizeof(struct rsdp_descriptor), - (void *)&rsdp); + ACPI_CAST_PTR(void, &rsdp)); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -95,11 +95,16 @@ acpi_status acpi_tb_verify_rsdp(struct acpi_pointer *address) goto cleanup; } - /* The RSDP supplied is OK */ + /* RSDP is ok. Init the table info */ table_info.pointer = ACPI_CAST_PTR(struct acpi_table_header, rsdp); table_info.length = sizeof(struct rsdp_descriptor); - table_info.allocation = ACPI_MEM_MAPPED; + + if (address->pointer_type == ACPI_PHYSICAL_POINTER) { + table_info.allocation = ACPI_MEM_MAPPED; + } else { + table_info.allocation = ACPI_MEM_NOT_ALLOCATED; + } /* Save the table pointers and allocation info */ diff --git a/drivers/acpi/utilities/utalloc.c b/drivers/acpi/utilities/utalloc.c index 65a7c2ed9aa1..7940fc1bd69e 100644 --- a/drivers/acpi/utilities/utalloc.c +++ b/drivers/acpi/utilities/utalloc.c @@ -61,24 +61,6 @@ acpi_status acpi_ut_create_caches(void) { acpi_status status; -#ifdef ACPI_DBG_TRACK_ALLOCATIONS - - /* Memory allocation lists */ - - status = acpi_ut_create_list("Acpi-Global", 0, &acpi_gbl_global_list); - if (ACPI_FAILURE(status)) { - return (status); - } - - status = - acpi_ut_create_list("Acpi-Namespace", - sizeof(struct acpi_namespace_node), - &acpi_gbl_ns_node_list); - if (ACPI_FAILURE(status)) { - return (status); - } -#endif - /* Object Caches, for frequently used objects */ status = @@ -125,6 +107,24 @@ acpi_status acpi_ut_create_caches(void) return (status); } +#ifdef ACPI_DBG_TRACK_ALLOCATIONS + + /* Memory allocation lists */ + + status = acpi_ut_create_list("Acpi-Global", 0, &acpi_gbl_global_list); + if (ACPI_FAILURE(status)) { + return (status); + } + + status = + acpi_ut_create_list("Acpi-Namespace", + sizeof(struct acpi_namespace_node), + &acpi_gbl_ns_node_list); + if (ACPI_FAILURE(status)) { + return (status); + } +#endif + return (AE_OK); } @@ -158,6 +158,21 @@ acpi_status acpi_ut_delete_caches(void) (void)acpi_os_delete_cache(acpi_gbl_ps_node_ext_cache); acpi_gbl_ps_node_ext_cache = NULL; +#ifdef ACPI_DBG_TRACK_ALLOCATIONS + + /* Debug only - display leftover memory allocation, if any */ + + acpi_ut_dump_allocations(ACPI_UINT32_MAX, NULL); + + /* Free memory lists */ + + acpi_os_free(acpi_gbl_global_list); + acpi_gbl_global_list = NULL; + + acpi_os_free(acpi_gbl_ns_node_list); + acpi_gbl_ns_node_list = NULL; +#endif + return (AE_OK); } diff --git a/drivers/acpi/utilities/utdelete.c b/drivers/acpi/utilities/utdelete.c index 0bb4b59b2804..67b9f325c6fa 100644 --- a/drivers/acpi/utilities/utdelete.c +++ b/drivers/acpi/utilities/utdelete.c @@ -319,11 +319,9 @@ acpi_ut_update_ref_count(union acpi_operand_object *object, u32 action) new_count = count; /* - * Perform the reference count action - * (increment, decrement, or force delete) + * Perform the reference count action (increment, decrement, force delete) */ switch (action) { - case REF_INCREMENT: new_count++; @@ -360,7 +358,6 @@ acpi_ut_update_ref_count(union acpi_operand_object *object, u32 action) if (new_count == 0) { acpi_ut_delete_internal_obj(object); } - break; case REF_FORCE_DELETE: @@ -385,13 +382,10 @@ acpi_ut_update_ref_count(union acpi_operand_object *object, u32 action) * (A deleted object will have a huge reference count) */ if (count > ACPI_MAX_REFERENCE_COUNT) { - ACPI_WARNING((AE_INFO, - "Large Reference Count (%X) in object %p", - count, object)); + "Large Reference Count (%X) in object %p", count, + object)); } - - return; } /******************************************************************************* @@ -417,7 +411,7 @@ acpi_ut_update_ref_count(union acpi_operand_object *object, u32 action) ******************************************************************************/ acpi_status -acpi_ut_update_object_reference(union acpi_operand_object * object, u16 action) +acpi_ut_update_object_reference(union acpi_operand_object *object, u16 action) { acpi_status status = AE_OK; union acpi_generic_state *state_list = NULL; @@ -521,11 +515,11 @@ acpi_ut_update_object_reference(union acpi_operand_object * object, u16 action) case ACPI_TYPE_REGION: default: - break; /* No subobjects */ + break; /* No subobjects for all other types */ } /* - * Now we can update the count in the main object. This can only + * Now we can update the count in the main object. This can only * happen after we update the sub-objects in case this causes the * main object to be deleted. */ @@ -606,8 +600,8 @@ void acpi_ut_remove_reference(union acpi_operand_object *object) ACPI_FUNCTION_TRACE_PTR(ut_remove_reference, object); /* - * Allow a NULL pointer to be passed in, just ignore it. This saves - * each caller from having to check. Also, ignore NS nodes. + * Allow a NULL pointer to be passed in, just ignore it. This saves + * each caller from having to check. Also, ignore NS nodes. * */ if (!object || @@ -627,7 +621,7 @@ void acpi_ut_remove_reference(union acpi_operand_object *object) /* * Decrement the reference count, and only actually delete the object - * if the reference count becomes 0. (Must also decrement the ref count + * if the reference count becomes 0. (Must also decrement the ref count * of all subobjects!) */ (void)acpi_ut_update_object_reference(object, REF_DECREMENT); diff --git a/drivers/acpi/utilities/uteval.c b/drivers/acpi/utilities/uteval.c index 444d3a502c46..d6d7121583c0 100644 --- a/drivers/acpi/utilities/uteval.c +++ b/drivers/acpi/utilities/uteval.c @@ -181,19 +181,26 @@ acpi_ut_evaluate_object(struct acpi_namespace_node *prefix_node, u32 expected_return_btypes, union acpi_operand_object **return_desc) { - struct acpi_parameter_info info; + struct acpi_evaluate_info *info; acpi_status status; u32 return_btype; ACPI_FUNCTION_TRACE(ut_evaluate_object); - info.node = prefix_node; - info.parameters = NULL; - info.parameter_type = ACPI_PARAM_ARGS; + /* Allocate the evaluation information block */ + + info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info)); + if (!info) { + return_ACPI_STATUS(AE_NO_MEMORY); + } + + info->prefix_node = prefix_node; + info->pathname = path; + info->parameter_type = ACPI_PARAM_ARGS; /* Evaluate the object/method */ - status = acpi_ns_evaluate_relative(path, &info); + status = acpi_ns_evaluate(info); if (ACPI_FAILURE(status)) { if (status == AE_NOT_FOUND) { ACPI_DEBUG_PRINT((ACPI_DB_EXEC, @@ -205,25 +212,25 @@ acpi_ut_evaluate_object(struct acpi_namespace_node *prefix_node, prefix_node, path, status); } - return_ACPI_STATUS(status); + goto cleanup; } /* Did we get a return object? */ - if (!info.return_object) { + if (!info->return_object) { if (expected_return_btypes) { ACPI_ERROR_METHOD("No object was returned from", prefix_node, path, AE_NOT_EXIST); - return_ACPI_STATUS(AE_NOT_EXIST); + status = AE_NOT_EXIST; } - return_ACPI_STATUS(AE_OK); + goto cleanup; } /* Map the return object type to the bitmapped type */ - switch (ACPI_GET_OBJECT_TYPE(info.return_object)) { + switch (ACPI_GET_OBJECT_TYPE(info->return_object)) { case ACPI_TYPE_INTEGER: return_btype = ACPI_BTYPE_INTEGER; break; @@ -251,8 +258,8 @@ acpi_ut_evaluate_object(struct acpi_namespace_node *prefix_node, * happen frequently if the "implicit return" feature is enabled. * Just delete the return object and return AE_OK. */ - acpi_ut_remove_reference(info.return_object); - return_ACPI_STATUS(AE_OK); + acpi_ut_remove_reference(info->return_object); + goto cleanup; } /* Is the return object one of the expected types? */ @@ -264,19 +271,23 @@ acpi_ut_evaluate_object(struct acpi_namespace_node *prefix_node, ACPI_ERROR((AE_INFO, "Type returned from %s was incorrect: %s, expected Btypes: %X", path, - acpi_ut_get_object_type_name(info.return_object), + acpi_ut_get_object_type_name(info->return_object), expected_return_btypes)); /* On error exit, we must delete the return object */ - acpi_ut_remove_reference(info.return_object); - return_ACPI_STATUS(AE_TYPE); + acpi_ut_remove_reference(info->return_object); + status = AE_TYPE; + goto cleanup; } /* Object type is OK, return it */ - *return_desc = info.return_object; - return_ACPI_STATUS(AE_OK); + *return_desc = info->return_object; + + cleanup: + ACPI_FREE(info); + return_ACPI_STATUS(status); } /******************************************************************************* diff --git a/drivers/acpi/utilities/utinit.c b/drivers/acpi/utilities/utinit.c index c65747d3c880..ff76055eb7d6 100644 --- a/drivers/acpi/utilities/utinit.c +++ b/drivers/acpi/utilities/utinit.c @@ -228,6 +228,7 @@ void acpi_ut_subsystem_shutdown(void) /* Subsystem appears active, go ahead and shut it down */ acpi_gbl_shutdown = TRUE; + acpi_gbl_startup_flags = 0; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Shutting down ACPI Subsystem\n")); /* Close the acpi_event Handling */ @@ -245,12 +246,5 @@ void acpi_ut_subsystem_shutdown(void) /* Purge the local caches */ (void)acpi_ut_delete_caches(); - - /* Debug only - display leftover memory allocation, if any */ - -#ifdef ACPI_DBG_TRACK_ALLOCATIONS - acpi_ut_dump_allocations(ACPI_UINT32_MAX, NULL); -#endif - return_VOID; } diff --git a/drivers/acpi/utilities/utmisc.c b/drivers/acpi/utilities/utmisc.c index 874467117cec..5c75d35ad1cd 100644 --- a/drivers/acpi/utilities/utmisc.c +++ b/drivers/acpi/utilities/utmisc.c @@ -601,7 +601,8 @@ acpi_name acpi_ut_repair_name(acpi_name name) * FUNCTION: acpi_ut_strtoul64 * * PARAMETERS: String - Null terminated string - * Base - Radix of the string: 10, 16, or ACPI_ANY_BASE + * Base - Radix of the string: 16 or ACPI_ANY_BASE; + * ACPI_ANY_BASE means 'in behalf of to_integer' * ret_integer - Where the converted integer is returned * * RETURN: Status and Converted value @@ -617,16 +618,17 @@ acpi_ut_strtoul64(char *string, u32 base, acpi_integer * ret_integer) u32 this_digit = 0; acpi_integer return_value = 0; acpi_integer quotient; + acpi_integer dividend; + u32 to_integer_op = (base == ACPI_ANY_BASE); + u32 mode32 = (acpi_gbl_integer_byte_width == 4); + u8 valid_digits = 0; + u8 sign_of0x = 0; + u8 term = 0; ACPI_FUNCTION_TRACE(ut_stroul64); - if ((!string) || !(*string)) { - goto error_exit; - } - switch (base) { case ACPI_ANY_BASE: - case 10: case 16: break; @@ -635,39 +637,45 @@ acpi_ut_strtoul64(char *string, u32 base, acpi_integer * ret_integer) return_ACPI_STATUS(AE_BAD_PARAMETER); } + if (!string) { + goto error_exit; + } + /* Skip over any white space in the buffer */ - while (ACPI_IS_SPACE(*string) || *string == '\t') { + while ((*string) && (ACPI_IS_SPACE(*string) || *string == '\t')) { string++; } - /* - * If the input parameter Base is zero, then we need to - * determine if it is decimal or hexadecimal: - */ - if (base == 0) { + if (to_integer_op) { + /* + * Base equal to ACPI_ANY_BASE means 'to_integer operation case'. + * We need to determine if it is decimal or hexadecimal. + */ if ((*string == '0') && (ACPI_TOLOWER(*(string + 1)) == 'x')) { + sign_of0x = 1; base = 16; + + /* Skip over the leading '0x' */ string += 2; } else { base = 10; } } - /* - * For hexadecimal base, skip over the leading - * 0 or 0x, if they are present. - */ - if ((base == 16) && - (*string == '0') && (ACPI_TOLOWER(*(string + 1)) == 'x')) { - string += 2; + /* Any string left? Check that '0x' is not followed by white space. */ + + if (!(*string) || ACPI_IS_SPACE(*string) || *string == '\t') { + if (to_integer_op) { + goto error_exit; + } else { + goto all_done; + } } - /* Any string left? */ + dividend = (mode32) ? ACPI_UINT32_MAX : ACPI_UINT64_MAX; - if (!(*string)) { - goto error_exit; - } + /* At least one character in the string here */ /* Main loop: convert the string to a 64-bit integer */ @@ -677,14 +685,12 @@ acpi_ut_strtoul64(char *string, u32 base, acpi_integer * ret_integer) /* Convert ASCII 0-9 to Decimal value */ this_digit = ((u8) * string) - '0'; - } else { - if (base == 10) { + } else if (base == 10) { - /* Digit is out of range */ - - goto error_exit; - } + /* Digit is out of range; possible in to_integer case only */ + term = 1; + } else { this_digit = (u8) ACPI_TOUPPER(*string); if (ACPI_IS_XDIGIT((char)this_digit)) { @@ -692,22 +698,49 @@ acpi_ut_strtoul64(char *string, u32 base, acpi_integer * ret_integer) this_digit = this_digit - 'A' + 10; } else { - /* - * We allow non-hex chars, just stop now, same as end-of-string. - * See ACPI spec, string-to-integer conversion. - */ + term = 1; + } + } + + if (term) { + if (to_integer_op) { + goto error_exit; + } else { break; } + } else if ((valid_digits == 0) && (this_digit == 0) + && !sign_of0x) { + + /* Skip zeros */ + string++; + continue; + } + + valid_digits++; + + if (sign_of0x + && ((valid_digits > 16) + || ((valid_digits > 8) && mode32))) { + /* + * This is to_integer operation case. + * No any restrictions for string-to-integer conversion, + * see ACPI spec. + */ + goto error_exit; } /* Divide the digit into the correct position */ (void) - acpi_ut_short_divide((ACPI_INTEGER_MAX - - (acpi_integer) this_digit), base, - "ient, NULL); + acpi_ut_short_divide((dividend - (acpi_integer) this_digit), + base, "ient, NULL); + if (return_value > quotient) { - goto error_exit; + if (to_integer_op) { + goto error_exit; + } else { + break; + } } return_value *= base; @@ -717,6 +750,8 @@ acpi_ut_strtoul64(char *string, u32 base, acpi_integer * ret_integer) /* All done, normal exit */ + all_done: + *ret_integer = return_value; return_ACPI_STATUS(AE_OK); diff --git a/include/acpi/acconfig.h b/include/acpi/acconfig.h index 0177ed3dc807..8b52e44ad2ab 100644 --- a/include/acpi/acconfig.h +++ b/include/acpi/acconfig.h @@ -63,7 +63,7 @@ /* Current ACPICA subsystem version in YYYYMMDD format */ -#define ACPI_CA_VERSION 0x20060512 +#define ACPI_CA_VERSION 0x20060526 /* * OS name, used for the _OS object. The _OS object is essentially obsolete, diff --git a/include/acpi/acdispat.h b/include/acpi/acdispat.h index fcf03eb41374..288f84903af7 100644 --- a/include/acpi/acdispat.h +++ b/include/acpi/acdispat.h @@ -304,7 +304,7 @@ acpi_ds_init_aml_walk(struct acpi_walk_state *walk_state, struct acpi_namespace_node *method_node, u8 * aml_start, u32 aml_length, - struct acpi_parameter_info *info, u8 pass_number); + struct acpi_evaluate_info *info, u8 pass_number); acpi_status acpi_ds_obj_stack_pop_and_delete(u32 pop_count, diff --git a/include/acpi/acnamesp.h b/include/acpi/acnamesp.h index 2ef8540c0fba..83b52f9f899a 100644 --- a/include/acpi/acnamesp.h +++ b/include/acpi/acnamesp.h @@ -173,13 +173,7 @@ acpi_ns_dump_objects(acpi_object_type type, /* * nseval - Namespace evaluation functions */ -acpi_status acpi_ns_evaluate_by_handle(struct acpi_parameter_info *info); - -acpi_status -acpi_ns_evaluate_by_name(char *pathname, struct acpi_parameter_info *info); - -acpi_status -acpi_ns_evaluate_relative(char *pathname, struct acpi_parameter_info *info); +acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info); /* * nsnames - Name and Scope manipulation @@ -202,9 +196,9 @@ u8 acpi_ns_pattern_match(struct acpi_namespace_node *obj_node, char *search_for); acpi_status -acpi_ns_get_node_by_path(char *external_pathname, - struct acpi_namespace_node *in_prefix_node, - u32 flags, struct acpi_namespace_node **out_node); +acpi_ns_get_node(struct acpi_namespace_node *prefix_node, + char *external_pathname, + u32 flags, struct acpi_namespace_node **out_node); acpi_size acpi_ns_get_pathname_length(struct acpi_namespace_node *node); @@ -247,10 +241,10 @@ acpi_ns_search_and_enter(u32 entry_name, u32 flags, struct acpi_namespace_node **ret_node); acpi_status -acpi_ns_search_node(u32 entry_name, - struct acpi_namespace_node *node, - acpi_object_type type, - struct acpi_namespace_node **ret_node); +acpi_ns_search_one_scope(u32 entry_name, + struct acpi_namespace_node *node, + acpi_object_type type, + struct acpi_namespace_node **ret_node); void acpi_ns_install_node(struct acpi_walk_state *walk_state, diff --git a/include/acpi/acopcode.h b/include/acpi/acopcode.h index e6d78bd9e90a..7659a46bc432 100644 --- a/include/acpi/acopcode.h +++ b/include/acpi/acopcode.h @@ -94,7 +94,7 @@ #define ARGP_CONCAT_RES_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) #define ARGP_COND_REF_OF_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_SUPERNAME) #define ARGP_CONTINUE_OP ARG_NONE -#define ARGP_COPY_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_SIMPLENAME) +#define ARGP_COPY_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_SIMPLENAME) #define ARGP_CREATE_BIT_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) #define ARGP_CREATE_BYTE_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) #define ARGP_CREATE_DWORD_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) diff --git a/include/acpi/acparser.h b/include/acpi/acparser.h index de14492a5985..9d49d3c41cd9 100644 --- a/include/acpi/acparser.h +++ b/include/acpi/acparser.h @@ -71,7 +71,7 @@ /* * psxface - Parser external interfaces */ -acpi_status acpi_ps_execute_method(struct acpi_parameter_info *info); +acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info); /* * psargs - Parse AML opcode arguments diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h index 982e7ea177e3..8f473c83b7c4 100644 --- a/include/acpi/acpiosxf.h +++ b/include/acpi/acpiosxf.h @@ -58,8 +58,7 @@ typedef enum { OSL_GPE_HANDLER, OSL_DEBUGGER_THREAD, OSL_EC_POLL_HANDLER, - OSL_EC_BURST_HANDLER, - + OSL_EC_BURST_HANDLER } acpi_execute_type; #define ACPI_NO_UNIT_LIMIT ((u32) -1) @@ -217,7 +216,6 @@ acpi_os_derive_pci_id(acpi_handle rhandle, /* * Miscellaneous */ - acpi_status acpi_os_validate_interface(char *interface); acpi_status @@ -265,11 +263,4 @@ char *acpi_os_get_next_filename(void *dir_handle); void acpi_os_close_directory(void *dir_handle); -/* - * Debug - */ -void -acpi_os_dbg_assert(void *failed_assertion, - void *file_name, u32 line_number, char *message); - #endif /* __ACPIOSXF_H__ */ diff --git a/include/acpi/acresrc.h b/include/acpi/acresrc.h index bdd6584bbcf1..ad11fc13fbef 100644 --- a/include/acpi/acresrc.h +++ b/include/acpi/acresrc.h @@ -164,23 +164,26 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object, /* * rsutils */ + acpi_status -acpi_rs_get_prt_method_data(acpi_handle handle, struct acpi_buffer *ret_buffer); +acpi_rs_get_prt_method_data(struct acpi_namespace_node *node, + struct acpi_buffer *ret_buffer); acpi_status -acpi_rs_get_crs_method_data(acpi_handle handle, struct acpi_buffer *ret_buffer); +acpi_rs_get_crs_method_data(struct acpi_namespace_node *node, + struct acpi_buffer *ret_buffer); -#ifdef ACPI_FUTURE_USAGE acpi_status -acpi_rs_get_prs_method_data(acpi_handle handle, struct acpi_buffer *ret_buffer); -#endif /* ACPI_FUTURE_USAGE */ +acpi_rs_get_prs_method_data(struct acpi_namespace_node *node, + struct acpi_buffer *ret_buffer); acpi_status acpi_rs_get_method_data(acpi_handle handle, char *path, struct acpi_buffer *ret_buffer); acpi_status -acpi_rs_set_srs_method_data(acpi_handle handle, struct acpi_buffer *ret_buffer); +acpi_rs_set_srs_method_data(struct acpi_namespace_node *node, + struct acpi_buffer *ret_buffer); /* * rscalc diff --git a/include/acpi/acstruct.h b/include/acpi/acstruct.h index b8a6d6110d57..5e8095f0f78f 100644 --- a/include/acpi/acstruct.h +++ b/include/acpi/acstruct.h @@ -53,17 +53,25 @@ ****************************************************************************/ /* - * Walk state - current state of a parse tree walk. Used for both a leisurely stroll through - * the tree (for whatever reason), and for control method execution. + * Walk state - current state of a parse tree walk. Used for both a leisurely + * stroll through the tree (for whatever reason), and for control method + * execution. */ #define ACPI_NEXT_OP_DOWNWARD 1 #define ACPI_NEXT_OP_UPWARD 2 +/* + * Groups of definitions for walk_type used for different implementations of + * walkers (never simultaneously) - flags for interpreter: + */ #define ACPI_WALK_NON_METHOD 0 -#define ACPI_WALK_METHOD 1 -#define ACPI_WALK_METHOD_RESTART 2 -#define ACPI_WALK_CONST_REQUIRED 3 -#define ACPI_WALK_CONST_OPTIONAL 4 +#define ACPI_WALK_METHOD 0x01 +#define ACPI_WALK_METHOD_RESTART 0x02 + +/* Flags for i_aSL compiler only */ + +#define ACPI_WALK_CONST_REQUIRED 0x10 +#define ACPI_WALK_CONST_OPTIONAL 0x20 struct acpi_walk_state { struct acpi_walk_state *next; /* Next walk_state in list */ @@ -134,32 +142,6 @@ struct acpi_init_walk_info { struct acpi_table_desc *table_desc; }; -/* Info used by acpi_ns_initialize_devices */ - -struct acpi_device_walk_info { - u16 device_count; - u16 num_STA; - u16 num_INI; - struct acpi_table_desc *table_desc; -}; - -/* TBD: [Restructure] Merge with struct above */ - -struct acpi_walk_info { - u32 debug_level; - u32 count; - acpi_owner_id owner_id; - u8 display_type; -}; - -/* Display Types */ - -#define ACPI_DISPLAY_SUMMARY (u8) 0 -#define ACPI_DISPLAY_OBJECTS (u8) 1 -#define ACPI_DISPLAY_MASK (u8) 1 - -#define ACPI_DISPLAY_SHORT (u8) 2 - struct acpi_get_devices_info { acpi_walk_callback user_function; void *context; @@ -192,16 +174,21 @@ union acpi_aml_operands { } mid; }; -/* Internal method parameter list */ - -struct acpi_parameter_info { - struct acpi_namespace_node *node; +/* + * Structure used to pass object evaluation parameters. + * Purpose is to reduce CPU stack use. + */ +struct acpi_evaluate_info { + struct acpi_namespace_node *prefix_node; + char *pathname; union acpi_operand_object *obj_desc; union acpi_operand_object **parameters; + struct acpi_namespace_node *resolved_node; union acpi_operand_object *return_object; u8 pass_number; u8 parameter_type; u8 return_object_type; + u8 flags; }; /* Types for parameter_type above */ @@ -209,4 +196,35 @@ struct acpi_parameter_info { #define ACPI_PARAM_ARGS 0 #define ACPI_PARAM_GPE 1 +/* Values for Flags above */ + +#define ACPI_IGNORE_RETURN_VALUE 1 + +/* Info used by acpi_ns_initialize_devices */ + +struct acpi_device_walk_info { + u16 device_count; + u16 num_STA; + u16 num_INI; + struct acpi_table_desc *table_desc; + struct acpi_evaluate_info *evaluate_info; +}; + +/* TBD: [Restructure] Merge with struct above */ + +struct acpi_walk_info { + u32 debug_level; + u32 count; + acpi_owner_id owner_id; + u8 display_type; +}; + +/* Display Types */ + +#define ACPI_DISPLAY_SUMMARY (u8) 0 +#define ACPI_DISPLAY_OBJECTS (u8) 1 +#define ACPI_DISPLAY_MASK (u8) 1 + +#define ACPI_DISPLAY_SHORT (u8) 2 + #endif -- cgit v1.2.3 From 4c90ece249992c7a2e3fc921e5cdb8eb92193067 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 8 Jun 2006 16:29:00 -0400 Subject: ACPI: ACPICA 20060608 Converted the locking mutex used for the ACPI hardware to a spinlock. This change should eliminate all problems caused by attempting to acquire a semaphore at interrupt level, and it means that all ACPICA external interfaces that directly access the ACPI hardware can be safely called from interrupt level. Fixed a regression introduced in 20060526 where the ACPI device initialization could be prematurely aborted with an AE_NOT_FOUND if a device did not have an optional _INI method. Fixed an IndexField issue where a write to the Data Register should be limited in size to the AccessSize (width) of the IndexField itself. (BZ 433, Fiodor Suietov) Fixed problem reports (Valery Podrezov) integrated: - Allow store of ThermalZone objects to Debug object. http://bugzilla.kernel.org/show_bug.cgi?id=5369 http://bugzilla.kernel.org/show_bug.cgi?id=5370 Fixed problem reports (Fiodor Suietov) integrated: - acpi_get_table_header() doesn't handle multiple instances correctly (BZ 364) Removed four global mutexes that were obsolete and were no longer being used. Signed-off-by: Bob Moore Signed-off-by: Len Brown --- drivers/acpi/dispatcher/dsmethod.c | 4 +-- drivers/acpi/events/evgpe.c | 17 ++++++++--- drivers/acpi/executer/exfldio.c | 8 ++++-- drivers/acpi/executer/exoparg1.c | 10 +++---- drivers/acpi/executer/exresnte.c | 6 ++-- drivers/acpi/executer/exresolv.c | 20 +++++++++++-- drivers/acpi/executer/exutils.c | 4 +-- drivers/acpi/hardware/hwregs.c | 59 ++++++++++++-------------------------- drivers/acpi/namespace/nsinit.c | 5 +++- drivers/acpi/osl.c | 3 -- drivers/acpi/tables/tbutils.c | 17 ++++------- drivers/acpi/utilities/utglobal.c | 4 +-- drivers/acpi/utilities/utmutex.c | 26 +++++++++++------ include/acpi/acconfig.h | 11 ++----- include/acpi/acglobal.h | 6 +++- include/acpi/aclocal.h | 55 ++++++++++++++++++----------------- 16 files changed, 132 insertions(+), 123 deletions(-) (limited to 'include') diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c index 21f059986273..bc9aca4e7401 100644 --- a/drivers/acpi/dispatcher/dsmethod.c +++ b/drivers/acpi/dispatcher/dsmethod.c @@ -507,7 +507,7 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, * If this is the last thread executing the method, * we have additional cleanup to perform */ - status = acpi_ut_acquire_mutex(ACPI_MTX_PARSER); + status = acpi_ut_acquire_mutex(ACPI_MTX_CONTROL_METHOD); if (ACPI_FAILURE(status)) { return_VOID; } @@ -600,7 +600,7 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, } exit: - (void)acpi_ut_release_mutex(ACPI_MTX_PARSER); + (void)acpi_ut_release_mutex(ACPI_MTX_CONTROL_METHOD); return_VOID; } diff --git a/drivers/acpi/events/evgpe.c b/drivers/acpi/events/evgpe.c index 23fe53ba7375..f01d339407f8 100644 --- a/drivers/acpi/events/evgpe.c +++ b/drivers/acpi/events/evgpe.c @@ -382,6 +382,7 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list) u32 status_reg; u32 enable_reg; acpi_cpu_flags flags; + acpi_cpu_flags hw_flags; acpi_native_uint i; acpi_native_uint j; @@ -393,9 +394,12 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list) return (int_status); } - /* Examine all GPE blocks attached to this interrupt level */ + /* We need to hold the GPE lock now, hardware lock in the loop */ flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); + + /* Examine all GPE blocks attached to this interrupt level */ + gpe_block = gpe_xrupt_list->gpe_block_list_head; while (gpe_block) { /* @@ -409,6 +413,8 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list) gpe_register_info = &gpe_block->register_info[i]; + hw_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock); + /* Read the Status Register */ status = @@ -417,6 +423,8 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list) &gpe_register_info-> status_address); if (ACPI_FAILURE(status)) { + acpi_os_release_lock(acpi_gbl_hardware_lock, + hw_flags); goto unlock_and_exit; } @@ -427,6 +435,8 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list) &enable_reg, &gpe_register_info-> enable_address); + acpi_os_release_lock(acpi_gbl_hardware_lock, hw_flags); + if (ACPI_FAILURE(status)) { goto unlock_and_exit; } @@ -499,7 +509,6 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list) static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) { struct acpi_gpe_event_info *gpe_event_info = (void *)context; - u32 gpe_number = 0; acpi_status status; struct acpi_gpe_event_info local_gpe_event_info; struct acpi_evaluate_info *info; @@ -565,10 +574,10 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, - "While evaluating method [%4.4s] for GPE[%2X]", + "While evaluating GPE method [%4.4s]", acpi_ut_get_node_name (local_gpe_event_info.dispatch. - method_node), gpe_number)); + method_node))); } } diff --git a/drivers/acpi/executer/exfldio.c b/drivers/acpi/executer/exfldio.c index 3b7c4352ec57..051053f7cccb 100644 --- a/drivers/acpi/executer/exfldio.c +++ b/drivers/acpi/executer/exfldio.c @@ -785,6 +785,7 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc, { acpi_status status; acpi_integer mask; + acpi_integer width_mask; acpi_integer merged_datum; acpi_integer raw_datum = 0; u32 field_offset = 0; @@ -809,8 +810,11 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc, /* Compute the number of datums (access width data items) */ + width_mask = + ACPI_MASK_BITS_ABOVE(obj_desc->common_field.access_bit_width); mask = - ACPI_MASK_BITS_BELOW(obj_desc->common_field.start_field_bit_offset); + width_mask & ACPI_MASK_BITS_BELOW(obj_desc->common_field. + start_field_bit_offset); datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length, obj_desc->common_field.access_bit_width); @@ -850,7 +854,7 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc, merged_datum = raw_datum >> (obj_desc->common_field.access_bit_width - obj_desc->common_field.start_field_bit_offset); - mask = ACPI_INTEGER_MAX; + mask = width_mask; if (i == datum_count) { break; diff --git a/drivers/acpi/executer/exoparg1.c b/drivers/acpi/executer/exoparg1.c index 8284c52875be..6374d8be88e0 100644 --- a/drivers/acpi/executer/exoparg1.c +++ b/drivers/acpi/executer/exoparg1.c @@ -322,8 +322,9 @@ acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state) /* Since the bit position is one-based, subtract from 33 (65) */ - return_desc->integer.value = temp32 == 0 ? 0 : - (ACPI_INTEGER_BIT_SIZE + 1) - temp32; + return_desc->integer.value = + temp32 == + 0 ? 0 : (ACPI_INTEGER_BIT_SIZE + 1) - temp32; break; case AML_FROM_BCD_OP: /* from_bcd (BCDValue, Result) */ @@ -698,6 +699,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state) if (ACPI_FAILURE(status)) { goto cleanup; } + /* Allocate a descriptor to hold the type. */ return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); @@ -967,7 +969,6 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state) acpi_ut_add_reference (return_desc); } - break; default: @@ -987,7 +988,6 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state) if (ACPI_GET_DESCRIPTOR_TYPE(return_desc) == ACPI_DESC_TYPE_NAMED) { - return_desc = acpi_ns_get_attached_object((struct acpi_namespace_node @@ -1002,7 +1002,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state) default: ACPI_ERROR((AE_INFO, - "Unknown opcode in ref(%p) - %X", + "Unknown opcode in reference(%p) - %X", operand[0], operand[0]->reference.opcode)); diff --git a/drivers/acpi/executer/exresnte.c b/drivers/acpi/executer/exresnte.c index f9b9f5008596..3089b05a1368 100644 --- a/drivers/acpi/executer/exresnte.c +++ b/drivers/acpi/executer/exresnte.c @@ -114,10 +114,11 @@ acpi_ex_resolve_node_to_value(struct acpi_namespace_node **object_ptr, /* * Several object types require no further processing: - * 1) Devices rarely have an attached object, return the Node + * 1) Device/Thermal objects don't have a "real" subobject, return the Node * 2) Method locals and arguments have a pseudo-Node */ - if (entry_type == ACPI_TYPE_DEVICE || + if ((entry_type == ACPI_TYPE_DEVICE) || + (entry_type == ACPI_TYPE_THERMAL) || (node->flags & (ANOBJ_METHOD_ARG | ANOBJ_METHOD_LOCAL))) { return_ACPI_STATUS(AE_OK); } @@ -216,7 +217,6 @@ acpi_ex_resolve_node_to_value(struct acpi_namespace_node **object_ptr, case ACPI_TYPE_METHOD: case ACPI_TYPE_POWER: case ACPI_TYPE_PROCESSOR: - case ACPI_TYPE_THERMAL: case ACPI_TYPE_EVENT: case ACPI_TYPE_REGION: diff --git a/drivers/acpi/executer/exresolv.c b/drivers/acpi/executer/exresolv.c index 006bba035d51..6499de878017 100644 --- a/drivers/acpi/executer/exresolv.c +++ b/drivers/acpi/executer/exresolv.c @@ -257,10 +257,24 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr, case AML_INT_NAMEPATH_OP: /* Reference to a named object */ - /* Get the object pointed to by the namespace node */ + /* Dereference the name */ + + if ((stack_desc->reference.node->type == + ACPI_TYPE_DEVICE) + || (stack_desc->reference.node->type == + ACPI_TYPE_THERMAL)) { + + /* These node types do not have 'real' subobjects */ + + *stack_ptr = (void *)stack_desc->reference.node; + } else { + /* Get the object pointed to by the namespace node */ + + *stack_ptr = + (stack_desc->reference.node)->object; + acpi_ut_add_reference(*stack_ptr); + } - *stack_ptr = (stack_desc->reference.node)->object; - acpi_ut_add_reference(*stack_ptr); acpi_ut_remove_reference(stack_desc); break; diff --git a/drivers/acpi/executer/exutils.c b/drivers/acpi/executer/exutils.c index 3ef8cd703e06..982c8b65876f 100644 --- a/drivers/acpi/executer/exutils.c +++ b/drivers/acpi/executer/exutils.c @@ -89,7 +89,7 @@ acpi_status acpi_ex_enter_interpreter(void) ACPI_FUNCTION_TRACE(ex_enter_interpreter); - status = acpi_ut_acquire_mutex(ACPI_MTX_EXECUTE); + status = acpi_ut_acquire_mutex(ACPI_MTX_INTERPRETER); if (ACPI_FAILURE(status)) { ACPI_ERROR((AE_INFO, "Could not acquire interpreter mutex")); } @@ -125,7 +125,7 @@ void acpi_ex_exit_interpreter(void) ACPI_FUNCTION_TRACE(ex_exit_interpreter); - status = acpi_ut_release_mutex(ACPI_MTX_EXECUTE); + status = acpi_ut_release_mutex(ACPI_MTX_INTERPRETER); if (ACPI_FAILURE(status)) { ACPI_ERROR((AE_INFO, "Could not release interpreter mutex")); } diff --git a/drivers/acpi/hardware/hwregs.c b/drivers/acpi/hardware/hwregs.c index 5a3aa8dd8cb7..ae142de19507 100644 --- a/drivers/acpi/hardware/hwregs.c +++ b/drivers/acpi/hardware/hwregs.c @@ -61,10 +61,13 @@ ACPI_MODULE_NAME("hwregs") * DESCRIPTION: Clears all fixed and general purpose status bits * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED * + * NOTE: TBD: Flags parameter is obsolete, to be removed + * ******************************************************************************/ acpi_status acpi_hw_clear_acpi_status(u32 flags) { acpi_status status; + acpi_cpu_flags lock_flags = 0; ACPI_FUNCTION_TRACE(hw_clear_acpi_status); @@ -72,12 +75,7 @@ acpi_status acpi_hw_clear_acpi_status(u32 flags) ACPI_BITMASK_ALL_FIXED_STATUS, (u16) acpi_gbl_FADT->xpm1a_evt_blk.address)); - if (flags & ACPI_MTX_LOCK) { - status = acpi_ut_acquire_mutex(ACPI_MTX_HARDWARE); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - } + lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock); status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_STATUS, @@ -102,9 +100,7 @@ acpi_status acpi_hw_clear_acpi_status(u32 flags) status = acpi_ev_walk_gpe_list(acpi_hw_clear_gpe_block); unlock_and_exit: - if (flags & ACPI_MTX_LOCK) { - (void)acpi_ut_release_mutex(ACPI_MTX_HARDWARE); - } + acpi_os_release_lock(acpi_gbl_hardware_lock, lock_flags); return_ACPI_STATUS(status); } @@ -264,6 +260,8 @@ struct acpi_bit_register_info *acpi_hw_get_bit_register_info(u32 register_id) * * DESCRIPTION: ACPI bit_register read function. * + * NOTE: TBD: Flags parameter is obsolete, to be removed + * ******************************************************************************/ acpi_status acpi_get_register(u32 register_id, u32 * return_value, u32 flags) @@ -281,23 +279,12 @@ acpi_status acpi_get_register(u32 register_id, u32 * return_value, u32 flags) return_ACPI_STATUS(AE_BAD_PARAMETER); } - if (flags & ACPI_MTX_LOCK) { - status = acpi_ut_acquire_mutex(ACPI_MTX_HARDWARE); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - } - /* Read from the register */ - status = acpi_hw_register_read(ACPI_MTX_DO_NOT_LOCK, + status = acpi_hw_register_read(ACPI_MTX_LOCK, bit_reg_info->parent_register, ®ister_value); - if (flags & ACPI_MTX_LOCK) { - (void)acpi_ut_release_mutex(ACPI_MTX_HARDWARE); - } - if (ACPI_SUCCESS(status)) { /* Normalize the value that was read */ @@ -331,12 +318,15 @@ ACPI_EXPORT_SYMBOL(acpi_get_register) * * DESCRIPTION: ACPI Bit Register write function. * + * NOTE: TBD: Flags parameter is obsolete, to be removed + * ******************************************************************************/ acpi_status acpi_set_register(u32 register_id, u32 value, u32 flags) { u32 register_value = 0; struct acpi_bit_register_info *bit_reg_info; acpi_status status; + acpi_cpu_flags lock_flags; ACPI_FUNCTION_TRACE_U32(acpi_set_register, register_id); @@ -349,12 +339,7 @@ acpi_status acpi_set_register(u32 register_id, u32 value, u32 flags) return_ACPI_STATUS(AE_BAD_PARAMETER); } - if (flags & ACPI_MTX_LOCK) { - status = acpi_ut_acquire_mutex(ACPI_MTX_HARDWARE); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - } + lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock); /* Always do a register read first so we can insert the new bits */ @@ -462,9 +447,7 @@ acpi_status acpi_set_register(u32 register_id, u32 value, u32 flags) unlock_and_exit: - if (flags & ACPI_MTX_LOCK) { - (void)acpi_ut_release_mutex(ACPI_MTX_HARDWARE); - } + acpi_os_release_lock(acpi_gbl_hardware_lock, lock_flags); /* Normalize the value that was read */ @@ -500,14 +483,12 @@ acpi_hw_register_read(u8 use_lock, u32 register_id, u32 * return_value) u32 value1 = 0; u32 value2 = 0; acpi_status status; + acpi_cpu_flags lock_flags = 0; ACPI_FUNCTION_TRACE(hw_register_read); if (ACPI_MTX_LOCK == use_lock) { - status = acpi_ut_acquire_mutex(ACPI_MTX_HARDWARE); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } + lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock); } switch (register_id) { @@ -585,7 +566,7 @@ acpi_hw_register_read(u8 use_lock, u32 register_id, u32 * return_value) unlock_and_exit: if (ACPI_MTX_LOCK == use_lock) { - (void)acpi_ut_release_mutex(ACPI_MTX_HARDWARE); + acpi_os_release_lock(acpi_gbl_hardware_lock, lock_flags); } if (ACPI_SUCCESS(status)) { @@ -613,14 +594,12 @@ acpi_hw_register_read(u8 use_lock, u32 register_id, u32 * return_value) acpi_status acpi_hw_register_write(u8 use_lock, u32 register_id, u32 value) { acpi_status status; + acpi_cpu_flags lock_flags = 0; ACPI_FUNCTION_TRACE(hw_register_write); if (ACPI_MTX_LOCK == use_lock) { - status = acpi_ut_acquire_mutex(ACPI_MTX_HARDWARE); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } + lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock); } switch (register_id) { @@ -710,7 +689,7 @@ acpi_status acpi_hw_register_write(u8 use_lock, u32 register_id, u32 value) unlock_and_exit: if (ACPI_MTX_LOCK == use_lock) { - (void)acpi_ut_release_mutex(ACPI_MTX_HARDWARE); + acpi_os_release_lock(acpi_gbl_hardware_lock, lock_flags); } return_ACPI_STATUS(status); diff --git a/drivers/acpi/namespace/nsinit.c b/drivers/acpi/namespace/nsinit.c index 1c9ca6e05314..aec8488c0019 100644 --- a/drivers/acpi/namespace/nsinit.c +++ b/drivers/acpi/namespace/nsinit.c @@ -557,10 +557,13 @@ acpi_ns_init_one_device(acpi_handle obj_handle, ACPI_EXCEPTION((AE_INFO, status, "during %s._INI execution", scope_name)); ACPI_FREE(scope_name); - status = AE_OK; } #endif + /* Ignore errors from above */ + + status = AE_OK; + /* * The _INI method has been run if present; call the Global Initialization * Handler for this device. diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index e80ca4730a44..1bb558adee66 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -795,9 +795,6 @@ acpi_status acpi_os_wait_semaphore(acpi_handle handle, u32 units, u16 timeout) ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Waiting for semaphore[%p|%d|%d]\n", handle, units, timeout)); - if (in_atomic()) - timeout = 0; - switch (timeout) { /* * No Wait: diff --git a/drivers/acpi/tables/tbutils.c b/drivers/acpi/tables/tbutils.c index 5f1440376514..209a401801e3 100644 --- a/drivers/acpi/tables/tbutils.c +++ b/drivers/acpi/tables/tbutils.c @@ -160,12 +160,8 @@ acpi_tb_validate_table_header(struct acpi_table_header *table_header) ACPI_MOVE_32_TO_32(&signature, table_header->signature); if (!acpi_ut_valid_acpi_name(signature)) { - ACPI_ERROR((AE_INFO, - "Table signature at %p [%p] has invalid characters", - table_header, &signature)); - - ACPI_WARNING((AE_INFO, "Invalid table signature found: [%4.4s]", - ACPI_CAST_PTR(char, &signature))); + ACPI_ERROR((AE_INFO, "Invalid table signature 0x%8.8X", + signature)); ACPI_DUMP_BUFFER(table_header, sizeof(struct acpi_table_header)); @@ -176,12 +172,9 @@ acpi_tb_validate_table_header(struct acpi_table_header *table_header) if (table_header->length < sizeof(struct acpi_table_header)) { ACPI_ERROR((AE_INFO, - "Invalid length in table header %p name %4.4s", - table_header, (char *)&signature)); - - ACPI_WARNING((AE_INFO, - "Invalid table header length (0x%X) found", - (u32) table_header->length)); + "Invalid length 0x%X in table with signature %4.4s", + (u32) table_header->length, + ACPI_CAST_PTR(char, &signature))); ACPI_DUMP_BUFFER(table_header, sizeof(struct acpi_table_header)); diff --git a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c index 9450f9b5bfb2..e5999c65c0b8 100644 --- a/drivers/acpi/utilities/utglobal.c +++ b/drivers/acpi/utilities/utglobal.c @@ -691,7 +691,7 @@ char *acpi_ut_get_descriptor_name(void *object) char *acpi_ut_get_mutex_name(u32 mutex_id) { - if (mutex_id > MAX_MUTEX) { + if (mutex_id > ACPI_MAX_MUTEX) { return ("Invalid Mutex ID"); } @@ -760,7 +760,7 @@ void acpi_ut_init_globals(void) /* Mutex locked flags */ - for (i = 0; i < NUM_MUTEX; i++) { + for (i = 0; i < ACPI_NUM_MUTEX; i++) { acpi_gbl_mutex_info[i].mutex = NULL; acpi_gbl_mutex_info[i].thread_id = ACPI_MUTEX_NOT_ACQUIRED; acpi_gbl_mutex_info[i].use_count = 0; diff --git a/drivers/acpi/utilities/utmutex.c b/drivers/acpi/utilities/utmutex.c index b851f7be5d58..25eb34369afa 100644 --- a/drivers/acpi/utilities/utmutex.c +++ b/drivers/acpi/utilities/utmutex.c @@ -73,14 +73,21 @@ acpi_status acpi_ut_mutex_initialize(void) /* * Create each of the predefined mutex objects */ - for (i = 0; i < NUM_MUTEX; i++) { + for (i = 0; i < ACPI_NUM_MUTEX; i++) { status = acpi_ut_create_mutex(i); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } } + /* Create the spinlocks for use at interrupt level */ + status = acpi_os_create_lock(&acpi_gbl_gpe_lock); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + status = acpi_os_create_lock(&acpi_gbl_hardware_lock); return_ACPI_STATUS(status); } @@ -105,11 +112,14 @@ void acpi_ut_mutex_terminate(void) /* * Delete each predefined mutex object */ - for (i = 0; i < NUM_MUTEX; i++) { + for (i = 0; i < ACPI_NUM_MUTEX; i++) { (void)acpi_ut_delete_mutex(i); } + /* Delete the spinlocks */ + acpi_os_delete_lock(acpi_gbl_gpe_lock); + acpi_os_delete_lock(acpi_gbl_hardware_lock); return_VOID; } @@ -131,7 +141,7 @@ static acpi_status acpi_ut_create_mutex(acpi_mutex_handle mutex_id) ACPI_FUNCTION_TRACE_U32(ut_create_mutex, mutex_id); - if (mutex_id > MAX_MUTEX) { + if (mutex_id > ACPI_MAX_MUTEX) { return_ACPI_STATUS(AE_BAD_PARAMETER); } @@ -165,7 +175,7 @@ static acpi_status acpi_ut_delete_mutex(acpi_mutex_handle mutex_id) ACPI_FUNCTION_TRACE_U32(ut_delete_mutex, mutex_id); - if (mutex_id > MAX_MUTEX) { + if (mutex_id > ACPI_MAX_MUTEX) { return_ACPI_STATUS(AE_BAD_PARAMETER); } @@ -196,7 +206,7 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id) ACPI_FUNCTION_NAME(ut_acquire_mutex); - if (mutex_id > MAX_MUTEX) { + if (mutex_id > ACPI_MAX_MUTEX) { return (AE_BAD_PARAMETER); } @@ -213,7 +223,7 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id) * the mutex ordering rule. This indicates a coding error somewhere in * the ACPI subsystem code. */ - for (i = mutex_id; i < MAX_MUTEX; i++) { + for (i = mutex_id; i < ACPI_MAX_MUTEX; i++) { if (acpi_gbl_mutex_info[i].thread_id == this_thread_id) { if (i == mutex_id) { ACPI_ERROR((AE_INFO, @@ -284,7 +294,7 @@ acpi_status acpi_ut_release_mutex(acpi_mutex_handle mutex_id) "Thread %X releasing Mutex [%s]\n", this_thread_id, acpi_ut_get_mutex_name(mutex_id))); - if (mutex_id > MAX_MUTEX) { + if (mutex_id > ACPI_MAX_MUTEX) { return (AE_BAD_PARAMETER); } @@ -309,7 +319,7 @@ acpi_status acpi_ut_release_mutex(acpi_mutex_handle mutex_id) * ordering rule. This indicates a coding error somewhere in * the ACPI subsystem code. */ - for (i = mutex_id; i < MAX_MUTEX; i++) { + for (i = mutex_id; i < ACPI_MAX_MUTEX; i++) { if (acpi_gbl_mutex_info[i].thread_id == this_thread_id) { if (i == mutex_id) { continue; diff --git a/include/acpi/acconfig.h b/include/acpi/acconfig.h index 8b52e44ad2ab..b9beceb33141 100644 --- a/include/acpi/acconfig.h +++ b/include/acpi/acconfig.h @@ -63,7 +63,7 @@ /* Current ACPICA subsystem version in YYYYMMDD format */ -#define ACPI_CA_VERSION 0x20060526 +#define ACPI_CA_VERSION 0x20060608 /* * OS name, used for the _OS object. The _OS object is essentially obsolete, @@ -171,15 +171,8 @@ #define ACPI_MAX_ADDRESS_SPACE 255 /* Array sizes. Used for range checking also */ -#define ACPI_MAX_MATCH_OPCODE 5 -#if 0 -#define ACPI_NUM_ACCESS_TYPES 6 -#define ACPI_NUM_UPDATE_RULES 3 -#define ACPI_NUM_LOCK_RULES 2 -#define ACPI_NUM_FIELD_NAMES 2 -#define ACPI_NUM_OPCODES 256 -#endif +#define ACPI_MAX_MATCH_OPCODE 5 /* RSDP checksums */ diff --git a/include/acpi/acglobal.h b/include/acpi/acglobal.h index 9297f293b2c0..14531d48f6b6 100644 --- a/include/acpi/acglobal.h +++ b/include/acpi/acglobal.h @@ -186,7 +186,7 @@ extern struct acpi_table_support acpi_gbl_table_data[ACPI_TABLE_ID_MAX + 1]; * actual OS mutex handles, indexed by the local ACPI_MUTEX_HANDLEs. * (The table maps local handles to the real OS handles) */ -ACPI_EXTERN struct acpi_mutex_info acpi_gbl_mutex_info[NUM_MUTEX]; +ACPI_EXTERN struct acpi_mutex_info acpi_gbl_mutex_info[ACPI_NUM_MUTEX]; /***************************************************************************** * @@ -314,7 +314,11 @@ ACPI_EXTERN struct acpi_fixed_event_handler ACPI_EXTERN struct acpi_gpe_xrupt_info *acpi_gbl_gpe_xrupt_list_head; ACPI_EXTERN struct acpi_gpe_block_info *acpi_gbl_gpe_fadt_blocks[ACPI_MAX_GPE_BLOCKS]; + +/* Spinlocks */ + ACPI_EXTERN acpi_handle acpi_gbl_gpe_lock; +ACPI_EXTERN acpi_handle acpi_gbl_hardware_lock; /***************************************************************************** * diff --git a/include/acpi/aclocal.h b/include/acpi/aclocal.h index 98c697e3c486..1eeca7adca95 100644 --- a/include/acpi/aclocal.h +++ b/include/acpi/aclocal.h @@ -72,52 +72,55 @@ union acpi_parse_object; * Predefined handles for the mutex objects used within the subsystem * All mutex objects are automatically created by acpi_ut_mutex_initialize. * - * The acquire/release ordering protocol is implied via this list. Mutexes + * The acquire/release ordering protocol is implied via this list. Mutexes * with a lower value must be acquired before mutexes with a higher value. * - * NOTE: any changes here must be reflected in the acpi_gbl_mutex_names table also! + * NOTE: any changes here must be reflected in the acpi_gbl_mutex_names + * table below also! */ -#define ACPI_MTX_EXECUTE 0 -#define ACPI_MTX_INTERPRETER 1 -#define ACPI_MTX_PARSER 2 -#define ACPI_MTX_DISPATCHER 3 -#define ACPI_MTX_TABLES 4 -#define ACPI_MTX_OP_REGIONS 5 -#define ACPI_MTX_NAMESPACE 6 -#define ACPI_MTX_EVENTS 7 -#define ACPI_MTX_HARDWARE 8 -#define ACPI_MTX_CACHES 9 -#define ACPI_MTX_MEMORY 10 -#define ACPI_MTX_DEBUG_CMD_COMPLETE 11 -#define ACPI_MTX_DEBUG_CMD_READY 12 - -#define MAX_MUTEX 12 -#define NUM_MUTEX MAX_MUTEX+1 +#define ACPI_MTX_INTERPRETER 0 /* AML Interpreter, main lock */ +#define ACPI_MTX_CONTROL_METHOD 1 /* Control method termination [TBD: may no longer be necessary] */ +#define ACPI_MTX_TABLES 2 /* Data for ACPI tables */ +#define ACPI_MTX_NAMESPACE 3 /* ACPI Namespace */ +#define ACPI_MTX_EVENTS 4 /* Data for ACPI events */ +#define ACPI_MTX_CACHES 5 /* Internal caches, general purposes */ +#define ACPI_MTX_MEMORY 6 /* Debug memory tracking lists */ +#define ACPI_MTX_DEBUG_CMD_COMPLETE 7 /* AML debugger */ +#define ACPI_MTX_DEBUG_CMD_READY 8 /* AML debugger */ + +#define ACPI_MAX_MUTEX 8 +#define ACPI_NUM_MUTEX ACPI_MAX_MUTEX+1 #if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) #ifdef DEFINE_ACPI_GLOBALS -/* Names for the mutexes used in the subsystem */ +/* Debug names for the mutexes above */ -static char *acpi_gbl_mutex_names[] = { - "ACPI_MTX_Execute", +static char *acpi_gbl_mutex_names[ACPI_NUM_MUTEX] = { "ACPI_MTX_Interpreter", - "ACPI_MTX_Parser", - "ACPI_MTX_Dispatcher", + "ACPI_MTX_Method", "ACPI_MTX_Tables", - "ACPI_MTX_OpRegions", "ACPI_MTX_Namespace", "ACPI_MTX_Events", - "ACPI_MTX_Hardware", "ACPI_MTX_Caches", "ACPI_MTX_Memory", "ACPI_MTX_DebugCmdComplete", - "ACPI_MTX_DebugCmdReady", + "ACPI_MTX_DebugCmdReady" }; #endif #endif +/* + * Predefined handles for spinlocks used within the subsystem. + * These spinlocks are created by acpi_ut_mutex_initialize + */ +#define ACPI_LOCK_GPES 0 +#define ACPI_LOCK_HARDWARE 1 + +#define ACPI_MAX_LOCK 1 +#define ACPI_NUM_LOCK ACPI_MAX_LOCK+1 + /* Owner IDs are used to track namespace nodes for selective deletion */ typedef u8 acpi_owner_id; -- cgit v1.2.3 From bf72aeba2ffef599d1d386425c9e46b82be657cd Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 15 Jun 2006 10:45:18 +1000 Subject: powerpc: Use 64k pages without needing cache-inhibited large pages Some POWER5+ machines can do 64k hardware pages for normal memory but not for cache-inhibited pages. This patch lets us use 64k hardware pages for most user processes on such machines (assuming the kernel has been configured with CONFIG_PPC_64K_PAGES=y). User processes start out using 64k pages and get switched to 4k pages if they use any non-cacheable mappings. With this, we use 64k pages for the vmalloc region and 4k pages for the imalloc region. If anything creates a non-cacheable mapping in the vmalloc region, the vmalloc region will get switched to 4k pages. I don't know of any driver other than the DRM that would do this, though, and these machines don't have AGP. When a region gets switched from 64k pages to 4k pages, we do not have to clear out all the 64k HPTEs from the hash table immediately. We use the _PAGE_COMBO bit in the Linux PTE to indicate whether the page was hashed in as a 64k page or a set of 4k pages. If hash_page is trying to insert a 4k page for a Linux PTE and it sees that it has already been inserted as a 64k page, it first invalidates the 64k HPTE before inserting the 4k HPTE. The hash invalidation routines also use the _PAGE_COMBO bit, to determine whether to look for a 64k HPTE or a set of 4k HPTEs to remove. With those two changes, we can tolerate a mix of 4k and 64k HPTEs in the hash table, and they will all get removed when the address space is torn down. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/asm-offsets.c | 2 + arch/powerpc/kernel/prom.c | 3 ++ arch/powerpc/mm/hash_low_64.S | 28 +++++++++++++ arch/powerpc/mm/hash_utils_64.c | 84 ++++++++++++++++++++++++++++++++++----- arch/powerpc/mm/mmu_context_64.c | 3 ++ arch/powerpc/mm/slb.c | 29 +++++++------- arch/powerpc/mm/slb_low.S | 17 +++++--- arch/powerpc/mm/tlb_64.c | 5 ++- include/asm-powerpc/mmu.h | 13 ++++++ include/asm-powerpc/paca.h | 1 + include/asm-powerpc/pgtable-4k.h | 2 + include/asm-powerpc/pgtable-64k.h | 2 + include/asm-powerpc/pgtable.h | 10 +---- 13 files changed, 160 insertions(+), 39 deletions(-) (limited to 'include') diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index aa0486d552a3..ff2940548929 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -122,6 +122,8 @@ int main(void) DEFINE(PACASLBCACHE, offsetof(struct paca_struct, slb_cache)); DEFINE(PACASLBCACHEPTR, offsetof(struct paca_struct, slb_cache_ptr)); DEFINE(PACACONTEXTID, offsetof(struct paca_struct, context.id)); + DEFINE(PACACONTEXTSLLP, offsetof(struct paca_struct, context.sllp)); + DEFINE(PACAVMALLOCSLLP, offsetof(struct paca_struct, vmalloc_sllp)); #ifdef CONFIG_HUGETLB_PAGE DEFINE(PACALOWHTLBAREAS, offsetof(struct paca_struct, context.low_htlb_areas)); DEFINE(PACAHIGHHTLBAREAS, offsetof(struct paca_struct, context.high_htlb_areas)); diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 969f4abcc0be..d77d24a89b39 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -948,7 +948,10 @@ static struct ibm_pa_feature { {CPU_FTR_CTRL, 0, 0, 3, 0}, {CPU_FTR_NOEXECUTE, 0, 0, 6, 0}, {CPU_FTR_NODSISRALIGN, 0, 1, 1, 1}, +#if 0 + /* put this back once we know how to test if firmware does 64k IO */ {CPU_FTR_CI_LARGE_PAGE, 0, 1, 2, 0}, +#endif }; static void __init check_cpu_pa_features(unsigned long node) diff --git a/arch/powerpc/mm/hash_low_64.S b/arch/powerpc/mm/hash_low_64.S index 106fba391987..52e914238959 100644 --- a/arch/powerpc/mm/hash_low_64.S +++ b/arch/powerpc/mm/hash_low_64.S @@ -369,6 +369,7 @@ _GLOBAL(__hash_page_4K) rlwinm r30,r4,32-9+7,31-7,31-7 /* _PAGE_RW -> _PAGE_DIRTY */ or r30,r30,r31 ori r30,r30,_PAGE_BUSY | _PAGE_ACCESSED | _PAGE_HASHPTE + oris r30,r30,_PAGE_COMBO@h /* Write the linux PTE atomically (setting busy) */ stdcx. r30,0,r6 bne- 1b @@ -428,6 +429,14 @@ END_FTR_SECTION(CPU_FTR_NOEXECUTE|CPU_FTR_COHERENT_ICACHE, CPU_FTR_NOEXECUTE) andi. r0,r31,_PAGE_HASHPTE li r26,0 /* Default hidx */ beq htab_insert_pte + + /* + * Check if the pte was already inserted into the hash table + * as a 64k HW page, and invalidate the 64k HPTE if so. + */ + andis. r0,r31,_PAGE_COMBO@h + beq htab_inval_old_hpte + ld r6,STK_PARM(r6)(r1) ori r26,r6,0x8000 /* Load the hidx mask */ ld r26,0(r26) @@ -498,6 +507,19 @@ _GLOBAL(htab_call_hpte_remove) /* Try all again */ b htab_insert_pte + /* + * Call out to C code to invalidate an 64k HW HPTE that is + * useless now that the segment has been switched to 4k pages. + */ +htab_inval_old_hpte: + mr r3,r29 /* virtual addr */ + mr r4,r31 /* PTE.pte */ + li r5,0 /* PTE.hidx */ + li r6,MMU_PAGE_64K /* psize */ + ld r7,STK_PARM(r8)(r1) /* local */ + bl .flush_hash_page + b htab_insert_pte + htab_bail_ok: li r3,0 b htab_bail @@ -638,6 +660,12 @@ _GLOBAL(__hash_page_64K) * is changing this PTE anyway and might hash it. */ bne- ht64_bail_ok +BEGIN_FTR_SECTION + /* Check if PTE has the cache-inhibit bit set */ + andi. r0,r31,_PAGE_NO_CACHE + /* If so, bail out and refault as a 4k page */ + bne- ht64_bail_ok +END_FTR_SECTION_IFCLR(CPU_FTR_CI_LARGE_PAGE) /* Prepare new PTE value (turn access RW into DIRTY, then * add BUSY,HASHPTE and ACCESSED) */ diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index b43ed92ef471..d03fd2b4445e 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c @@ -92,10 +92,15 @@ unsigned long htab_size_bytes; unsigned long htab_hash_mask; int mmu_linear_psize = MMU_PAGE_4K; int mmu_virtual_psize = MMU_PAGE_4K; +int mmu_vmalloc_psize = MMU_PAGE_4K; +int mmu_io_psize = MMU_PAGE_4K; #ifdef CONFIG_HUGETLB_PAGE int mmu_huge_psize = MMU_PAGE_16M; unsigned int HPAGE_SHIFT; #endif +#ifdef CONFIG_PPC_64K_PAGES +int mmu_ci_restrictions; +#endif /* There are definitions of page sizes arrays to be used when none * is provided by the firmware. @@ -308,20 +313,31 @@ static void __init htab_init_page_sizes(void) else if (mmu_psize_defs[MMU_PAGE_1M].shift) mmu_linear_psize = MMU_PAGE_1M; +#ifdef CONFIG_PPC_64K_PAGES /* * Pick a size for the ordinary pages. Default is 4K, we support - * 64K if cache inhibited large pages are supported by the - * processor + * 64K for user mappings and vmalloc if supported by the processor. + * We only use 64k for ioremap if the processor + * (and firmware) support cache-inhibited large pages. + * If not, we use 4k and set mmu_ci_restrictions so that + * hash_page knows to switch processes that use cache-inhibited + * mappings to 4k pages. */ -#ifdef CONFIG_PPC_64K_PAGES - if (mmu_psize_defs[MMU_PAGE_64K].shift && - cpu_has_feature(CPU_FTR_CI_LARGE_PAGE)) + if (mmu_psize_defs[MMU_PAGE_64K].shift) { mmu_virtual_psize = MMU_PAGE_64K; + mmu_vmalloc_psize = MMU_PAGE_64K; + if (cpu_has_feature(CPU_FTR_CI_LARGE_PAGE)) + mmu_io_psize = MMU_PAGE_64K; + else + mmu_ci_restrictions = 1; + } #endif - printk(KERN_DEBUG "Page orders: linear mapping = %d, others = %d\n", + printk(KERN_DEBUG "Page orders: linear mapping = %d, " + "virtual = %d, io = %d\n", mmu_psize_defs[mmu_linear_psize].shift, - mmu_psize_defs[mmu_virtual_psize].shift); + mmu_psize_defs[mmu_virtual_psize].shift, + mmu_psize_defs[mmu_io_psize].shift); #ifdef CONFIG_HUGETLB_PAGE /* Init large page size. Currently, we pick 16M or 1M depending @@ -556,6 +572,7 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap) pte_t *ptep; cpumask_t tmp; int rc, user_region = 0, local = 0; + int psize; DBG_LOW("hash_page(ea=%016lx, access=%lx, trap=%lx\n", ea, access, trap); @@ -575,10 +592,15 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap) return 1; } vsid = get_vsid(mm->context.id, ea); + psize = mm->context.user_psize; break; case VMALLOC_REGION_ID: mm = &init_mm; vsid = get_kernel_vsid(ea); + if (ea < VMALLOC_END) + psize = mmu_vmalloc_psize; + else + psize = mmu_io_psize; break; default: /* Not a valid range @@ -629,7 +651,40 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap) #ifndef CONFIG_PPC_64K_PAGES rc = __hash_page_4K(ea, access, vsid, ptep, trap, local); #else - if (mmu_virtual_psize == MMU_PAGE_64K) + if (mmu_ci_restrictions) { + /* If this PTE is non-cacheable, switch to 4k */ + if (psize == MMU_PAGE_64K && + (pte_val(*ptep) & _PAGE_NO_CACHE)) { + if (user_region) { + psize = MMU_PAGE_4K; + mm->context.user_psize = MMU_PAGE_4K; + mm->context.sllp = SLB_VSID_USER | + mmu_psize_defs[MMU_PAGE_4K].sllp; + } else if (ea < VMALLOC_END) { + /* + * some driver did a non-cacheable mapping + * in vmalloc space, so switch vmalloc + * to 4k pages + */ + printk(KERN_ALERT "Reducing vmalloc segment " + "to 4kB pages because of " + "non-cacheable mapping\n"); + psize = mmu_vmalloc_psize = MMU_PAGE_4K; + } + } + if (user_region) { + if (psize != get_paca()->context.user_psize) { + get_paca()->context = mm->context; + slb_flush_and_rebolt(); + } + } else if (get_paca()->vmalloc_sllp != + mmu_psize_defs[mmu_vmalloc_psize].sllp) { + get_paca()->vmalloc_sllp = + mmu_psize_defs[mmu_vmalloc_psize].sllp; + slb_flush_and_rebolt(); + } + } + if (psize == MMU_PAGE_64K) rc = __hash_page_64K(ea, access, vsid, ptep, trap, local); else rc = __hash_page_4K(ea, access, vsid, ptep, trap, local); @@ -681,7 +736,18 @@ void hash_preload(struct mm_struct *mm, unsigned long ea, #ifndef CONFIG_PPC_64K_PAGES __hash_page_4K(ea, access, vsid, ptep, trap, local); #else - if (mmu_virtual_psize == MMU_PAGE_64K) + if (mmu_ci_restrictions) { + /* If this PTE is non-cacheable, switch to 4k */ + if (mm->context.user_psize == MMU_PAGE_64K && + (pte_val(*ptep) & _PAGE_NO_CACHE)) { + mm->context.user_psize = MMU_PAGE_4K; + mm->context.sllp = SLB_VSID_USER | + mmu_psize_defs[MMU_PAGE_4K].sllp; + get_paca()->context = mm->context; + slb_flush_and_rebolt(); + } + } + if (mm->context.user_psize == MMU_PAGE_64K) __hash_page_64K(ea, access, vsid, ptep, trap, local); else __hash_page_4K(ea, access, vsid, ptep, trap, local); diff --git a/arch/powerpc/mm/mmu_context_64.c b/arch/powerpc/mm/mmu_context_64.c index 714a84dd8d5d..65d18dca266f 100644 --- a/arch/powerpc/mm/mmu_context_64.c +++ b/arch/powerpc/mm/mmu_context_64.c @@ -49,6 +49,9 @@ again: } mm->context.id = index; + mm->context.user_psize = mmu_virtual_psize; + mm->context.sllp = SLB_VSID_USER | + mmu_psize_defs[mmu_virtual_psize].sllp; return 0; } diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c index 2cc61736feee..6a8bf6c6000e 100644 --- a/arch/powerpc/mm/slb.c +++ b/arch/powerpc/mm/slb.c @@ -60,19 +60,19 @@ static inline void create_slbe(unsigned long ea, unsigned long flags, : "memory" ); } -static void slb_flush_and_rebolt(void) +void slb_flush_and_rebolt(void) { /* If you change this make sure you change SLB_NUM_BOLTED * appropriately too. */ - unsigned long linear_llp, virtual_llp, lflags, vflags; + unsigned long linear_llp, vmalloc_llp, lflags, vflags; unsigned long ksp_esid_data; WARN_ON(!irqs_disabled()); linear_llp = mmu_psize_defs[mmu_linear_psize].sllp; - virtual_llp = mmu_psize_defs[mmu_virtual_psize].sllp; + vmalloc_llp = mmu_psize_defs[mmu_vmalloc_psize].sllp; lflags = SLB_VSID_KERNEL | linear_llp; - vflags = SLB_VSID_KERNEL | virtual_llp; + vflags = SLB_VSID_KERNEL | vmalloc_llp; ksp_esid_data = mk_esid_data(get_paca()->kstack, 2); if ((ksp_esid_data & ESID_MASK) == PAGE_OFFSET) @@ -164,11 +164,10 @@ static inline void patch_slb_encoding(unsigned int *insn_addr, void slb_initialize(void) { - unsigned long linear_llp, virtual_llp; + unsigned long linear_llp, vmalloc_llp, io_llp; static int slb_encoding_inited; extern unsigned int *slb_miss_kernel_load_linear; - extern unsigned int *slb_miss_kernel_load_virtual; - extern unsigned int *slb_miss_user_load_normal; + extern unsigned int *slb_miss_kernel_load_io; #ifdef CONFIG_HUGETLB_PAGE extern unsigned int *slb_miss_user_load_huge; unsigned long huge_llp; @@ -178,18 +177,19 @@ void slb_initialize(void) /* Prepare our SLB miss handler based on our page size */ linear_llp = mmu_psize_defs[mmu_linear_psize].sllp; - virtual_llp = mmu_psize_defs[mmu_virtual_psize].sllp; + io_llp = mmu_psize_defs[mmu_io_psize].sllp; + vmalloc_llp = mmu_psize_defs[mmu_vmalloc_psize].sllp; + get_paca()->vmalloc_sllp = SLB_VSID_KERNEL | vmalloc_llp; + if (!slb_encoding_inited) { slb_encoding_inited = 1; patch_slb_encoding(slb_miss_kernel_load_linear, SLB_VSID_KERNEL | linear_llp); - patch_slb_encoding(slb_miss_kernel_load_virtual, - SLB_VSID_KERNEL | virtual_llp); - patch_slb_encoding(slb_miss_user_load_normal, - SLB_VSID_USER | virtual_llp); + patch_slb_encoding(slb_miss_kernel_load_io, + SLB_VSID_KERNEL | io_llp); DBG("SLB: linear LLP = %04x\n", linear_llp); - DBG("SLB: virtual LLP = %04x\n", virtual_llp); + DBG("SLB: io LLP = %04x\n", io_llp); #ifdef CONFIG_HUGETLB_PAGE patch_slb_encoding(slb_miss_user_load_huge, SLB_VSID_USER | huge_llp); @@ -204,7 +204,7 @@ void slb_initialize(void) unsigned long lflags, vflags; lflags = SLB_VSID_KERNEL | linear_llp; - vflags = SLB_VSID_KERNEL | virtual_llp; + vflags = SLB_VSID_KERNEL | vmalloc_llp; /* Invalidate the entire SLB (even slot 0) & all the ERATS */ asm volatile("isync":::"memory"); @@ -212,7 +212,6 @@ void slb_initialize(void) asm volatile("isync; slbia; isync":::"memory"); create_slbe(PAGE_OFFSET, lflags, 0); - /* VMALLOC space has 4K pages always for now */ create_slbe(VMALLOC_START, vflags, 1); /* We don't bolt the stack for the time being - we're in boot, diff --git a/arch/powerpc/mm/slb_low.S b/arch/powerpc/mm/slb_low.S index abfaabf667bf..8548dcf8ef8b 100644 --- a/arch/powerpc/mm/slb_low.S +++ b/arch/powerpc/mm/slb_low.S @@ -59,10 +59,19 @@ _GLOBAL(slb_miss_kernel_load_linear) li r11,0 b slb_finish_load -1: /* vmalloc/ioremap mapping encoding bits, the "li" instruction below +1: /* vmalloc/ioremap mapping encoding bits, the "li" instructions below * will be patched by the kernel at boot */ -_GLOBAL(slb_miss_kernel_load_virtual) +BEGIN_FTR_SECTION + /* check whether this is in vmalloc or ioremap space */ + clrldi r11,r10,48 + cmpldi r11,(VMALLOC_SIZE >> 28) - 1 + bgt 5f + lhz r11,PACAVMALLOCSLLP(r13) + b slb_finish_load +5: +END_FTR_SECTION_IFCLR(CPU_FTR_CI_LARGE_PAGE) +_GLOBAL(slb_miss_kernel_load_io) li r11,0 b slb_finish_load @@ -96,9 +105,7 @@ _GLOBAL(slb_miss_user_load_huge) 1: #endif /* CONFIG_HUGETLB_PAGE */ -_GLOBAL(slb_miss_user_load_normal) - li r11,0 - + lhz r11,PACACONTEXTSLLP(r13) 2: ld r9,PACACONTEXTID(r13) rldimi r10,r9,USER_ESID_BITS,0 diff --git a/arch/powerpc/mm/tlb_64.c b/arch/powerpc/mm/tlb_64.c index f734b11566c2..e7449b068c82 100644 --- a/arch/powerpc/mm/tlb_64.c +++ b/arch/powerpc/mm/tlb_64.c @@ -131,7 +131,7 @@ void hpte_update(struct mm_struct *mm, unsigned long addr, { struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch); unsigned long vsid; - unsigned int psize = mmu_virtual_psize; + unsigned int psize; int i; i = batch->index; @@ -148,7 +148,8 @@ void hpte_update(struct mm_struct *mm, unsigned long addr, #else BUG(); #endif - } + } else + psize = pte_pagesize_index(pte); /* * This can happen when we are in the middle of a TLB batch and diff --git a/include/asm-powerpc/mmu.h b/include/asm-powerpc/mmu.h index 885397420104..3a5ebe229af5 100644 --- a/include/asm-powerpc/mmu.h +++ b/include/asm-powerpc/mmu.h @@ -165,6 +165,16 @@ struct mmu_psize_def extern struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT]; extern int mmu_linear_psize; extern int mmu_virtual_psize; +extern int mmu_vmalloc_psize; +extern int mmu_io_psize; + +/* + * If the processor supports 64k normal pages but not 64k cache + * inhibited pages, we have to be prepared to switch processes + * to use 4k pages when they create cache-inhibited mappings. + * If this is the case, mmu_ci_restrictions will be set to 1. + */ +extern int mmu_ci_restrictions; #ifdef CONFIG_HUGETLB_PAGE /* @@ -256,6 +266,7 @@ extern long iSeries_hpte_insert(unsigned long hpte_group, extern void stabs_alloc(void); extern void slb_initialize(void); +extern void slb_flush_and_rebolt(void); extern void stab_initialize(unsigned long stab); #endif /* __ASSEMBLY__ */ @@ -359,6 +370,8 @@ typedef unsigned long mm_context_id_t; typedef struct { mm_context_id_t id; + u16 user_psize; /* page size index */ + u16 sllp; /* SLB entry page size encoding */ #ifdef CONFIG_HUGETLB_PAGE u16 low_htlb_areas, high_htlb_areas; #endif diff --git a/include/asm-powerpc/paca.h b/include/asm-powerpc/paca.h index c17fd54d995b..17406353e2ce 100644 --- a/include/asm-powerpc/paca.h +++ b/include/asm-powerpc/paca.h @@ -81,6 +81,7 @@ struct paca_struct { * on the linear mapping */ mm_context_t context; + u16 vmalloc_sllp; u16 slb_cache[SLB_CACHE_ENTRIES]; u16 slb_cache_ptr; diff --git a/include/asm-powerpc/pgtable-4k.h b/include/asm-powerpc/pgtable-4k.h index b2e18629932a..e7036155672e 100644 --- a/include/asm-powerpc/pgtable-4k.h +++ b/include/asm-powerpc/pgtable-4k.h @@ -78,6 +78,8 @@ #define pte_iterate_hashed_end() } while(0) +#define pte_pagesize_index(pte) MMU_PAGE_4K + /* * 4-level page tables related bits */ diff --git a/include/asm-powerpc/pgtable-64k.h b/include/asm-powerpc/pgtable-64k.h index 653915014dcd..4b7126c53f37 100644 --- a/include/asm-powerpc/pgtable-64k.h +++ b/include/asm-powerpc/pgtable-64k.h @@ -90,6 +90,8 @@ #define pte_iterate_hashed_end() } while(0); } } while(0) +#define pte_pagesize_index(pte) \ + (((pte) & _PAGE_COMBO)? MMU_PAGE_4K: MMU_PAGE_64K) #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ diff --git a/include/asm-powerpc/pgtable.h b/include/asm-powerpc/pgtable.h index e9f1f4627e6b..260a0fabe97e 100644 --- a/include/asm-powerpc/pgtable.h +++ b/include/asm-powerpc/pgtable.h @@ -47,8 +47,8 @@ struct mm_struct; /* * Define the address range of the vmalloc VM area. */ -#define VMALLOC_START (0xD000000000000000ul) -#define VMALLOC_SIZE (0x80000000000UL) +#define VMALLOC_START ASM_CONST(0xD000000000000000) +#define VMALLOC_SIZE ASM_CONST(0x80000000000) #define VMALLOC_END (VMALLOC_START + VMALLOC_SIZE) /* @@ -413,12 +413,6 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, flush_tlb_pending(); } pte = __pte(pte_val(pte) & ~_PAGE_HPTEFLAGS); - -#ifdef CONFIG_PPC_64K_PAGES - if (mmu_virtual_psize != MMU_PAGE_64K) - pte = __pte(pte_val(pte) | _PAGE_COMBO); -#endif /* CONFIG_PPC_64K_PAGES */ - *ptep = pte; } -- cgit v1.2.3 From 204face4fb3ba2ca09a4073e7debc595e14c2388 Mon Sep 17 00:00:00 2001 From: Jake Moilanen Date: Wed, 7 Jun 2006 16:15:10 -0500 Subject: [POWERPC] MSI abstraction Instead of trying to make PPC64 MSI fit in a Intel-centric MSI layer, a simple short-term solution is to hook the pci_{en/dis}able_msi() calls and make a machdep call. The rest of the MSI functions are superfluous for what is needed at this time. Many of which can have machdep calls added as needed. Ben and Michael Ellerman are looking into rewrite the MSI layer to be more generic. However, in the meantime this works as a interim solution. Signed-off-by: Jake Moilanen Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/irq.c | 25 +++++++++++++++++++++++++ include/asm-powerpc/machdep.h | 5 +++++ 2 files changed, 30 insertions(+) (limited to 'include') diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 57d560c68897..bfcec4cc70a7 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include @@ -436,6 +437,30 @@ void do_softirq(void) } EXPORT_SYMBOL(do_softirq); +#ifdef CONFIG_PCI_MSI +int pci_enable_msi(struct pci_dev * pdev) +{ + if (ppc_md.enable_msi) + return ppc_md.enable_msi(pdev); + else + return -1; +} + +void pci_disable_msi(struct pci_dev * pdev) +{ + if (ppc_md.disable_msi) + ppc_md.disable_msi(pdev); +} + +void pci_scan_msi_device(struct pci_dev *dev) {} +int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) {return -1;} +void pci_disable_msix(struct pci_dev *dev) {} +void msi_remove_pci_irq_vectors(struct pci_dev *dev) {} +void disable_msi_mode(struct pci_dev *dev, int pos, int type) {} +void pci_no_msi(void) {} + +#endif + #ifdef CONFIG_PPC64 static int __init setup_noirqdistrib(char *str) { diff --git a/include/asm-powerpc/machdep.h b/include/asm-powerpc/machdep.h index 0f9254c18914..fc984bd11d8f 100644 --- a/include/asm-powerpc/machdep.h +++ b/include/asm-powerpc/machdep.h @@ -238,6 +238,11 @@ struct machdep_calls { */ void (*machine_kexec)(struct kimage *image); #endif /* CONFIG_KEXEC */ + +#ifdef CONFIG_PCI_MSI + int (*enable_msi)(struct pci_dev *pdev); + void (*disable_msi)(struct pci_dev *pdev); +#endif /* CONFIG_PCI_MSI */ }; extern void power4_idle(void); -- cgit v1.2.3 From 3a2c48cfc97f9046abbd810f1efb1aa824bcfaf1 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sat, 10 Jun 2006 20:18:39 +1000 Subject: [POWERPC] 64bit FPSCR support Forthcoming machines will extend the FPSCR to 64 bits. We already had a 64-bit save area for the FPSCR, but we need to use a new form of the mtfsf instruction. Fortunately this new form is decoded as an ordinary mtfsf by existing 64-bit processors. Signed-off-by: Anton Blanchard Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/fpu.S | 6 +++--- arch/powerpc/kernel/vector.S | 4 ++-- include/asm-powerpc/reg.h | 13 +++++++++++++ 3 files changed, 18 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/arch/powerpc/kernel/fpu.S b/arch/powerpc/kernel/fpu.S index 340730fb8c91..01f71200c603 100644 --- a/arch/powerpc/kernel/fpu.S +++ b/arch/powerpc/kernel/fpu.S @@ -72,7 +72,7 @@ _GLOBAL(load_up_fpu) std r12,_MSR(r1) #endif lfd fr0,THREAD_FPSCR(r5) - mtfsf 0xff,fr0 + MTFSF_L(fr0) REST_32FPRS(0, r5) #ifndef CONFIG_SMP subi r4,r5,THREAD @@ -127,7 +127,7 @@ _GLOBAL(giveup_fpu) _GLOBAL(cvt_fd) lfd 0,THREAD_FPSCR(r5) /* load up fpscr value */ - mtfsf 0xff,0 + MTFSF_L(0) lfs 0,0(r3) stfd 0,0(r4) mffs 0 @@ -136,7 +136,7 @@ _GLOBAL(cvt_fd) _GLOBAL(cvt_df) lfd 0,THREAD_FPSCR(r5) /* load up fpscr value */ - mtfsf 0xff,0 + MTFSF_L(0) lfd 0,0(r3) stfs 0,0(r4) mffs 0 diff --git a/arch/powerpc/kernel/vector.S b/arch/powerpc/kernel/vector.S index 66b3d03c5fa5..9416b4ab92ec 100644 --- a/arch/powerpc/kernel/vector.S +++ b/arch/powerpc/kernel/vector.S @@ -53,12 +53,12 @@ fpenable: stfd fr31,8(r1) LDCONST(fr1, fpzero) mffs fr31 - mtfsf 0xff,fr1 + MTFSF_L(fr1) blr fpdisable: mtlr r12 - mtfsf 0xff,fr31 + MTFSF_L(fr31) lfd fr31,8(r1) lfd fr1,16(r1) lfd fr0,24(r1) diff --git a/include/asm-powerpc/reg.h b/include/asm-powerpc/reg.h index 3779b21a7c71..bfc7dc14ffcc 100644 --- a/include/asm-powerpc/reg.h +++ b/include/asm-powerpc/reg.h @@ -499,6 +499,19 @@ #define MMCR0_PMC2_LOADMISSTIME 0x5 #endif +/* + * An mtfsf instruction with the L bit set. On CPUs that support this a + * full 64bits of FPSCR is restored and on other CPUs it is ignored. + * + * Until binutils gets the new form of mtfsf, hardwire the instruction. + */ +#ifdef CONFIG_PPC64 +#define MTFSF_L(REG) \ + .long (0xfc00058e | ((0xff) << 17) | ((REG) << 11) | (1 << 25)) +#else +#define MTFSF_L(REG) mtfsf 0xff, (REG) +#endif + /* Processor Version Register (PVR) field extraction */ #define PVR_VER(pvr) (((pvr) >> 16) & 0xFFFF) /* Version field */ -- cgit v1.2.3 From 227318bbde6c8309b1d20ab46532ec2b737e1fee Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sat, 10 Jun 2006 20:32:01 +1000 Subject: [POWERPC] Remove stale 64bit on 32bit kernel code Remove some stale POWER3/POWER4/970 on 32bit kernel support. Signed-off-by: Anton Blanchard Signed-off-by: Paul Mackerras --- arch/powerpc/Makefile | 1 - arch/powerpc/kernel/cputable.c | 8 -------- arch/powerpc/mm/hash_low_32.S | 34 ---------------------------------- arch/powerpc/mm/ppc_mmu_32.c | 10 ---------- arch/um/sys-ppc/misc.S | 6 +----- include/asm-powerpc/cputable.h | 19 ------------------- include/asm-ppc/mmu.h | 17 ----------------- 7 files changed, 1 insertion(+), 94 deletions(-) (limited to 'include') diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index ed5b26aa8be3..01667d1d571d 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -108,7 +108,6 @@ ifeq ($(CONFIG_6xx),y) CFLAGS += -mcpu=powerpc endif -cpu-as-$(CONFIG_PPC64BRIDGE) += -Wa,-mppc64bridge cpu-as-$(CONFIG_4xx) += -Wa,-m405 cpu-as-$(CONFIG_6xx) += -Wa,-maltivec cpu-as-$(CONFIG_POWER4) += -Wa,-maltivec diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index dfe2fcfb20a0..abf7d42a8b07 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -189,17 +189,11 @@ struct cpu_spec cpu_specs[] = { .oprofile_type = PPC_OPROFILE_POWER4, .platform = "ppc970", }, -#endif /* CONFIG_PPC64 */ -#if defined(CONFIG_PPC64) || defined(CONFIG_POWER4) { /* PPC970FX */ .pvr_mask = 0xffff0000, .pvr_value = 0x003c0000, .cpu_name = "PPC970FX", -#ifdef CONFIG_PPC32 - .cpu_features = CPU_FTRS_970_32, -#else .cpu_features = CPU_FTRS_PPC970, -#endif .cpu_user_features = COMMON_USER_POWER4 | PPC_FEATURE_HAS_ALTIVEC_COMP, .icache_bsize = 128, @@ -210,8 +204,6 @@ struct cpu_spec cpu_specs[] = { .oprofile_type = PPC_OPROFILE_POWER4, .platform = "ppc970", }, -#endif /* defined(CONFIG_PPC64) || defined(CONFIG_POWER4) */ -#ifdef CONFIG_PPC64 { /* PPC970MP */ .pvr_mask = 0xffff0000, .pvr_value = 0x00440000, diff --git a/arch/powerpc/mm/hash_low_32.S b/arch/powerpc/mm/hash_low_32.S index ea469eefa146..94255beeecd3 100644 --- a/arch/powerpc/mm/hash_low_32.S +++ b/arch/powerpc/mm/hash_low_32.S @@ -74,12 +74,6 @@ _GLOBAL(hash_page_sync) */ .text _GLOBAL(hash_page) -#ifdef CONFIG_PPC64BRIDGE - mfmsr r0 - clrldi r0,r0,1 /* make sure it's in 32-bit mode */ - MTMSRD(r0) - isync -#endif tophys(r7,0) /* gets -KERNELBASE into r7 */ #ifdef CONFIG_SMP addis r8,r7,mmu_hash_lock@h @@ -285,7 +279,6 @@ Hash_base = 0xc0180000 Hash_bits = 12 /* e.g. 256kB hash table */ Hash_msk = (((1 << Hash_bits) - 1) * 64) -#ifndef CONFIG_PPC64BRIDGE /* defines for the PTE format for 32-bit PPCs */ #define PTE_SIZE 8 #define PTEG_SIZE 64 @@ -299,21 +292,6 @@ Hash_msk = (((1 << Hash_bits) - 1) * 64) #define SET_V(r) oris r,r,PTE_V@h #define CLR_V(r,t) rlwinm r,r,0,1,31 -#else -/* defines for the PTE format for 64-bit PPCs */ -#define PTE_SIZE 16 -#define PTEG_SIZE 128 -#define LG_PTEG_SIZE 7 -#define LDPTEu ldu -#define STPTE std -#define CMPPTE cmpd -#define PTE_H 2 -#define PTE_V 1 -#define TST_V(r) andi. r,r,PTE_V -#define SET_V(r) ori r,r,PTE_V -#define CLR_V(r,t) li t,PTE_V; andc r,r,t -#endif /* CONFIG_PPC64BRIDGE */ - #define HASH_LEFT 31-(LG_PTEG_SIZE+Hash_bits-1) #define HASH_RIGHT 31-LG_PTEG_SIZE @@ -331,14 +309,8 @@ BEGIN_FTR_SECTION END_FTR_SECTION_IFSET(CPU_FTR_NEED_COHERENT) /* Construct the high word of the PPC-style PTE (r5) */ -#ifndef CONFIG_PPC64BRIDGE rlwinm r5,r3,7,1,24 /* put VSID in 0x7fffff80 bits */ rlwimi r5,r4,10,26,31 /* put in API (abbrev page index) */ -#else /* CONFIG_PPC64BRIDGE */ - clrlwi r3,r3,8 /* reduce vsid to 24 bits */ - sldi r5,r3,12 /* shift vsid into position */ - rlwimi r5,r4,16,20,24 /* put in API (abbrev page index) */ -#endif /* CONFIG_PPC64BRIDGE */ SET_V(r5) /* set V (valid) bit */ /* Get the address of the primary PTE group in the hash table (r3) */ @@ -516,14 +488,8 @@ _GLOBAL(flush_hash_pages) add r3,r3,r0 /* note code below trims to 24 bits */ /* Construct the high word of the PPC-style PTE (r11) */ -#ifndef CONFIG_PPC64BRIDGE rlwinm r11,r3,7,1,24 /* put VSID in 0x7fffff80 bits */ rlwimi r11,r4,10,26,31 /* put in API (abbrev page index) */ -#else /* CONFIG_PPC64BRIDGE */ - clrlwi r3,r3,8 /* reduce vsid to 24 bits */ - sldi r11,r3,12 /* shift vsid into position */ - rlwimi r11,r4,16,20,24 /* put in API (abbrev page index) */ -#endif /* CONFIG_PPC64BRIDGE */ SET_V(r11) /* set V (valid) bit */ #ifdef CONFIG_SMP diff --git a/arch/powerpc/mm/ppc_mmu_32.c b/arch/powerpc/mm/ppc_mmu_32.c index 1df731e42b50..ab5cd724b122 100644 --- a/arch/powerpc/mm/ppc_mmu_32.c +++ b/arch/powerpc/mm/ppc_mmu_32.c @@ -42,11 +42,7 @@ unsigned long _SDR1; union ubat { /* BAT register values to be loaded */ BAT bat; -#ifdef CONFIG_PPC64BRIDGE - u64 word[2]; -#else u32 word[2]; -#endif } BATS[4][2]; /* 4 pairs of IBAT, DBAT */ struct batrange { /* stores address ranges mapped by BATs */ @@ -220,15 +216,9 @@ void __init MMU_init_hw(void) if ( ppc_md.progress ) ppc_md.progress("hash:enter", 0x105); -#ifdef CONFIG_PPC64BRIDGE -#define LG_HPTEG_SIZE 7 /* 128 bytes per HPTEG */ -#define SDR1_LOW_BITS (lg_n_hpteg - 11) -#define MIN_N_HPTEG 2048 /* min 256kB hash table */ -#else #define LG_HPTEG_SIZE 6 /* 64 bytes per HPTEG */ #define SDR1_LOW_BITS ((n_hpteg - 1) >> 10) #define MIN_N_HPTEG 1024 /* min 64kB hash table */ -#endif /* * Allow 1 HPTE (1/8 HPTEG) for each page of memory. diff --git a/arch/um/sys-ppc/misc.S b/arch/um/sys-ppc/misc.S index 11b7bd768cfd..f0c971db47e4 100644 --- a/arch/um/sys-ppc/misc.S +++ b/arch/um/sys-ppc/misc.S @@ -23,14 +23,10 @@ #define CACHE_LINE_SIZE 16 #define LG_CACHE_LINE_SIZE 4 #define MAX_COPY_PREFETCH 1 -#elif !defined(CONFIG_PPC64BRIDGE) +#else #define CACHE_LINE_SIZE 32 #define LG_CACHE_LINE_SIZE 5 #define MAX_COPY_PREFETCH 4 -#else -#define CACHE_LINE_SIZE 128 -#define LG_CACHE_LINE_SIZE 7 -#define MAX_COPY_PREFETCH 1 #endif /* CONFIG_4xx || CONFIG_8xx */ .text diff --git a/include/asm-powerpc/cputable.h b/include/asm-powerpc/cputable.h index 69f2c242797f..da6f417d2ca7 100644 --- a/include/asm-powerpc/cputable.h +++ b/include/asm-powerpc/cputable.h @@ -300,13 +300,6 @@ extern void do_cpu_ftr_fixups(unsigned long offset); CPU_FTR_COMMON) #define CPU_FTRS_CLASSIC32 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \ CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE) -#define CPU_FTRS_POWER3_32 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \ - CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE) -#define CPU_FTRS_POWER4_32 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \ - CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_NODSISRALIGN) -#define CPU_FTRS_970_32 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \ - CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_ALTIVEC_COMP | \ - CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_NODSISRALIGN) #define CPU_FTRS_8XX (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB) #define CPU_FTRS_40X (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \ CPU_FTR_NODSISRALIGN) @@ -367,12 +360,6 @@ enum { #else CPU_FTRS_GENERIC_32 | #endif -#ifdef CONFIG_PPC64BRIDGE - CPU_FTRS_POWER3_32 | -#endif -#ifdef CONFIG_POWER4 - CPU_FTRS_POWER4_32 | CPU_FTRS_970_32 | -#endif #ifdef CONFIG_8xx CPU_FTRS_8XX | #endif @@ -412,12 +399,6 @@ enum { #else CPU_FTRS_GENERIC_32 & #endif -#ifdef CONFIG_PPC64BRIDGE - CPU_FTRS_POWER3_32 & -#endif -#ifdef CONFIG_POWER4 - CPU_FTRS_POWER4_32 & CPU_FTRS_970_32 & -#endif #ifdef CONFIG_8xx CPU_FTRS_8XX & #endif diff --git a/include/asm-ppc/mmu.h b/include/asm-ppc/mmu.h index 80ae60481fb7..8915c4c3ecb3 100644 --- a/include/asm-ppc/mmu.h +++ b/include/asm-ppc/mmu.h @@ -31,20 +31,11 @@ typedef struct { /* Hardware Page Table Entry */ typedef struct _PTE { -#ifdef CONFIG_PPC64BRIDGE - unsigned long long vsid:52; - unsigned long api:5; - unsigned long :5; - unsigned long h:1; - unsigned long v:1; - unsigned long long rpn:52; -#else /* CONFIG_PPC64BRIDGE */ unsigned long v:1; /* Entry is valid */ unsigned long vsid:24; /* Virtual segment identifier */ unsigned long h:1; /* Hash algorithm indicator */ unsigned long api:6; /* Abbreviated page index */ unsigned long rpn:20; /* Real (physical) page number */ -#endif /* CONFIG_PPC64BRIDGE */ unsigned long :3; /* Unused */ unsigned long r:1; /* Referenced */ unsigned long c:1; /* Changed */ @@ -85,11 +76,7 @@ typedef struct _P601_BATU { /* Upper part of BAT for 601 processor */ } P601_BATU; typedef struct _BATU { /* Upper part of BAT (all except 601) */ -#ifdef CONFIG_PPC64BRIDGE - unsigned long long bepi:47; -#else /* CONFIG_PPC64BRIDGE */ unsigned long bepi:15; /* Effective page index (virtual address) */ -#endif /* CONFIG_PPC64BRIDGE */ unsigned long :4; /* Unused */ unsigned long bl:11; /* Block size mask */ unsigned long vs:1; /* Supervisor valid */ @@ -104,11 +91,7 @@ typedef struct _P601_BATL { /* Lower part of BAT for 601 processor */ } P601_BATL; typedef struct _BATL { /* Lower part of BAT (all except 601) */ -#ifdef CONFIG_PPC64BRIDGE - unsigned long long brpn:47; -#else /* CONFIG_PPC64BRIDGE */ unsigned long brpn:15; /* Real page index (physical address) */ -#endif /* CONFIG_PPC64BRIDGE */ unsigned long :10; /* Unused */ unsigned long w:1; /* Write-thru cache */ unsigned long i:1; /* Cache inhibit */ -- cgit v1.2.3 From 357518fa34d9dceda42bfc09642356a58370050d Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sat, 10 Jun 2006 20:53:06 +1000 Subject: [POWERPC] pcibus_to_node fixes of_node_to_nid returns -1 if the associativity cannot be found. This means pcibus_to_cpumask has to be careful not to pass a negative index into node_to_cpumask. Since pcibus_to_node could be used a lot, and of_node_to_nid is slow (it walks a list doing strcmps), lets also cache the node in the pci_controller struct. Signed-off-by: Anton Blanchard Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/pci_64.c | 13 ++++++++++++- include/asm-powerpc/pci-bridge.h | 8 ++++++++ include/asm-powerpc/topology.h | 14 +++++++------- 3 files changed, 27 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c index 74dc76653e1b..5ad87c426bed 100644 --- a/arch/powerpc/kernel/pci_64.c +++ b/arch/powerpc/kernel/pci_64.c @@ -227,8 +227,10 @@ struct pci_controller * pcibios_alloc_controller(struct device_node *dev) pci_setup_pci_controller(phb); phb->arch_data = dev; phb->is_dynamic = mem_init_done; - if (dev) + if (dev) { + PHB_SET_NODE(phb, of_node_to_nid(dev)); add_linux_pci_domain(dev, phb); + } return phb; } @@ -1415,3 +1417,12 @@ long sys_pciconfig_iobase(long which, unsigned long in_bus, return -EOPNOTSUPP; } + +#ifdef CONFIG_NUMA +int pcibus_to_node(struct pci_bus *bus) +{ + struct pci_controller *phb = pci_bus_to_host(bus); + return phb->node; +} +EXPORT_SYMBOL(pcibus_to_node); +#endif diff --git a/include/asm-powerpc/pci-bridge.h b/include/asm-powerpc/pci-bridge.h index 84a3075db524..4f55573762bb 100644 --- a/include/asm-powerpc/pci-bridge.h +++ b/include/asm-powerpc/pci-bridge.h @@ -6,6 +6,7 @@ #include #else +#include #include #include @@ -22,6 +23,7 @@ struct pci_controller { struct pci_bus *bus; char is_dynamic; + int node; void *arch_data; struct list_head list_node; @@ -165,6 +167,12 @@ static inline unsigned long pci_address_to_pio(phys_addr_t address) #define PCI_PROBE_NORMAL 0 /* Do normal PCI probing */ #define PCI_PROBE_DEVTREE 1 /* Instantiate from device tree */ +#ifdef CONFIG_NUMA +#define PHB_SET_NODE(PHB, NODE) ((PHB)->node = (NODE)) +#else +#define PHB_SET_NODE(PHB, NODE) ((PHB)->node = -1) +#endif + #endif /* CONFIG_PPC64 */ #endif /* __KERNEL__ */ #endif diff --git a/include/asm-powerpc/topology.h b/include/asm-powerpc/topology.h index b7abd423c570..f4c759b5f6cc 100644 --- a/include/asm-powerpc/topology.h +++ b/include/asm-powerpc/topology.h @@ -32,13 +32,13 @@ static inline int node_to_first_cpu(int node) int of_node_to_nid(struct device_node *device); -#ifdef CONFIG_PPC64 -#define pcibus_to_node(bus) (of_node_to_nid(bus->sysdata)) -#define pcibus_to_cpumask(bus) (node_to_cpumask(of_node_to_nid(bus->sysdata))) -#else -#define pcibus_to_node(node) (-1) -#define pcibus_to_cpumask(bus) (cpu_online_map) -#endif +struct pci_bus; +extern int pcibus_to_node(struct pci_bus *bus); + +#define pcibus_to_cpumask(bus) (pcibus_to_node(bus) == -1 ? \ + CPU_MASK_ALL : \ + node_to_cpumask(pcibus_to_node(bus)) \ + ) /* sched_domains SD_NODE_INIT for PPC64 machines */ #define SD_NODE_INIT (struct sched_domain) { \ -- cgit v1.2.3 From ca1588e71b70534e18368a46a3aad9b25dff941d Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sat, 10 Jun 2006 20:58:08 +1000 Subject: [POWERPC] node local IOMMU tables Allocate IOMMU tables local to the relevant node. Signed-off-by: Anton Blanchard Acked-by: Olof Johansson Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/iommu.c | 9 +++++---- arch/powerpc/kernel/vio.c | 6 +++--- arch/powerpc/platforms/iseries/iommu.c | 2 +- arch/powerpc/platforms/pseries/iommu.c | 23 +++++++++++++---------- arch/powerpc/sysdev/dart_iommu.c | 2 +- include/asm-powerpc/iommu.h | 3 ++- 6 files changed, 25 insertions(+), 20 deletions(-) (limited to 'include') diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c index cef8cba8329b..7cb77c20fc5d 100644 --- a/arch/powerpc/kernel/iommu.c +++ b/arch/powerpc/kernel/iommu.c @@ -418,10 +418,11 @@ void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist, * Build a iommu_table structure. This contains a bit map which * is used to manage allocation of the tce space. */ -struct iommu_table *iommu_init_table(struct iommu_table *tbl) +struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid) { unsigned long sz; static int welcomed = 0; + struct page *page; /* Set aside 1/4 of the table for large allocations. */ tbl->it_halfpoint = tbl->it_size * 3 / 4; @@ -429,10 +430,10 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl) /* number of bytes needed for the bitmap */ sz = (tbl->it_size + 7) >> 3; - tbl->it_map = (unsigned long *)__get_free_pages(GFP_ATOMIC, get_order(sz)); - if (!tbl->it_map) + page = alloc_pages_node(nid, GFP_ATOMIC, get_order(sz)); + if (!page) panic("iommu_init_table: Can't allocate %ld bytes\n", sz); - + tbl->it_map = page_address(page); memset(tbl->it_map, 0, sz); tbl->it_hint = 0; diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index e746686d48b8..cdf5867838a6 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c @@ -60,9 +60,9 @@ static void __init iommu_vio_init(void) vio_iommu_table = veth_iommu_table; vio_iommu_table.it_offset += veth_iommu_table.it_size; - if (!iommu_init_table(&veth_iommu_table)) + if (!iommu_init_table(&veth_iommu_table, -1)) printk("Virtual Bus VETH TCE table failed.\n"); - if (!iommu_init_table(&vio_iommu_table)) + if (!iommu_init_table(&vio_iommu_table, -1)) printk("Virtual Bus VIO TCE table failed.\n"); } #endif @@ -98,7 +98,7 @@ static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev) tbl->it_busno = 0; tbl->it_type = TCE_VB; - return iommu_init_table(tbl); + return iommu_init_table(tbl, -1); } } diff --git a/arch/powerpc/platforms/iseries/iommu.c b/arch/powerpc/platforms/iseries/iommu.c index a992f6af249f..e3bd2015f2c9 100644 --- a/arch/powerpc/platforms/iseries/iommu.c +++ b/arch/powerpc/platforms/iseries/iommu.c @@ -173,7 +173,7 @@ void iommu_devnode_init_iSeries(struct device_node *dn) /* Look for existing tce table */ pdn->iommu_table = iommu_table_find(tbl); if (pdn->iommu_table == NULL) - pdn->iommu_table = iommu_init_table(tbl); + pdn->iommu_table = iommu_init_table(tbl, -1); else kfree(tbl); } diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index 44a507e6fb34..2f66dc6503ff 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -368,10 +368,11 @@ static void iommu_bus_setup_pSeries(struct pci_bus *bus) pci->phb->dma_window_size = 0x8000000ul; pci->phb->dma_window_base_cur = 0x8000000ul; - tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL); + tbl = kmalloc_node(sizeof(struct iommu_table), GFP_KERNEL, + pci->phb->node); iommu_table_setparms(pci->phb, dn, tbl); - pci->iommu_table = iommu_init_table(tbl); + pci->iommu_table = iommu_init_table(tbl, pci->phb->node); /* Divide the rest (1.75GB) among the children */ pci->phb->dma_window_size = 0x80000000ul; @@ -414,12 +415,12 @@ static void iommu_bus_setup_pSeriesLP(struct pci_bus *bus) ppci->bussubno = bus->number; - tbl = (struct iommu_table *)kmalloc(sizeof(struct iommu_table), - GFP_KERNEL); + tbl = kmalloc_node(sizeof(struct iommu_table), GFP_KERNEL, + ppci->phb->node); iommu_table_setparms_lpar(ppci->phb, pdn, tbl, dma_window); - ppci->iommu_table = iommu_init_table(tbl); + ppci->iommu_table = iommu_init_table(tbl, ppci->phb->node); } if (pdn != dn) @@ -442,9 +443,11 @@ static void iommu_dev_setup_pSeries(struct pci_dev *dev) */ if (!dev->bus->self) { DBG(" --> first child, no bridge. Allocating iommu table.\n"); - tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL); + tbl = kmalloc_node(sizeof(struct iommu_table), GFP_KERNEL, + PCI_DN(dn)->phb->node); iommu_table_setparms(PCI_DN(dn)->phb, dn, tbl); - PCI_DN(mydn)->iommu_table = iommu_init_table(tbl); + PCI_DN(dn)->iommu_table = iommu_init_table(tbl, + PCI_DN(dn)->phb->node); return; } @@ -526,12 +529,12 @@ static void iommu_dev_setup_pSeriesLP(struct pci_dev *dev) /* iommu_table_setparms_lpar needs bussubno. */ pci->bussubno = pci->phb->bus->number; - tbl = (struct iommu_table *)kmalloc(sizeof(struct iommu_table), - GFP_KERNEL); + tbl = kmalloc_node(sizeof(struct iommu_table), GFP_KERNEL, + pci->phb->node); iommu_table_setparms_lpar(pci->phb, pdn, tbl, dma_window); - pci->iommu_table = iommu_init_table(tbl); + pci->iommu_table = iommu_init_table(tbl, pci->phb->node); } if (pdn != dn) diff --git a/arch/powerpc/sysdev/dart_iommu.c b/arch/powerpc/sysdev/dart_iommu.c index 38087bd6e3cf..6232091cc72b 100644 --- a/arch/powerpc/sysdev/dart_iommu.c +++ b/arch/powerpc/sysdev/dart_iommu.c @@ -246,7 +246,7 @@ static void iommu_table_dart_setup(void) iommu_table_dart.it_base = (unsigned long)dart_vbase; iommu_table_dart.it_index = 0; iommu_table_dart.it_blocksize = 1; - iommu_init_table(&iommu_table_dart); + iommu_init_table(&iommu_table_dart, -1); /* Reserve the last page of the DART to avoid possible prefetch * past the DART mapped area diff --git a/include/asm-powerpc/iommu.h b/include/asm-powerpc/iommu.h index 9065f6c972a4..32dac0ac683a 100644 --- a/include/asm-powerpc/iommu.h +++ b/include/asm-powerpc/iommu.h @@ -67,7 +67,8 @@ extern void iommu_free_table(struct device_node *dn); /* Initializes an iommu_table based in values set in the passed-in * structure */ -extern struct iommu_table *iommu_init_table(struct iommu_table * tbl); +extern struct iommu_table *iommu_init_table(struct iommu_table * tbl, + int nid); extern int iommu_map_sg(struct device *dev, struct iommu_table *tbl, struct scatterlist *sglist, int nelems, unsigned long mask, -- cgit v1.2.3 From 9e6e3c2c796f1e0ef335804d5c87073e365dea50 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sat, 10 Jun 2006 23:14:51 +1000 Subject: [POWERPC] Fix HV bit handling on non partitioned machines On non partitioned machines we currently set the HV bit in kernel space only. It turns out we are supposed to maintain the HV bit in both user and kernel space. Signed-off-by: Anton Blanchard Signed-off-by: Paul Mackerras --- include/asm-powerpc/reg.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/asm-powerpc/reg.h b/include/asm-powerpc/reg.h index bfc7dc14ffcc..f2ed7577aa35 100644 --- a/include/asm-powerpc/reg.h +++ b/include/asm-powerpc/reg.h @@ -93,8 +93,8 @@ #define MSR_LE __MASK(MSR_LE_LG) /* Little Endian */ #ifdef CONFIG_PPC64 -#define MSR_ MSR_ME | MSR_RI | MSR_IR | MSR_DR | MSR_ISF -#define MSR_KERNEL MSR_ | MSR_SF | MSR_HV +#define MSR_ MSR_ME | MSR_RI | MSR_IR | MSR_DR | MSR_ISF |MSR_HV +#define MSR_KERNEL MSR_ | MSR_SF #define MSR_USER32 MSR_ | MSR_PR | MSR_EE #define MSR_USER64 MSR_USER32 | MSR_SF -- cgit v1.2.3 From 368a6ba5d188552aea2a668301a259164c9f355e Mon Sep 17 00:00:00 2001 From: Dave C Boutcher Date: Mon, 12 Jun 2006 19:49:20 -0500 Subject: [POWERPC] check firmware state before suspending Currently the kernel blindly halts all the processors and calls the ibm,suspend-me rtas call. If the firmware is not in the correct state, we then re-start all the processors and return. It is much smarter to first check the firmware state, and only if it is waiting, call the ibm,suspend-me call. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/rtas.c | 22 ++++++++++++++++++++++ include/asm-powerpc/hvcall.h | 10 ++++++++++ include/asm-powerpc/rtas.h | 1 + 3 files changed, 33 insertions(+) (limited to 'include') diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c index 13496f319855..fd15e3e3bb33 100644 --- a/arch/powerpc/kernel/rtas.c +++ b/arch/powerpc/kernel/rtas.c @@ -593,9 +593,31 @@ out: static int rtas_ibm_suspend_me(struct rtas_args *args) { int i; + long state; + long rc; + unsigned long dummy; struct rtas_suspend_me_data data; + /* Make sure the state is valid */ + rc = plpar_hcall(H_VASI_STATE, + ((u64)args->args[0] << 32) | args->args[1], + 0, 0, 0, + &state, &dummy, &dummy); + + if (rc) { + printk(KERN_ERR "rtas_ibm_suspend_me: vasi_state returned %ld\n",rc); + return rc; + } else if (state == H_VASI_ENABLED) { + args->args[args->nargs] = RTAS_NOT_SUSPENDABLE; + return 0; + } else if (state != H_VASI_SUSPENDING) { + printk(KERN_ERR "rtas_ibm_suspend_me: vasi_state returned state %ld\n", + state); + args->args[args->nargs] = -1; + return 0; + } + data.waiting = 1; data.args = args; diff --git a/include/asm-powerpc/hvcall.h b/include/asm-powerpc/hvcall.h index 6cc7e1fb7bfd..0d3c4e85711a 100644 --- a/include/asm-powerpc/hvcall.h +++ b/include/asm-powerpc/hvcall.h @@ -102,6 +102,15 @@ #define H_PP1 (1UL<<(63-62)) #define H_PP2 (1UL<<(63-63)) +/* VASI States */ +#define H_VASI_INVALID 0 +#define H_VASI_ENABLED 1 +#define H_VASI_ABORTED 2 +#define H_VASI_SUSPENDING 3 +#define H_VASI_SUSPENDED 4 +#define H_VASI_RESUMED 5 +#define H_VASI_COMPLETED 6 + /* DABRX flags */ #define H_DABRX_HYPERVISOR (1UL<<(63-61)) #define H_DABRX_KERNEL (1UL<<(63-62)) @@ -190,6 +199,7 @@ #define H_QUERY_INT_STATE 0x1E4 #define H_POLL_PENDING 0x1D8 #define H_JOIN 0x298 +#define H_VASI_STATE 0x2A4 #define H_ENABLE_CRQ 0x2B0 #ifndef __ASSEMBLY__ diff --git a/include/asm-powerpc/rtas.h b/include/asm-powerpc/rtas.h index a3b4e55569c7..02e213e3d69f 100644 --- a/include/asm-powerpc/rtas.h +++ b/include/asm-powerpc/rtas.h @@ -24,6 +24,7 @@ #define RTAS_RMOBUF_MAX (64 * 1024) /* RTAS return status codes */ +#define RTAS_NOT_SUSPENDABLE -9004 #define RTAS_BUSY -2 /* RTAS Busy */ #define RTAS_EXTENDED_DELAY_MIN 9900 #define RTAS_EXTENDED_DELAY_MAX 9905 -- cgit v1.2.3 From 74f4903363579d3336c294ebb11f02c8f35845ca Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 30 May 2006 11:55:42 -0500 Subject: [PATCH] wireless: Changes to ieee80211.h for user space regulatory daemon Attached are two small patches for include/net/ieee80211.h to prepare for later submission of code to implement a user-space daemon that supplies 802.11 regulatory information. The first change adds a bit indicating that 802.11h rules are to be applied to a channel. As discussed earlier in this list, a single bit is unlikely to be sufficient; however, at this time I have been unable to find any regulations implementing differences between 802.11a and 802.11h other than DFS, radar detection and passive scanning. A single bit is thus sufficient to convey to the driver that these rules should be obeyed. The second change adds comments to the freq and max_power fields of struct ieee80211_channel to indicate the units that are used. Signed-Off-By: Larry Finger Signed-off-by: John W. Linville --- include/net/ieee80211.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index d5147770ad47..ecc42864b001 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h @@ -968,6 +968,7 @@ enum ieee80211_state { enum { IEEE80211_CH_PASSIVE_ONLY = (1 << 0), + IEEE80211_CH_80211H_RULES = (1 << 1), IEEE80211_CH_B_ONLY = (1 << 2), IEEE80211_CH_NO_IBSS = (1 << 3), IEEE80211_CH_UNIFORM_SPREADING = (1 << 4), @@ -976,10 +977,10 @@ enum { }; struct ieee80211_channel { - u32 freq; + u32 freq; /* in MHz */ u8 channel; u8 flags; - u8 max_power; + u8 max_power; /* in dBm */ }; struct ieee80211_geo { -- cgit v1.2.3 From ab76fb13d73488ded53c87b77b1b5e38df2acf74 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Mon, 19 Jun 2006 13:24:32 +0100 Subject: [ARM] 3566/1: netX: register definitions Patch from Sascha Hauer This patch adds the register definitions for Hilscher's netX network processors. Signed-off-by: Robert Schwebel Signed-off-by: Sascha Hauer Signed-off-by: Russell King --- include/asm-arm/arch-netx/netx-regs.h | 410 ++++++++++++++++++++++++++++++++++ 1 file changed, 410 insertions(+) create mode 100644 include/asm-arm/arch-netx/netx-regs.h (limited to 'include') diff --git a/include/asm-arm/arch-netx/netx-regs.h b/include/asm-arm/arch-netx/netx-regs.h new file mode 100644 index 000000000000..8ab45bea83ca --- /dev/null +++ b/include/asm-arm/arch-netx/netx-regs.h @@ -0,0 +1,410 @@ +/* + * include/asm-arm/arch-netx/netx-regs.h + * + * Copyright (c) 2005 Sascha Hauer , Pengutronix + * + * 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 published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __ASM_ARCH_NETX_REGS_H +#define __ASM_ARCH_NETX_REGS_H + +/* offsets relative to the beginning of the io space */ +#define NETX_OFS_SYSTEM 0x00000 +#define NETX_OFS_MEMCR 0x00100 +#define NETX_OFS_DPMAS 0x03000 +#define NETX_OFS_GPIO 0x00800 +#define NETX_OFS_PIO 0x00900 +#define NETX_OFS_UART0 0x00a00 +#define NETX_OFS_UART1 0x00a40 +#define NETX_OFS_UART2 0x00a80 +#define NETX_OF_MIIMU 0x00b00 +#define NETX_OFS_SPI 0x00c00 +#define NETX_OFS_I2C 0x00d00 +#define NETX_OFS_SYSTIME 0x01100 +#define NETX_OFS_RTC 0x01200 +#define NETX_OFS_EXTBUS 0x03600 +#define NETX_OFS_LCD 0x04000 +#define NETX_OFS_USB 0x20000 +#define NETX_OFS_XMAC0 0x60000 +#define NETX_OFS_XMAC1 0x61000 +#define NETX_OFS_XMAC2 0x62000 +#define NETX_OFS_XMAC3 0x63000 +#define NETX_OFS_XMAC(no) (0x60000 + (no) * 0x1000) +#define NETX_OFS_PFIFO 0x64000 +#define NETX_OFS_XPEC0 0x70000 +#define NETX_OFS_XPEC1 0x74000 +#define NETX_OFS_XPEC2 0x78000 +#define NETX_OFS_XPEC3 0x7c000 +#define NETX_OFS_XPEC(no) (0x70000 + (no) * 0x4000) +#define NETX_OFS_VIC 0xff000 + +/* physical addresses */ +#define NETX_PA_SYSTEM (NETX_IO_PHYS + NETX_OFS_SYSTEM) +#define NETX_PA_MEMCR (NETX_IO_PHYS + NETX_OFS_MEMCR) +#define NETX_PA_DPMAS (NETX_IO_PHYS + NETX_OFS_DPMAS) +#define NETX_PA_GPIO (NETX_IO_PHYS + NETX_OFS_GPIO) +#define NETX_PA_PIO (NETX_IO_PHYS + NETX_OFS_PIO) +#define NETX_PA_UART0 (NETX_IO_PHYS + NETX_OFS_UART0) +#define NETX_PA_UART1 (NETX_IO_PHYS + NETX_OFS_UART1) +#define NETX_PA_UART2 (NETX_IO_PHYS + NETX_OFS_UART2) +#define NETX_PA_MIIMU (NETX_IO_PHYS + NETX_OF_MIIMU) +#define NETX_PA_SPI (NETX_IO_PHYS + NETX_OFS_SPI) +#define NETX_PA_I2C (NETX_IO_PHYS + NETX_OFS_I2C) +#define NETX_PA_SYSTIME (NETX_IO_PHYS + NETX_OFS_SYSTIME) +#define NETX_PA_RTC (NETX_IO_PHYS + NETX_OFS_RTC) +#define NETX_PA_EXTBUS (NETX_IO_PHYS + NETX_OFS_EXTBUS) +#define NETX_PA_LCD (NETX_IO_PHYS + NETX_OFS_LCD) +#define NETX_PA_USB (NETX_IO_PHYS + NETX_OFS_USB) +#define NETX_PA_XMAC0 (NETX_IO_PHYS + NETX_OFS_XMAC0) +#define NETX_PA_XMAC1 (NETX_IO_PHYS + NETX_OFS_XMAC1) +#define NETX_PA_XMAC2 (NETX_IO_PHYS + NETX_OFS_XMAC2) +#define NETX_PA_XMAC3 (NETX_IO_PHYS + NETX_OFS_XMAC3) +#define NETX_PA_XMAC(no) (NETX_IO_PHYS + NETX_OFS_XMAC(no)) +#define NETX_PA_PFIFO (NETX_IO_PHYS + NETX_OFS_PFIFO) +#define NETX_PA_XPEC0 (NETX_IO_PHYS + NETX_OFS_XPEC0) +#define NETX_PA_XPEC1 (NETX_IO_PHYS + NETX_OFS_XPEC1) +#define NETX_PA_XPEC2 (NETX_IO_PHYS + NETX_OFS_XPEC2) +#define NETX_PA_XPEC3 (NETX_IO_PHYS + NETX_OFS_XPEC3) +#define NETX_PA_XPEC(no) (NETX_IO_PHYS + NETX_OFS_XPEC(no)) +#define NETX_PA_VIC (NETX_IO_PHYS + NETX_OFS_VIC) + +/* virual addresses */ +#define NETX_VA_SYSTEM (NETX_IO_VIRT + NETX_OFS_SYSTEM) +#define NETX_VA_MEMCR (NETX_IO_VIRT + NETX_OFS_MEMCR) +#define NETX_VA_DPMAS (NETX_IO_VIRT + NETX_OFS_DPMAS) +#define NETX_VA_GPIO (NETX_IO_VIRT + NETX_OFS_GPIO) +#define NETX_VA_PIO (NETX_IO_VIRT + NETX_OFS_PIO) +#define NETX_VA_UART0 (NETX_IO_VIRT + NETX_OFS_UART0) +#define NETX_VA_UART1 (NETX_IO_VIRT + NETX_OFS_UART1) +#define NETX_VA_UART2 (NETX_IO_VIRT + NETX_OFS_UART2) +#define NETX_VA_MIIMU (NETX_IO_VIRT + NETX_OF_MIIMU) +#define NETX_VA_SPI (NETX_IO_VIRT + NETX_OFS_SPI) +#define NETX_VA_I2C (NETX_IO_VIRT + NETX_OFS_I2C) +#define NETX_VA_SYSTIME (NETX_IO_VIRT + NETX_OFS_SYSTIME) +#define NETX_VA_RTC (NETX_IO_VIRT + NETX_OFS_RTC) +#define NETX_VA_EXTBUS (NETX_IO_VIRT + NETX_OFS_EXTBUS) +#define NETX_VA_LCD (NETX_IO_VIRT + NETX_OFS_LCD) +#define NETX_VA_USB (NETX_IO_VIRT + NETX_OFS_USB) +#define NETX_VA_XMAC0 (NETX_IO_VIRT + NETX_OFS_XMAC0) +#define NETX_VA_XMAC1 (NETX_IO_VIRT + NETX_OFS_XMAC1) +#define NETX_VA_XMAC2 (NETX_IO_VIRT + NETX_OFS_XMAC2) +#define NETX_VA_XMAC3 (NETX_IO_VIRT + NETX_OFS_XMAC3) +#define NETX_VA_XMAC(no) (NETX_IO_VIRT + NETX_OFS_XMAC(no)) +#define NETX_VA_PFIFO (NETX_IO_VIRT + NETX_OFS_PFIFO) +#define NETX_VA_XPEC0 (NETX_IO_VIRT + NETX_OFS_XPEC0) +#define NETX_VA_XPEC1 (NETX_IO_VIRT + NETX_OFS_XPEC1) +#define NETX_VA_XPEC2 (NETX_IO_VIRT + NETX_OFS_XPEC2) +#define NETX_VA_XPEC3 (NETX_IO_VIRT + NETX_OFS_XPEC3) +#define NETX_VA_XPEC(no) (NETX_IO_VIRT + NETX_OFS_XPEC(no)) +#define NETX_VA_VIC (NETX_IO_VIRT + NETX_OFS_VIC) + +/********************************* + * System functions * + *********************************/ + +/* Registers */ +#define NETX_SYSTEM_REG(ofs) __io(NETX_VA_SYSTEM + (ofs)) +#define NETX_SYSTEM_BOO_SR NETX_SYSTEM_REG(0x00) +#define NETX_SYSTEM_IOC_CR NETX_SYSTEM_REG(0x04) +#define NETX_SYSTEM_IOC_MR NETX_SYSTEM_REG(0x08) + +/* FIXME: Docs are not consistent */ +#define NETX_SYSTEM_RES_CR NETX_SYSTEM_REG(0x08) +/* #define NETX_SYSTEM_RES_CR NETX_SYSTEM_REG(0x0c) */ + +#define NETX_SYSTEM_PHY_CONTROL NETX_SYSTEM_REG(0x10) +#define NETX_SYSTEM_REV NETX_SYSTEM_REG(0x34) +#define NETX_SYSTEM_IOC_ACCESS_KEY NETX_SYSTEM_REG(0x70) +#define NETX_SYSTEM_WDG_TR NETX_SYSTEM_REG(0x200) +#define NETX_SYSTEM_WDG_CTR NETX_SYSTEM_REG(0x204) +#define NETX_SYSTEM_WDG_IRQ_TIMEOUT NETX_SYSTEM_REG(0x208) +#define NETX_SYSTEM_WDG_RES_TIMEOUT NETX_SYSTEM_REG(0x20c) + +/* Bits */ +#define NETX_SYSTEM_RES_CR_RSTIN (1<<0) +#define NETX_SYSTEM_RES_CR_WDG_RES (1<<1) +#define NETX_SYSTEM_RES_CR_HOST_RES (1<<2) +#define NETX_SYSTEM_RES_CR_FIRMW_RES (1<<3) +#define NETX_SYSTEM_RES_CR_XPEC0_RES (1<<4) +#define NETX_SYSTEM_RES_CR_XPEC1_RES (1<<5) +#define NETX_SYSTEM_RES_CR_XPEC2_RES (1<<6) +#define NETX_SYSTEM_RES_CR_XPEC3_RES (1<<7) +#define NETX_SYSTEM_RES_CR_DIS_XPEC0_RES (1<<16) +#define NETX_SYSTEM_RES_CR_DIS_XPEC1_RES (1<<17) +#define NETX_SYSTEM_RES_CR_DIS_XPEC2_RES (1<<18) +#define NETX_SYSTEM_RES_CR_DIS_XPEC3_RES (1<<19) +#define NETX_SYSTEM_RES_CR_FIRMW_FLG0 (1<<20) +#define NETX_SYSTEM_RES_CR_FIRMW_FLG1 (1<<21) +#define NETX_SYSTEM_RES_CR_FIRMW_FLG2 (1<<22) +#define NETX_SYSTEM_RES_CR_FIRMW_FLG3 (1<<23) +#define NETX_SYSTEM_RES_CR_FIRMW_RES_EN (1<<24) +#define NETX_SYSTEM_RES_CR_RSTOUT (1<<25) +#define NETX_SYSTEM_RES_CR_EN_RSTOUT (1<<26) + +#define PHY_CONTROL_RESET (1<<31) +#define PHY_CONTROL_SIM_BYP (1<<30) +#define PHY_CONTROL_CLK_XLATIN (1<<29) +#define PHY_CONTROL_PHY1_EN (1<<21) +#define PHY_CONTROL_PHY1_NP_MSG_CODE +#define PHY_CONTROL_PHY1_AUTOMDIX (1<<17) +#define PHY_CONTROL_PHY1_FIXMODE (1<<16) +#define PHY_CONTROL_PHY1_MODE(mode) (((mode) & 0x7) << 13) +#define PHY_CONTROL_PHY0_EN (1<<12) +#define PHY_CONTROL_PHY0_NP_MSG_CODE +#define PHY_CONTROL_PHY0_AUTOMDIX (1<<8) +#define PHY_CONTROL_PHY0_FIXMODE (1<<7) +#define PHY_CONTROL_PHY0_MODE(mode) (((mode) & 0x7) << 4) +#define PHY_CONTROL_PHY_ADDRESS(adr) ((adr) & 0xf) + +#define PHY_MODE_10BASE_T_HALF 0 +#define PHY_MODE_10BASE_T_FULL 1 +#define PHY_MODE_100BASE_TX_FX_FULL 2 +#define PHY_MODE_100BASE_TX_FX_HALF 3 +#define PHY_MODE_100BASE_TX_HALF 4 +#define PHY_MODE_REPEATER 5 +#define PHY_MODE_POWER_DOWN 6 +#define PHY_MODE_ALL 7 + +/* Bits */ +#define VECT_CNTL_ENABLE (1 << 5) + +/******************************* + * GPIO and timer module * + *******************************/ + +/* Registers */ +#define NETX_GPIO_REG(ofs) __io(NETX_VA_GPIO + (ofs)) +#define NETX_GPIO_CFG(gpio) NETX_GPIO_REG(0x0 + ((gpio)<<2)) +#define NETX_GPIO_THRESHOLD_CAPTURE(gpio) NETX_GPIO_REG(0x40 + ((gpio)<<2)) +#define NETX_GPIO_COUNTER_CTRL(counter) NETX_GPIO_REG(0x80 + ((counter)<<2)) +#define NETX_GPIO_COUNTER_MAX(counter) NETX_GPIO_REG(0x94 + ((counter)<<2)) +#define NETX_GPIO_COUNTER_CURRENT(counter) NETX_GPIO_REG(0xa8 + ((counter)<<2)) +#define NETX_GPIO_IRQ_ENABLE NETX_GPIO_REG(0xbc) +#define NETX_GPIO_IRQ_DISABLE NETX_GPIO_REG(0xc0) +#define NETX_GPIO_SYSTIME_NS_CMP NETX_GPIO_REG(0xc4) +#define NETX_GPIO_LINE NETX_GPIO_REG(0xc8) +#define NETX_GPIO_IRQ NETX_GPIO_REG(0xd0) + +/* Bits */ +#define NETX_GPIO_CFG_IOCFG_GP_INPUT (0x0) +#define NETX_GPIO_CFG_IOCFG_GP_OUTPUT (0x1) +#define NETX_GPIO_CFG_IOCFG_GP_UART (0x2) +#define NETX_GPIO_CFG_INV (1<<2) +#define NETX_GPIO_CFG_MODE_INPUT_READ (0<<3) +#define NETX_GPIO_CFG_MODE_INPUT_CAPTURE_CONT_RISING (1<<3) +#define NETX_GPIO_CFG_MODE_INPUT_CAPTURE_ONCE_RISING (2<<3) +#define NETX_GPIO_CFG_MODE_INPUT_CAPTURE_HIGH_LEVEL (3<<3) +#define NETX_GPIO_CFG_COUNT_REF_COUNTER0 (0<<5) +#define NETX_GPIO_CFG_COUNT_REF_COUNTER1 (1<<5) +#define NETX_GPIO_CFG_COUNT_REF_COUNTER2 (2<<5) +#define NETX_GPIO_CFG_COUNT_REF_COUNTER3 (3<<5) +#define NETX_GPIO_CFG_COUNT_REF_COUNTER4 (4<<5) +#define NETX_GPIO_CFG_COUNT_REF_SYSTIME (7<<5) + +#define NETX_GPIO_COUNTER_CTRL_RUN (1<<0) +#define NETX_GPIO_COUNTER_CTRL_SYM (1<<1) +#define NETX_GPIO_COUNTER_CTRL_ONCE (1<<2) +#define NETX_GPIO_COUNTER_CTRL_IRQ_EN (1<<3) +#define NETX_GPIO_COUNTER_CTRL_CNT_EVENT (1<<4) +#define NETX_GPIO_COUNTER_CTRL_RST_EN (1<<5) +#define NETX_GPIO_COUNTER_CTRL_SEL_EVENT (1<<6) +#define NETX_GPIO_COUNTER_CTRL_GPIO_REF /* FIXME */ + +#define GPIO_BIT(gpio) (1<<(gpio)) +#define COUNTER_BIT(counter) ((1<<16)<<(counter)) + +/******************************* + * PIO * + *******************************/ + +/* Registers */ +#define NETX_PIO_REG(ofs) __io(NETX_VA_PIO + (ofs)) +#define NETX_PIO_INPIO NETX_PIO_REG(0x0) +#define NETX_PIO_OUTPIO NETX_PIO_REG(0x4) +#define NETX_PIO_OEPIO NETX_PIO_REG(0x8) + +/******************************* + * MII Unit * + *******************************/ + +/* Registers */ +#define NETX_MIIMU __io(NETX_VA_MIIMU) + +/* Bits */ +#define MIIMU_SNRDY (1<<0) +#define MIIMU_PREAMBLE (1<<1) +#define MIIMU_OPMODE_WRITE (1<<2) +#define MIIMU_MDC_PERIOD (1<<3) +#define MIIMU_PHY_NRES (1<<4) +#define MIIMU_RTA (1<<5) +#define MIIMU_REGADDR(adr) (((adr) & 0x1f) << 6) +#define MIIMU_PHYADDR(adr) (((adr) & 0x1f) << 11) +#define MIIMU_DATA(data) (((data) & 0xffff) << 16) + +/******************************* + * xmac / xpec * + *******************************/ + +/* XPEC register offsets relative to NETX_VA_XPEC(no) */ +#define NETX_XPEC_R0_OFS 0x00 +#define NETX_XPEC_R1_OFS 0x04 +#define NETX_XPEC_R2_OFS 0x08 +#define NETX_XPEC_R3_OFS 0x0c +#define NETX_XPEC_R4_OFS 0x10 +#define NETX_XPEC_R5_OFS 0x14 +#define NETX_XPEC_R6_OFS 0x18 +#define NETX_XPEC_R7_OFS 0x1c +#define NETX_XPEC_RANGE01_OFS 0x20 +#define NETX_XPEC_RANGE23_OFS 0x24 +#define NETX_XPEC_RANGE45_OFS 0x28 +#define NETX_XPEC_RANGE67_OFS 0x2c +#define NETX_XPEC_PC_OFS 0x48 +#define NETX_XPEC_TIMER_OFS(timer) (0x30 + ((timer)<<2)) +#define NETX_XPEC_IRQ_OFS 0x8c +#define NETX_XPEC_SYSTIME_NS_OFS 0x90 +#define NETX_XPEC_FIFO_DATA_OFS 0x94 +#define NETX_XPEC_SYSTIME_S_OFS 0x98 +#define NETX_XPEC_ADC_OFS 0x9c +#define NETX_XPEC_URX_COUNT_OFS 0x40 +#define NETX_XPEC_UTX_COUNT_OFS 0x44 +#define NETX_XPEC_PC_OFS 0x48 +#define NETX_XPEC_ZERO_OFS 0x4c +#define NETX_XPEC_STATCFG_OFS 0x50 +#define NETX_XPEC_EC_MASKA_OFS 0x54 +#define NETX_XPEC_EC_MASKB_OFS 0x58 +#define NETX_XPEC_EC_MASK0_OFS 0x5c +#define NETX_XPEC_EC_MASK8_OFS 0x7c +#define NETX_XPEC_EC_MASK9_OFS 0x80 +#define NETX_XPEC_XPU_HOLD_PC_OFS 0x100 +#define NETX_XPEC_RAM_START_OFS 0x2000 + +/* Bits */ +#define XPU_HOLD_PC (1<<0) + +/* XMAC register offsets relative to NETX_VA_XMAC(no) */ +#define NETX_XMAC_RPU_PROGRAM_START_OFS 0x000 +#define NETX_XMAC_RPU_PROGRAM_END_OFS 0x3ff +#define NETX_XMAC_TPU_PROGRAM_START_OFS 0x400 +#define NETX_XMAC_TPU_PROGRAM_END_OFS 0x7ff +#define NETX_XMAC_RPU_HOLD_PC_OFS 0xa00 +#define NETX_XMAC_TPU_HOLD_PC_OFS 0xa04 +#define NETX_XMAC_STATUS_SHARED0_OFS 0x840 +#define NETX_XMAC_CONFIG_SHARED0_OFS 0x844 +#define NETX_XMAC_STATUS_SHARED1_OFS 0x848 +#define NETX_XMAC_CONFIG_SHARED1_OFS 0x84c +#define NETX_XMAC_STATUS_SHARED2_OFS 0x850 +#define NETX_XMAC_CONFIG_SHARED2_OFS 0x854 +#define NETX_XMAC_STATUS_SHARED3_OFS 0x858 +#define NETX_XMAC_CONFIG_SHARED3_OFS 0x85c + +#define RPU_HOLD_PC (1<<15) +#define TPU_HOLD_PC (1<<15) + +/******************************* + * Pointer FIFO * + *******************************/ + +/* Registers */ +#define NETX_PFIFO_REG(ofs) __io(NETX_VA_PFIFO + (ofs)) +#define NETX_PFIFO_BASE(pfifo) NETX_PFIFO_REG(0x00 + ((pfifo)<<2)) +#define NETX_PFIFO_BORDER_BASE(pfifo) NETX_PFIFO_REG(0x80 + ((pfifo)<<2)) +#define NETX_PFIFO_RESET NETX_PFIFO_REG(0x100) +#define NETX_PFIFO_FULL NETX_PFIFO_REG(0x104) +#define NETX_PFIFO_EMPTY NETX_PFIFO_REG(0x108) +#define NETX_PFIFO_OVEFLOW NETX_PFIFO_REG(0x10c) +#define NETX_PFIFO_UNDERRUN NETX_PFIFO_REG(0x110) +#define NETX_PFIFO_FILL_LEVEL(pfifo) NETX_PFIFO_REG(0x180 + ((pfifo)<<2)) +#define NETX_PFIFO_XPEC_ISR(xpec) NETX_PFIFO_REG(0x400 + ((xpec) << 2)) + +/******************************* + * Dual Port Memory * + *******************************/ + +/* Registers */ +#define NETX_DPMAS_REG(ofs) __io(NETX_VA_DPMAS + (ofs)) +#define NETX_DPMAS_SYS_STAT NETX_DPMAS_REG(0x4d8) +#define NETX_DPMAS_INT_STAT NETX_DPMAS_REG(0x4e0) +#define NETX_DPMAS_INT_EN NETX_DPMAS_REG(0x4f0) +#define NETX_DPMAS_IF_CONF0 NETX_DPMAS_REG(0x608) +#define NETX_DPMAS_IF_CONF1 NETX_DPMAS_REG(0x60c) +#define NETX_DPMAS_EXT_CONFIG(cs) NETX_DPMAS_REG(0x610 + 4 * (cs)) +#define NETX_DPMAS_IO_MODE0 NETX_DPMAS_REG(0x620) /* I/O 32..63 */ +#define NETX_DPMAS_DRV_EN0 NETX_DPMAS_REG(0x624) +#define NETX_DPMAS_DATA0 NETX_DPMAS_REG(0x628) +#define NETX_DPMAS_IO_MODE1 NETX_DPMAS_REG(0x630) /* I/O 64..84 */ +#define NETX_DPMAS_DRV_EN1 NETX_DPMAS_REG(0x634) +#define NETX_DPMAS_DATA1 NETX_DPMAS_REG(0x638) + +/* Bits */ +#define NETX_DPMAS_INT_EN_GLB_EN (1<<31) +#define NETX_DPMAS_INT_EN_MEM_LCK (1<<30) +#define NETX_DPMAS_INT_EN_WDG (1<<29) +#define NETX_DPMAS_INT_EN_PIO72 (1<<28) +#define NETX_DPMAS_INT_EN_PIO47 (1<<27) +#define NETX_DPMAS_INT_EN_PIO40 (1<<26) +#define NETX_DPMAS_INT_EN_PIO36 (1<<25) +#define NETX_DPMAS_INT_EN_PIO35 (1<<24) + +#define NETX_DPMAS_IF_CONF0_HIF_DISABLED (0<<28) +#define NETX_DPMAS_IF_CONF0_HIF_EXT_BUS (1<<28) +#define NETX_DPMAS_IF_CONF0_HIF_UP_8BIT (2<<28) +#define NETX_DPMAS_IF_CONF0_HIF_UP_16BIT (3<<28) +#define NETX_DPMAS_IF_CONF0_HIF_IO (4<<28) +#define NETX_DPMAS_IF_CONF0_WAIT_DRV_PP (1<<14) +#define NETX_DPMAS_IF_CONF0_WAIT_DRV_OD (2<<14) +#define NETX_DPMAS_IF_CONF0_WAIT_DRV_TRI (3<<14) + +#define NETX_DPMAS_IF_CONF1_IRQ_POL_PIO35 (1<<26) +#define NETX_DPMAS_IF_CONF1_IRQ_POL_PIO36 (1<<27) +#define NETX_DPMAS_IF_CONF1_IRQ_POL_PIO40 (1<<28) +#define NETX_DPMAS_IF_CONF1_IRQ_POL_PIO47 (1<<29) +#define NETX_DPMAS_IF_CONF1_IRQ_POL_PIO72 (1<<30) + +#define NETX_EXT_CONFIG_TALEWIDTH(x) (((x) & 0x7) << 29) +#define NETX_EXT_CONFIG_TADRHOLD(x) (((x) & 0x7) << 26) +#define NETX_EXT_CONFIG_TCSON(x) (((x) & 0x7) << 23) +#define NETX_EXT_CONFIG_TRDON(x) (((x) & 0x7) << 20) +#define NETX_EXT_CONFIG_TWRON(x) (((x) & 0x7) << 17) +#define NETX_EXT_CONFIG_TWROFF(x) (((x) & 0x1f) << 12) +#define NETX_EXT_CONFIG_TRDWRCYC(x) (((x) & 0x1f) << 7) +#define NETX_EXT_CONFIG_WAIT_POL (1<<6) +#define NETX_EXT_CONFIG_WAIT_EN (1<<5) +#define NETX_EXT_CONFIG_NRD_MODE (1<<4) +#define NETX_EXT_CONFIG_DS_MODE (1<<3) +#define NETX_EXT_CONFIG_NWR_MODE (1<<2) +#define NETX_EXT_CONFIG_16BIT (1<<1) +#define NETX_EXT_CONFIG_CS_ENABLE (1<<0) + +#define NETX_DPMAS_IO_MODE0_WRL (1<<13) +#define NETX_DPMAS_IO_MODE0_WAIT (1<<14) +#define NETX_DPMAS_IO_MODE0_READY (1<<15) +#define NETX_DPMAS_IO_MODE0_CS0 (1<<19) +#define NETX_DPMAS_IO_MODE0_EXTRD (1<<20) + +#define NETX_DPMAS_IO_MODE1_CS2 (1<<15) +#define NETX_DPMAS_IO_MODE1_CS1 (1<<16) +#define NETX_DPMAS_IO_MODE1_SAMPLE_NPOR (0<<30) +#define NETX_DPMAS_IO_MODE1_SAMPLE_100MHZ (1<<30) +#define NETX_DPMAS_IO_MODE1_SAMPLE_NPIO36 (2<<30) +#define NETX_DPMAS_IO_MODE1_SAMPLE_PIO36 (3<<30) + +/******************************* + * I2C * + *******************************/ +#define NETX_I2C_REG(ofs) __io(NETX_VA_I2C, (ofs)) +#define NETX_I2C_CTRL NETX_I2C_REG(0x0) +#define NETX_I2C_DATA NETX_I2C_REG(0x4) + +#endif /* __ASM_ARCH_NETX_REGS_H */ -- cgit v1.2.3 From 10e8e1fb758eed5cfb0cae1b770f842624851e7b Mon Sep 17 00:00:00 2001 From: Andrew Victor Date: Mon, 19 Jun 2006 15:26:51 +0100 Subject: [ARM] 3581/1: AT91RM9200 Internal SRAM Patch from Andrew Victor This patch maps the AT91RM9200's internal SRAM into the virtual memory address space - just below the internal peripheral registers. Signed-off-by: Andrew Victor Signed-off-by: Russell King --- arch/arm/mach-at91rm9200/common.c | 6 ++++++ include/asm-arm/arch-at91rm9200/hardware.h | 5 ++++- include/asm-arm/arch-at91rm9200/vmalloc.h | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/arch/arm/mach-at91rm9200/common.c b/arch/arm/mach-at91rm9200/common.c index 3848fd2d5596..40d29a73b5c5 100644 --- a/arch/arm/mach-at91rm9200/common.c +++ b/arch/arm/mach-at91rm9200/common.c @@ -17,6 +17,7 @@ #include #include +#include "generic.h" static struct map_desc at91rm9200_io_desc[] __initdata = { { @@ -94,6 +95,11 @@ static struct map_desc at91rm9200_io_desc[] __initdata = { .pfn = __phys_to_pfn(AT91_BASE_TCB0), .length = SZ_16K, .type = MT_DEVICE, + }, { + .virtual = AT91_SRAM_VIRT_BASE, + .pfn = __phys_to_pfn(AT91_SRAM_BASE), + .length = AT91_SRAM_SIZE, + .type = MT_DEVICE, }, }; diff --git a/include/asm-arm/arch-at91rm9200/hardware.h b/include/asm-arm/arch-at91rm9200/hardware.h index 59e6f44d3a0d..87f40df57140 100644 --- a/include/asm-arm/arch-at91rm9200/hardware.h +++ b/include/asm-arm/arch-at91rm9200/hardware.h @@ -50,9 +50,12 @@ #define AT91_VA_BASE_TCB0 AT91_IO_P2V(AT91_BASE_TCB0) /* Internal SRAM */ -#define AT91_BASE_SRAM 0x00200000 /* Internal SRAM base address */ +#define AT91_SRAM_BASE 0x00200000 /* Internal SRAM base address */ #define AT91_SRAM_SIZE 0x00004000 /* Internal SRAM SIZE (16Kb) */ + /* Internal SRAM is mapped below the IO devices */ +#define AT91_SRAM_VIRT_BASE (AT91_IO_VIRT_BASE - AT91_SRAM_SIZE) + /* Serial ports */ #define AT91_NR_UART 5 /* 4 USART3's and one DBGU port */ diff --git a/include/asm-arm/arch-at91rm9200/vmalloc.h b/include/asm-arm/arch-at91rm9200/vmalloc.h index 34d9718feb90..4c367eb57f47 100644 --- a/include/asm-arm/arch-at91rm9200/vmalloc.h +++ b/include/asm-arm/arch-at91rm9200/vmalloc.h @@ -21,6 +21,6 @@ #ifndef __ASM_ARCH_VMALLOC_H #define __ASM_ARCH_VMALLOC_H -#define VMALLOC_END (AT91_IO_VIRT_BASE & PGDIR_MASK) +#define VMALLOC_END (AT91_SRAM_VIRT_BASE & PGDIR_MASK) #endif -- cgit v1.2.3 From bb6d8c8828123e01e2ae6c9d9c4870477889fd94 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Mon, 19 Jun 2006 15:27:53 +0100 Subject: [ARM] 3567/2: arm: base support for Hilscher netX Patch from Sascha Hauer This patch adds the base support for Hilscher's netX network processors. Signed-off-by: Robert Schwebel Signed-off-by: Sascha Hauer Signed-off-by: Russell King --- arch/arm/Kconfig | 8 ++ arch/arm/Makefile | 1 + arch/arm/mach-netx/Makefile | 11 ++ arch/arm/mach-netx/Makefile.boot | 2 + arch/arm/mach-netx/generic.c | 193 ++++++++++++++++++++++++++++++++ arch/arm/mach-netx/generic.h | 24 ++++ arch/arm/mach-netx/time.c | 88 +++++++++++++++ arch/arm/mm/Kconfig | 4 +- include/asm-arm/arch-netx/debug-macro.S | 38 +++++++ include/asm-arm/arch-netx/dma.h | 21 ++++ include/asm-arm/arch-netx/entry-macro.S | 35 ++++++ include/asm-arm/arch-netx/hardware.h | 39 +++++++ include/asm-arm/arch-netx/io.h | 29 +++++ include/asm-arm/arch-netx/irqs.h | 70 ++++++++++++ include/asm-arm/arch-netx/memory.h | 36 ++++++ include/asm-arm/arch-netx/param.h | 18 +++ include/asm-arm/arch-netx/system.h | 38 +++++++ include/asm-arm/arch-netx/timex.h | 20 ++++ include/asm-arm/arch-netx/uncompress.h | 76 +++++++++++++ include/asm-arm/arch-netx/vmalloc.h | 19 ++++ 20 files changed, 768 insertions(+), 2 deletions(-) create mode 100644 arch/arm/mach-netx/Makefile create mode 100644 arch/arm/mach-netx/Makefile.boot create mode 100644 arch/arm/mach-netx/generic.c create mode 100644 arch/arm/mach-netx/generic.h create mode 100644 arch/arm/mach-netx/time.c create mode 100644 include/asm-arm/arch-netx/debug-macro.S create mode 100644 include/asm-arm/arch-netx/dma.h create mode 100644 include/asm-arm/arch-netx/entry-macro.S create mode 100644 include/asm-arm/arch-netx/hardware.h create mode 100644 include/asm-arm/arch-netx/io.h create mode 100644 include/asm-arm/arch-netx/irqs.h create mode 100644 include/asm-arm/arch-netx/memory.h create mode 100644 include/asm-arm/arch-netx/param.h create mode 100644 include/asm-arm/arch-netx/system.h create mode 100644 include/asm-arm/arch-netx/timex.h create mode 100644 include/asm-arm/arch-netx/uncompress.h create mode 100644 include/asm-arm/arch-netx/vmalloc.h (limited to 'include') diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index f47cf9af3bc8..dfb97fe045d0 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -275,6 +275,12 @@ config ARCH_PNX4008 help This enables support for Philips PNX4008 mobile platform. +config ARCH_NETX + bool "Hilscher NetX based" + select ARM_VIC + help + This enables support for systems based on the Hilscher NetX Soc + endchoice source "arch/arm/mach-clps711x/Kconfig" @@ -319,6 +325,8 @@ source "arch/arm/mach-realview/Kconfig" source "arch/arm/mach-at91rm9200/Kconfig" +source "arch/arm/mach-netx/Kconfig" + # Definitions to make life easier config ARCH_ACORN bool diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 6c97aa70d3bc..282b14e2f464 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -117,6 +117,7 @@ endif machine-$(CONFIG_ARCH_AT91RM9200) := at91rm9200 machine-$(CONFIG_ARCH_EP93XX) := ep93xx machine-$(CONFIG_ARCH_PNX4008) := pnx4008 + machine-$(CONFIG_ARCH_NETX) := netx ifeq ($(CONFIG_ARCH_EBSA110),y) # This is what happens if you forget the IOCS16 line. diff --git a/arch/arm/mach-netx/Makefile b/arch/arm/mach-netx/Makefile new file mode 100644 index 000000000000..257d02ef66d8 --- /dev/null +++ b/arch/arm/mach-netx/Makefile @@ -0,0 +1,11 @@ +# +# Makefile for the linux kernel. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). + +# Object file lists. + +obj-y += time.o generic.o + diff --git a/arch/arm/mach-netx/Makefile.boot b/arch/arm/mach-netx/Makefile.boot new file mode 100644 index 000000000000..b81cf6aff0ac --- /dev/null +++ b/arch/arm/mach-netx/Makefile.boot @@ -0,0 +1,2 @@ + zreladdr-y := 0x80008000 + diff --git a/arch/arm/mach-netx/generic.c b/arch/arm/mach-netx/generic.c new file mode 100644 index 000000000000..af0b13534cfd --- /dev/null +++ b/arch/arm/mach-netx/generic.c @@ -0,0 +1,193 @@ +/* + * arch/arm/mach-netx/generic.c + * + * Copyright (C) 2005 Sascha Hauer , Pengutronix + * + * 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 published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct map_desc netx_io_desc[] __initdata = { + { + .virtual = NETX_IO_VIRT, + .pfn = __phys_to_pfn(NETX_IO_PHYS), + .length = NETX_IO_SIZE, + .type = MT_DEVICE + } +}; + +void __init netx_map_io(void) +{ + iotable_init(netx_io_desc, ARRAY_SIZE(netx_io_desc)); +} + +static struct resource netx_rtc_resources[] = { + [0] = { + .start = 0x00101200, + .end = 0x00101220, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device netx_rtc_device = { + .name = "netx-rtc", + .id = 0, + .num_resources = ARRAY_SIZE(netx_rtc_resources), + .resource = netx_rtc_resources, +}; + +static struct platform_device *devices[] __initdata = { + &netx_rtc_device, +}; + +#if 0 +#define DEBUG_IRQ(fmt...) printk(fmt) +#else +#define DEBUG_IRQ(fmt...) while (0) {} +#endif + +static void +netx_hif_demux_handler(unsigned int irq_unused, struct irqdesc *desc, + struct pt_regs *regs) +{ + unsigned int irq = NETX_IRQ_HIF_CHAINED(0); + unsigned int stat; + + stat = ((readl(NETX_DPMAS_INT_EN) & + readl(NETX_DPMAS_INT_STAT)) >> 24) & 0x1f; + + desc = irq_desc + NETX_IRQ_HIF_CHAINED(0); + + while (stat) { + if (stat & 1) { + DEBUG_IRQ("handling irq %d\n", irq); + desc_handle_irq(irq, desc, regs); + } + irq++; + desc++; + stat >>= 1; + } +} + +static int +netx_hif_irq_type(unsigned int _irq, unsigned int type) +{ + unsigned int val, irq; + + val = readl(NETX_DPMAS_IF_CONF1); + + irq = _irq - NETX_IRQ_HIF_CHAINED(0); + + if (type & __IRQT_RISEDGE) { + DEBUG_IRQ("rising edges\n"); + val |= (1 << 26) << irq; + } + if (type & __IRQT_FALEDGE) { + DEBUG_IRQ("falling edges\n"); + val &= ~((1 << 26) << irq); + } + if (type & __IRQT_LOWLVL) { + DEBUG_IRQ("low level\n"); + val &= ~((1 << 26) << irq); + } + if (type & __IRQT_HIGHLVL) { + DEBUG_IRQ("high level\n"); + val |= (1 << 26) << irq; + } + + writel(val, NETX_DPMAS_IF_CONF1); + + return 0; +} + +static void +netx_hif_ack_irq(unsigned int _irq) +{ + unsigned int val, irq; + + irq = _irq - NETX_IRQ_HIF_CHAINED(0); + writel((1 << 24) << irq, NETX_DPMAS_INT_STAT); + + val = readl(NETX_DPMAS_INT_EN); + val &= ~((1 << 24) << irq); + writel(val, NETX_DPMAS_INT_EN); + + DEBUG_IRQ("%s: irq %d\n", __FUNCTION__, _irq); +} + +static void +netx_hif_mask_irq(unsigned int _irq) +{ + unsigned int val, irq; + + irq = _irq - NETX_IRQ_HIF_CHAINED(0); + val = readl(NETX_DPMAS_INT_EN); + val &= ~((1 << 24) << irq); + writel(val, NETX_DPMAS_INT_EN); + DEBUG_IRQ("%s: irq %d\n", __FUNCTION__, _irq); +} + +static void +netx_hif_unmask_irq(unsigned int _irq) +{ + unsigned int val, irq; + + irq = _irq - NETX_IRQ_HIF_CHAINED(0); + val = readl(NETX_DPMAS_INT_EN); + val |= (1 << 24) << irq; + writel(val, NETX_DPMAS_INT_EN); + DEBUG_IRQ("%s: irq %d\n", __FUNCTION__, _irq); +} + +static struct irqchip netx_hif_chip = { + .ack = netx_hif_ack_irq, + .mask = netx_hif_mask_irq, + .unmask = netx_hif_unmask_irq, + .set_type = netx_hif_irq_type, +}; + +void __init netx_init_irq(void) +{ + int irq; + + vic_init(__io(io_p2v(NETX_PA_VIC)), 0, ~0); + + for (irq = NETX_IRQ_HIF_CHAINED(0); irq <= NETX_IRQ_HIF_LAST; irq++) { + set_irq_chip(irq, &netx_hif_chip); + set_irq_handler(irq, do_level_IRQ); + set_irq_flags(irq, IRQF_VALID); + } + + writel(NETX_DPMAS_INT_EN_GLB_EN, NETX_DPMAS_INT_EN); + set_irq_chained_handler(NETX_IRQ_HIF, netx_hif_demux_handler); +} + +static int __init netx_init(void) +{ + return platform_add_devices(devices, ARRAY_SIZE(devices)); +} + +subsys_initcall(netx_init); + diff --git a/arch/arm/mach-netx/generic.h b/arch/arm/mach-netx/generic.h new file mode 100644 index 000000000000..ede2d35341c3 --- /dev/null +++ b/arch/arm/mach-netx/generic.h @@ -0,0 +1,24 @@ +/* + * arch/arm/mach-netx/generic.h + * + * Copyright (c) 2005 Sascha Hauer , Pengutronix + * + * 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 published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +extern void __init netx_map_io(void); +extern void __init netx_init_irq(void); + +struct sys_timer; +extern struct sys_timer netx_timer; diff --git a/arch/arm/mach-netx/time.c b/arch/arm/mach-netx/time.c new file mode 100644 index 000000000000..edfbdf40c600 --- /dev/null +++ b/arch/arm/mach-netx/time.c @@ -0,0 +1,88 @@ +/* + * arch/arm/mach-netx/time.c + * + * Copyright (c) 2005 Sascha Hauer , Pengutronix + * + * 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 published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include + +#include +#include +#include +#include + +/* + * Returns number of us since last clock interrupt. Note that interrupts + * will have been disabled by do_gettimeoffset() + */ +static unsigned long netx_gettimeoffset(void) +{ + return readl(NETX_GPIO_COUNTER_CURRENT(0)) / 100; +} + +/* + * IRQ handler for the timer + */ +static irqreturn_t +netx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + write_seqlock(&xtime_lock); + + timer_tick(regs); + write_sequnlock(&xtime_lock); + + /* acknowledge interrupt */ + writel(COUNTER_BIT(0), NETX_GPIO_IRQ); + + return IRQ_HANDLED; +} + + +static struct irqaction netx_timer_irq = { + .name = "NetX Timer Tick", + .flags = SA_INTERRUPT | SA_TIMER, + .handler = netx_timer_interrupt, +}; + +/* + * Set up timer interrupt + */ +static void __init netx_timer_init(void) +{ + /* disable timer initially */ + writel(0, NETX_GPIO_COUNTER_CTRL(0)); + + /* Reset the timer value to zero */ + writel(0, NETX_GPIO_COUNTER_CURRENT(0)); + + writel(LATCH, NETX_GPIO_COUNTER_MAX(0)); + + /* acknowledge interrupt */ + writel(COUNTER_BIT(0), NETX_GPIO_IRQ); + + /* Enable the interrupt in the specific timer register and start timer */ + writel(COUNTER_BIT(0), NETX_GPIO_IRQ_ENABLE); + writel(NETX_GPIO_COUNTER_CTRL_IRQ_EN | NETX_GPIO_COUNTER_CTRL_RUN, + NETX_GPIO_COUNTER_CTRL(0)); + + setup_irq(NETX_IRQ_TIMER0, &netx_timer_irq); +} + +struct sys_timer netx_timer = { + .init = netx_timer_init, + .offset = netx_gettimeoffset, +}; diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index 1ff2f073a55d..4221d054a1e9 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -121,8 +121,8 @@ config CPU_ARM925T # ARM926T config CPU_ARM926T bool "Support ARM926T processor" - depends on ARCH_INTEGRATOR || ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || MACH_REALVIEW_EB || ARCH_PNX4008 - default y if ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || ARCH_PNX4008 + depends on ARCH_INTEGRATOR || ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || MACH_REALVIEW_EB || ARCH_PNX4008 || ARCH_NETX + default y if ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || ARCH_PNX4008 || ARCH_NETX select CPU_32v5 select CPU_ABRT_EV5TJ select CPU_CACHE_VIVT diff --git a/include/asm-arm/arch-netx/debug-macro.S b/include/asm-arm/arch-netx/debug-macro.S new file mode 100644 index 000000000000..a940d0e80cb2 --- /dev/null +++ b/include/asm-arm/arch-netx/debug-macro.S @@ -0,0 +1,38 @@ +/* linux/include/asm-arm/arch-netx/debug-macro.S + * + * Debugging macro include header + * + * Copyright (C) 1994-1999 Russell King + * Moved from linux/arch/arm/kernel/debug.S by Ben Dooks + * + * 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 + * published by the Free Software Foundation. + * +*/ + +#include "hardware.h" + + .macro addruart,rx + mrc p15, 0, \rx, c1, c0 + tst \rx, #1 @ MMU enabled? + moveq \rx, #0x00100000 @ physical + movne \rx, #io_p2v(0x00100000) @ virtual + orr \rx, \rx, #0x00000a00 + .endm + + .macro senduart,rd,rx + str \rd, [\rx, #0] + .endm + + .macro busyuart,rd,rx +1002: ldr \rd, [\rx, #0x18] + tst \rd, #(1 << 3) + bne 1002b + .endm + + .macro waituart,rd,rx +1001: ldr \rd, [\rx, #0x18] + tst \rd, #(1 << 3) + bne 1001b + .endm diff --git a/include/asm-arm/arch-netx/dma.h b/include/asm-arm/arch-netx/dma.h new file mode 100644 index 000000000000..4eda5feed81c --- /dev/null +++ b/include/asm-arm/arch-netx/dma.h @@ -0,0 +1,21 @@ +/* + * linux/include/asm-arm/arch-netx/dma.h + * + * Copyright (C) 2005 Sascha Hauer , Pengutronix + * + * 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 published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define MAX_DMA_CHANNELS 0 +#define MAX_DMA_ADDRESS ~0 diff --git a/include/asm-arm/arch-netx/entry-macro.S b/include/asm-arm/arch-netx/entry-macro.S new file mode 100644 index 000000000000..658df4d60ff3 --- /dev/null +++ b/include/asm-arm/arch-netx/entry-macro.S @@ -0,0 +1,35 @@ +/* + * include/asm-arm/arch-netx/entry-macro.S + * + * Low-level IRQ helper macros for Hilscher netX based platforms + * + * Copyright (C) 2005 Sascha Hauer , Pengutronix + * + * 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 published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include + + .macro disable_fiq + .endm + + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp + mov \base, #io_p2v(0x00100000) + add \base, \base, #0x000ff000 + + ldr \irqstat, [\base, #0] + clz \irqnr, \irqstat + rsb \irqnr, \irqnr, #31 + cmp \irqstat, #0 + .endm + diff --git a/include/asm-arm/arch-netx/hardware.h b/include/asm-arm/arch-netx/hardware.h new file mode 100644 index 000000000000..7786c45455cd --- /dev/null +++ b/include/asm-arm/arch-netx/hardware.h @@ -0,0 +1,39 @@ +/* + * include/asm-arm/arch-netx/hardware.h + * + * Copyright (C) 2005 Sascha Hauer , Pengutronix + * + * 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 published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __ASM_ARCH_HARDWARE_H +#define __ASM_ARCH_HARDWARE_H + +#define NETX_IO_PHYS 0x00100000 +#define NETX_IO_VIRT 0xe0000000 +#define NETX_IO_SIZE 0x00100000 + +#define SRAM_INTERNAL_PHYS_0 0x00000 +#define SRAM_INTERNAL_PHYS_1 0x08000 +#define SRAM_INTERNAL_PHYS_2 0x10000 +#define SRAM_INTERNAL_PHYS_3 0x18000 +#define SRAM_INTERNAL_PHYS(no) ((no) * 0x8000) + +#define XPEC_MEM_SIZE 0x4000 +#define XMAC_MEM_SIZE 0x1000 +#define SRAM_MEM_SIZE 0x8000 + +#define io_p2v(x) ((x) - NETX_IO_PHYS + NETX_IO_VIRT) +#define io_v2p(x) ((x) - NETX_IO_VIRT + NETX_IO_PHYS) + +#endif diff --git a/include/asm-arm/arch-netx/io.h b/include/asm-arm/arch-netx/io.h new file mode 100644 index 000000000000..81b7bc47747e --- /dev/null +++ b/include/asm-arm/arch-netx/io.h @@ -0,0 +1,29 @@ +/* + * linux/include/asm-arm/arch-netx/io.h + * + * Copyright (C) 2005 Sascha Hauer , Pengutronix + * + * 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 published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __ASM_ARM_ARCH_IO_H +#define __ASM_ARM_ARCH_IO_H + +#define IO_SPACE_LIMIT 0xffffffff + +#define __io(a) ((void __iomem *)(a)) +#define __mem_pci(a) (a) +#define __mem_isa(a) (a) + +#endif diff --git a/include/asm-arm/arch-netx/irqs.h b/include/asm-arm/arch-netx/irqs.h new file mode 100644 index 000000000000..a487dc6e2661 --- /dev/null +++ b/include/asm-arm/arch-netx/irqs.h @@ -0,0 +1,70 @@ +/* + * include/asm-arm/arch-netx/irqs.h + * + * Copyright (C) 2005 Sascha Hauer , Pengutronix + * + * 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 published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define NETX_IRQ_VIC_START 0 +#define NETX_IRQ_SOFTINT 0 +#define NETX_IRQ_TIMER0 1 +#define NETX_IRQ_TIMER1 2 +#define NETX_IRQ_TIMER2 3 +#define NETX_IRQ_SYSTIME_NS 4 +#define NETX_IRQ_SYSTIME_S 5 +#define NETX_IRQ_GPIO_15 6 +#define NETX_IRQ_WATCHDOG 7 +#define NETX_IRQ_UART0 8 +#define NETX_IRQ_UART1 9 +#define NETX_IRQ_UART2 10 +#define NETX_IRQ_USB 11 +#define NETX_IRQ_SPI 12 +#define NETX_IRQ_I2C 13 +#define NETX_IRQ_LCD 14 +#define NETX_IRQ_HIF 15 +#define NETX_IRQ_GPIO_0_14 16 +#define NETX_IRQ_XPEC0 17 +#define NETX_IRQ_XPEC1 18 +#define NETX_IRQ_XPEC2 19 +#define NETX_IRQ_XPEC3 20 +#define NETX_IRQ_XPEC(no) (17 + (no)) +#define NETX_IRQ_MSYNC0 21 +#define NETX_IRQ_MSYNC1 22 +#define NETX_IRQ_MSYNC2 23 +#define NETX_IRQ_MSYNC3 24 +#define NETX_IRQ_IRQ_PHY 25 +#define NETX_IRQ_ISO_AREA 26 +/* int 27 is reserved */ +/* int 28 is reserved */ +#define NETX_IRQ_TIMER3 29 +#define NETX_IRQ_TIMER4 30 +/* int 31 is reserved */ + +#define NETX_IRQS 32 + +/* for multiplexed irqs on gpio 0..14 */ +#define NETX_IRQ_GPIO(x) (NETX_IRQS + (x)) +#define NETX_IRQ_GPIO_LAST NETX_IRQ_GPIO(14) + +/* Host interface interrupts */ +#define NETX_IRQ_HIF_CHAINED(x) (NETX_IRQ_GPIO_LAST + 1 + (x)) +#define NETX_IRQ_HIF_PIO35 NETX_IRQ_HIF_CHAINED(0) +#define NETX_IRQ_HIF_PIO36 NETX_IRQ_HIF_CHAINED(1) +#define NETX_IRQ_HIF_PIO40 NETX_IRQ_HIF_CHAINED(2) +#define NETX_IRQ_HIF_PIO47 NETX_IRQ_HIF_CHAINED(3) +#define NETX_IRQ_HIF_PIO72 NETX_IRQ_HIF_CHAINED(4) +#define NETX_IRQ_HIF_LAST NETX_IRQ_HIF_CHAINED(4) + +#define NR_IRQS (NETX_IRQ_HIF_LAST + 1) diff --git a/include/asm-arm/arch-netx/memory.h b/include/asm-arm/arch-netx/memory.h new file mode 100644 index 000000000000..6d8d2df3e99d --- /dev/null +++ b/include/asm-arm/arch-netx/memory.h @@ -0,0 +1,36 @@ +/* + * linux/include/asm-arm/arch-netx/memory.h + * + * Copyright (C) 2005 Sascha Hauer , Pengutronix + * + * 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 published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __ASM_ARCH_MEMORY_H +#define __ASM_ARCH_MEMORY_H + +#define PHYS_OFFSET UL(0x80000000) + +/* + * Virtual view <-> DMA view memory address translations + * virt_to_bus: Used to translate the virtual address to an + * address suitable to be passed to set_dma_addr + * bus_to_virt: Used to convert an address for DMA operations + * to an address that the kernel can use. + */ +#define __virt_to_bus(x) __virt_to_phys(x) +#define __bus_to_virt(x) __phys_to_virt(x) + +#endif + diff --git a/include/asm-arm/arch-netx/param.h b/include/asm-arm/arch-netx/param.h new file mode 100644 index 000000000000..7a80c26178a8 --- /dev/null +++ b/include/asm-arm/arch-netx/param.h @@ -0,0 +1,18 @@ +/* + * linux/include/asm-arm/arch-netx/param.h + * + * Copyright (C) 2005 Sascha Hauer , Pengutronix + * + * 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 published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ diff --git a/include/asm-arm/arch-netx/system.h b/include/asm-arm/arch-netx/system.h new file mode 100644 index 000000000000..52adf368d765 --- /dev/null +++ b/include/asm-arm/arch-netx/system.h @@ -0,0 +1,38 @@ +/* + * include/asm-arm/arch-netx/system.h + * + * Copyright (C) 2005 Sascha Hauer , Pengutronix + * + * 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 published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __ASM_ARCH_SYSTEM_H +#define __ASM_ARCH_SYSTEM_H + +#include +#include +#include "netx-regs.h" + +static inline void arch_idle(void) +{ + cpu_do_idle(); +} + +static inline void arch_reset(char mode) +{ + writel(NETX_SYSTEM_RES_CR_FIRMW_RES_EN | NETX_SYSTEM_RES_CR_FIRMW_RES, + NETX_SYSTEM_RES_CR); +} + +#endif + diff --git a/include/asm-arm/arch-netx/timex.h b/include/asm-arm/arch-netx/timex.h new file mode 100644 index 000000000000..7fdb42da0b40 --- /dev/null +++ b/include/asm-arm/arch-netx/timex.h @@ -0,0 +1,20 @@ +/* + * include/asm-arm/arch-netx/timex.h + * + * Copyright (C) 2005 Sascha Hauer , Pengutronix + * + * 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 published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define CLOCK_TICK_RATE 100000000 diff --git a/include/asm-arm/arch-netx/uncompress.h b/include/asm-arm/arch-netx/uncompress.h new file mode 100644 index 000000000000..f89434547102 --- /dev/null +++ b/include/asm-arm/arch-netx/uncompress.h @@ -0,0 +1,76 @@ +/* + * include/asm-arm/arch-netx/uncompress.h + * + * Copyright (C) 2005 Sascha Hauer , Pengutronix + * + * 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 published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * The following code assumes the serial port has already been + * initialized by the bootloader. We search for the first enabled + * port in the most probable order. If you didn't setup a port in + * your bootloader then nothing will appear (which might be desired). + * + * This does not append a newline + */ + +#define REG(x) (*(volatile unsigned long *)(x)) + +#define UART1_BASE 0x100a00 +#define UART2_BASE 0x100a80 + +#define UART_DR 0x0 + +#define UART_CR 0x14 +#define CR_UART_EN (1<<0) + +#define UART_FR 0x18 +#define FR_BUSY (1<<3) +#define FR_TXFF (1<<5) + +static void putc(char c) +{ + unsigned long base; + + if (REG(UART1_BASE + UART_CR) & CR_UART_EN) + base = UART1_BASE; + else if (REG(UART2_BASE + UART_CR) & CR_UART_EN) + base = UART2_BASE; + else + return; + + while (REG(base + UART_FR) & FR_TXFF); + REG(base + UART_DR) = c; +} + +static inline void flush(void) +{ + unsigned long base; + + if (REG(UART1_BASE + UART_CR) & CR_UART_EN) + base = UART1_BASE; + else if (REG(UART2_BASE + UART_CR) & CR_UART_EN) + base = UART2_BASE; + else + return; + + while (REG(base + UART_FR) & FR_BUSY); +} + +/* + * nothing to do + */ +#define arch_decomp_setup() +#define arch_decomp_wdog() diff --git a/include/asm-arm/arch-netx/vmalloc.h b/include/asm-arm/arch-netx/vmalloc.h new file mode 100644 index 000000000000..da2da5a595da --- /dev/null +++ b/include/asm-arm/arch-netx/vmalloc.h @@ -0,0 +1,19 @@ +/* + * linux/include/asm-arm/arch-netx/vmalloc.h + * + * Copyright (C) 2005 Sascha Hauer , Pengutronix + * + * 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 published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#define VMALLOC_END (PAGE_OFFSET + 0x10000000) -- cgit v1.2.3 From ef70cd4d247defcd7c0f789a5a98deab0afadf53 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Mon, 19 Jun 2006 15:28:19 +0100 Subject: [ARM] 3568/2: netX: pointer fifo driver Patch from Sascha Hauer This patch adds support for the pointer FIFOs on netX. Signed-off-by: Robert Schwebel Signed-off-by: Sascha Hauer Signed-off-by: Russell King --- arch/arm/mach-netx/Makefile | 2 +- arch/arm/mach-netx/pfifo.c | 68 +++++++++++++++++++++++++++++++++++++++ include/asm-arm/arch-netx/pfifo.h | 54 +++++++++++++++++++++++++++++++ 3 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-netx/pfifo.c create mode 100644 include/asm-arm/arch-netx/pfifo.h (limited to 'include') diff --git a/arch/arm/mach-netx/Makefile b/arch/arm/mach-netx/Makefile index 257d02ef66d8..cd424083e5b9 100644 --- a/arch/arm/mach-netx/Makefile +++ b/arch/arm/mach-netx/Makefile @@ -7,5 +7,5 @@ # Object file lists. -obj-y += time.o generic.o +obj-y += time.o generic.o pfifo.o diff --git a/arch/arm/mach-netx/pfifo.c b/arch/arm/mach-netx/pfifo.c new file mode 100644 index 000000000000..44dea61a9de4 --- /dev/null +++ b/arch/arm/mach-netx/pfifo.c @@ -0,0 +1,68 @@ +/* + * arch/arm/mach-netx/pfifo.c + * + * Copyright (c) 2005 Sascha Hauer , Pengutronix + * + * 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 published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include + +#include +#include +#include +#include + +static DEFINE_MUTEX(pfifo_lock); + +static unsigned int pfifo_used = 0; + +int pfifo_request(unsigned int pfifo_mask) +{ + int err = 0; + unsigned int val; + + mutex_lock(&pfifo_lock); + + if (pfifo_mask & pfifo_used) { + err = -EBUSY; + goto out; + } + + pfifo_used |= pfifo_mask; + + val = readl(NETX_PFIFO_RESET); + writel(val | pfifo_mask, NETX_PFIFO_RESET); + writel(val, NETX_PFIFO_RESET); + +out: + mutex_unlock(&pfifo_lock); + return err; +} + +void pfifo_free(unsigned int pfifo_mask) +{ + mutex_lock(&pfifo_lock); + pfifo_used &= ~pfifo_mask; + mutex_unlock(&pfifo_lock); +} + +EXPORT_SYMBOL(pfifo_push); +EXPORT_SYMBOL(pfifo_pop); +EXPORT_SYMBOL(pfifo_fill_level); +EXPORT_SYMBOL(pfifo_empty); +EXPORT_SYMBOL(pfifo_request); +EXPORT_SYMBOL(pfifo_free); diff --git a/include/asm-arm/arch-netx/pfifo.h b/include/asm-arm/arch-netx/pfifo.h new file mode 100644 index 000000000000..4af2ee4a32c1 --- /dev/null +++ b/include/asm-arm/arch-netx/pfifo.h @@ -0,0 +1,54 @@ +/* + * include/asm-arm/arch-netx/pfifo.h + * + * Copyright (c) 2005 Sascha Hauer , Pengutronix + * + * 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 published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef ASM_ARCH_PFIFO_H +#define ASM_ARCH_PFIFO_H + +static inline int pfifo_push(int no, unsigned int pointer) +{ + writel(pointer, NETX_PFIFO_BASE(no)); + return 0; +} + +static inline unsigned int pfifo_pop(int no) +{ + return readl(NETX_PFIFO_BASE(no)); +} + +static inline int pfifo_fill_level(int no) +{ + + return readl(NETX_PFIFO_FILL_LEVEL(no)); +} + +static inline int pfifo_full(int no) +{ + return readl(NETX_PFIFO_FULL) & (1< Date: Mon, 19 Jun 2006 15:28:20 +0100 Subject: [ARM] 3569/2: netX: driver for XMAC/XPEC engines Patch from Sascha Hauer The netX processors have generic network bitstream engines (XMAC/XPEC). This driver adds support for firmware loading and start, stop, reset commands. Signed-off-by: Robert Schwebel Signed-off-by: Sascha Hauer Signed-off-by: Russell King --- arch/arm/mach-netx/Makefile | 2 +- arch/arm/mach-netx/xc.c | 255 +++++++++++++++++++++++++++++++++++++++++ include/asm-arm/arch-netx/xc.h | 42 +++++++ 3 files changed, 298 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-netx/xc.c create mode 100644 include/asm-arm/arch-netx/xc.h (limited to 'include') diff --git a/arch/arm/mach-netx/Makefile b/arch/arm/mach-netx/Makefile index cd424083e5b9..b2b7dd25f218 100644 --- a/arch/arm/mach-netx/Makefile +++ b/arch/arm/mach-netx/Makefile @@ -7,5 +7,5 @@ # Object file lists. -obj-y += time.o generic.o pfifo.o +obj-y += time.o generic.o pfifo.o xc.o diff --git a/arch/arm/mach-netx/xc.c b/arch/arm/mach-netx/xc.c new file mode 100644 index 000000000000..172a058ddd66 --- /dev/null +++ b/arch/arm/mach-netx/xc.c @@ -0,0 +1,255 @@ +/* + * arch/arm/mach-netx/xc.c + * + * Copyright (c) 2005 Sascha Hauer , Pengutronix + * + * 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 published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include + +static DEFINE_MUTEX(xc_lock); + +static int xc_in_use = 0; + +struct fw_desc { + unsigned int ofs; + unsigned int size; + unsigned int patch_ofs; + unsigned int patch_entries; +}; + +struct fw_header { + unsigned int magic; + unsigned int type; + unsigned int version; + unsigned int reserved[5]; + struct fw_desc fw_desc[3]; +} __attribute__ ((packed)); + +int xc_stop(struct xc *x) +{ + writel(RPU_HOLD_PC, x->xmac_base + NETX_XMAC_RPU_HOLD_PC_OFS); + writel(TPU_HOLD_PC, x->xmac_base + NETX_XMAC_TPU_HOLD_PC_OFS); + writel(XPU_HOLD_PC, x->xpec_base + NETX_XPEC_XPU_HOLD_PC_OFS); + return 0; +} + +int xc_start(struct xc *x) +{ + writel(0, x->xmac_base + NETX_XMAC_RPU_HOLD_PC_OFS); + writel(0, x->xmac_base + NETX_XMAC_TPU_HOLD_PC_OFS); + writel(0, x->xpec_base + NETX_XPEC_XPU_HOLD_PC_OFS); + return 0; +} + +int xc_running(struct xc *x) +{ + return (readl(x->xmac_base + NETX_XMAC_RPU_HOLD_PC_OFS) & RPU_HOLD_PC) + || (readl(x->xmac_base + NETX_XMAC_TPU_HOLD_PC_OFS) & TPU_HOLD_PC) + || (readl(x->xpec_base + NETX_XPEC_XPU_HOLD_PC_OFS) & XPU_HOLD_PC) ? + 0 : 1; +} + +int xc_reset(struct xc *x) +{ + writel(0, x->xpec_base + NETX_XPEC_PC_OFS); + return 0; +} + +static int xc_check_ptr(struct xc *x, unsigned long adr, unsigned int size) +{ + if (adr >= NETX_PA_XMAC(x->no) && + adr + size < NETX_PA_XMAC(x->no) + XMAC_MEM_SIZE) + return 0; + + if (adr >= NETX_PA_XPEC(x->no) && + adr + size < NETX_PA_XPEC(x->no) + XPEC_MEM_SIZE) + return 0; + + dev_err(x->dev, "Illegal pointer in firmware found. aborting\n"); + + return -1; +} + +static int xc_patch(struct xc *x, void *patch, int count) +{ + unsigned int val, adr; + unsigned int *data = patch; + + int i; + for (i = 0; i < count; i++) { + adr = *data++; + val = *data++; + if (xc_check_ptr(x, adr, 4) < 0) + return -EINVAL; + + writel(val, (void __iomem *)io_p2v(adr)); + } + return 0; +} + +int xc_request_firmware(struct xc *x) +{ + int ret; + char name[16]; + const struct firmware *fw; + struct fw_header *head; + unsigned int size; + int i; + void *src; + unsigned long dst; + + sprintf(name, "xc%d.bin", x->no); + + ret = request_firmware(&fw, name, x->dev); + + if (ret < 0) { + dev_err(x->dev, "request_firmware failed\n"); + return ret; + } + + head = (struct fw_header *)fw->data; + if (head->magic != 0x4e657458) { + if (head->magic == 0x5874654e) { + dev_err(x->dev, + "firmware magic is 'XteN'. Endianess problems?\n"); + ret = -ENODEV; + goto exit_release_firmware; + } + dev_err(x->dev, "unrecognized firmware magic 0x%08x\n", + head->magic); + ret = -ENODEV; + goto exit_release_firmware; + } + + x->type = head->type; + x->version = head->version; + + ret = -EINVAL; + + for (i = 0; i < 3; i++) { + src = fw->data + head->fw_desc[i].ofs; + dst = *(unsigned int *)src; + src += sizeof (unsigned int); + size = head->fw_desc[i].size - sizeof (unsigned int); + + if (xc_check_ptr(x, dst, size)) + goto exit_release_firmware; + + memcpy((void *)io_p2v(dst), src, size); + + src = fw->data + head->fw_desc[i].patch_ofs; + size = head->fw_desc[i].patch_entries; + ret = xc_patch(x, src, size); + if (ret < 0) + goto exit_release_firmware; + } + + ret = 0; + + exit_release_firmware: + release_firmware(fw); + + return ret; +} + +struct xc *request_xc(int xcno, struct device *dev) +{ + struct xc *x = NULL; + + mutex_lock(&xc_lock); + + if (xcno > 3) + goto exit; + if (xc_in_use & (1 << xcno)) + goto exit; + + x = kmalloc(sizeof (struct xc), GFP_KERNEL); + if (!x) + goto exit; + + if (!request_mem_region + (NETX_PA_XPEC(xcno), XPEC_MEM_SIZE, dev->kobj.name)) + goto exit_free; + + if (!request_mem_region + (NETX_PA_XMAC(xcno), XMAC_MEM_SIZE, dev->kobj.name)) + goto exit_release_1; + + if (!request_mem_region + (SRAM_INTERNAL_PHYS(xcno), SRAM_MEM_SIZE, dev->kobj.name)) + goto exit_release_2; + + x->xpec_base = (void * __iomem)io_p2v(NETX_PA_XPEC(xcno)); + x->xmac_base = (void * __iomem)io_p2v(NETX_PA_XMAC(xcno)); + x->sram_base = ioremap(SRAM_INTERNAL_PHYS(xcno), SRAM_MEM_SIZE); + if (!x->sram_base) + goto exit_release_3; + + x->irq = NETX_IRQ_XPEC(xcno); + + x->no = xcno; + x->dev = dev; + + xc_in_use |= (1 << xcno); + + goto exit; + + exit_release_3: + release_mem_region(SRAM_INTERNAL_PHYS(xcno), SRAM_MEM_SIZE); + exit_release_2: + release_mem_region(NETX_PA_XMAC(xcno), XMAC_MEM_SIZE); + exit_release_1: + release_mem_region(NETX_PA_XPEC(xcno), XPEC_MEM_SIZE); + exit_free: + kfree(x); + x = NULL; + exit: + mutex_unlock(&xc_lock); + return x; +} + +void free_xc(struct xc *x) +{ + int xcno = x->no; + + mutex_lock(&xc_lock); + + iounmap(x->sram_base); + release_mem_region(SRAM_INTERNAL_PHYS(xcno), SRAM_MEM_SIZE); + release_mem_region(NETX_PA_XMAC(xcno), XMAC_MEM_SIZE); + release_mem_region(NETX_PA_XPEC(xcno), XPEC_MEM_SIZE); + xc_in_use &= ~(1 << x->no); + kfree(x); + + mutex_unlock(&xc_lock); +} + +EXPORT_SYMBOL(free_xc); +EXPORT_SYMBOL(request_xc); +EXPORT_SYMBOL(xc_request_firmware); +EXPORT_SYMBOL(xc_reset); +EXPORT_SYMBOL(xc_running); +EXPORT_SYMBOL(xc_start); +EXPORT_SYMBOL(xc_stop); diff --git a/include/asm-arm/arch-netx/xc.h b/include/asm-arm/arch-netx/xc.h new file mode 100644 index 000000000000..659af19512a9 --- /dev/null +++ b/include/asm-arm/arch-netx/xc.h @@ -0,0 +1,42 @@ +/* + * linux/include/asm-arm/arch-netx/xc.h + * + * Copyright (C) 2005 Sascha Hauer , Pengutronix + * + * 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 published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __ASM_ARCH_XC_H +#define __ASM_ARCH_XC_H + +struct xc { + int no; + unsigned int type; + unsigned int version; + void __iomem *xpec_base; + void __iomem *xmac_base; + void __iomem *sram_base; + int irq; + struct device *dev; +}; + +int xc_reset(struct xc *x); +int xc_stop(struct xc* x); +int xc_start(struct xc *x); +int xc_running(struct xc *x); +int xc_request_firmware(struct xc* x); +struct xc* request_xc(int xcno, struct device *dev); +void free_xc(struct xc *x); + +#endif /* __ASM_ARCH_XC_H */ -- cgit v1.2.3 From 441ff855f3edf5d355bea30f557bbed6bcd42c6c Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Mon, 19 Jun 2006 15:35:36 +0100 Subject: [ARM] Fix byte order macros for Thumb The byte order functions are visible to userspace. Unfortunately, __arch_swab32() contains an assembly instruction which is invalid when compiling for Thumb. This reverts to the C version when compiling for Thumb. Signed-off-by: H. Peter Anvin Signed-off-by: Russell King --- include/asm-arm/byteorder.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/asm-arm/byteorder.h b/include/asm-arm/byteorder.h index 17eaf8bdf092..e6f7fcdc73b0 100644 --- a/include/asm-arm/byteorder.h +++ b/include/asm-arm/byteorder.h @@ -22,16 +22,18 @@ static inline __attribute_const__ __u32 ___arch__swab32(__u32 x) { __u32 t; - if (__builtin_constant_p(x)) { - t = x ^ ((x << 16) | (x >> 16)); /* eor r1,r0,r0,ror #16 */ - } else { +#ifndef __thumb__ + if (!__builtin_constant_p(x)) { /* * The compiler needs a bit of a hint here to always do the * right thing and not screw it up to different degrees * depending on the gcc version. */ asm ("eor\t%0, %1, %1, ror #16" : "=r" (t) : "r" (x)); - } + } else +#endif + t = x ^ ((x << 16) | (x >> 16)); /* eor r1,r0,r0,ror #16 */ + x = (x << 24) | (x >> 8); /* mov r0,r0,ror #8 */ t &= ~0x00FF0000; /* bic r1,r1,#0x00FF0000 */ x ^= (t >> 8); /* eor r0,r0,r1,lsr #8 */ -- cgit v1.2.3 From 7238d7ee82d325212e83630047e9844943225118 Mon Sep 17 00:00:00 2001 From: Andrew Victor Date: Mon, 19 Jun 2006 16:57:00 +0100 Subject: [ARM] 3586/1: AT91RM9200 header update Patch from Andrew Victor Added definition for the bits in the Chip ID register. Corrected the capitalization of AT91_RTC_AMPM register name. Signed-off-by: Andrew Victor Signed-off-by: Russell King --- include/asm-arm/arch-at91rm9200/at91rm9200_sys.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/asm-arm/arch-at91rm9200/at91rm9200_sys.h b/include/asm-arm/arch-at91rm9200/at91rm9200_sys.h index 2910d359f919..0f4c12d5f0cd 100644 --- a/include/asm-arm/arch-at91rm9200/at91rm9200_sys.h +++ b/include/asm-arm/arch-at91rm9200/at91rm9200_sys.h @@ -68,8 +68,17 @@ #define AT91_DBGU_RHR (AT91_DBGU + 0x18) /* Receiver Holding Register */ #define AT91_DBGU_THR (AT91_DBGU + 0x1c) /* Transmitter Holding Register */ #define AT91_DBGU_BRGR (AT91_DBGU + 0x20) /* Baud Rate Generator Register */ + #define AT91_DBGU_CIDR (AT91_DBGU + 0x40) /* Chip ID Register */ #define AT91_DBGU_EXID (AT91_DBGU + 0x44) /* Chip ID Extension Register */ +#define AT91_CIDR_VERSION (0x1f << 0) /* Version of the Device */ +#define AT91_CIDR_EPROC (7 << 5) /* Embedded Processor */ +#define AT91_CIDR_NVPSIZ (0xf << 8) /* Nonvolatile Program Memory Size */ +#define AT91_CIDR_NVPSIZ2 (0xf << 12) /* Second Nonvolatile Program Memory Size */ +#define AT91_CIDR_SRAMSIZ (0xf << 16) /* Internal SRAM Size */ +#define AT91_CIDR_ARCH (0xff << 20) /* Architecture Identifier */ +#define AT91_CIDR_NVPTYP (7 << 28) /* Nonvolatile Program Memory Type */ +#define AT91_CIDR_EXT (1 << 31) /* Extension Flag */ /* @@ -241,7 +250,7 @@ #define AT91_RTC_SEC (0x7f << 0) /* Current Second */ #define AT91_RTC_MIN (0x7f << 8) /* Current Minute */ #define AT91_RTC_HOUR (0x3f << 16) /* Current Hour */ -#define At91_RTC_AMPM (1 << 22) /* Ante Meridiem Post Meridiem Indicator */ +#define AT91_RTC_AMPM (1 << 22) /* Ante Meridiem Post Meridiem Indicator */ #define AT91_RTC_CALR (AT91_RTC + 0x0c) /* Calendar Register */ #define AT91_RTC_CENT (0x7f << 0) /* Current Century */ -- cgit v1.2.3 From 82c583e3ae31ffa76d1280197274cc1e1cde3179 Mon Sep 17 00:00:00 2001 From: Andrew Victor Date: Mon, 19 Jun 2006 16:57:00 +0100 Subject: [ARM] 3587/1: AT91RM9200 hardware headers Patch from Andrew Victor These headers define the registers and bits for the SPI (Serial Peripheral Interface), SSC (Synchronous Serial), TC (Timer/Counter) and UDP (USB Device) peripherals integrated in the AT91RM9200 processor. (They will probably also be usable for the AT91SAM9 series of SoC processors) Signed-off-by: Andrew Victor Signed-off-by: Russell King --- include/asm-arm/arch-at91rm9200/at91rm9200_spi.h | 81 +++++++++++++ include/asm-arm/arch-at91rm9200/at91rm9200_ssc.h | 96 +++++++++++++++ include/asm-arm/arch-at91rm9200/at91rm9200_tc.h | 146 +++++++++++++++++++++++ include/asm-arm/arch-at91rm9200/at91rm9200_udp.h | 77 ++++++++++++ 4 files changed, 400 insertions(+) create mode 100644 include/asm-arm/arch-at91rm9200/at91rm9200_spi.h create mode 100644 include/asm-arm/arch-at91rm9200/at91rm9200_ssc.h create mode 100644 include/asm-arm/arch-at91rm9200/at91rm9200_tc.h create mode 100644 include/asm-arm/arch-at91rm9200/at91rm9200_udp.h (limited to 'include') diff --git a/include/asm-arm/arch-at91rm9200/at91rm9200_spi.h b/include/asm-arm/arch-at91rm9200/at91rm9200_spi.h new file mode 100644 index 000000000000..bff5ea45f604 --- /dev/null +++ b/include/asm-arm/arch-at91rm9200/at91rm9200_spi.h @@ -0,0 +1,81 @@ +/* + * include/asm-arm/arch-at91rm9200/at91rm9200_spi.h + * + * Copyright (C) 2005 Ivan Kokshaysky + * Copyright (C) SAN People + * + * Serial Peripheral Interface (SPI) registers. + * Based on AT91RM9200 datasheet revision E. + * + * 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. + */ + +#ifndef AT91RM9200_SPI_H +#define AT91RM9200_SPI_H + +#define AT91_SPI_CR 0x00 /* Control Register */ +#define AT91_SPI_SPIEN (1 << 0) /* SPI Enable */ +#define AT91_SPI_SPIDIS (1 << 1) /* SPI Disable */ +#define AT91_SPI_SWRST (1 << 7) /* SPI Software Reset */ +#define AT91_SPI_LASTXFER (1 << 24) /* Last Transfer [SAM9261 only] */ + +#define AT91_SPI_MR 0x04 /* Mode Register */ +#define AT91_SPI_MSTR (1 << 0) /* Master/Slave Mode */ +#define AT91_SPI_PS (1 << 1) /* Peripheral Select */ +#define AT91_SPI_PS_FIXED (0 << 1) +#define AT91_SPI_PS_VARIABLE (1 << 1) +#define AT91_SPI_PCSDEC (1 << 2) /* Chip Select Decode */ +#define AT91_SPI_DIV32 (1 << 3) /* Clock Selection */ +#define AT91_SPI_MODFDIS (1 << 4) /* Mode Fault Detection */ +#define AT91_SPI_LLB (1 << 7) /* Local Loopback Enable */ +#define AT91_SPI_PCS (0xf << 16) /* Peripheral Chip Select */ +#define AT91_SPI_DLYBCS (0xff << 24) /* Delay Between Chip Selects */ + +#define AT91_SPI_RDR 0x08 /* Receive Data Register */ +#define AT91_SPI_RD (0xffff << 0) /* Receive Data */ +#define AT91_SPI_PCS (0xf << 16) /* Peripheral Chip Select */ + +#define AT91_SPI_TDR 0x0c /* Transmit Data Register */ +#define AT91_SPI_TD (0xffff << 0) /* Transmit Data */ +#define AT91_SPI_PCS (0xf << 16) /* Peripheral Chip Select */ +#define AT91_SPI_LASTXFER (1 << 24) /* Last Transfer [SAM9261 only] */ + +#define AT91_SPI_SR 0x10 /* Status Register */ +#define AT91_SPI_RDRF (1 << 0) /* Receive Data Register Full */ +#define AT91_SPI_TDRE (1 << 1) /* Transmit Data Register Full */ +#define AT91_SPI_MODF (1 << 2) /* Mode Fault Error */ +#define AT91_SPI_OVRES (1 << 3) /* Overrun Error Status */ +#define AT91_SPI_ENDRX (1 << 4) /* End of RX buffer */ +#define AT91_SPI_ENDTX (1 << 5) /* End of TX buffer */ +#define AT91_SPI_RXBUFF (1 << 6) /* RX Buffer Full */ +#define AT91_SPI_TXBUFE (1 << 7) /* TX Buffer Empty */ +#define AT91_SPI_NSSR (1 << 8) /* NSS Rising [SAM9261 only] */ +#define AT91_SPI_TXEMPTY (1 << 9) /* Transmission Register Empty [SAM9261 only] */ +#define AT91_SPI_SPIENS (1 << 16) /* SPI Enable Status */ + +#define AT91_SPI_IER 0x14 /* Interrupt Enable Register */ +#define AT91_SPI_IDR 0x18 /* Interrupt Disable Register */ +#define AT91_SPI_IMR 0x1c /* Interrupt Mask Register */ + +#define AT91_SPI_CSR(n) (0x30 + ((n) * 4)) /* Chip Select Registers 0-3 */ +#define AT91_SPI_CPOL (1 << 0) /* Clock Polarity */ +#define AT91_SPI_NCPHA (1 << 1) /* Clock Phase */ +#define AT91_SPI_CSAAT (1 << 3) /* Chip Select Active After Transfer [SAM9261 only] */ +#define AT91_SPI_BITS (0xf << 4) /* Bits Per Transfer */ +#define AT91_SPI_BITS_8 (0 << 4) +#define AT91_SPI_BITS_9 (1 << 4) +#define AT91_SPI_BITS_10 (2 << 4) +#define AT91_SPI_BITS_11 (3 << 4) +#define AT91_SPI_BITS_12 (4 << 4) +#define AT91_SPI_BITS_13 (5 << 4) +#define AT91_SPI_BITS_14 (6 << 4) +#define AT91_SPI_BITS_15 (7 << 4) +#define AT91_SPI_BITS_16 (8 << 4) +#define AT91_SPI_SCBR (0xff << 8) /* Serial Clock Baud Rate */ +#define AT91_SPI_DLYBS (0xff << 16) /* Delay before SPCK */ +#define AT91_SPI_DLYBCT (0xff << 24) /* Delay between Consecutive Transfers */ + +#endif diff --git a/include/asm-arm/arch-at91rm9200/at91rm9200_ssc.h b/include/asm-arm/arch-at91rm9200/at91rm9200_ssc.h new file mode 100644 index 000000000000..ac880227147f --- /dev/null +++ b/include/asm-arm/arch-at91rm9200/at91rm9200_ssc.h @@ -0,0 +1,96 @@ +/* + * include/asm-arm/arch-at91rm9200/at91rm9200_ssc.h + * + * Copyright (C) SAN People + * + * Serial Synchronous Controller (SSC) registers. + * Based on AT91RM9200 datasheet revision E. + * + * 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. + */ + +#ifndef AT91RM9200_SSC_H +#define AT91RM9200_SSC_H + +#define AT91_SSC_CR 0x00 /* Control Register */ +#define AT91_SSC_RXEN (1 << 0) /* Receive Enable */ +#define AT91_SSC_RXDIS (1 << 1) /* Receive Disable */ +#define AT91_SSC_TXEN (1 << 8) /* Transmit Enable */ +#define AT91_SSC_TXDIS (1 << 9) /* Transmit Disable */ +#define AT91_SSC_SWRST (1 << 15) /* Software Reset */ + +#define AT91_SSC_CMR 0x04 /* Clock Mode Register */ +#define AT91_SSC_CMR_DIV (0xfff << 0) /* Clock Divider */ + +#define AT91_SSC_RCMR 0x10 /* Receive Clock Mode Register */ +#define AT91_SSC_CKS (3 << 0) /* Clock Selection */ +#define AT91_SSC_CKS_DIV (0 << 0) +#define AT91_SSC_CKS_CLOCK (1 << 0) +#define AT91_SSC_CKS_PIN (2 << 0) +#define AT91_SSC_CKO (7 << 2) /* Clock Output Mode Selection */ +#define AT91_SSC_CKO_NONE (0 << 2) +#define AT91_SSC_CKO_CONTINUOUS (1 << 2) +#define AT91_SSC_CKI (1 << 5) /* Clock Inversion */ +#define AT91_SSC_CKI_FALLING (0 << 5) +#define AT91_SSC_CK_RISING (1 << 5) +#define AT91_SSC_START (0xf << 8) /* Start Selection */ +#define AT91_SSC_START_CONTINUOUS (0 << 8) +#define AT91_SSC_START_TX_RX (1 << 8) +#define AT91_SSC_START_LOW_RF (2 << 8) +#define AT91_SSC_START_HIGH_RF (3 << 8) +#define AT91_SSC_START_FALLING_RF (4 << 8) +#define AT91_SSC_START_RISING_RF (5 << 8) +#define AT91_SSC_START_LEVEL_RF (6 << 8) +#define AT91_SSC_START_EDGE_RF (7 << 8) +#define AT91_SSC_STTDLY (0xff << 16) /* Start Delay */ +#define AT91_SSC_PERIOD (0xff << 24) /* Period Divider Selection */ + +#define AT91_SSC_RFMR 0x14 /* Receive Frame Mode Register */ +#define AT91_SSC_DATALEN (0x1f << 0) /* Data Length */ +#define AT91_SSC_LOOP (1 << 5) /* Loop Mode */ +#define AT91_SSC_MSBF (1 << 7) /* Most Significant Bit First */ +#define AT91_SSC_DATNB (0xf << 8) /* Data Number per Frame */ +#define AT91_SSC_FSLEN (0xf << 16) /* Frame Sync Length */ +#define AT91_SSC_FSOS (7 << 20) /* Frame Sync Output Selection */ +#define AT91_SSC_FSOS_NONE (0 << 20) +#define AT91_SSC_FSOS_NEGATIVE (1 << 20) +#define AT91_SSC_FSOS_POSITIVE (2 << 20) +#define AT91_SSC_FSOS_LOW (3 << 20) +#define AT91_SSC_FSOS_HIGH (4 << 20) +#define AT91_SSC_FSOS_TOGGLE (5 << 20) +#define AT91_SSC_FSEDGE (1 << 24) /* Frame Sync Edge Detection */ +#define AT91_SSC_FSEDGE_POSITIVE (0 << 24) +#define AT91_SSC_FSEDGE_NEGATIVE (1 << 24) + +#define AT91_SSC_TCMR 0x18 /* Transmit Clock Mode Register */ +#define AT91_SSC_TFMR 0x1c /* Transmit Fram Mode Register */ +#define AT91_SSC_DATDEF (1 << 5) /* Data Default Value */ +#define AT91_SSC_FSDEN (1 << 23) /* Frame Sync Data Enable */ + +#define AT91_SSC_RHR 0x20 /* Receive Holding Register */ +#define AT91_SSC_THR 0x24 /* Transmit Holding Register */ +#define AT91_SSC_RSHR 0x30 /* Receive Sync Holding Register */ +#define AT91_SSC_TSHR 0x34 /* Transmit Sync Holding Register */ + +#define AT91_SSC_SR 0x40 /* Status Register */ +#define AT91_SSC_TXRDY (1 << 0) /* Transmit Ready */ +#define AT91_SSC_TXEMPTY (1 << 1) /* Transmit Empty */ +#define AT91_SSC_ENDTX (1 << 2) /* End of Transmission */ +#define AT91_SSC_TXBUFE (1 << 3) /* Transmit Buffer Empty */ +#define AT91_SSC_RXRDY (1 << 4) /* Receive Ready */ +#define AT91_SSC_OVRUN (1 << 5) /* Receive Overrun */ +#define AT91_SSC_ENDRX (1 << 6) /* End of Reception */ +#define AT91_SSC_RXBUFF (1 << 7) /* Receive Buffer Full */ +#define AT91_SSC_TXSYN (1 << 10) /* Transmit Sync */ +#define AT91_SSC_RXSYN (1 << 11) /* Receive Sync */ +#define AT91_SSC_TXENA (1 << 16) /* Transmit Enable */ +#define AT91_SSC_RXENA (1 << 17) /* Receive Enable */ + +#define AT91_SSC_IER 0x44 /* Interrupt Enable Register */ +#define AT91_SSC_IDR 0x48 /* Interrupt Disable Register */ +#define AT91_SSC_IMR 0x4c /* Interrupt Mask Register */ + +#endif diff --git a/include/asm-arm/arch-at91rm9200/at91rm9200_tc.h b/include/asm-arm/arch-at91rm9200/at91rm9200_tc.h new file mode 100644 index 000000000000..f4da752bb0c8 --- /dev/null +++ b/include/asm-arm/arch-at91rm9200/at91rm9200_tc.h @@ -0,0 +1,146 @@ +/* + * include/asm-arm/arch-at91rm9200/at91rm9200_tc.h + * + * Copyright (C) SAN People + * + * Timer/Counter Unit (TC) registers. + * Based on AT91RM9200 datasheet revision E. + * + * 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. + */ + +#ifndef AT91RM9200_TC_H +#define AT91RM9200_TC_H + +#define AT91_TC_BCR 0xc0 /* TC Block Control Register */ +#define AT91_TC_SYNC (1 << 0) /* Synchro Command */ + +#define AT91_TC_BMR 0xc4 /* TC Block Mode Register */ +#define AT91_TC_TC0XC0S (3 << 0) /* External Clock Signal 0 Selection */ +#define AT91_TC_TC0XC0S_TCLK0 (0 << 0) +#define AT91_TC_TC0XC0S_NONE (1 << 0) +#define AT91_TC_TC0XC0S_TIOA1 (2 << 0) +#define AT91_TC_TC0XC0S_TIOA2 (3 << 0) +#define AT91_TC_TC1XC1S (3 << 2) /* External Clock Signal 1 Selection */ +#define AT91_TC_TC1XC1S_TCLK1 (0 << 2) +#define AT91_TC_TC1XC1S_NONE (1 << 2) +#define AT91_TC_TC1XC1S_TIOA0 (2 << 2) +#define AT91_TC_TC1XC1S_TIOA2 (3 << 2) +#define AT91_TC_TC2XC2S (3 << 4) /* External Clock Signal 2 Selection */ +#define AT91_TC_TC2XC2S_TCLK2 (0 << 4) +#define AT91_TC_TC2XC2S_NONE (1 << 4) +#define AT91_TC_TC2XC2S_TIOA0 (2 << 4) +#define AT91_TC_TC2XC2S_TIOA1 (3 << 4) + + +#define AT91_TC_CCR 0x00 /* Channel Control Register */ +#define AT91_TC_CLKEN (1 << 0) /* Counter Clock Enable Command */ +#define AT91_TC_CLKDIS (1 << 1) /* Counter CLock Disable Command */ +#define AT91_TC_SWTRG (1 << 2) /* Software Trigger Command */ + +#define AT91_TC_CMR 0x04 /* Channel Mode Register */ +#define AT91_TC_TCCLKS (7 << 0) /* Capture/Waveform Mode: Clock Selection */ +#define AT91_TC_TIMER_CLOCK1 (0 << 0) +#define AT91_TC_TIMER_CLOCK2 (1 << 0) +#define AT91_TC_TIMER_CLOCK3 (2 << 0) +#define AT91_TC_TIMER_CLOCK4 (3 << 0) +#define AT91_TC_TIMER_CLOCK5 (4 << 0) +#define AT91_TC_XC0 (5 << 0) +#define AT91_TC_XC1 (6 << 0) +#define AT91_TC_XC2 (7 << 0) +#define AT91_TC_CLKI (1 << 3) /* Capture/Waveform Mode: Clock Invert */ +#define AT91_TC_BURST (3 << 4) /* Capture/Waveform Mode: Burst Signal Selection */ +#define AT91_TC_LDBSTOP (1 << 6) /* Capture Mode: Counter Clock Stopped with TB Loading */ +#define AT91_TC_LDBDIS (1 << 7) /* Capture Mode: Counter Clock Disable with RB Loading */ +#define AT91_TC_ETRGEDG (3 << 8) /* Capture Mode: External Trigger Edge Selection */ +#define AT91_TC_ABETRG (1 << 10) /* Capture Mode: TIOA or TIOB External Trigger Selection */ +#define AT91_TC_CPCTRG (1 << 14) /* Capture Mode: RC Compare Trigger Enable */ +#define AT91_TC_WAVE (1 << 15) /* Capture/Waveform mode */ +#define AT91_TC_LDRA (3 << 16) /* Capture Mode: RA Loading Selection */ +#define AT91_TC_LDRB (3 << 18) /* Capture Mode: RB Loading Selection */ + +#define AT91_TC_CPCSTOP (1 << 6) /* Waveform Mode: Counter Clock Stopped with RC Compare */ +#define AT91_TC_CPCDIS (1 << 7) /* Waveform Mode: Counter Clock Disable with RC Compare */ +#define AT91_TC_EEVTEDG (3 << 8) /* Waveform Mode: External Event Edge Selection */ +#define AT91_TC_EEVTEDG_NONE (0 << 8) +#define AT91_TC_EEVTEDG_RISING (1 << 8) +#define AT91_TC_EEVTEDG_FALLING (2 << 8) +#define AT91_TC_EEVTEDG_BOTH (3 << 8) +#define AT91_TC_EEVT (3 << 10) /* Waveform Mode: External Event Selection */ +#define AT91_TC_EEVT_TIOB (0 << 10) +#define AT91_TC_EEVT_XC0 (1 << 10) +#define AT91_TC_EEVT_XC1 (2 << 10) +#define AT91_TC_EEVT_XC2 (3 << 10) +#define AT91_TC_ENETRG (1 << 12) /* Waveform Mode: External Event Trigger Enable */ +#define AT91_TC_WAVESEL (3 << 13) /* Waveform Mode: Waveform Selection */ +#define AT91_TC_WAVESEL_UP (0 << 13) +#define AT91_TC_WAVESEL_UP_AUTO (2 << 13) +#define AT91_TC_WAVESEL_UPDOWN (1 << 13) +#define AT91_TC_WAVESEL_UPDOWN_AUTO (3 << 13) +#define AT91_TC_ACPA (3 << 16) /* Waveform Mode: RA Compare Effect on TIOA */ +#define AT91_TC_ACPA_NONE (0 << 16) +#define AT91_TC_ACPA_SET (1 << 16) +#define AT91_TC_ACPA_CLEAR (2 << 16) +#define AT91_TC_ACPA_TOGGLE (3 << 16) +#define AT91_TC_ACPC (3 << 18) /* Waveform Mode: RC Compre Effect on TIOA */ +#define AT91_TC_ACPC_NONE (0 << 18) +#define AT91_TC_ACPC_SET (1 << 18) +#define AT91_TC_ACPC_CLEAR (2 << 18) +#define AT91_TC_ACPC_TOGGLE (3 << 18) +#define AT91_TC_AEEVT (3 << 20) /* Waveform Mode: External Event Effect on TIOA */ +#define AT91_TC_AEEVT_NONE (0 << 20) +#define AT91_TC_AEEVT_SET (1 << 20) +#define AT91_TC_AEEVT_CLEAR (2 << 20) +#define AT91_TC_AEEVT_TOGGLE (3 << 20) +#define AT91_TC_ASWTRG (3 << 22) /* Waveform Mode: Software Trigger Effect on TIOA */ +#define AT91_TC_ASWTRG_NONE (0 << 22) +#define AT91_TC_ASWTRG_SET (1 << 22) +#define AT91_TC_ASWTRG_CLEAR (2 << 22) +#define AT91_TC_ASWTRG_TOGGLE (3 << 22) +#define AT91_TC_BCPB (3 << 24) /* Waveform Mode: RB Compare Effect on TIOB */ +#define AT91_TC_BCPB_NONE (0 << 24) +#define AT91_TC_BCPB_SET (1 << 24) +#define AT91_TC_BCPB_CLEAR (2 << 24) +#define AT91_TC_BCPB_TOGGLE (3 << 24) +#define AT91_TC_BCPC (3 << 26) /* Waveform Mode: RC Compare Effect on TIOB */ +#define AT91_TC_BCPC_NONE (0 << 26) +#define AT91_TC_BCPC_SET (1 << 26) +#define AT91_TC_BCPC_CLEAR (2 << 26) +#define AT91_TC_BCPC_TOGGLE (3 << 26) +#define AT91_TC_BEEVT (3 << 28) /* Waveform Mode: External Event Effect on TIOB */ +#define AT91_TC_BEEVT_NONE (0 << 28) +#define AT91_TC_BEEVT_SET (1 << 28) +#define AT91_TC_BEEVT_CLEAR (2 << 28) +#define AT91_TC_BEEVT_TOGGLE (3 << 28) +#define AT91_TC_BSWTRG (3 << 30) /* Waveform Mode: Software Trigger Effect on TIOB */ +#define AT91_TC_BSWTRG_NONE (0 << 30) +#define AT91_TC_BSWTRG_SET (1 << 30) +#define AT91_TC_BSWTRG_CLEAR (2 << 30) +#define AT91_TC_BSWTRG_TOGGLE (3 << 30) + +#define AT91_TC_CV 0x10 /* Counter Value */ +#define AT91_TC_RA 0x14 /* Register A */ +#define AT91_TC_RB 0x18 /* Register B */ +#define AT91_TC_RC 0x1c /* Register C */ + +#define AT91_TC_SR 0x20 /* Status Register */ +#define AT91_TC_COVFS (1 << 0) /* Counter Overflow Status */ +#define AT91_TC_LOVRS (1 << 1) /* Load Overrun Status */ +#define AT91_TC_CPAS (1 << 2) /* RA Compare Status */ +#define AT91_TC_CPBS (1 << 3) /* RB Compare Status */ +#define AT91_TC_CPCS (1 << 4) /* RC Compare Status */ +#define AT91_TC_LDRAS (1 << 5) /* RA Loading Status */ +#define AT91_TC_LDRBS (1 << 6) /* RB Loading Status */ +#define AT91_TC_ETRGS (1 << 7) /* External Trigger Status */ +#define AT91_TC_CLKSTA (1 << 16) /* Clock Enabling Status */ +#define AT91_TC_MTIOA (1 << 17) /* TIOA Mirror */ +#define AT91_TC_MTIOB (1 << 18) /* TIOB Mirror */ + +#define AT91_TC_IER 0x24 /* Interrupt Enable Register */ +#define AT91_TC_IDR 0x28 /* Interrupt Disable Register */ +#define AT91_TC_IMR 0x2c /* Interrupt Mask Register */ + +#endif diff --git a/include/asm-arm/arch-at91rm9200/at91rm9200_udp.h b/include/asm-arm/arch-at91rm9200/at91rm9200_udp.h new file mode 100644 index 000000000000..951e3f61cef4 --- /dev/null +++ b/include/asm-arm/arch-at91rm9200/at91rm9200_udp.h @@ -0,0 +1,77 @@ +/* + * include/asm-arm/arch-at91rm9200/at91rm9200_udp.h + * + * Copyright (C) 2005 Ivan Kokshaysky + * Copyright (C) SAN People + * + * USB Device Port (UDP) registers. + * Based on AT91RM9200 datasheet revision E. + * + * 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. + */ + +#ifndef AT91RM9200_UDP_H +#define AT91RM9200_UDP_H + +#define AT91_UDP_FRM_NUM 0x00 /* Frame Number Register */ +#define AT91_UDP_NUM (0x7ff << 0) /* Frame Number */ +#define AT91_UDP_FRM_ERR (1 << 16) /* Frame Error */ +#define AT91_UDP_FRM_OK (1 << 17) /* Frame OK */ + +#define AT91_UDP_GLB_STAT 0x04 /* Global State Register */ +#define AT91_UDP_FADDEN (1 << 0) /* Function Address Enable */ +#define AT91_UDP_CONFG (1 << 1) /* Configured */ +#define AT91_UDP_ESR (1 << 2) /* Enable Send Resume */ +#define AT91_UDP_RSMINPR (1 << 3) /* Resume has been sent */ +#define AT91_UDP_RMWUPE (1 << 4) /* Remote Wake Up Enable */ + +#define AT91_UDP_FADDR 0x08 /* Function Address Register */ +#define AT91_UDP_FADD (0x7f << 0) /* Function Address Value */ +#define AT91_UDP_FEN (1 << 8) /* Function Enable */ + +#define AT91_UDP_IER 0x10 /* Interrupt Enable Register */ +#define AT91_UDP_IDR 0x14 /* Interrupt Disable Register */ +#define AT91_UDP_IMR 0x18 /* Interrupt Mask Register */ + +#define AT91_UDP_ISR 0x1c /* Interrupt Status Register */ +#define AT91_UDP_EP(n) (1 << (n)) /* Endpoint Interrupt Status */ +#define AT91_UDP_RXSUSP (1 << 8) /* USB Suspend Interrupt Status */ +#define AT91_UDP_RXRSM (1 << 9) /* USB Resume Interrupt Status */ +#define AT91_UDP_EXTRSM (1 << 10) /* External Resume Interrupt Status */ +#define AT91_UDP_SOFINT (1 << 11) /* Start of Frame Interrupt Status */ +#define AT91_UDP_ENDBUSRES (1 << 12) /* End of Bus Reset Interrpt Status */ +#define AT91_UDP_WAKEUP (1 << 13) /* USB Wakeup Interrupt Status */ + +#define AT91_UDP_ICR 0x20 /* Interrupt Clear Register */ +#define AT91_UDP_RST_EP 0x28 /* Reset Endpoint Register */ + +#define AT91_UDP_CSR(n) (0x30 + ((n) * 4)) /* Endpoint Control/Status Registers 0-7 */ +#define AT91_UDP_TXCOMP (1 << 0) /* Generates IN packet with data previously written in DPR */ +#define AT91_UDP_RX_DATA_BK0 (1 << 1) /* Receive Data Bank 0 */ +#define AT91_UDP_RXSETUP (1 << 2) /* Send STALL to the host */ +#define AT91_UDP_STALLSENT (1 << 3) /* Stall Sent / Isochronous error (Isochronous endpoints) */ +#define AT91_UDP_TXPKTRDY (1 << 4) /* Transmit Packet Ready */ +#define AT91_UDP_FORCESTALL (1 << 5) /* Force Stall */ +#define AT91_UDP_RX_DATA_BK1 (1 << 6) /* Receive Data Bank 1 */ +#define AT91_UDP_DIR (1 << 7) /* Transfer Direction */ +#define AT91_UDP_EPTYPE (7 << 8) /* Endpoint Type */ +#define AT91_UDP_EPTYPE_CTRL (0 << 8) +#define AT91_UDP_EPTYPE_ISO_OUT (1 << 8) +#define AT91_UDP_EPTYPE_BULK_OUT (2 << 8) +#define AT91_UDP_EPTYPE_INT_OUT (3 << 8) +#define AT91_UDP_EPTYPE_ISO_IN (5 << 8) +#define AT91_UDP_EPTYPE_BULK_IN (6 << 8) +#define AT91_UDP_EPTYPE_INT_IN (7 << 8) +#define AT91_UDP_DTGLE (1 << 11) /* Data Toggle */ +#define AT91_UDP_EPEDS (1 << 15) /* Endpoint Enable/Disable */ +#define AT91_UDP_RXBYTECNT (0x7ff << 16) /* Number of bytes in FIFO */ + +#define AT91_UDP_FDR(n) (0x50 + ((n) * 4)) /* Endpoint FIFO Data Registers 0-7 */ + +#define AT91_UDP_TXVC 0x74 /* Transceiver Control Register */ +#define AT91_UDP_TXVC_TXVDIS (1 << 8) /* Transceiver Disable */ + +#endif -- cgit v1.2.3 From 82dc0772a892f8b430a2d567c981fe47a11489c3 Mon Sep 17 00:00:00 2001 From: Andrew Victor Date: Mon, 19 Jun 2006 18:16:46 +0100 Subject: [ARM] 3590/1: AT91RM9200 Platform devices support Patch from Andrew Victor This patch includes the structures and exported functions required for the platform-device support (added in patch 3585/1). Also adds the arch_identify() function for run-time detection of which AT91 processor the code is running on. [Original patch from Ivan Kokshaysky] Signed-off-by: Andrew Victor Signed-off-by: Russell King --- include/asm-arm/arch-at91rm9200/board.h | 23 ++++++++++++++++++++--- include/asm-arm/arch-at91rm9200/system.h | 8 ++++++++ 2 files changed, 28 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/asm-arm/arch-at91rm9200/board.h b/include/asm-arm/arch-at91rm9200/board.h index 4fdef13d01d4..587948d56753 100644 --- a/include/asm-arm/arch-at91rm9200/board.h +++ b/include/asm-arm/arch-at91rm9200/board.h @@ -39,6 +39,8 @@ extern int at91_serial_map[AT91_NR_UART]; extern int at91_console_port; #include +#include +#include /* USB Device */ struct at91_udc_data { @@ -91,10 +93,25 @@ struct at91_nand_data { extern void __init at91_add_device_nand(struct at91_nand_data *data); /* I2C*/ -void __init at91_add_device_i2c(void); +extern void __init at91_add_device_i2c(void); - /* RTC */ -void __init at91_add_device_rtc(void); + /* SPI */ +extern void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices); + + /* Serial */ +struct at91_uart_config { + unsigned short console_tty; /* tty number of serial console */ + unsigned short nr_tty; /* number of serial tty's */ + short tty_map[]; /* map UART to tty number */ +}; +extern struct platform_device *at91_default_console_device; +extern void __init at91_init_serial(struct at91_uart_config *config); + +struct at91_uart_data { + short use_dma_tx; /* use transmit DMA? */ + short use_dma_rx; /* use receive DMA? */ +}; +extern void __init at91_add_device_serial(void); /* LEDs */ extern u8 at91_leds_cpu; diff --git a/include/asm-arm/arch-at91rm9200/system.h b/include/asm-arm/arch-at91rm9200/system.h index 29c42655f05c..945e66507a78 100644 --- a/include/asm-arm/arch-at91rm9200/system.h +++ b/include/asm-arm/arch-at91rm9200/system.h @@ -48,4 +48,12 @@ static inline void arch_reset(char mode) at91_sys_write(AT91_ST_CR, AT91_ST_WDRST); } +#define ARCH_ID_AT91RM9200 0x09200080 +#define ARCH_ID_AT91SAM9261 0x019000a0 + +static inline unsigned long arch_identify(void) +{ + return at91_sys_read(AT91_DBGU_CIDR) & (AT91_CIDR_EPROC | AT91_CIDR_ARCH); +} + #endif -- cgit v1.2.3 From afefc4158f3c8529e4bb99c1dc119fd792bac220 Mon Sep 17 00:00:00 2001 From: Andrew Victor Date: Mon, 19 Jun 2006 19:53:19 +0100 Subject: [ARM] 3592/1: AT91RM9200 Serial driver update Patch from Andrew Victor This patch includes a number of updates to the AT91RM9200 serial driver. Changes include: 1. Conversion to a platform_driver. [Ivan Kokshaysky] 2. Replaced all references to AT91RM9200 with AT91. This driver can now also be used for the AT91SAM9216. 3. Allow TIOCM_LOOP to configure local loopback mode. 4. Cleaned up the 'read_status_mask' usage and interrupt handler code. [Chip Coldwell] 5. Suspend/resume support. [David Brownell] There are a few 'unused variable' warning when compiling this - I removed the new DMA support to keep this first patch simpler. Signed-off-by: Andrew Victor Signed-off-by: Russell King --- drivers/serial/Kconfig | 17 +- drivers/serial/at91_serial.c | 463 +++++++++++++++++++------------ include/asm-arm/mach/serial_at91.h | 34 +++ include/asm-arm/mach/serial_at91rm9200.h | 36 --- include/linux/serial_core.h | 4 +- 5 files changed, 325 insertions(+), 229 deletions(-) create mode 100644 include/asm-arm/mach/serial_at91.h delete mode 100644 include/asm-arm/mach/serial_at91rm9200.h (limited to 'include') diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 7d22dc0478d3..5ea778fc1caa 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -300,21 +300,22 @@ config SERIAL_AMBA_PL011_CONSOLE kernel at boot time.) config SERIAL_AT91 - bool "AT91RM9200 serial port support" - depends on ARM && ARCH_AT91RM9200 + bool "AT91RM9200 / AT91SAM9261 serial port support" + depends on ARM && (ARCH_AT91RM9200 || ARCH_AT91SAM9261) select SERIAL_CORE help - This enables the driver for the on-chip UARTs of the AT91RM9200 - processor. + This enables the driver for the on-chip UARTs of the Atmel + AT91RM9200 and AT91SAM926 processor. config SERIAL_AT91_CONSOLE - bool "Support for console on AT91RM9200 serial port" + bool "Support for console on AT91RM9200 / AT91SAM9261 serial port" depends on SERIAL_AT91=y select SERIAL_CORE_CONSOLE help - Say Y here if you wish to use a UART on the AT91RM9200 as the system - console (the system console is the device which receives all kernel - messages and warnings and which allows logins in single user mode). + Say Y here if you wish to use a UART on the Atmel AT91RM9200 or + AT91SAM9261 as the system console (the system console is the device + which receives all kernel messages and warnings and which allows + logins in single user mode). config SERIAL_AT91_TTYAT bool "Install as device ttyAT0-4 instead of ttyS0-4" diff --git a/drivers/serial/at91_serial.c b/drivers/serial/at91_serial.c index 6547fe0cef96..db5b25fafed4 100644 --- a/drivers/serial/at91_serial.c +++ b/drivers/serial/at91_serial.c @@ -2,7 +2,6 @@ * linux/drivers/char/at91_serial.c * * Driver for Atmel AT91RM9200 Serial ports - * * Copyright (C) 2003 Rick Bronson * * Based on drivers/char/serial_sa1100.c, by Deep Blue Solutions Ltd. @@ -30,17 +29,19 @@ #include #include #include +#include #include #include #include +#include #include #include -#include +#include +#include #include -#include - +#include #if defined(CONFIG_SERIAL_AT91_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) #define SUPPORT_SYSRQ @@ -67,7 +68,6 @@ #endif -#define AT91_VA_BASE_DBGU ((unsigned long) AT91_VA_BASE_SYS + AT91_DBGU) #define AT91_ISR_PASS_LIMIT 256 #define UART_PUT_CR(port,v) writel(v, (port)->membase + AT91_US_CR) @@ -87,16 +87,33 @@ /* PDC registers */ #define UART_PUT_PTCR(port,v) writel(v, (port)->membase + AT91_PDC_PTCR) +#define UART_GET_PTSR(port) readl((port)->membase + AT91_PDC_PTSR) + #define UART_PUT_RPR(port,v) writel(v, (port)->membase + AT91_PDC_RPR) +#define UART_GET_RPR(port) readl((port)->membase + AT91_PDC_RPR) #define UART_PUT_RCR(port,v) writel(v, (port)->membase + AT91_PDC_RCR) -#define UART_GET_RCR(port) readl((port)->membase + AT91_PDC_RCR) #define UART_PUT_RNPR(port,v) writel(v, (port)->membase + AT91_PDC_RNPR) #define UART_PUT_RNCR(port,v) writel(v, (port)->membase + AT91_PDC_RNCR) +#define UART_PUT_TPR(port,v) writel(v, (port)->membase + AT91_PDC_TPR) +#define UART_PUT_TCR(port,v) writel(v, (port)->membase + AT91_PDC_TCR) +//#define UART_PUT_TNPR(port,v) writel(v, (port)->membase + AT91_PDC_TNPR) +//#define UART_PUT_TNCR(port,v) writel(v, (port)->membase + AT91_PDC_TNCR) static int (*at91_open)(struct uart_port *); static void (*at91_close)(struct uart_port *); +/* + * We wrap our port structure around the generic uart_port. + */ +struct at91_uart_port { + struct uart_port uart; /* uart */ + struct clk *clk; /* uart clock */ + unsigned short suspended; /* is port suspended? */ +}; + +static struct at91_uart_port at91_ports[AT91_NR_UART]; + #ifdef SUPPORT_SYSRQ static struct console at91_console; #endif @@ -115,16 +132,19 @@ static u_int at91_tx_empty(struct uart_port *port) static void at91_set_mctrl(struct uart_port *port, u_int mctrl) { unsigned int control = 0; + unsigned int mode; - /* - * Errata #39: RTS0 is not internally connected to PA21. We need to drive - * the pin manually. - */ - if (port->mapbase == AT91_VA_BASE_US0) { - if (mctrl & TIOCM_RTS) - at91_sys_write(AT91_PIOA + PIO_CODR, AT91_PA21_RTS0); - else - at91_sys_write(AT91_PIOA + PIO_SODR, AT91_PA21_RTS0); + if (arch_identify() == ARCH_ID_AT91RM9200) { + /* + * AT91RM9200 Errata #39: RTS0 is not internally connected to PA21. + * We need to drive the pin manually. + */ + if (port->mapbase == AT91_BASE_US0) { + if (mctrl & TIOCM_RTS) + at91_sys_write(AT91_PIOA + PIO_CODR, AT91_PA21_RTS0); + else + at91_sys_write(AT91_PIOA + PIO_SODR, AT91_PA21_RTS0); + } } if (mctrl & TIOCM_RTS) @@ -137,7 +157,15 @@ static void at91_set_mctrl(struct uart_port *port, u_int mctrl) else control |= AT91_US_DTRDIS; - UART_PUT_CR(port,control); + UART_PUT_CR(port, control); + + /* Local loopback mode? */ + mode = UART_GET_MR(port) & ~AT91_US_CHMODE; + if (mctrl & TIOCM_LOOP) + mode |= AT91_US_CHMODE_LOC_LOOP; + else + mode |= AT91_US_CHMODE_NORMAL; + UART_PUT_MR(port, mode); } /* @@ -169,8 +197,9 @@ static u_int at91_get_mctrl(struct uart_port *port) */ static void at91_stop_tx(struct uart_port *port) { + struct at91_uart_port *at91_port = (struct at91_uart_port *) port; + UART_PUT_IDR(port, AT91_US_TXRDY); - port->read_status_mask &= ~AT91_US_TXRDY; } /* @@ -178,7 +207,8 @@ static void at91_stop_tx(struct uart_port *port) */ static void at91_start_tx(struct uart_port *port) { - port->read_status_mask |= AT91_US_TXRDY; + struct at91_uart_port *at91_port = (struct at91_uart_port *) port; + UART_PUT_IER(port, AT91_US_TXRDY); } @@ -187,6 +217,8 @@ static void at91_start_tx(struct uart_port *port) */ static void at91_stop_rx(struct uart_port *port) { + struct at91_uart_port *at91_port = (struct at91_uart_port *) port; + UART_PUT_IDR(port, AT91_US_RXRDY); } @@ -195,7 +227,6 @@ static void at91_stop_rx(struct uart_port *port) */ static void at91_enable_ms(struct uart_port *port) { - port->read_status_mask |= (AT91_US_RIIC | AT91_US_DSRIC | AT91_US_DCDIC | AT91_US_CTSIC); UART_PUT_IER(port, AT91_US_RIIC | AT91_US_DSRIC | AT91_US_DCDIC | AT91_US_CTSIC); } @@ -218,8 +249,8 @@ static void at91_rx_chars(struct uart_port *port, struct pt_regs *regs) struct tty_struct *tty = port->info->tty; unsigned int status, ch, flg; - status = UART_GET_CSR(port) & port->read_status_mask; - while (status & (AT91_US_RXRDY)) { + status = UART_GET_CSR(port); + while (status & AT91_US_RXRDY) { ch = UART_GET_CHAR(port); port->icount.rx++; @@ -230,40 +261,38 @@ static void at91_rx_chars(struct uart_port *port, struct pt_regs *regs) * note that the error handling code is * out of the main execution path */ - if (unlikely(status & (AT91_US_PARE | AT91_US_FRAME | AT91_US_OVRE))) { + if (unlikely(status & (AT91_US_PARE | AT91_US_FRAME | AT91_US_OVRE | AT91_US_RXBRK))) { UART_PUT_CR(port, AT91_US_RSTSTA); /* clear error */ - if (status & (AT91_US_PARE)) + if (status & AT91_US_RXBRK) { + status &= ~(AT91_US_PARE | AT91_US_FRAME); /* ignore side-effect */ + port->icount.brk++; + if (uart_handle_break(port)) + goto ignore_char; + } + if (status & AT91_US_PARE) port->icount.parity++; - if (status & (AT91_US_FRAME)) + if (status & AT91_US_FRAME) port->icount.frame++; - if (status & (AT91_US_OVRE)) + if (status & AT91_US_OVRE) port->icount.overrun++; - if (status & AT91_US_PARE) + status &= port->read_status_mask; + + if (status & AT91_US_RXBRK) + flg = TTY_BREAK; + else if (status & AT91_US_PARE) flg = TTY_PARITY; else if (status & AT91_US_FRAME) flg = TTY_FRAME; - if (status & AT91_US_OVRE) { - /* - * overrun does *not* affect the character - * we read from the FIFO - */ - tty_insert_flip_char(tty, ch, flg); - ch = 0; - flg = TTY_OVERRUN; - } -#ifdef SUPPORT_SYSRQ - port->sysrq = 0; -#endif } if (uart_handle_sysrq_char(port, ch, regs)) goto ignore_char; - tty_insert_flip_char(tty, ch, flg); + uart_insert_char(port, status, AT91_US_OVRE, ch, flg); ignore_char: - status = UART_GET_CSR(port) & port->read_status_mask; + status = UART_GET_CSR(port); } tty_flip_buffer_push(tty); @@ -308,40 +337,35 @@ static void at91_tx_chars(struct uart_port *port) static irqreturn_t at91_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct uart_port *port = dev_id; + struct at91_uart_port *at91_port = (struct at91_uart_port *) port; unsigned int status, pending, pass_counter = 0; status = UART_GET_CSR(port); - pending = status & port->read_status_mask; - if (pending) { - do { - if (pending & AT91_US_RXRDY) - at91_rx_chars(port, regs); - - /* Clear the relevent break bits */ - if (pending & AT91_US_RXBRK) { - UART_PUT_CR(port, AT91_US_RSTSTA); - port->icount.brk++; - uart_handle_break(port); - } + pending = status & UART_GET_IMR(port); + while (pending) { + /* Interrupt receive */ + if (pending & AT91_US_RXRDY) + at91_rx_chars(port, regs); + + // TODO: All reads to CSR will clear these interrupts! + if (pending & AT91_US_RIIC) port->icount.rng++; + if (pending & AT91_US_DSRIC) port->icount.dsr++; + if (pending & AT91_US_DCDIC) + uart_handle_dcd_change(port, !(status & AT91_US_DCD)); + if (pending & AT91_US_CTSIC) + uart_handle_cts_change(port, !(status & AT91_US_CTS)); + if (pending & (AT91_US_RIIC | AT91_US_DSRIC | AT91_US_DCDIC | AT91_US_CTSIC)) + wake_up_interruptible(&port->info->delta_msr_wait); + + /* Interrupt transmit */ + if (pending & AT91_US_TXRDY) + at91_tx_chars(port); + + if (pass_counter++ > AT91_ISR_PASS_LIMIT) + break; - // TODO: All reads to CSR will clear these interrupts! - if (pending & AT91_US_RIIC) port->icount.rng++; - if (pending & AT91_US_DSRIC) port->icount.dsr++; - if (pending & AT91_US_DCDIC) - uart_handle_dcd_change(port, !(status & AT91_US_DCD)); - if (pending & AT91_US_CTSIC) - uart_handle_cts_change(port, !(status & AT91_US_CTS)); - if (pending & (AT91_US_RIIC | AT91_US_DSRIC | AT91_US_DCDIC | AT91_US_CTSIC)) - wake_up_interruptible(&port->info->delta_msr_wait); - - if (pending & AT91_US_TXRDY) - at91_tx_chars(port); - if (pass_counter++ > AT91_ISR_PASS_LIMIT) - break; - - status = UART_GET_CSR(port); - pending = status & port->read_status_mask; - } while (pending); + status = UART_GET_CSR(port); + pending = status & UART_GET_IMR(port); } return IRQ_HANDLED; } @@ -351,6 +375,7 @@ static irqreturn_t at91_interrupt(int irq, void *dev_id, struct pt_regs *regs) */ static int at91_startup(struct uart_port *port) { + struct at91_uart_port *at91_port = (struct at91_uart_port *) port; int retval; /* @@ -381,14 +406,14 @@ static int at91_startup(struct uart_port *port) } } - port->read_status_mask = AT91_US_RXRDY | AT91_US_TXRDY | AT91_US_OVRE - | AT91_US_FRAME | AT91_US_PARE | AT91_US_RXBRK; /* * Finally, enable the serial port */ UART_PUT_CR(port, AT91_US_RSTSTA | AT91_US_RSTRX); UART_PUT_CR(port, AT91_US_TXEN | AT91_US_RXEN); /* enable xmit & rcvr */ - UART_PUT_IER(port, AT91_US_RXRDY); /* do receive only */ + + UART_PUT_IER(port, AT91_US_RXRDY); /* enable receive only */ + return 0; } @@ -397,6 +422,8 @@ static int at91_startup(struct uart_port *port) */ static void at91_shutdown(struct uart_port *port) { + struct at91_uart_port *at91_port = (struct at91_uart_port *) port; + /* * Disable all interrupts, port and break condition. */ @@ -421,21 +448,22 @@ static void at91_shutdown(struct uart_port *port) */ static void at91_serial_pm(struct uart_port *port, unsigned int state, unsigned int oldstate) { + struct at91_uart_port *at91_port = (struct at91_uart_port *) port; + switch (state) { case 0: /* * Enable the peripheral clock for this serial port. * This is called on uart_open() or a resume event. */ - at91_sys_write(AT91_PMC_PCER, 1 << port->irq); + clk_enable(at91_port->clk); break; case 3: /* * Disable the peripheral clock for this serial port. * This is called on uart_close() or a suspend event. */ - if (port->irq != AT91_ID_SYS) /* is this a shared clock? */ - at91_sys_write(AT91_PMC_PCDR, 1 << port->irq); + clk_disable(at91_port->clk); break; default: printk(KERN_ERR "at91_serial: unknown pm %d\n", state); @@ -494,9 +522,9 @@ static void at91_set_termios(struct uart_port *port, struct termios * termios, s spin_lock_irqsave(&port->lock, flags); - port->read_status_mask |= AT91_US_OVRE; + port->read_status_mask = AT91_US_OVRE; if (termios->c_iflag & INPCK) - port->read_status_mask |= AT91_US_FRAME | AT91_US_PARE; + port->read_status_mask |= (AT91_US_FRAME | AT91_US_PARE); if (termios->c_iflag & (BRKINT | PARMRK)) port->read_status_mask |= AT91_US_RXBRK; @@ -552,7 +580,7 @@ static void at91_set_termios(struct uart_port *port, struct termios * termios, s */ static const char *at91_type(struct uart_port *port) { - return (port->type == PORT_AT91RM9200) ? "AT91_SERIAL" : NULL; + return (port->type == PORT_AT91) ? "AT91_SERIAL" : NULL; } /* @@ -560,8 +588,15 @@ static const char *at91_type(struct uart_port *port) */ static void at91_release_port(struct uart_port *port) { - release_mem_region(port->mapbase, - (port->mapbase == AT91_VA_BASE_DBGU) ? 512 : SZ_16K); + struct platform_device *pdev = to_platform_device(port->dev); + int size = pdev->resource[0].end - pdev->resource[0].start + 1; + + release_mem_region(port->mapbase, size); + + if (port->flags & UPF_IOREMAP) { + iounmap(port->membase); + port->membase = NULL; + } } /* @@ -569,10 +604,21 @@ static void at91_release_port(struct uart_port *port) */ static int at91_request_port(struct uart_port *port) { - return request_mem_region(port->mapbase, - (port->mapbase == AT91_VA_BASE_DBGU) ? 512 : SZ_16K, - "at91_serial") != NULL ? 0 : -EBUSY; + struct platform_device *pdev = to_platform_device(port->dev); + int size = pdev->resource[0].end - pdev->resource[0].start + 1; + + if (!request_mem_region(port->mapbase, size, "at91_serial")) + return -EBUSY; + + if (port->flags & UPF_IOREMAP) { + port->membase = ioremap(port->mapbase, size); + if (port->membase == NULL) { + release_mem_region(port->mapbase, size); + return -ENOMEM; + } + } + return 0; } /* @@ -581,7 +627,7 @@ static int at91_request_port(struct uart_port *port) static void at91_config_port(struct uart_port *port, int flags) { if (flags & UART_CONFIG_TYPE) { - port->type = PORT_AT91RM9200; + port->type = PORT_AT91; at91_request_port(port); } } @@ -592,7 +638,7 @@ static void at91_config_port(struct uart_port *port, int flags) static int at91_verify_port(struct uart_port *port, struct serial_struct *ser) { int ret = 0; - if (ser->type != PORT_UNKNOWN && ser->type != PORT_AT91RM9200) + if (ser->type != PORT_UNKNOWN && ser->type != PORT_AT91) ret = -EINVAL; if (port->irq != ser->irq) ret = -EINVAL; @@ -624,33 +670,47 @@ static struct uart_ops at91_pops = { .type = at91_type, .release_port = at91_release_port, .request_port = at91_request_port, - .config_port = at91_config_port, - .verify_port = at91_verify_port, + .config_port = at91_config_port, + .verify_port = at91_verify_port, .pm = at91_serial_pm, }; -static struct uart_port at91_ports[AT91_NR_UART]; - -void __init at91_init_ports(void) +/* + * Configure the port from the platform device resource info. + */ +static void __devinit at91_init_port(struct at91_uart_port *at91_port, struct platform_device *pdev) { - static int first = 1; - int i; - - if (!first) - return; - first = 0; + struct uart_port *port = &at91_port->uart; + struct at91_uart_data *data = pdev->dev.platform_data; + + port->iotype = UPIO_MEM; + port->flags = UPF_BOOT_AUTOCONF; + port->ops = &at91_pops; + port->fifosize = 1; + port->line = pdev->id; + port->dev = &pdev->dev; + + port->mapbase = pdev->resource[0].start; + port->irq = pdev->resource[1].start; + + if (port->mapbase == AT91_VA_BASE_SYS + AT91_DBGU) /* Part of system perpherals - already mapped */ + port->membase = (void __iomem *) port->mapbase; + else { + port->flags |= UPF_IOREMAP; + port->membase = NULL; + } - for (i = 0; i < AT91_NR_UART; i++) { - at91_ports[i].iotype = UPIO_MEM; - at91_ports[i].flags = UPF_BOOT_AUTOCONF; - at91_ports[i].uartclk = at91_master_clock; - at91_ports[i].ops = &at91_pops; - at91_ports[i].fifosize = 1; - at91_ports[i].line = i; - } + if (!at91_port->clk) { /* for console, the clock could already be configured */ + at91_port->clk = clk_get(&pdev->dev, "usart"); + clk_enable(at91_port->clk); + port->uartclk = clk_get_rate(at91_port->clk); + } } -void __init at91_register_uart_fns(struct at91rm9200_port_fns *fns) +/* + * Register board-specific modem-control line handlers. + */ +void __init at91_register_uart_fns(struct at91_port_fns *fns) { if (fns->enable_ms) at91_pops.enable_ms = fns->enable_ms; @@ -664,51 +724,6 @@ void __init at91_register_uart_fns(struct at91rm9200_port_fns *fns) at91_pops.set_wake = fns->set_wake; } -/* - * Setup ports. - */ -void __init at91_register_uart(int idx, int port) -{ - if ((idx < 0) || (idx >= AT91_NR_UART)) { - printk(KERN_ERR "%s: bad index number %d\n", __FUNCTION__, idx); - return; - } - - switch (port) { - case 0: - at91_ports[idx].membase = (void __iomem *) AT91_VA_BASE_US0; - at91_ports[idx].mapbase = AT91_VA_BASE_US0; - at91_ports[idx].irq = AT91_ID_US0; - AT91_CfgPIO_USART0(); - break; - case 1: - at91_ports[idx].membase = (void __iomem *) AT91_VA_BASE_US1; - at91_ports[idx].mapbase = AT91_VA_BASE_US1; - at91_ports[idx].irq = AT91_ID_US1; - AT91_CfgPIO_USART1(); - break; - case 2: - at91_ports[idx].membase = (void __iomem *) AT91_VA_BASE_US2; - at91_ports[idx].mapbase = AT91_VA_BASE_US2; - at91_ports[idx].irq = AT91_ID_US2; - AT91_CfgPIO_USART2(); - break; - case 3: - at91_ports[idx].membase = (void __iomem *) AT91_VA_BASE_US3; - at91_ports[idx].mapbase = AT91_VA_BASE_US3; - at91_ports[idx].irq = AT91_ID_US3; - AT91_CfgPIO_USART3(); - break; - case 4: - at91_ports[idx].membase = (void __iomem *) AT91_VA_BASE_DBGU; - at91_ports[idx].mapbase = AT91_VA_BASE_DBGU; - at91_ports[idx].irq = AT91_ID_SYS; - AT91_CfgPIO_DBGU(); - break; - default: - printk(KERN_ERR "%s : bad port number %d\n", __FUNCTION__, port); - } -} #ifdef CONFIG_SERIAL_AT91_CONSOLE static void at91_console_putchar(struct uart_port *port, int ch) @@ -723,7 +738,7 @@ static void at91_console_putchar(struct uart_port *port, int ch) */ static void at91_console_write(struct console *co, const char *s, u_int count) { - struct uart_port *port = at91_ports + co->index; + struct uart_port *port = &at91_ports[co->index].uart; unsigned int status, imr; /* @@ -778,23 +793,15 @@ static void __init at91_console_get_options(struct uart_port *port, int *baud, i static int __init at91_console_setup(struct console *co, char *options) { - struct uart_port *port; + struct uart_port *port = &at91_ports[co->index].uart; int baud = 115200; int bits = 8; int parity = 'n'; int flow = 'n'; - /* - * Check whether an invalid uart number has been specified, and - * if so, search for the first available port that does have - * console support. - */ - port = uart_get_console(at91_ports, AT91_NR_UART, co); + if (port->membase == 0) /* Port not initialized yet - delay setup */ + return -ENODEV; - /* - * Enable the serial console, in-case bootloader did not do it. - */ - at91_sys_write(AT91_PMC_PCER, 1 << port->irq); /* enable clock */ UART_PUT_IDR(port, -1); /* disable interrupts */ UART_PUT_CR(port, AT91_US_RSTSTA | AT91_US_RSTRX); UART_PUT_CR(port, AT91_US_TXEN | AT91_US_RXEN); @@ -821,23 +828,40 @@ static struct console at91_console = { #define AT91_CONSOLE_DEVICE &at91_console -static int __init at91_console_init(void) +/* + * Early console initialization (before VM subsystem initialized). + */ +static int __init at91_console_init(void) { - at91_init_ports(); + if (at91_default_console_device) { + add_preferred_console(AT91_DEVICENAME, at91_default_console_device->id, NULL); + at91_init_port(&(at91_ports[at91_default_console_device->id]), at91_default_console_device); + register_console(&at91_console); + } - at91_console.index = at91_console_port; - register_console(&at91_console); return 0; } console_initcall(at91_console_init); +/* + * Late console initialization. + */ +static int __init at91_late_console_init(void) +{ + if (at91_default_console_device && !(at91_console.flags & CON_ENABLED)) + register_console(&at91_console); + + return 0; +} +core_initcall(at91_late_console_init); + #else #define AT91_CONSOLE_DEVICE NULL #endif static struct uart_driver at91_uart = { .owner = THIS_MODULE, - .driver_name = AT91_DEVICENAME, + .driver_name = "at91_serial", .dev_name = AT91_DEVICENAME, .devfs_name = AT91_DEVICENAME, .major = SERIAL_AT91_MAJOR, @@ -846,33 +870,106 @@ static struct uart_driver at91_uart = { .cons = AT91_CONSOLE_DEVICE, }; -static int __init at91_serial_init(void) +#ifdef CONFIG_PM +static int at91_serial_suspend(struct platform_device *pdev, pm_message_t state) { - int ret, i; + struct uart_port *port = platform_get_drvdata(pdev); + struct at91_uart_port *at91_port = (struct at91_uart_port *) port; + + if (device_may_wakeup(&pdev->dev) && !at91_suspend_entering_slow_clock()) + enable_irq_wake(port->irq); + else { + disable_irq_wake(port->irq); + uart_suspend_port(&at91_uart, port); + at91_port->suspended = 1; + } - at91_init_ports(); + return 0; +} - ret = uart_register_driver(&at91_uart); - if (ret) - return ret; +static int at91_serial_resume(struct platform_device *pdev) +{ + struct uart_port *port = platform_get_drvdata(pdev); + struct at91_uart_port *at91_port = (struct at91_uart_port *) port; - for (i = 0; i < AT91_NR_UART; i++) { - if (at91_serial_map[i] >= 0) - uart_add_one_port(&at91_uart, &at91_ports[i]); + if (at91_port->suspended) { + uart_resume_port(&at91_uart, port); + at91_port->suspended = 0; } return 0; } +#else +#define at91_serial_suspend NULL +#define at91_serial_resume NULL +#endif -static void __exit at91_serial_exit(void) +static int __devinit at91_serial_probe(struct platform_device *pdev) { - int i; + struct at91_uart_port *port; + int ret; - for (i = 0; i < AT91_NR_UART; i++) { - if (at91_serial_map[i] >= 0) - uart_remove_one_port(&at91_uart, &at91_ports[i]); - } + port = &at91_ports[pdev->id]; + at91_init_port(port, pdev); + ret = uart_add_one_port(&at91_uart, &port->uart); + if (!ret) { + device_init_wakeup(&pdev->dev, 1); + platform_set_drvdata(pdev, port); + } + + return ret; +} + +static int __devexit at91_serial_remove(struct platform_device *pdev) +{ + struct uart_port *port = platform_get_drvdata(pdev); + struct at91_uart_port *at91_port = (struct at91_uart_port *) port; + int ret = 0; + + clk_disable(at91_port->clk); + clk_put(at91_port->clk); + + device_init_wakeup(&pdev->dev, 0); + platform_set_drvdata(pdev, NULL); + + if (port) { + ret = uart_remove_one_port(&at91_uart, port); + kfree(port); + } + + return ret; +} + +static struct platform_driver at91_serial_driver = { + .probe = at91_serial_probe, + .remove = __devexit_p(at91_serial_remove), + .suspend = at91_serial_suspend, + .resume = at91_serial_resume, + .driver = { + .name = "at91_usart", + .owner = THIS_MODULE, + }, +}; + +static int __init at91_serial_init(void) +{ + int ret; + + ret = uart_register_driver(&at91_uart); + if (ret) + return ret; + + ret = platform_driver_register(&at91_serial_driver); + if (ret) + uart_unregister_driver(&at91_uart); + + return ret; +} + +static void __exit at91_serial_exit(void) +{ + platform_driver_unregister(&at91_serial_driver); uart_unregister_driver(&at91_uart); } diff --git a/include/asm-arm/mach/serial_at91.h b/include/asm-arm/mach/serial_at91.h new file mode 100644 index 000000000000..18bc4e00e475 --- /dev/null +++ b/include/asm-arm/mach/serial_at91.h @@ -0,0 +1,34 @@ +/* + * linux/include/asm-arm/mach/serial_at91.h + * + * Based on serial_sa1100.h by Nicolas Pitre + * + * Copyright (C) 2002 ATMEL Rousset + * + * Low level machine dependent UART functions. + */ +#include + +struct uart_port; + +/* + * This is a temporary structure for registering these + * functions; it is intended to be discarded after boot. + */ +struct at91_port_fns { + void (*set_mctrl)(struct uart_port *, u_int); + u_int (*get_mctrl)(struct uart_port *); + void (*enable_ms)(struct uart_port *); + void (*pm)(struct uart_port *, u_int, u_int); + int (*set_wake)(struct uart_port *, u_int); + int (*open)(struct uart_port *); + void (*close)(struct uart_port *); +}; + +#if defined(CONFIG_SERIAL_AT91) +void at91_register_uart_fns(struct at91_port_fns *fns); +#else +#define at91_register_uart_fns(fns) do { } while (0) +#endif + + diff --git a/include/asm-arm/mach/serial_at91rm9200.h b/include/asm-arm/mach/serial_at91rm9200.h deleted file mode 100644 index 98f4b0cb883c..000000000000 --- a/include/asm-arm/mach/serial_at91rm9200.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * linux/include/asm-arm/mach/serial_at91rm9200.h - * - * Based on serial_sa1100.h by Nicolas Pitre - * - * Copyright (C) 2002 ATMEL Rousset - * - * Low level machine dependent UART functions. - */ -#include - -struct uart_port; - -/* - * This is a temporary structure for registering these - * functions; it is intended to be discarded after boot. - */ -struct at91rm9200_port_fns { - void (*set_mctrl)(struct uart_port *, u_int); - u_int (*get_mctrl)(struct uart_port *); - void (*enable_ms)(struct uart_port *); - void (*pm)(struct uart_port *, u_int, u_int); - int (*set_wake)(struct uart_port *, u_int); - int (*open)(struct uart_port *); - void (*close)(struct uart_port *); -}; - -#if defined(CONFIG_SERIAL_AT91) -void at91_register_uart_fns(struct at91rm9200_port_fns *fns); -void at91_register_uart(int idx, int port); -#else -#define at91_register_uart_fns(fns) do { } while (0) -#define at91_register_uart(idx,port) do { } while (0) -#endif - - diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index bd14858121ea..56c2a1db4a90 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -67,8 +67,8 @@ /* Parisc type numbers. */ #define PORT_MUX 48 -/* Atmel AT91RM9200 SoC */ -#define PORT_AT91RM9200 49 +/* Atmel AT91xxx SoC */ +#define PORT_AT91 49 /* Macintosh Zilog type numbers */ #define PORT_MAC_ZILOG 50 /* m68k : not yet implemented */ -- cgit v1.2.3 From 74617fb6b825ea370ae72565f7543306bc08ef6e Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Mon, 19 Jun 2006 19:57:12 +0100 Subject: [ARM] 3593/1: Add reboot and shutdown handlers for Zaurus handhelds Patch from Richard Purdie Add functionality to allow machine specific reboot handlers on ARM. Add machine specific reboot and poweroff handlers for all PXA Zaurus models. Signed-off-by: Richard Purdie Signed-off-by: Russell King --- arch/arm/kernel/process.c | 61 ++++++++++++++++++++++----------------- arch/arm/mach-pxa/corgi.c | 25 ++++++++++++++++ arch/arm/mach-pxa/poodle.c | 17 +++++++++++ arch/arm/mach-pxa/spitz.c | 25 ++++++++++++++++ arch/arm/mach-pxa/tosa.c | 25 ++++++++++++++++ include/asm-arm/arch-pxa/system.h | 1 + include/asm-arm/system.h | 3 ++ 7 files changed, 131 insertions(+), 26 deletions(-) (limited to 'include') diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 7df6e1aaa323..17c38dbf2f3c 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -71,8 +72,36 @@ static int __init hlt_setup(char *__unused) __setup("nohlt", nohlt_setup); __setup("hlt", hlt_setup); +void arm_machine_restart(char mode) +{ + /* + * Clean and disable cache, and turn off interrupts + */ + cpu_proc_fin(); + + /* + * Tell the mm system that we are going to reboot - + * we may need it to insert some 1:1 mappings so that + * soft boot works. + */ + setup_mm_for_reboot(mode); + + /* + * Now call the architecture specific reboot code. + */ + arch_reset(mode); + + /* + * Whoops - the architecture was unable to reboot. + * Tell the user! + */ + mdelay(1000); + printk("Reboot failed -- System halted\n"); + while (1); +} + /* - * The following aren't currently used. + * Function pointers to optional machine specific functions */ void (*pm_idle)(void); EXPORT_SYMBOL(pm_idle); @@ -80,6 +109,10 @@ EXPORT_SYMBOL(pm_idle); void (*pm_power_off)(void); EXPORT_SYMBOL(pm_power_off); +void (*arm_pm_restart)(char str) = arm_machine_restart; +EXPORT_SYMBOL_GPL(arm_pm_restart); + + /* * This is our default idle handler. We need to disable * interrupts here to ensure we don't miss a wakeup call. @@ -151,33 +184,9 @@ void machine_power_off(void) pm_power_off(); } - void machine_restart(char * __unused) { - /* - * Clean and disable cache, and turn off interrupts - */ - cpu_proc_fin(); - - /* - * Tell the mm system that we are going to reboot - - * we may need it to insert some 1:1 mappings so that - * soft boot works. - */ - setup_mm_for_reboot(reboot_mode); - - /* - * Now call the architecture specific reboot code. - */ - arch_reset(reboot_mode); - - /* - * Whoops - the architecture was unable to reboot. - * Tell the user! - */ - mdelay(1000); - printk("Reboot failed -- System halted\n"); - while (1); + arm_pm_restart(reboot_mode); } void __show_regs(struct pt_regs *regs) diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c index d6d726036361..bf6648a83901 100644 --- a/arch/arm/mach-pxa/corgi.c +++ b/arch/arm/mach-pxa/corgi.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -26,6 +27,7 @@ #include #include #include +#include #include #include @@ -310,8 +312,31 @@ static struct platform_device *devices[] __initdata = { &corgiled_device, }; +static void corgi_poweroff(void) +{ + RCSR = RCSR_HWR | RCSR_WDR | RCSR_SMR | RCSR_GPR; + + if (!machine_is_corgi()) + /* Green LED off tells the bootloader to halt */ + reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_LED_GREEN); + arm_machine_restart('h'); +} + +static void corgi_restart(char mode) +{ + RCSR = RCSR_HWR | RCSR_WDR | RCSR_SMR | RCSR_GPR; + + if (!machine_is_corgi()) + /* Green LED on tells the bootloader to reboot */ + set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_LED_GREEN); + arm_machine_restart('h'); +} + static void __init corgi_init(void) { + pm_power_off = corgi_poweroff; + arm_pm_restart = corgi_restart; + /* setup sleep mode values */ PWER = 0x00000002; PFER = 0x00000000; diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c index a042473deedd..1d516d317e89 100644 --- a/arch/arm/mach-pxa/poodle.c +++ b/arch/arm/mach-pxa/poodle.c @@ -18,11 +18,13 @@ #include #include #include +#include #include #include #include #include +#include #include #include @@ -247,10 +249,25 @@ static struct platform_device *devices[] __initdata = { &poodle_scoop_device, }; +static void poodle_poweroff(void) +{ + RCSR = RCSR_HWR | RCSR_WDR | RCSR_SMR | RCSR_GPR; + arm_machine_restart('h'); +} + +static void poodle_restart(char mode) +{ + RCSR = RCSR_HWR | RCSR_WDR | RCSR_SMR | RCSR_GPR; + arm_machine_restart('h'); +} + static void __init poodle_init(void) { int ret = 0; + pm_power_off = poodle_poweroff; + arm_pm_restart = poodle_restart; + /* setup sleep mode values */ PWER = 0x00000002; PFER = 0x00000000; diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c index 44bcb8097c7a..eb9937f6f5cd 100644 --- a/arch/arm/mach-pxa/spitz.c +++ b/arch/arm/mach-pxa/spitz.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -27,6 +28,7 @@ #include #include #include +#include #include #include @@ -432,8 +434,31 @@ static struct platform_device *devices[] __initdata = { &spitzled_device, }; +static void spitz_poweroff(void) +{ + RCSR = RCSR_HWR | RCSR_WDR | RCSR_SMR | RCSR_GPR; + + pxa_gpio_mode(SPITZ_GPIO_ON_RESET | GPIO_OUT); + GPSR(SPITZ_GPIO_ON_RESET) = GPIO_bit(SPITZ_GPIO_ON_RESET); + + mdelay(1000); + arm_machine_restart('h'); +} + +static void spitz_restart(char mode) +{ + /* Bootloader magic for a reboot */ + if((MSC0 & 0xffff0000) == 0x7ff00000) + MSC0 = (MSC0 & 0xffff) | 0x7ee00000; + + spitz_poweroff(); +} + static void __init common_init(void) { + pm_power_off = spitz_poweroff; + arm_pm_restart = spitz_restart; + PMCR = 0x00; /* setup sleep mode values */ diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c index 76c0e7f0a219..afa223b9e7a2 100644 --- a/arch/arm/mach-pxa/tosa.c +++ b/arch/arm/mach-pxa/tosa.c @@ -19,12 +19,14 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -266,8 +268,31 @@ static struct platform_device *devices[] __initdata = { &tosaled_device, }; +static void tosa_poweroff(void) +{ + RCSR = RCSR_HWR | RCSR_WDR | RCSR_SMR | RCSR_GPR; + + pxa_gpio_mode(TOSA_GPIO_ON_RESET | GPIO_OUT); + GPSR(TOSA_GPIO_ON_RESET) = GPIO_bit(TOSA_GPIO_ON_RESET); + + mdelay(1000); + arm_machine_restart('h'); +} + +static void tosa_restart(char mode) +{ + /* Bootloader magic for a reboot */ + if((MSC0 & 0xffff0000) == 0x7ff00000) + MSC0 = (MSC0 & 0xffff) | 0x7ee00000; + + tosa_poweroff(); +} + static void __init tosa_init(void) { + pm_power_off = tosa_poweroff; + arm_pm_restart = tosa_restart; + pxa_gpio_mode(TOSA_GPIO_ON_RESET | GPIO_IN); pxa_gpio_mode(TOSA_GPIO_TC6393_INT | GPIO_IN); pxa_gpio_mode(TOSA_GPIO_USB_IN | GPIO_IN); diff --git a/include/asm-arm/arch-pxa/system.h b/include/asm-arm/arch-pxa/system.h index 840a46bfbc54..1d56a3ef89fd 100644 --- a/include/asm-arm/arch-pxa/system.h +++ b/include/asm-arm/arch-pxa/system.h @@ -10,6 +10,7 @@ * published by the Free Software Foundation. */ +#include #include "hardware.h" #include "pxa-regs.h" diff --git a/include/asm-arm/system.h b/include/asm-arm/system.h index 7c9568d30307..e6b762b31488 100644 --- a/include/asm-arm/system.h +++ b/include/asm-arm/system.h @@ -108,6 +108,9 @@ extern void __show_regs(struct pt_regs *); extern int cpu_architecture(void); extern void cpu_init(void); +void arm_machine_restart(char mode); +extern void (*arm_pm_restart)(char str); + /* * Intel's XScale3 core supports some v6 features (supersections, L2) * but advertises itself as v5 as it does not support the v6 ISA. For -- cgit v1.2.3 From 88660351cb6daa85baf9700f12dff3af564dc14a Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Mon, 19 Jun 2006 19:58:51 +0100 Subject: [ARM] 3561/1: Poodle: Correct the MMC/SD power control Patch from Richard Purdie Correct the Poodle power control for the MMC/SD port. Also add write protection switch support. Signed-off-by: Richard Purdie Signed-off-by: Russell King --- arch/arm/mach-pxa/poodle.c | 22 ++++++++++++++++++---- include/asm-arm/arch-pxa/poodle.h | 2 ++ 2 files changed, 20 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c index 1d516d317e89..234877a09dfb 100644 --- a/arch/arm/mach-pxa/poodle.c +++ b/arch/arm/mach-pxa/poodle.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -143,7 +144,9 @@ static int poodle_mci_init(struct device *dev, irqreturn_t (*poodle_detect_int)( pxa_gpio_mode(GPIO6_MMCCLK_MD); pxa_gpio_mode(GPIO8_MMCCS0_MD); pxa_gpio_mode(POODLE_GPIO_nSD_DETECT | GPIO_IN); + pxa_gpio_mode(POODLE_GPIO_nSD_WP | GPIO_IN); pxa_gpio_mode(POODLE_GPIO_SD_PWR | GPIO_OUT); + pxa_gpio_mode(POODLE_GPIO_SD_PWR1 | GPIO_OUT); poodle_mci_platform_data.detect_delay = msecs_to_jiffies(250); @@ -162,12 +165,22 @@ static void poodle_mci_setpower(struct device *dev, unsigned int vdd) { struct pxamci_platform_data* p_d = dev->platform_data; - if (( 1 << vdd) & p_d->ocr_mask) - GPSR1 = GPIO_bit(POODLE_GPIO_SD_PWR); - else - GPCR1 = GPIO_bit(POODLE_GPIO_SD_PWR); + if (( 1 << vdd) & p_d->ocr_mask) { + GPSR(POODLE_GPIO_SD_PWR) = GPIO_bit(POODLE_GPIO_SD_PWR); + mdelay(2); + GPSR(POODLE_GPIO_SD_PWR1) = GPIO_bit(POODLE_GPIO_SD_PWR1); + } else { + GPCR(POODLE_GPIO_SD_PWR1) = GPIO_bit(POODLE_GPIO_SD_PWR1); + GPCR(POODLE_GPIO_SD_PWR) = GPIO_bit(POODLE_GPIO_SD_PWR); + } +} + +static int poodle_mci_get_ro(struct device *dev) +{ + return GPLR(POODLE_GPIO_nSD_WP) & GPIO_bit(POODLE_GPIO_nSD_WP); } + static void poodle_mci_exit(struct device *dev, void *data) { free_irq(POODLE_IRQ_GPIO_nSD_DETECT, data); @@ -176,6 +189,7 @@ static void poodle_mci_exit(struct device *dev, void *data) static struct pxamci_platform_data poodle_mci_platform_data = { .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, .init = poodle_mci_init, + .get_ro = poodle_mci_get_ro, .setpower = poodle_mci_setpower, .exit = poodle_mci_exit, }; diff --git a/include/asm-arm/arch-pxa/poodle.h b/include/asm-arm/arch-pxa/poodle.h index 6b5ac5144e70..6079e0aa1ab9 100644 --- a/include/asm-arm/arch-pxa/poodle.h +++ b/include/asm-arm/arch-pxa/poodle.h @@ -31,6 +31,7 @@ #define POODLE_GPIO_CF_CD (14) #define POODLE_GPIO_CF_STSCHG (14) #define POODLE_GPIO_SD_PWR (33) +#define POODLE_GPIO_SD_PWR1 (3) #define POODLE_GPIO_nSD_CLK (6) #define POODLE_GPIO_nSD_WP (7) #define POODLE_GPIO_nSD_INT (8) @@ -42,6 +43,7 @@ #define POODLE_GPIO_BYPASS_ON (36) #define POODLE_GPIO_CHRG_ON (38) #define POODLE_GPIO_CHRG_FULL (16) +#define POODLE_GPIO_DISCHARGE_ON (42) /* Enable battery discharge */ /* PXA GPIOs */ #define POODLE_IRQ_GPIO_ON_KEY IRQ_GPIO(0) -- cgit v1.2.3 From f8703dc8cb10eca7f6fe6ef364d8e106fe07f034 Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Mon, 19 Jun 2006 19:58:52 +0100 Subject: [ARM] 3564/1: sharpsl_pm: Abstract some machine specific parameters Patch from Richard Purdie Abstract some machine specific parameters from the sharpsl_pm core into the machine specific drivers. This allows the core to support tosa/poodle. Signed-off-by: Richard Purdie Signed-off-by: Russell King --- arch/arm/common/sharpsl_pm.c | 28 +++++++++++----------------- arch/arm/mach-pxa/corgi_pm.c | 23 ++++++++++++++++++++--- arch/arm/mach-pxa/sharpsl_pm.c | 7 +++++-- arch/arm/mach-pxa/spitz_pm.c | 15 +++++++++++++++ include/asm-arm/hardware/sharpsl_pm.h | 11 +++++++++++ 5 files changed, 62 insertions(+), 22 deletions(-) (limited to 'include') diff --git a/arch/arm/common/sharpsl_pm.c b/arch/arm/common/sharpsl_pm.c index 3cd8c9ee4510..045e37e07330 100644 --- a/arch/arm/common/sharpsl_pm.c +++ b/arch/arm/common/sharpsl_pm.c @@ -49,13 +49,6 @@ #define SHARPSL_CHARGE_CO_CHECK_TIME 5 /* 5 msec */ #define SHARPSL_CHARGE_RETRY_CNT 1 /* eqv. 10 min */ -#define SHARPSL_CHARGE_ON_VOLT 0x99 /* 2.9V */ -#define SHARPSL_CHARGE_ON_TEMP 0xe0 /* 2.9V */ -#define SHARPSL_CHARGE_ON_ACIN_HIGH 0x9b /* 6V */ -#define SHARPSL_CHARGE_ON_ACIN_LOW 0x34 /* 2V */ -#define SHARPSL_FATAL_ACIN_VOLT 182 /* 3.45V */ -#define SHARPSL_FATAL_NOACIN_VOLT 170 /* 3.40V */ - /* * Prototypes */ @@ -82,12 +75,13 @@ DEFINE_LED_TRIGGER(sharpsl_charge_led_trigger); static int get_percentage(int voltage) { int i = sharpsl_pm.machinfo->bat_levels - 1; + int bl_status = sharpsl_pm.machinfo->backlight_get_status ? sharpsl_pm.machinfo->backlight_get_status() : 0; struct battery_thresh *thresh; if (sharpsl_pm.charge_mode == CHRG_ON) - thresh=sharpsl_pm.machinfo->bat_levels_acin; + thresh = bl_status ? sharpsl_pm.machinfo->bat_levels_acin_bl : sharpsl_pm.machinfo->bat_levels_acin; else - thresh=sharpsl_pm.machinfo->bat_levels_noac; + thresh = bl_status ? sharpsl_pm.machinfo->bat_levels_noac_bl : sharpsl_pm.machinfo->bat_levels_noac; while (i > 0 && (voltage > thresh[i].voltage)) i--; @@ -131,7 +125,7 @@ static void sharpsl_battery_thread(void *private_) sharpsl_pm.battstat.ac_status = (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN) ? APM_AC_ONLINE : APM_AC_OFFLINE); /* Corgi cannot confirm when battery fully charged so periodically kick! */ - if (machine_is_corgi() && (sharpsl_pm.charge_mode == CHRG_ON) + if (!sharpsl_pm.machinfo->batfull_irq && (sharpsl_pm.charge_mode == CHRG_ON) && time_after(jiffies, sharpsl_pm.charge_start_time + SHARPSL_CHARGE_ON_TIME_INTERVAL)) schedule_work(&toggle_charger); @@ -166,11 +160,11 @@ static void sharpsl_battery_thread(void *private_) && ((sharpsl_pm.battstat.mainbat_status == APM_BATTERY_STATUS_LOW) || (sharpsl_pm.battstat.mainbat_status == APM_BATTERY_STATUS_CRITICAL))) { if (!(sharpsl_pm.flags & SHARPSL_BL_LIMIT)) { - corgibl_limit_intensity(1); + sharpsl_pm.machinfo->backlight_limit(1); sharpsl_pm.flags |= SHARPSL_BL_LIMIT; } } else if (sharpsl_pm.flags & SHARPSL_BL_LIMIT) { - corgibl_limit_intensity(0); + sharpsl_pm.machinfo->backlight_limit(0); sharpsl_pm.flags &= ~SHARPSL_BL_LIMIT; } @@ -418,7 +412,7 @@ static int sharpsl_check_battery_temp(void) val = get_select_val(buff); dev_dbg(sharpsl_pm.dev, "Temperature: %d\n", val); - if (val > SHARPSL_CHARGE_ON_TEMP) + if (val > sharpsl_pm.machinfo->charge_on_temp) return -1; return 0; @@ -450,7 +444,7 @@ static int sharpsl_check_battery_voltage(void) val = get_select_val(buff); dev_dbg(sharpsl_pm.dev, "Battery Voltage: %d\n", val); - if (val < SHARPSL_CHARGE_ON_VOLT) + if (val < sharpsl_pm.machinfo->charge_on_volt) return -1; return 0; @@ -468,7 +462,7 @@ static int sharpsl_ac_check(void) temp = get_select_val(buff); dev_dbg(sharpsl_pm.dev, "AC Voltage: %d\n",temp); - if ((temp > SHARPSL_CHARGE_ON_ACIN_HIGH) || (temp < SHARPSL_CHARGE_ON_ACIN_LOW)) { + if ((temp > sharpsl_pm.machinfo->charge_acin_high) || (temp < sharpsl_pm.machinfo->charge_acin_low)) { dev_err(sharpsl_pm.dev, "Error: AC check failed.\n"); return -1; } @@ -627,8 +621,8 @@ static int sharpsl_fatal_check(void) temp = get_select_val(buff); dev_dbg(sharpsl_pm.dev, "sharpsl_fatal_check: acin: %d, discharge voltage: %d, no discharge: %d\n", acin, temp, sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT)); - if ((acin && (temp < SHARPSL_FATAL_ACIN_VOLT)) || - (!acin && (temp < SHARPSL_FATAL_NOACIN_VOLT))) + if ((acin && (temp < sharpsl_pm.machinfo->fatal_acin_volt)) || + (!acin && (temp < sharpsl_pm.machinfo->fatal_noacin_volt))) return -1; return 0; } diff --git a/arch/arm/mach-pxa/corgi_pm.c b/arch/arm/mach-pxa/corgi_pm.c index 7a1ab73e9e10..4c3de4008a43 100644 --- a/arch/arm/mach-pxa/corgi_pm.c +++ b/arch/arm/mach-pxa/corgi_pm.c @@ -27,6 +27,13 @@ #include #include "sharpsl.h" +#define SHARPSL_CHARGE_ON_VOLT 0x99 /* 2.9V */ +#define SHARPSL_CHARGE_ON_TEMP 0xe0 /* 2.9V */ +#define SHARPSL_CHARGE_ON_ACIN_HIGH 0x9b /* 6V */ +#define SHARPSL_CHARGE_ON_ACIN_LOW 0x34 /* 2V */ +#define SHARPSL_FATAL_ACIN_VOLT 182 /* 3.45V */ +#define SHARPSL_FATAL_NOACIN_VOLT 170 /* 3.40V */ + static void corgi_charger_init(void) { pxa_gpio_mode(CORGI_GPIO_ADC_TEMP_ON | GPIO_OUT); @@ -195,9 +202,16 @@ static struct sharpsl_charger_machinfo corgi_pm_machinfo = { .read_devdata = corgipm_read_devdata, .charger_wakeup = corgi_charger_wakeup, .should_wakeup = corgi_should_wakeup, - .bat_levels = 40, - .bat_levels_noac = spitz_battery_levels_noac, - .bat_levels_acin = spitz_battery_levels_acin, + .backlight_limit = corgibl_limit_intensity, + .charge_on_volt = SHARPSL_CHARGE_ON_VOLT, + .charge_on_temp = SHARPSL_CHARGE_ON_TEMP, + .charge_acin_high = SHARPSL_CHARGE_ON_ACIN_HIGH, + .charge_acin_low = SHARPSL_CHARGE_ON_ACIN_LOW, + .fatal_acin_volt = SHARPSL_FATAL_ACIN_VOLT, + .fatal_noacin_volt= SHARPSL_FATAL_NOACIN_VOLT, + .bat_levels = 40, + .bat_levels_noac = spitz_battery_levels_noac, + .bat_levels_acin = spitz_battery_levels_acin, .status_high_acin = 188, .status_low_acin = 178, .status_high_noac = 185, @@ -214,6 +228,9 @@ static int __devinit corgipm_init(void) if (!corgipm_device) return -ENOMEM; + if (!machine_is_corgi()) + corgi_pm_machinfo.batfull_irq = 1; + corgipm_device->dev.platform_data = &corgi_pm_machinfo; ret = platform_device_add(corgipm_device); diff --git a/arch/arm/mach-pxa/sharpsl_pm.c b/arch/arm/mach-pxa/sharpsl_pm.c index 6d402b262d8a..0f1648780c41 100644 --- a/arch/arm/mach-pxa/sharpsl_pm.c +++ b/arch/arm/mach-pxa/sharpsl_pm.c @@ -128,6 +128,9 @@ struct battery_thresh spitz_battery_levels_noac[] = { */ int sharpsl_pm_pxa_read_max1111(int channel) { + if (machine_is_tosa()) // Ugly, better move this function into another module + return 0; + return corgi_ssp_max1111_get((channel << MAXCTRL_SEL_SH) | MAXCTRL_PD0 | MAXCTRL_PD1 | MAXCTRL_SGL | MAXCTRL_UNI | MAXCTRL_STR); } @@ -156,7 +159,7 @@ void sharpsl_pm_pxa_init(void) else set_irq_type(IRQ_GPIO(sharpsl_pm.machinfo->gpio_fatal),IRQT_FALLING); } - if (!machine_is_corgi()) + if (sharpsl_pm.machinfo->batfull_irq) { /* Register interrupt handler. */ if (request_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batfull), sharpsl_chrg_full_isr, SA_INTERRUPT, "CO", sharpsl_chrg_full_isr)) { @@ -174,6 +177,6 @@ void sharpsl_pm_pxa_remove(void) if (sharpsl_pm.machinfo->gpio_fatal) free_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_fatal), sharpsl_fatal_isr); - if (!machine_is_corgi()) + if (sharpsl_pm.machinfo->batfull_irq) free_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batfull), sharpsl_chrg_full_isr); } diff --git a/arch/arm/mach-pxa/spitz_pm.c b/arch/arm/mach-pxa/spitz_pm.c index 5e5bdc898482..40be833079c7 100644 --- a/arch/arm/mach-pxa/spitz_pm.c +++ b/arch/arm/mach-pxa/spitz_pm.c @@ -27,6 +27,13 @@ #include #include "sharpsl.h" +#define SHARPSL_CHARGE_ON_VOLT 0x99 /* 2.9V */ +#define SHARPSL_CHARGE_ON_TEMP 0xe0 /* 2.9V */ +#define SHARPSL_CHARGE_ON_ACIN_HIGH 0x9b /* 6V */ +#define SHARPSL_CHARGE_ON_ACIN_LOW 0x34 /* 2V */ +#define SHARPSL_FATAL_ACIN_VOLT 182 /* 3.45V */ +#define SHARPSL_FATAL_NOACIN_VOLT 170 /* 3.40V */ + static int spitz_last_ac_status; static void spitz_charger_init(void) @@ -190,6 +197,7 @@ struct sharpsl_charger_machinfo spitz_pm_machinfo = { .gpio_batlock = SPITZ_GPIO_BAT_COVER, .gpio_acin = SPITZ_GPIO_AC_IN, .gpio_batfull = SPITZ_GPIO_CHRG_FULL, + .batfull_irq = 1, .gpio_fatal = SPITZ_GPIO_FATAL_BAT, .discharge = spitz_discharge, .discharge1 = spitz_discharge1, @@ -200,6 +208,13 @@ struct sharpsl_charger_machinfo spitz_pm_machinfo = { .read_devdata = spitzpm_read_devdata, .charger_wakeup = spitz_charger_wakeup, .should_wakeup = spitz_should_wakeup, + .backlight_limit = corgibl_limit_intensity, + .charge_on_volt = SHARPSL_CHARGE_ON_VOLT, + .charge_on_temp = SHARPSL_CHARGE_ON_TEMP, + .charge_acin_high = SHARPSL_CHARGE_ON_ACIN_HIGH, + .charge_acin_low = SHARPSL_CHARGE_ON_ACIN_LOW, + .fatal_acin_volt = SHARPSL_FATAL_ACIN_VOLT, + .fatal_noacin_volt= SHARPSL_FATAL_NOACIN_VOLT, .bat_levels = 40, .bat_levels_noac = spitz_battery_levels_noac, .bat_levels_acin = spitz_battery_levels_acin, diff --git a/include/asm-arm/hardware/sharpsl_pm.h b/include/asm-arm/hardware/sharpsl_pm.h index 36983e5f3665..ecf15b83956f 100644 --- a/include/asm-arm/hardware/sharpsl_pm.h +++ b/include/asm-arm/hardware/sharpsl_pm.h @@ -16,6 +16,7 @@ struct sharpsl_charger_machinfo { void (*exit)(void); int gpio_acin; int gpio_batfull; + int batfull_irq; int gpio_batlock; int gpio_fatal; void (*discharge)(int); @@ -34,9 +35,19 @@ struct sharpsl_charger_machinfo { #define SHARPSL_STATUS_FATAL 7 unsigned long (*charger_wakeup)(void); int (*should_wakeup)(unsigned int resume_on_alarm); + void (*backlight_limit)(int); + int (*backlight_get_status) (void); + int charge_on_volt; + int charge_on_temp; + int charge_acin_high; + int charge_acin_low; + int fatal_acin_volt; + int fatal_noacin_volt; int bat_levels; struct battery_thresh *bat_levels_noac; struct battery_thresh *bat_levels_acin; + struct battery_thresh *bat_levels_noac_bl; + struct battery_thresh *bat_levels_acin_bl; int status_high_acin; int status_low_acin; int status_high_noac; -- cgit v1.2.3 From faed568413e89f87cd60aa8b292cc4b9996bae42 Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Mon, 19 Jun 2006 20:46:05 +0100 Subject: [ARM] 3594/1: Poodle: Add touchscreen support + other updates Patch from Richard Purdie Poodle Updates: * Update corgi_ssp to make the GPIO chip selects optional * Enable corgi_ssp for use by poodle * Add corgi touchscreen platform device for poodle * Export locomo platform device. * Set framebuffer device parent correctly Signed-off-by: Richard Purdie Signed-off-by: Russell King --- arch/arm/mach-pxa/Kconfig | 1 + arch/arm/mach-pxa/Makefile | 2 +- arch/arm/mach-pxa/corgi_ssp.c | 42 ++++++++++++++++-------- arch/arm/mach-pxa/poodle.c | 69 +++++++++++++++++++++++++++++++++++++-- include/asm-arm/arch-pxa/poodle.h | 2 ++ 5 files changed, 99 insertions(+), 17 deletions(-) (limited to 'include') diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig index 0104fd142e70..ea5137f319c4 100644 --- a/arch/arm/mach-pxa/Kconfig +++ b/arch/arm/mach-pxa/Kconfig @@ -61,6 +61,7 @@ config MACH_POODLE bool "Enable Sharp SL-5600 (Poodle) Support" depends PXA_SHARPSL_25x select SHARP_LOCOMO + select PXA_SSP config MACH_CORGI bool "Enable Sharp SL-C700 (Corgi) Support" diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile index 4e8a983e2b83..1610690be419 100644 --- a/arch/arm/mach-pxa/Makefile +++ b/arch/arm/mach-pxa/Makefile @@ -15,7 +15,7 @@ obj-$(CONFIG_ARCH_PXA_IDP) += idp.o obj-$(CONFIG_PXA_SHARP_C7xx) += corgi.o corgi_ssp.o corgi_lcd.o sharpsl_pm.o corgi_pm.o obj-$(CONFIG_PXA_SHARP_Cxx00) += spitz.o corgi_ssp.o corgi_lcd.o sharpsl_pm.o spitz_pm.o obj-$(CONFIG_MACH_AKITA) += akita-ioexp.o -obj-$(CONFIG_MACH_POODLE) += poodle.o +obj-$(CONFIG_MACH_POODLE) += poodle.o corgi_ssp.o obj-$(CONFIG_MACH_TOSA) += tosa.o # Support for blinky lights diff --git a/arch/arm/mach-pxa/corgi_ssp.c b/arch/arm/mach-pxa/corgi_ssp.c index 8a25a1c8019f..f9421318cb7a 100644 --- a/arch/arm/mach-pxa/corgi_ssp.c +++ b/arch/arm/mach-pxa/corgi_ssp.c @@ -50,12 +50,14 @@ unsigned long corgi_ssp_ads7846_putget(ulong data) unsigned long ret,flag; spin_lock_irqsave(&corgi_ssp_lock, flag); - GPCR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846); + if (ssp_machinfo->cs_ads7846 >= 0) + GPCR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846); ssp_write_word(&corgi_ssp_dev,data); ret = ssp_read_word(&corgi_ssp_dev); - GPSR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846); + if (ssp_machinfo->cs_ads7846 >= 0) + GPSR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846); spin_unlock_irqrestore(&corgi_ssp_lock, flag); return ret; @@ -68,12 +70,14 @@ unsigned long corgi_ssp_ads7846_putget(ulong data) void corgi_ssp_ads7846_lock(void) { spin_lock(&corgi_ssp_lock); - GPCR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846); + if (ssp_machinfo->cs_ads7846 >= 0) + GPCR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846); } void corgi_ssp_ads7846_unlock(void) { - GPSR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846); + if (ssp_machinfo->cs_ads7846 >= 0) + GPSR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846); spin_unlock(&corgi_ssp_lock); } @@ -110,11 +114,13 @@ unsigned long corgi_ssp_dac_put(ulong data) ssp_config(&corgi_ssp_dev, (SSCR0_Motorola | (SSCR0_DSS & 0x07 )), sscr1, 0, SSCR0_SerClkDiv(ssp_machinfo->clk_lcdcon)); ssp_enable(&corgi_ssp_dev); - GPCR(ssp_machinfo->cs_lcdcon) = GPIO_bit(ssp_machinfo->cs_lcdcon); + if (ssp_machinfo->cs_lcdcon >= 0) + GPCR(ssp_machinfo->cs_lcdcon) = GPIO_bit(ssp_machinfo->cs_lcdcon); ssp_write_word(&corgi_ssp_dev,data); /* Read null data back from device to prevent SSP overflow */ ssp_read_word(&corgi_ssp_dev); - GPSR(ssp_machinfo->cs_lcdcon) = GPIO_bit(ssp_machinfo->cs_lcdcon); + if (ssp_machinfo->cs_lcdcon >= 0) + GPSR(ssp_machinfo->cs_lcdcon) = GPIO_bit(ssp_machinfo->cs_lcdcon); ssp_disable(&corgi_ssp_dev); ssp_config(&corgi_ssp_dev, (SSCR0_National | (SSCR0_DSS & 0x0b )), 0, 0, SSCR0_SerClkDiv(ssp_machinfo->clk_ads7846)); @@ -147,7 +153,8 @@ int corgi_ssp_max1111_get(ulong data) int voltage,voltage1,voltage2; spin_lock_irqsave(&corgi_ssp_lock, flag); - GPCR(ssp_machinfo->cs_max1111) = GPIO_bit(ssp_machinfo->cs_max1111); + if (ssp_machinfo->cs_max1111 >= 0) + GPCR(ssp_machinfo->cs_max1111) = GPIO_bit(ssp_machinfo->cs_max1111); ssp_disable(&corgi_ssp_dev); ssp_config(&corgi_ssp_dev, (SSCR0_Motorola | (SSCR0_DSS & 0x07 )), 0, 0, SSCR0_SerClkDiv(ssp_machinfo->clk_max1111)); ssp_enable(&corgi_ssp_dev); @@ -169,7 +176,8 @@ int corgi_ssp_max1111_get(ulong data) ssp_disable(&corgi_ssp_dev); ssp_config(&corgi_ssp_dev, (SSCR0_National | (SSCR0_DSS & 0x0b )), 0, 0, SSCR0_SerClkDiv(ssp_machinfo->clk_ads7846)); ssp_enable(&corgi_ssp_dev); - GPSR(ssp_machinfo->cs_max1111) = GPIO_bit(ssp_machinfo->cs_max1111); + if (ssp_machinfo->cs_max1111 >= 0) + GPSR(ssp_machinfo->cs_max1111) = GPIO_bit(ssp_machinfo->cs_max1111); spin_unlock_irqrestore(&corgi_ssp_lock, flag); if (voltage1 & 0xc0 || voltage2 & 0x3f) @@ -196,9 +204,12 @@ static int __init corgi_ssp_probe(struct platform_device *dev) int ret; /* Chip Select - Disable All */ - pxa_gpio_mode(ssp_machinfo->cs_lcdcon | GPIO_OUT | GPIO_DFLT_HIGH); - pxa_gpio_mode(ssp_machinfo->cs_max1111 | GPIO_OUT | GPIO_DFLT_HIGH); - pxa_gpio_mode(ssp_machinfo->cs_ads7846 | GPIO_OUT | GPIO_DFLT_HIGH); + if (ssp_machinfo->cs_lcdcon >= 0) + pxa_gpio_mode(ssp_machinfo->cs_lcdcon | GPIO_OUT | GPIO_DFLT_HIGH); + if (ssp_machinfo->cs_max1111 >= 0) + pxa_gpio_mode(ssp_machinfo->cs_max1111 | GPIO_OUT | GPIO_DFLT_HIGH); + if (ssp_machinfo->cs_ads7846 >= 0) + pxa_gpio_mode(ssp_machinfo->cs_ads7846 | GPIO_OUT | GPIO_DFLT_HIGH); ret = ssp_init(&corgi_ssp_dev, ssp_machinfo->port, 0); @@ -229,9 +240,12 @@ static int corgi_ssp_suspend(struct platform_device *dev, pm_message_t state) static int corgi_ssp_resume(struct platform_device *dev) { - GPSR(ssp_machinfo->cs_lcdcon) = GPIO_bit(ssp_machinfo->cs_lcdcon); /* High - Disable LCD Control/Timing Gen */ - GPSR(ssp_machinfo->cs_max1111) = GPIO_bit(ssp_machinfo->cs_max1111); /* High - Disable MAX1111*/ - GPSR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846); /* High - Disable ADS7846*/ + if (ssp_machinfo->cs_lcdcon >= 0) + GPSR(ssp_machinfo->cs_lcdcon) = GPIO_bit(ssp_machinfo->cs_lcdcon); /* High - Disable LCD Control/Timing Gen */ + if (ssp_machinfo->cs_max1111 >= 0) + GPSR(ssp_machinfo->cs_max1111) = GPIO_bit(ssp_machinfo->cs_max1111); /* High - Disable MAX1111*/ + if (ssp_machinfo->cs_ads7846 >= 0) + GPSR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846); /* High - Disable ADS7846*/ ssp_restore_state(&corgi_ssp_dev,&corgi_ssp_state); ssp_enable(&corgi_ssp_dev); diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c index 234877a09dfb..9a9fa87cea9f 100644 --- a/arch/arm/mach-pxa/poodle.c +++ b/arch/arm/mach-pxa/poodle.c @@ -37,12 +37,15 @@ #include #include #include +#include +#include #include #include #include #include "generic.h" +#include "sharpsl.h" static struct resource poodle_scoop_resources[] = { [0] = { @@ -120,13 +123,71 @@ static struct resource locomo_resources[] = { }, }; -static struct platform_device locomo_device = { +struct platform_device poodle_locomo_device = { .name = "locomo", .id = 0, .num_resources = ARRAY_SIZE(locomo_resources), .resource = locomo_resources, }; +EXPORT_SYMBOL(poodle_locomo_device); + +/* + * Poodle SSP Device + */ + +struct platform_device poodle_ssp_device = { + .name = "corgi-ssp", + .id = -1, +}; + +struct corgissp_machinfo poodle_ssp_machinfo = { + .port = 1, + .cs_lcdcon = -1, + .cs_ads7846 = -1, + .cs_max1111 = -1, + .clk_lcdcon = 2, + .clk_ads7846 = 36, + .clk_max1111 = 2, +}; + + +/* + * Poodle Touch Screen Device + */ +static struct resource poodlets_resources[] = { + [0] = { + .start = POODLE_IRQ_GPIO_TP_INT, + .end = POODLE_IRQ_GPIO_TP_INT, + .flags = IORESOURCE_IRQ, + }, +}; + +static unsigned long poodle_get_hsync_len(void) +{ + return 0; +} + +static void poodle_null_hsync(void) +{ +} + +static struct corgits_machinfo poodle_ts_machinfo = { + .get_hsync_len = poodle_get_hsync_len, + .put_hsync = poodle_null_hsync, + .wait_hsync = poodle_null_hsync, +}; + +static struct platform_device poodle_ts_device = { + .name = "corgi-ts", + .dev = { + .platform_data = &poodle_ts_machinfo, + }, + .id = -1, + .num_resources = ARRAY_SIZE(poodlets_resources), + .resource = poodlets_resources, +}; + /* * MMC/SD Device @@ -259,8 +320,10 @@ static struct pxafb_mach_info poodle_fb_info __initdata = { }; static struct platform_device *devices[] __initdata = { - &locomo_device, + &poodle_locomo_device, &poodle_scoop_device, + &poodle_ssp_device, + &poodle_ts_device, }; static void poodle_poweroff(void) @@ -319,6 +382,7 @@ static void __init poodle_init(void) GPSR1 = 0x00000000; GPSR2 = 0x00000000; + set_pxa_fb_parent(&poodle_locomo_device.dev); set_pxa_fb_info(&poodle_fb_info); pxa_gpio_mode(POODLE_GPIO_USB_PULLUP | GPIO_OUT); pxa_gpio_mode(POODLE_GPIO_IR_ON | GPIO_OUT); @@ -332,6 +396,7 @@ static void __init poodle_init(void) if (ret) { printk(KERN_WARNING "poodle: Unable to register LoCoMo device\n"); } + corgi_ssp_set_machinfo(&poodle_ssp_machinfo); } static void __init fixup_poodle(struct machine_desc *desc, diff --git a/include/asm-arm/arch-pxa/poodle.h b/include/asm-arm/arch-pxa/poodle.h index 6079e0aa1ab9..4d6a40315764 100644 --- a/include/asm-arm/arch-pxa/poodle.h +++ b/include/asm-arm/arch-pxa/poodle.h @@ -70,4 +70,6 @@ #define POODLE_SCOOP_IO_DIR ( POODLE_SCOOP_VPEN | POODLE_SCOOP_HS_OUT ) #define POODLE_SCOOP_IO_OUT ( 0 ) +extern struct platform_device poodle_locomo_device; + #endif /* __ASM_ARCH_POODLE_H */ -- cgit v1.2.3 From 48d83325b61043e3bbd24dd37b9fe433744cf330 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 19 Jun 2006 23:57:59 -0700 Subject: [NET]: Prevent multiple qdisc runs Having two or more qdisc_run's contend against each other is bad because it can induce packet reordering if the packets have to be requeued. It appears that this is an unintended consequence of relinquinshing the queue lock while transmitting. That in turn is needed for devices that spend a lot of time in their transmit routine. There are no advantages to be had as devices with queues are inherently single-threaded (the loopback device is not but then it doesn't have a queue). Even if you were to add a queue to a parallel virtual device (e.g., bolt a tbf filter in front of an ipip tunnel device), you would still want to process the queue in sequence to ensure that the packets are ordered correctly. The solution here is to steal a bit from net_device to prevent this. BTW, as qdisc_restart is no longer used by anyone as a module inside the kernel (IIRC it used to with netif_wake_queue), I have not exported the new __qdisc_run function. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- include/linux/netdevice.h | 1 + include/net/pkt_sched.h | 7 ++++--- net/sched/sch_generic.c | 11 +++++++++-- 3 files changed, 14 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index e432b743dda2..39919c882a25 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -233,6 +233,7 @@ enum netdev_state_t __LINK_STATE_RX_SCHED, __LINK_STATE_LINKWATCH_PENDING, __LINK_STATE_DORMANT, + __LINK_STATE_QDISC_RUNNING, }; diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h index b94d1ad92c4d..75b5b9333fc7 100644 --- a/include/net/pkt_sched.h +++ b/include/net/pkt_sched.h @@ -218,12 +218,13 @@ extern struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r, struct rtattr *tab); extern void qdisc_put_rtab(struct qdisc_rate_table *tab); -extern int qdisc_restart(struct net_device *dev); +extern void __qdisc_run(struct net_device *dev); static inline void qdisc_run(struct net_device *dev) { - while (!netif_queue_stopped(dev) && qdisc_restart(dev) < 0) - /* NOTHING */; + if (!netif_queue_stopped(dev) && + !test_and_set_bit(__LINK_STATE_QDISC_RUNNING, &dev->state)) + __qdisc_run(dev); } extern int tc_classify(struct sk_buff *skb, struct tcf_proto *tp, diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index b1e4c5e20ac7..d7aca8ef524a 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -90,7 +90,7 @@ void qdisc_unlock_tree(struct net_device *dev) NOTE: Called under dev->queue_lock with locally disabled BH. */ -int qdisc_restart(struct net_device *dev) +static inline int qdisc_restart(struct net_device *dev) { struct Qdisc *q = dev->qdisc; struct sk_buff *skb; @@ -179,6 +179,14 @@ requeue: return q->q.qlen; } +void __qdisc_run(struct net_device *dev) +{ + while (qdisc_restart(dev) < 0 && !netif_queue_stopped(dev)) + /* NOTHING */; + + clear_bit(__LINK_STATE_QDISC_RUNNING, &dev->state); +} + static void dev_watchdog(unsigned long arg) { struct net_device *dev = (struct net_device *)arg; @@ -620,6 +628,5 @@ EXPORT_SYMBOL(qdisc_create_dflt); EXPORT_SYMBOL(qdisc_alloc); EXPORT_SYMBOL(qdisc_destroy); EXPORT_SYMBOL(qdisc_reset); -EXPORT_SYMBOL(qdisc_restart); EXPORT_SYMBOL(qdisc_lock_tree); EXPORT_SYMBOL(qdisc_unlock_tree); -- cgit v1.2.3 From 65fd28f743be6e3e3fd8eefa9a517656636fee42 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 20 Jun 2006 00:07:52 -0700 Subject: [SCTP]: Fix unintentional change to SCTP_ASSERT when !SCTP_DEBUG A local debugging change slipped into a previous changeset. When SCTP_DEBUG is off SCTP_ASSERT should do nothing. Signed-off-by: David S. Miller --- include/net/sctp/sctp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index b2b40f951ae6..aa6033ca7cd8 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -255,7 +255,7 @@ extern int sctp_debug_flag; #define SCTP_DEBUG_PRINTK_IPADDR(whatever...) #define SCTP_ENABLE_DEBUG #define SCTP_DISABLE_DEBUG -#define SCTP_ASSERT(expr, str, func) BUG_ON(!(expr)) +#define SCTP_ASSERT(expr, str, func) #endif /* SCTP_DEBUG */ -- cgit v1.2.3 From 7202fb496af235506a3c6fea836fe4c9957f730e Mon Sep 17 00:00:00 2001 From: Bob Breuer Date: Tue, 20 Jun 2006 00:30:31 -0700 Subject: [SPARC]: Setup cpu_possible_map Setup cpu_possible_map so the secondary cpus will get started. Signed-off-by: Bob Breuer Signed-off-by: David S. Miller --- arch/sparc/kernel/setup.c | 2 ++ arch/sparc/kernel/smp.c | 30 ++++++++++++++++++++++-------- include/asm-sparc/smp.h | 8 +++++++- 3 files changed, 31 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c index 8531a8e15832..2cbf282f0d00 100644 --- a/arch/sparc/kernel/setup.c +++ b/arch/sparc/kernel/setup.c @@ -349,6 +349,8 @@ void __init setup_arch(char **cmdline_p) init_mm.context = (unsigned long) NO_CONTEXT; init_task.thread.kregs = &fake_swapper_regs; + smp_setup_cpu_possible_map(); + paging_init(); } diff --git a/arch/sparc/kernel/smp.c b/arch/sparc/kernel/smp.c index 40b42c88e6a7..d0ccb8ad1d54 100644 --- a/arch/sparc/kernel/smp.c +++ b/arch/sparc/kernel/smp.c @@ -267,22 +267,18 @@ int setup_profiling_timer(unsigned int multiplier) void __init smp_prepare_cpus(unsigned int max_cpus) { extern void smp4m_boot_cpus(void); - int i, cpuid, ncpus, extra; + int i, cpuid, extra; BUG_ON(sparc_cpu_model != sun4m); printk("Entering SMP Mode...\n"); - ncpus = 1; extra = 0; for (i = 0; !cpu_find_by_instance(i, NULL, &cpuid); i++) { - if (cpuid == boot_cpu_id) - continue; - if (cpuid < NR_CPUS && ncpus++ < max_cpus) - cpu_set(cpuid, phys_cpu_present_map); - else + if (cpuid >= NR_CPUS) extra++; } - if (max_cpus >= NR_CPUS && extra) + /* i = number of cpus */ + if (extra && max_cpus > i - extra) printk("Warning: NR_CPUS is too low to start all cpus\n"); smp_store_cpu_info(boot_cpu_id); @@ -290,6 +286,24 @@ void __init smp_prepare_cpus(unsigned int max_cpus) smp4m_boot_cpus(); } +/* Set this up early so that things like the scheduler can init + * properly. We use the same cpu mask for both the present and + * possible cpu map. + */ +void __init smp_setup_cpu_possible_map(void) +{ + int instance, mid; + + instance = 0; + while (!cpu_find_by_instance(instance, NULL, &mid)) { + if (mid < NR_CPUS) { + cpu_set(mid, phys_cpu_present_map); + cpu_set(mid, cpu_present_map); + } + instance++; + } +} + void __devinit smp_prepare_boot_cpu(void) { int cpuid = hard_smp_processor_id(); diff --git a/include/asm-sparc/smp.h b/include/asm-sparc/smp.h index 98c46e3fbe8a..c1a289327a79 100644 --- a/include/asm-sparc/smp.h +++ b/include/asm-sparc/smp.h @@ -146,6 +146,8 @@ static inline int hard_smp_processor_id(void) #define prof_multiplier(__cpu) cpu_data(__cpu).multiplier #define prof_counter(__cpu) cpu_data(__cpu).counter +void smp_setup_cpu_possible_map(void); + #endif /* !(__ASSEMBLY__) */ /* Sparc specific messages. */ @@ -162,7 +164,11 @@ static inline int hard_smp_processor_id(void) #define MBOX_IDLECPU2 0xFD #define MBOX_STOPCPU2 0xFE -#endif /* SMP */ +#else /* SMP */ + +#define smp_setup_cpu_possible_map() do { } while (0) + +#endif /* !(SMP) */ #define NO_PROC_ID 0xFF -- cgit v1.2.3 From 61fc12d8e5c94176e7c2e04a2eab4c6e36d8dd41 Mon Sep 17 00:00:00 2001 From: Bob Breuer Date: Tue, 20 Jun 2006 00:35:13 -0700 Subject: [SPARC]: Add missing rw can_lock macros Fix a link failure by adding the missing can_lock macros for the rw locks. Signed-off-by: Bob Breuer Signed-off-by: David S. Miller --- include/asm-sparc/spinlock.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include') diff --git a/include/asm-sparc/spinlock.h b/include/asm-sparc/spinlock.h index 3350c90c7869..1c75474ba1df 100644 --- a/include/asm-sparc/spinlock.h +++ b/include/asm-sparc/spinlock.h @@ -154,6 +154,9 @@ static inline int __raw_write_trylock(raw_rwlock_t *rw) #define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock) #define __raw_read_trylock(lock) generic__raw_read_trylock(lock) +#define __raw_read_can_lock(rw) (!((rw)->lock & 0xff)) +#define __raw_write_can_lock(rw) (!(rw)->lock) + #endif /* !(__ASSEMBLY__) */ #endif /* __SPARC_SPINLOCK_H */ -- cgit v1.2.3 From fd0504c3217d6d1bc8f33f53fb536299cae8feda Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 20 Jun 2006 01:20:00 -0700 Subject: [SPARC64]: Send all device interrupts via one PIL. This is the first in a series of cleanups that will hopefully allow a seamless attempt at using the generic IRQ handling infrastructure in the Linux kernel. Define PIL_DEVICE_IRQ and vector all device interrupts through there. Get rid of the ugly pil0_dummy_{bucket,desc}, instead vector the timer interrupt directly to a specific handler since the timer interrupt is the only event that will be signaled on PIL 14. The irq_worklist is now in the per-cpu trap_block[]. Signed-off-by: David S. Miller --- arch/sparc64/kernel/entry.S | 11 +-- arch/sparc64/kernel/irq.c | 163 +++++++++++++++++---------------------- arch/sparc64/kernel/sun4v_ivec.S | 13 +--- arch/sparc64/kernel/time.c | 16 +--- arch/sparc64/kernel/traps.c | 4 +- arch/sparc64/kernel/ttable.S | 10 +-- include/asm-sparc64/cpudata.h | 19 ++--- include/asm-sparc64/pil.h | 7 +- 8 files changed, 101 insertions(+), 142 deletions(-) (limited to 'include') diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S index 6d0b3ed77a02..c87365e59e71 100644 --- a/arch/sparc64/kernel/entry.S +++ b/arch/sparc64/kernel/entry.S @@ -22,6 +22,7 @@ #include #include #include +#include #define curptr g6 @@ -434,17 +435,13 @@ do_ivec: sllx %g3, 5, %g3 or %g2, %lo(ivector_table), %g2 add %g2, %g3, %g3 - ldub [%g3 + 0x04], %g4 /* pil */ - mov 1, %g2 - sllx %g2, %g4, %g2 - sllx %g4, 2, %g4 TRAP_LOAD_IRQ_WORK(%g6, %g1) - lduw [%g6 + %g4], %g5 /* g5 = irq_work(cpu, pil) */ + lduw [%g6], %g5 /* g5 = irq_work(cpu) */ stw %g5, [%g3 + 0x00] /* bucket->irq_chain = g5 */ - stw %g3, [%g6 + %g4] /* irq_work(cpu, pil) = bucket */ - wr %g2, 0x0, %set_softint + stw %g3, [%g6] /* irq_work(cpu) = bucket */ + wr %g0, 1 << PIL_DEVICE_IRQ, %set_softint retry do_ivec_xcall: mov 0x50, %g1 diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index 11e645c9ec50..0fb1738a4f3f 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c @@ -68,11 +68,7 @@ struct ino_bucket ivector_table[NUM_IVECS] __attribute__ ((aligned (SMP_CACHE_BY * access to this structure takes a TLB miss it could cause * the 5-level sparc v9 trap stack to overflow. */ -struct irq_work_struct { - unsigned int irq_worklists[16]; -}; -struct irq_work_struct __irq_work[NR_CPUS]; -#define irq_work(__cpu, __pil) &(__irq_work[(__cpu)].irq_worklists[(__pil)]) +#define irq_work(__cpu) &(trap_block[(__cpu)].irq_worklist) static struct irqaction *irq_action[NR_IRQS+1]; @@ -91,10 +87,8 @@ static void register_irq_proc (unsigned int irq); */ #define put_ino_in_irqaction(action, irq) \ action->flags &= 0xffffffffffffUL; \ - if (__bucket(irq) == &pil0_dummy_bucket) \ - action->flags |= 0xdeadUL << 48; \ - else \ - action->flags |= __irq_ino(irq) << 48; + action->flags |= __irq_ino(irq) << 48; + #define get_ino_in_irqaction(action) (action->flags >> 48) #define put_smpaff_in_irqaction(action, smpaff) (action)->mask = (smpaff) @@ -251,15 +245,6 @@ void disable_irq(unsigned int irq) } } -/* The timer is the one "weird" interrupt which is generated by - * the CPU %tick register and not by some normal vectored interrupt - * source. To handle this special case, we use this dummy INO bucket. - */ -static struct irq_desc pil0_dummy_desc; -static struct ino_bucket pil0_dummy_bucket = { - .irq_info = &pil0_dummy_desc, -}; - static void build_irq_error(const char *msg, unsigned int ino, int pil, int inofixup, unsigned long iclr, unsigned long imap, struct ino_bucket *bucket) @@ -276,15 +261,7 @@ unsigned int build_irq(int pil, int inofixup, unsigned long iclr, unsigned long struct ino_bucket *bucket; int ino; - if (pil == 0) { - if (iclr != 0UL || imap != 0UL) { - prom_printf("Invalid dummy bucket for PIL0 (%lx:%lx)\n", - iclr, imap); - prom_halt(); - } - return __irq(&pil0_dummy_bucket); - } - + BUG_ON(pil == 0); BUG_ON(tlb_type == hypervisor); /* RULE: Both must be specified in all other cases. */ @@ -371,7 +348,7 @@ static void atomic_bucket_insert(struct ino_bucket *bucket) __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate)); __asm__ __volatile__("wrpr %0, %1, %%pstate" : : "r" (pstate), "i" (PSTATE_IE)); - ent = irq_work(smp_processor_id(), bucket->pil); + ent = irq_work(smp_processor_id()); bucket->irq_chain = *ent; *ent = __irq(bucket); __asm__ __volatile__("wrpr %0, 0x0, %%pstate" : : "r" (pstate)); @@ -437,7 +414,7 @@ int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_ if (unlikely(!bucket->irq_info)) return -ENODEV; - if ((bucket != &pil0_dummy_bucket) && (irqflags & SA_SAMPLE_RANDOM)) { + if (irqflags & SA_SAMPLE_RANDOM) { /* * This function might sleep, we want to call it first, * outside of the atomic block. In SA_STATIC_ALLOC case, @@ -465,12 +442,9 @@ int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_ } bucket->flags |= IBF_ACTIVE; - pending = 0; - if (bucket != &pil0_dummy_bucket) { - pending = bucket->pending; - if (pending) - bucket->pending = 0; - } + pending = bucket->pending; + if (pending) + bucket->pending = 0; action->handler = handler; action->flags = irqflags; @@ -487,13 +461,12 @@ int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_ /* We ate the IVEC already, this makes sure it does not get lost. */ if (pending) { atomic_bucket_insert(bucket); - set_softint(1 << bucket->pil); + set_softint(1 << PIL_DEVICE_IRQ); } spin_unlock_irqrestore(&irq_action_lock, flags); - if (bucket != &pil0_dummy_bucket) - register_irq_proc(__irq_ino(irq)); + register_irq_proc(__irq_ino(irq)); #ifdef CONFIG_SMP distribute_irqs(); @@ -533,7 +506,9 @@ void free_irq(unsigned int irq, void *dev_id) { struct irqaction *action; struct ino_bucket *bucket; + struct irq_desc *desc; unsigned long flags; + int ent, i; spin_lock_irqsave(&irq_action_lock, flags); @@ -549,42 +524,39 @@ void free_irq(unsigned int irq, void *dev_id) spin_lock_irqsave(&irq_action_lock, flags); bucket = __bucket(irq); - if (bucket != &pil0_dummy_bucket) { - struct irq_desc *desc = bucket->irq_info; - int ent, i; + desc = bucket->irq_info; - for (i = 0; i < MAX_IRQ_DESC_ACTION; i++) { - struct irqaction *p = &desc->action[i]; + for (i = 0; i < MAX_IRQ_DESC_ACTION; i++) { + struct irqaction *p = &desc->action[i]; - if (p == action) { - desc->action_active_mask &= ~(1 << i); - break; - } + if (p == action) { + desc->action_active_mask &= ~(1 << i); + break; } + } - if (!desc->action_active_mask) { - unsigned long imap = bucket->imap; - - /* This unique interrupt source is now inactive. */ - bucket->flags &= ~IBF_ACTIVE; + if (!desc->action_active_mask) { + unsigned long imap = bucket->imap; - /* See if any other buckets share this bucket's IMAP - * and are still active. - */ - for (ent = 0; ent < NUM_IVECS; ent++) { - struct ino_bucket *bp = &ivector_table[ent]; - if (bp != bucket && - bp->imap == imap && - (bp->flags & IBF_ACTIVE) != 0) - break; - } + /* This unique interrupt source is now inactive. */ + bucket->flags &= ~IBF_ACTIVE; - /* Only disable when no other sub-irq levels of - * the same IMAP are active. - */ - if (ent == NUM_IVECS) - disable_irq(irq); + /* See if any other buckets share this bucket's IMAP + * and are still active. + */ + for (ent = 0; ent < NUM_IVECS; ent++) { + struct ino_bucket *bp = &ivector_table[ent]; + if (bp != bucket && + bp->imap == imap && + (bp->flags & IBF_ACTIVE) != 0) + break; } + + /* Only disable when no other sub-irq levels of + * the same IMAP are active. + */ + if (ent == NUM_IVECS) + disable_irq(irq); } spin_unlock_irqrestore(&irq_action_lock, flags); @@ -625,7 +597,7 @@ void synchronize_irq(unsigned int irq) } #endif /* CONFIG_SMP */ -static void process_bucket(int irq, struct ino_bucket *bp, struct pt_regs *regs) +static void process_bucket(struct ino_bucket *bp, struct pt_regs *regs) { struct irq_desc *desc = bp->irq_info; unsigned char flags = bp->flags; @@ -676,51 +648,54 @@ static void process_bucket(int irq, struct ino_bucket *bp, struct pt_regs *regs) /* Test and add entropy */ if (random & SA_SAMPLE_RANDOM) - add_interrupt_randomness(irq); + add_interrupt_randomness(bp->pil); } out: bp->flags &= ~IBF_INPROGRESS; } +#ifndef CONFIG_SMP +extern irqreturn_t timer_interrupt(int, void *, struct pt_regs *); + +void timer_irq(int irq, struct pt_regs *regs) +{ + unsigned long clr_mask = 1 << irq; + unsigned long tick_mask = tick_ops->softint_mask; + + if (get_softint() & tick_mask) { + irq = 0; + clr_mask = tick_mask; + } + clear_softint(clr_mask); + + irq_enter(); + kstat_this_cpu.irqs[irq]++; + timer_interrupt(irq, NULL, regs); + irq_exit(); +} +#endif + void handler_irq(int irq, struct pt_regs *regs) { struct ino_bucket *bp; int cpu = smp_processor_id(); -#ifndef CONFIG_SMP - /* - * Check for TICK_INT on level 14 softint. + /* XXX at this point we should be able to assert that + * XXX irq is PIL_DEVICE_IRQ... */ - { - unsigned long clr_mask = 1 << irq; - unsigned long tick_mask = tick_ops->softint_mask; - - if ((irq == 14) && (get_softint() & tick_mask)) { - irq = 0; - clr_mask = tick_mask; - } - clear_softint(clr_mask); - } -#else clear_softint(1 << irq); -#endif irq_enter(); - kstat_this_cpu.irqs[irq]++; /* Sliiiick... */ -#ifndef CONFIG_SMP - bp = ((irq != 0) ? - __bucket(xchg32(irq_work(cpu, irq), 0)) : - &pil0_dummy_bucket); -#else - bp = __bucket(xchg32(irq_work(cpu, irq), 0)); -#endif + bp = __bucket(xchg32(irq_work(cpu), 0)); while (bp) { struct ino_bucket *nbp = __bucket(bp->irq_chain); + kstat_this_cpu.irqs[bp->pil]++; + bp->irq_chain = 0; - process_bucket(irq, bp, regs); + process_bucket(bp, regs); bp = nbp; } irq_exit(); @@ -929,7 +904,7 @@ void init_irqwork_curcpu(void) { int cpu = hard_smp_processor_id(); - memset(__irq_work + cpu, 0, sizeof(struct irq_work_struct)); + trap_block[cpu].irq_worklist = 0; } static void __cpuinit register_one_mondo(unsigned long paddr, unsigned long type) diff --git a/arch/sparc64/kernel/sun4v_ivec.S b/arch/sparc64/kernel/sun4v_ivec.S index b49a68bdda43..f70e4774649d 100644 --- a/arch/sparc64/kernel/sun4v_ivec.S +++ b/arch/sparc64/kernel/sun4v_ivec.S @@ -5,6 +5,7 @@ #include #include +#include .text .align 32 @@ -106,19 +107,13 @@ sun4v_dev_mondo: or %g4, %lo(ivector_table), %g4 add %g4, %g3, %g4 - /* Load IRQ %pil into %g5. */ - ldub [%g4 + 0x04], %g5 - /* Insert ivector_table[] entry into __irq_work[] queue. */ - sllx %g5, 2, %g3 - lduw [%g1 + %g3], %g2 /* g2 = irq_work(cpu, pil) */ + lduw [%g1], %g2 /* g2 = irq_work(cpu) */ stw %g2, [%g4 + 0x00] /* bucket->irq_chain = g2 */ - stw %g4, [%g1 + %g3] /* irq_work(cpu, pil) = bucket */ + stw %g4, [%g1] /* irq_work(cpu) = bucket */ /* Signal the interrupt by setting (1 << pil) in %softint. */ - mov 1, %g2 - sllx %g2, %g5, %g2 - wr %g2, 0x0, %set_softint + wr %g0, 1 << PIL_DEVICE_IRQ, %set_softint sun4v_dev_mondo_queue_empty: retry diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index e55b5c6ece02..0f00a99927e9 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -457,7 +457,7 @@ static inline void timer_check_rtc(void) } } -static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs * regs) +irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs * regs) { unsigned long ticks, compare, pstate; @@ -1020,19 +1020,9 @@ static unsigned long sparc64_init_timers(void) return clock; } -static void sparc64_start_timers(irqreturn_t (*cfunc)(int, void *, struct pt_regs *)) +static void sparc64_start_timers(void) { unsigned long pstate; - int err; - - /* Register IRQ handler. */ - err = request_irq(build_irq(0, 0, 0UL, 0UL), cfunc, 0, - "timer", NULL); - - if (err) { - prom_printf("Serious problem, cannot register TICK_INT\n"); - prom_halt(); - } /* Guarantee that the following sequences execute * uninterrupted. @@ -1116,7 +1106,7 @@ void __init time_init(void) /* Now that the interpolator is registered, it is * safe to start the timer ticking. */ - sparc64_start_timers(timer_interrupt); + sparc64_start_timers(); timer_ticks_per_nsec_quotient = (((NSEC_PER_SEC << SPARC64_NSEC_PER_CYC_SHIFT) + diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c index 563db528e031..5059cbd4feee 100644 --- a/arch/sparc64/kernel/traps.c +++ b/arch/sparc64/kernel/traps.c @@ -2544,7 +2544,9 @@ void __init trap_init(void) (TRAP_PER_CPU_TSB_HUGE != offsetof(struct trap_per_cpu, tsb_huge)) || (TRAP_PER_CPU_TSB_HUGE_TEMP != - offsetof(struct trap_per_cpu, tsb_huge_temp))) + offsetof(struct trap_per_cpu, tsb_huge_temp)) || + (TRAP_PER_CPU_IRQ_WORKLIST != + offsetof(struct trap_per_cpu, irq_worklist))) trap_per_cpu_offsets_are_bolixed_dave(); if ((TSB_CONFIG_TSB != diff --git a/arch/sparc64/kernel/ttable.S b/arch/sparc64/kernel/ttable.S index 5d901519db55..ee45ca2d7a04 100644 --- a/arch/sparc64/kernel/ttable.S +++ b/arch/sparc64/kernel/ttable.S @@ -58,13 +58,11 @@ tl0_irq2: BTRAP(0x42) tl0_irq3: BTRAP(0x43) tl0_irq4: BTRAP(0x44) #endif -tl0_irq5: TRAP_IRQ(handler_irq, 5) TRAP_IRQ(handler_irq, 6) -tl0_irq7: TRAP_IRQ(handler_irq, 7) TRAP_IRQ(handler_irq, 8) -tl0_irq9: TRAP_IRQ(handler_irq, 9) TRAP_IRQ(handler_irq, 10) -tl0_irq11: TRAP_IRQ(handler_irq, 11) TRAP_IRQ(handler_irq, 12) -tl0_irq13: TRAP_IRQ(handler_irq, 13) +tl0_irq5: TRAP_IRQ(handler_irq, 5) +tl0_irq6: BTRAP(0x46) BTRAP(0x47) BTRAP(0x48) BTRAP(0x49) +tl0_irq10: BTRAP(0x4a) BTRAP(0x4b) BTRAP(0x4c) BTRAP(0x4d) #ifndef CONFIG_SMP -tl0_irq14: TRAP_IRQ(handler_irq, 14) +tl0_irq14: TRAP_IRQ(timer_irq, 14) #else tl0_irq14: TICK_SMP_IRQ #endif diff --git a/include/asm-sparc64/cpudata.h b/include/asm-sparc64/cpudata.h index 9d6a6dbaf126..f2cc9411b4c7 100644 --- a/include/asm-sparc64/cpudata.h +++ b/include/asm-sparc64/cpudata.h @@ -74,8 +74,10 @@ struct trap_per_cpu { unsigned long tsb_huge; unsigned long tsb_huge_temp; -/* Dcache line 8: Unused, needed to keep trap_block a power-of-2 in size. */ - unsigned long __pad2[4]; +/* Dcache line 8: IRQ work list, and keep trap_block a power-of-2 in size. */ + unsigned int irq_worklist; + unsigned int __pad1; + unsigned long __pad2[3]; } __attribute__((aligned(64))); extern struct trap_per_cpu trap_block[NR_CPUS]; extern void init_cur_cpu_trap(struct thread_info *); @@ -119,6 +121,7 @@ extern struct sun4v_2insn_patch_entry __sun4v_2insn_patch, #define TRAP_PER_CPU_CPU_LIST_PA 0xc8 #define TRAP_PER_CPU_TSB_HUGE 0xd0 #define TRAP_PER_CPU_TSB_HUGE_TEMP 0xd8 +#define TRAP_PER_CPU_IRQ_WORKLIST 0xe0 #define TRAP_BLOCK_SZ_SHIFT 8 @@ -171,11 +174,8 @@ extern struct sun4v_2insn_patch_entry __sun4v_2insn_patch, /* Clobbers TMP, loads local processor's IRQ work area into DEST. */ #define TRAP_LOAD_IRQ_WORK(DEST, TMP) \ - __GET_CPUID(TMP) \ - sethi %hi(__irq_work), DEST; \ - sllx TMP, 6, TMP; \ - or DEST, %lo(__irq_work), DEST; \ - add DEST, TMP, DEST; + TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ + add DEST, TRAP_PER_CPU_IRQ_WORKLIST, DEST; /* Clobbers TMP, loads DEST with current thread info pointer. */ #define TRAP_LOAD_THREAD_REG(DEST, TMP) \ @@ -211,9 +211,10 @@ extern struct sun4v_2insn_patch_entry __sun4v_2insn_patch, TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ ldx [DEST + TRAP_PER_CPU_PGD_PADDR], DEST; +/* Clobbers TMP, loads local processor's IRQ work area into DEST. */ #define TRAP_LOAD_IRQ_WORK(DEST, TMP) \ - sethi %hi(__irq_work), DEST; \ - or DEST, %lo(__irq_work), DEST; + TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ + add DEST, TRAP_PER_CPU_IRQ_WORKLIST, DEST; #define TRAP_LOAD_THREAD_REG(DEST, TMP) \ TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ diff --git a/include/asm-sparc64/pil.h b/include/asm-sparc64/pil.h index 79f827eb3f5d..72927749aebf 100644 --- a/include/asm-sparc64/pil.h +++ b/include/asm-sparc64/pil.h @@ -5,9 +5,9 @@ /* To avoid some locking problems, we hard allocate certain PILs * for SMP cross call messages that must do a etrap/rtrap. * - * A cli() does not block the cross call delivery, so when SMP - * locking is an issue we reschedule the event into a PIL interrupt - * which is blocked by cli(). + * A local_irq_disable() does not block the cross call delivery, so + * when SMP locking is an issue we reschedule the event into a PIL + * interrupt which is blocked by local_irq_disable(). * * In fact any XCALL which has to etrap/rtrap has a problem because * it is difficult to prevent rtrap from running BH's, and that would @@ -17,6 +17,7 @@ #define PIL_SMP_RECEIVE_SIGNAL 2 #define PIL_SMP_CAPTURE 3 #define PIL_SMP_CTX_NEW_VERSION 4 +#define PIL_DEVICE_IRQ 5 #ifndef __ASSEMBLY__ #define PIL_RESERVED(PIL) ((PIL) == PIL_SMP_CALL_FUNC || \ -- cgit v1.2.3 From c6387a48cf5958e43c201fc27a158c328927531a Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 20 Jun 2006 01:21:29 -0700 Subject: [SPARC]: Kill __irq_itoa(). This ugly hack was long overdue to die. It was a way to print out Sparc interrupts in a more freindly format, since IRQ numbers were arbitrary opaque 32-bit integers which vectored into PIL levels. These 32-bit integers were not necessarily in the 0-->NR_IRQS range, but the PILs they vectored to were. The idea now is that we will increase NR_IRQS a little bit and use a virtual<-->real IRQ number mapping scheme similar to PowerPC. That makes this IRQ printing hack irrelevant, and furthermore only a handful of drivers actually used __irq_itoa() making it even less useful. Signed-off-by: David S. Miller --- arch/sparc/kernel/pcic.c | 8 -------- arch/sparc/kernel/sparc_ksyms.c | 1 - arch/sparc/kernel/sun4c_irq.c | 3 --- arch/sparc/kernel/sun4d_irq.c | 12 ------------ arch/sparc/kernel/sun4m_irq.c | 8 -------- drivers/atm/fore200e.c | 4 ---- drivers/char/rtc.c | 4 ---- drivers/fc4/soc.c | 2 +- drivers/fc4/socal.c | 2 +- drivers/ide/ide-probe.c | 7 +------ drivers/ide/setup-pci.c | 5 ----- drivers/ieee1394/ohci1394.c | 4 ---- drivers/ieee1394/pcilynx.c | 4 ---- drivers/message/fusion/mptbase.c | 16 ---------------- drivers/net/3c59x.c | 5 ----- drivers/net/acenic.c | 6 +----- drivers/net/sunhme.c | 5 ----- drivers/net/sunlance.c | 2 +- drivers/sbus/char/cpwatchdog.c | 4 ++-- drivers/sbus/char/uctrl.c | 2 +- drivers/scsi/esp.c | 4 ++-- drivers/scsi/qlogicpti.c | 6 +++--- drivers/scsi/sym53c8xx_2/sym_glue.c | 6 ------ drivers/serial/sunsu.c | 4 ++-- drivers/serial/sunzilog.c | 4 ++-- drivers/usb/core/hcd.c | 12 ++---------- drivers/usb/gadget/goku_udc.c | 11 ++--------- drivers/usb/gadget/net2280.c | 14 ++++---------- include/asm-sparc/irq.h | 2 -- include/asm-sparc64/irq.h | 8 -------- sound/sparc/amd7930.c | 8 ++++---- sound/sparc/cs4231.c | 13 ++++++------- sound/sparc/dbri.c | 4 ++-- 33 files changed, 37 insertions(+), 163 deletions(-) (limited to 'include') diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c index 42002b742deb..bcdf5ad0f035 100644 --- a/arch/sparc/kernel/pcic.c +++ b/arch/sparc/kernel/pcic.c @@ -896,13 +896,6 @@ static inline unsigned long get_irqmask(int irq_nr) return 1 << irq_nr; } -static inline char *pcic_irq_itoa(unsigned int irq) -{ - static char buff[16]; - sprintf(buff, "%d", irq); - return buff; -} - static void pcic_disable_irq(unsigned int irq_nr) { unsigned long mask, flags; @@ -955,7 +948,6 @@ void __init sun4m_pci_init_IRQ(void) BTFIXUPSET_CALL(clear_clock_irq, pcic_clear_clock_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(clear_profile_irq, pcic_clear_profile_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(load_profile_irq, pcic_load_profile_irq, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(__irq_itoa, pcic_irq_itoa, BTFIXUPCALL_NORM); } int pcibios_assign_resource(struct pci_dev *pdev, int resource) diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c index 4b376fae752c..fd7deabf9982 100644 --- a/arch/sparc/kernel/sparc_ksyms.c +++ b/arch/sparc/kernel/sparc_ksyms.c @@ -163,7 +163,6 @@ EXPORT_SYMBOL(BTFIXUP_CALL(__hard_smp_processor_id)); #endif EXPORT_SYMBOL(BTFIXUP_CALL(enable_irq)); EXPORT_SYMBOL(BTFIXUP_CALL(disable_irq)); -EXPORT_SYMBOL(BTFIXUP_CALL(__irq_itoa)); EXPORT_SYMBOL(BTFIXUP_CALL(mmu_unlockarea)); EXPORT_SYMBOL(BTFIXUP_CALL(mmu_lockarea)); EXPORT_SYMBOL(BTFIXUP_CALL(mmu_get_scsi_sgl)); diff --git a/arch/sparc/kernel/sun4c_irq.c b/arch/sparc/kernel/sun4c_irq.c index 3d6a99073c42..0f2d8d9cbdba 100644 --- a/arch/sparc/kernel/sun4c_irq.c +++ b/arch/sparc/kernel/sun4c_irq.c @@ -198,8 +198,6 @@ static void __init sun4c_init_timers(irqreturn_t (*counter_fn)(int, void *, stru static void sun4c_nop(void) {} #endif -extern char *sun4m_irq_itoa(unsigned int irq); - void __init sun4c_init_IRQ(void) { struct linux_prom_registers int_regs[2]; @@ -238,7 +236,6 @@ void __init sun4c_init_IRQ(void) BTFIXUPSET_CALL(clear_clock_irq, sun4c_clear_clock_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(clear_profile_irq, sun4c_clear_profile_irq, BTFIXUPCALL_NOP); BTFIXUPSET_CALL(load_profile_irq, sun4c_load_profile_irq, BTFIXUPCALL_NOP); - BTFIXUPSET_CALL(__irq_itoa, sun4m_irq_itoa, BTFIXUPCALL_NORM); sparc_init_timers = sun4c_init_timers; #ifdef CONFIG_SMP BTFIXUPSET_CALL(set_cpu_int, sun4c_nop, BTFIXUPCALL_NOP); diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c index ca656d9bd6fd..9c30e35c88f7 100644 --- a/arch/sparc/kernel/sun4d_irq.c +++ b/arch/sparc/kernel/sun4d_irq.c @@ -560,17 +560,6 @@ void __init sun4d_init_sbi_irq(void) } } -static char *sun4d_irq_itoa(unsigned int irq) -{ - static char buff[16]; - - if (irq < (1 << 5)) - sprintf(buff, "%d", irq); - else - sprintf(buff, "%d,%x", sbus_to_pil[(irq >> 2) & 7], irq); - return buff; -} - void __init sun4d_init_IRQ(void) { local_irq_disable(); @@ -581,7 +570,6 @@ void __init sun4d_init_IRQ(void) BTFIXUPSET_CALL(clear_clock_irq, sun4d_clear_clock_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(clear_profile_irq, sun4d_clear_profile_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(load_profile_irq, sun4d_load_profile_irq, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(__irq_itoa, sun4d_irq_itoa, BTFIXUPCALL_NORM); sparc_init_timers = sun4d_init_timers; #ifdef CONFIG_SMP BTFIXUPSET_CALL(set_cpu_int, sun4d_set_cpu_int, BTFIXUPCALL_NORM); diff --git a/arch/sparc/kernel/sun4m_irq.c b/arch/sparc/kernel/sun4m_irq.c index 39d712c3c809..a296c13ac18f 100644 --- a/arch/sparc/kernel/sun4m_irq.c +++ b/arch/sparc/kernel/sun4m_irq.c @@ -229,13 +229,6 @@ static void sun4m_load_profile_irq(int cpu, unsigned int limit) sun4m_timers->cpu_timers[cpu].l14_timer_limit = limit; } -char *sun4m_irq_itoa(unsigned int irq) -{ - static char buff[16]; - sprintf(buff, "%d", irq); - return buff; -} - static void __init sun4m_init_timers(irqreturn_t (*counter_fn)(int, void *, struct pt_regs *)) { int reg_count, irq, cpu; @@ -388,7 +381,6 @@ void __init sun4m_init_IRQ(void) BTFIXUPSET_CALL(clear_clock_irq, sun4m_clear_clock_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(clear_profile_irq, sun4m_clear_profile_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(load_profile_irq, sun4m_load_profile_irq, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(__irq_itoa, sun4m_irq_itoa, BTFIXUPCALL_NORM); sparc_init_timers = sun4m_init_timers; #ifdef CONFIG_SMP BTFIXUPSET_CALL(set_cpu_int, sun4m_send_ipi, BTFIXUPCALL_NORM); diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c index 05983a312d50..92923bf27233 100644 --- a/drivers/atm/fore200e.c +++ b/drivers/atm/fore200e.c @@ -167,13 +167,9 @@ fore200e_atm2fore_aal(int aal) static char* fore200e_irq_itoa(int irq) { -#if defined(__sparc_v9__) - return __irq_itoa(irq); -#else static char str[8]; sprintf(str, "%d", irq); return str; -#endif } diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index 7cac6d05d723..f6686fcce809 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -960,10 +960,6 @@ found: * PCI Slot 2 INTA# (and some INTx# in Slot 1). */ if (request_irq(rtc_irq, rtc_interrupt, SA_SHIRQ, "rtc", (void *)&rtc_port)) { - /* - * Standard way for sparc to print irq's is to use - * __irq_itoa(). I think for EBus it's ok to use %d. - */ printk(KERN_ERR "rtc: cannot register IRQ %d\n", rtc_irq); return -EIO; } diff --git a/drivers/fc4/soc.c b/drivers/fc4/soc.c index ec1f94738c59..cf8768b8d1f1 100644 --- a/drivers/fc4/soc.c +++ b/drivers/fc4/soc.c @@ -643,7 +643,7 @@ static inline void soc_init(struct sbus_dev *sdev, int no) return; } - SOD(("SOC uses IRQ%s\n", __irq_itoa(irq))) + SOD(("SOC uses IRQ %d\n", irq)) s->port[0].fc.irq = irq; s->port[1].fc.irq = irq; diff --git a/drivers/fc4/socal.c b/drivers/fc4/socal.c index 922e9613b2cf..f52d1e5bd5a5 100644 --- a/drivers/fc4/socal.c +++ b/drivers/fc4/socal.c @@ -767,7 +767,7 @@ static inline void socal_init(struct sbus_dev *sdev, int no) return; } - SOD(("SOCAL uses IRQ %s\n", __irq_itoa(irq))) + SOD(("SOCAL uses IRQ %d\n", irq)) s->port[0].fc.irq = irq; s->port[1].fc.irq = irq; diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 1b7b4c531bc2..9ebf8ae2a5e3 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -1138,16 +1138,11 @@ static int init_irq (ide_hwif_t *hwif) spin_unlock_irq(&ide_lock); } -#if !defined(__mc68000__) && !defined(CONFIG_APUS) && !defined(__sparc__) +#if !defined(__mc68000__) && !defined(CONFIG_APUS) printk("%s at 0x%03lx-0x%03lx,0x%03lx on irq %d", hwif->name, hwif->io_ports[IDE_DATA_OFFSET], hwif->io_ports[IDE_DATA_OFFSET]+7, hwif->io_ports[IDE_CONTROL_OFFSET], hwif->irq); -#elif defined(__sparc__) - printk("%s at 0x%03lx-0x%03lx,0x%03lx on irq %s", hwif->name, - hwif->io_ports[IDE_DATA_OFFSET], - hwif->io_ports[IDE_DATA_OFFSET]+7, - hwif->io_ports[IDE_CONTROL_OFFSET], __irq_itoa(hwif->irq)); #else printk("%s at 0x%08lx on irq %d", hwif->name, hwif->io_ports[IDE_DATA_OFFSET], hwif->irq); diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c index 462ed3006c30..c11e3b2e67a6 100644 --- a/drivers/ide/setup-pci.c +++ b/drivers/ide/setup-pci.c @@ -694,13 +694,8 @@ static int do_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t *d, goto out; } if (noisy) -#ifdef __sparc__ - printk(KERN_INFO "%s: 100%% native mode on irq %s\n", - d->name, __irq_itoa(pciirq)); -#else printk(KERN_INFO "%s: 100%% native mode on irq %d\n", d->name, pciirq); -#endif } /* FIXME: silent failure can happen */ diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c index 11f13778f139..c031650a1c74 100644 --- a/drivers/ieee1394/ohci1394.c +++ b/drivers/ieee1394/ohci1394.c @@ -586,11 +586,7 @@ static void ohci_initialize(struct ti_ohci *ohci) reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_linkEnable); buf = reg_read(ohci, OHCI1394_Version); -#ifndef __sparc__ sprintf (irq_buf, "%d", ohci->dev->irq); -#else - sprintf (irq_buf, "%s", __irq_itoa(ohci->dev->irq)); -#endif PRINT(KERN_INFO, "OHCI-1394 %d.%d (PCI): IRQ=[%s] " "MMIO=[%lx-%lx] Max Packet=[%d] IR/IT contexts=[%d/%d]", ((((buf) >> 16) & 0xf) + (((buf) >> 20) & 0xf) * 10), diff --git a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c index e2edc41e1b6f..e29dfd280bee 100644 --- a/drivers/ieee1394/pcilynx.c +++ b/drivers/ieee1394/pcilynx.c @@ -1252,11 +1252,7 @@ static int __devinit add_card(struct pci_dev *dev, /* Fix buggy cards with autoboot pin not tied low: */ reg_write(lynx, DMA0_CHAN_CTRL, 0); -#ifndef __sparc__ sprintf (irq_buf, "%d", dev->irq); -#else - sprintf (irq_buf, "%s", __irq_itoa(dev->irq)); -#endif if (!request_irq(dev->irq, lynx_irq_handler, SA_SHIRQ, PCILYNX_DRIVER_NAME, lynx)) { diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index a30084076ac8..59690cbabfca 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -63,9 +63,6 @@ #ifdef CONFIG_MTRR #include #endif -#ifdef __sparc__ -#include /* needed for __irq_itoa() proto */ -#endif #include "mptbase.h" @@ -1394,13 +1391,8 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) r = request_irq(pdev->irq, mpt_interrupt, SA_SHIRQ, ioc->name, ioc); if (r < 0) { -#ifndef __sparc__ printk(MYIOC_s_ERR_FMT "Unable to allocate interrupt %d!\n", ioc->name, pdev->irq); -#else - printk(MYIOC_s_ERR_FMT "Unable to allocate interrupt %s!\n", - ioc->name, __irq_itoa(pdev->irq)); -#endif list_del(&ioc->list); iounmap(mem); kfree(ioc); @@ -1412,11 +1404,7 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) pci_set_master(pdev); /* ?? */ pci_set_drvdata(pdev, ioc); -#ifndef __sparc__ dprintk((KERN_INFO MYNAM ": %s installed at interrupt %d\n", ioc->name, pdev->irq)); -#else - dprintk((KERN_INFO MYNAM ": %s installed at interrupt %s\n", ioc->name, __irq_itoa(pdev->irq))); -#endif } /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets. @@ -5647,11 +5635,7 @@ mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int sh a[5], a[4], a[3], a[2], a[1], a[0]); } -#ifndef __sparc__ y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq); -#else - y += sprintf(buffer+len+y, ", IRQ=%s", __irq_itoa(ioc->pci_irq)); -#endif if (!ioc->active) y += sprintf(buffer+len+y, " (disabled)"); diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 274b0138d442..e27778926eba 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -1382,17 +1382,12 @@ static int __devinit vortex_probe1(struct device *gendev, for (i = 0; i < 6; i++) iowrite8(dev->dev_addr[i], ioaddr + i); -#ifdef __sparc__ - if (print_info) - printk(", IRQ %s\n", __irq_itoa(dev->irq)); -#else if (print_info) printk(", IRQ %d\n", dev->irq); /* Tell them about an invalid IRQ. */ if (dev->irq <= 0 || dev->irq >= NR_IRQS) printk(KERN_WARNING " *** Warning: IRQ %d is unlikely to work! ***\n", dev->irq); -#endif EL3WINDOW(4); step = (ioread8(ioaddr + Wn4_NetDiag) & 0x1e) >> 1; diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c index b508812e97ac..23ff22ba5d31 100644 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c @@ -579,11 +579,7 @@ static int __devinit acenic_probe_one(struct pci_dev *pdev, } printk("Gigabit Ethernet at 0x%08lx, ", dev->base_addr); -#ifdef __sparc__ - printk("irq %s\n", __irq_itoa(pdev->irq)); -#else - printk("irq %i\n", pdev->irq); -#endif + printk("irq %d\n", pdev->irq); #ifdef CONFIG_ACENIC_OMIT_TIGON_I if ((readl(&ap->regs->HostCtrl) >> 28) == 4) { diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index 9f046cae2f71..bd5d2668a362 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -2221,13 +2221,8 @@ static int happy_meal_open(struct net_device *dev) if (request_irq(dev->irq, &happy_meal_interrupt, SA_SHIRQ, dev->name, (void *)dev)) { HMD(("EAGAIN\n")); -#ifdef __sparc__ - printk(KERN_ERR "happy_meal(SBUS): Can't order irq %s to go.\n", - __irq_itoa(dev->irq)); -#else printk(KERN_ERR "happy_meal(SBUS): Can't order irq %d to go.\n", dev->irq); -#endif return -EAGAIN; } diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c index b7d87d4690b4..6381243d8d00 100644 --- a/drivers/net/sunlance.c +++ b/drivers/net/sunlance.c @@ -936,7 +936,7 @@ static int lance_open(struct net_device *dev) if (request_irq(dev->irq, &lance_interrupt, SA_SHIRQ, lancestr, (void *) dev)) { - printk(KERN_ERR "Lance: Can't get irq %s\n", __irq_itoa(dev->irq)); + printk(KERN_ERR "Lance: Can't get irq %d\n", dev->irq); return -EAGAIN; } diff --git a/drivers/sbus/char/cpwatchdog.c b/drivers/sbus/char/cpwatchdog.c index fd2cc7782f76..5bf3dd901b65 100644 --- a/drivers/sbus/char/cpwatchdog.c +++ b/drivers/sbus/char/cpwatchdog.c @@ -304,8 +304,8 @@ static int wd_open(struct inode *inode, struct file *f) SA_SHIRQ, WD_OBPNAME, (void *)wd_dev.regs)) { - printk("%s: Cannot register IRQ %s\n", - WD_OBPNAME, __irq_itoa(wd_dev.irq)); + printk("%s: Cannot register IRQ %d\n", + WD_OBPNAME, wd_dev.irq); return(-EBUSY); } wd_dev.initialized = 1; diff --git a/drivers/sbus/char/uctrl.c b/drivers/sbus/char/uctrl.c index e2d9a7c85427..575b1f7ed410 100644 --- a/drivers/sbus/char/uctrl.c +++ b/drivers/sbus/char/uctrl.c @@ -400,7 +400,7 @@ static int __init ts102_uctrl_init(void) } driver->regs->uctrl_intr = UCTRL_INTR_RXNE_REQ|UCTRL_INTR_RXNE_MSK; - printk("uctrl: 0x%x (irq %s)\n", driver->regs, __irq_itoa(driver->irq)); + printk("uctrl: 0x%x (irq %d)\n", driver->regs, driver->irq); uctrl_get_event_status(); uctrl_get_external_status(); return 0; diff --git a/drivers/scsi/esp.c b/drivers/scsi/esp.c index 87a8c3d2072c..0a3e45d7a972 100644 --- a/drivers/scsi/esp.c +++ b/drivers/scsi/esp.c @@ -821,8 +821,8 @@ static int __init esp_register_irq(struct esp *esp) return -1; } - printk("esp%d: IRQ %s ", esp->esp_id, - __irq_itoa(esp->ehost->irq)); + printk("esp%d: IRQ %d ", esp->esp_id, + esp->ehost->irq); return 0; } diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c index c7e78dcf09df..7c27ecc6fb5d 100644 --- a/drivers/scsi/qlogicpti.c +++ b/drivers/scsi/qlogicpti.c @@ -725,7 +725,7 @@ static int __init qpti_register_irq(struct qlogicpti *qpti) SA_SHIRQ, "Qlogic/PTI", qpti)) goto fail; - printk("qpti%d: IRQ %s ", qpti->qpti_id, __irq_itoa(qpti->irq)); + printk("qpti%d: IRQ %d ", qpti->qpti_id, qpti->irq); return 0; @@ -988,8 +988,8 @@ const char *qlogicpti_info(struct Scsi_Host *host) static char buf[80]; struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata; - sprintf(buf, "PTI Qlogic,ISP SBUS SCSI irq %s regs at %p", - __irq_itoa(qpti->qhost->irq), qpti->qregs); + sprintf(buf, "PTI Qlogic,ISP SBUS SCSI irq %d regs at %p", + qpti->qhost->irq, qpti->qregs); return buf; } diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c index 9c83b4d39a26..7677fba2ceb5 100644 --- a/drivers/scsi/sym53c8xx_2/sym_glue.c +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c @@ -54,14 +54,8 @@ #define NAME53C "sym53c" #define NAME53C8XX "sym53c8xx" -/* SPARC just has to be different ... */ -#ifdef __sparc__ -#define IRQ_FMT "%s" -#define IRQ_PRM(x) __irq_itoa(x) -#else #define IRQ_FMT "%d" #define IRQ_PRM(x) (x) -#endif struct sym_driver_setup sym_driver_setup = SYM_LINUX_DRIVER_SETUP; unsigned int sym_debug_flags = 0; diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c index 2b4f96541b8e..4cdb610cdd37 100644 --- a/drivers/serial/sunsu.c +++ b/drivers/serial/sunsu.c @@ -1295,9 +1295,9 @@ static int __init sunsu_kbd_ms_init(struct uart_sunsu_port *up, int channel) if (up->port.type == PORT_UNKNOWN) return -1; - printk(KERN_INFO "su%d at 0x%p (irq = %s) is a %s\n", + printk(KERN_INFO "su%d at 0x%p (irq = %d) is a %s\n", channel, - up->port.membase, __irq_itoa(up->port.irq), + up->port.membase, up->port.irq, sunsu_type(&up->port)); #ifdef CONFIG_SERIO diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c index cd49ebbf4a45..5b6569728a9c 100644 --- a/drivers/serial/sunzilog.c +++ b/drivers/serial/sunzilog.c @@ -1540,8 +1540,8 @@ static void __init sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channe up->cflag = B4800 | CS8 | CLOCAL | CREAD; baud = 4800; } - printk(KERN_INFO "zs%d at 0x%p (irq = %s) is a SunZilog\n", - channel, up->port.membase, __irq_itoa(zilog_irq)); + printk(KERN_INFO "zs%d at 0x%p (irq = %d) is a SunZilog\n", + channel, up->port.membase, zilog_irq); up->curregs[R15] = BRKIE; brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index e2e00ba4e1e6..4bf914d00a14 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1826,24 +1826,16 @@ int usb_add_hcd(struct usb_hcd *hcd, /* enable irqs just before we start the controller */ if (hcd->driver->irq) { - char buf[8], *bufp = buf; - -#ifdef __sparc__ - bufp = __irq_itoa(irqnum); -#else - sprintf(buf, "%d", irqnum); -#endif - snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d", hcd->driver->description, hcd->self.busnum); if ((retval = request_irq(irqnum, &usb_hcd_irq, irqflags, hcd->irq_descr, hcd)) != 0) { dev_err(hcd->self.controller, - "request interrupt %s failed\n", bufp); + "request interrupt %d failed\n", irqnum); goto err_request_irq; } hcd->irq = irqnum; - dev_info(hcd->self.controller, "irq %s, %s 0x%08llx\n", bufp, + dev_info(hcd->self.controller, "irq %d, %s 0x%08llx\n", irqnum, (hcd->driver->flags & HCD_MEMORY) ? "io mem" : "io base", (unsigned long long)hcd->rsrc_start); diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index 66b81bbf6bee..5378c1757292 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -1850,7 +1850,6 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id) unsigned long resource, len; void __iomem *base = NULL; int retval; - char buf [8], *bufp; /* if you want to support more than one controller in a system, * usb_gadget_driver_{register,unregister}() must change. @@ -1913,20 +1912,14 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id) pci_set_drvdata(pdev, dev); INFO(dev, "%s\n", driver_desc); INFO(dev, "version: " DRIVER_VERSION " %s\n", dmastr()); -#ifndef __sparc__ - scnprintf(buf, sizeof buf, "%d", pdev->irq); - bufp = buf; -#else - bufp = __irq_itoa(pdev->irq); -#endif - INFO(dev, "irq %s, pci mem %p\n", bufp, base); + INFO(dev, "irq %d, pci mem %p\n", pdev->irq, base); /* init to known state, then setup irqs */ udc_reset(dev); udc_reinit (dev); if (request_irq(pdev->irq, goku_irq, SA_SHIRQ/*|SA_SAMPLE_RANDOM*/, driver_name, dev) != 0) { - DBG(dev, "request interrupt %s failed\n", bufp); + DBG(dev, "request interrupt %d failed\n", pdev->irq); retval = -EBUSY; goto done; } diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 0b9293493957..020d3c42b1af 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -2822,7 +2822,6 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) unsigned long resource, len; void __iomem *base = NULL; int retval, i; - char buf [8], *bufp; /* if you want to support more than one controller in a system, * usb_gadget_driver_{register,unregister}() must change. @@ -2896,15 +2895,10 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) retval = -ENODEV; goto done; } -#ifndef __sparc__ - scnprintf (buf, sizeof buf, "%d", pdev->irq); - bufp = buf; -#else - bufp = __irq_itoa(pdev->irq); -#endif + if (request_irq (pdev->irq, net2280_irq, SA_SHIRQ, driver_name, dev) != 0) { - ERROR (dev, "request interrupt %s failed\n", bufp); + ERROR (dev, "request interrupt %d failed\n", pdev->irq); retval = -EBUSY; goto done; } @@ -2953,8 +2947,8 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) /* done */ INFO (dev, "%s\n", driver_desc); - INFO (dev, "irq %s, pci mem %p, chip rev %04x\n", - bufp, base, dev->chiprev); + INFO (dev, "irq %d, pci mem %p, chip rev %04x\n", + pdev->irq, base, dev->chiprev); INFO (dev, "version: " DRIVER_VERSION "; dma %s\n", use_dma ? (use_dma_chaining ? "chaining" : "enabled") diff --git a/include/asm-sparc/irq.h b/include/asm-sparc/irq.h index cee356b0dae3..a6115c6ed6e3 100644 --- a/include/asm-sparc/irq.h +++ b/include/asm-sparc/irq.h @@ -17,8 +17,6 @@ #define __irq_ino(irq) irq #define __irq_pil(irq) irq -BTFIXUPDEF_CALL(char *, __irq_itoa, unsigned int) -#define __irq_itoa(irq) BTFIXUP_CALL(__irq_itoa)(irq) #define NR_IRQS 16 diff --git a/include/asm-sparc64/irq.h b/include/asm-sparc64/irq.h index de33d6e1afb5..bbdf89e6faa4 100644 --- a/include/asm-sparc64/irq.h +++ b/include/asm-sparc64/irq.h @@ -99,14 +99,6 @@ extern struct ino_bucket ivector_table[NUM_IVECS]; #define __bucket(irq) ((struct ino_bucket *)(unsigned long)(irq)) #define __irq(bucket) ((unsigned int)(unsigned long)(bucket)) -static __inline__ char *__irq_itoa(unsigned int irq) -{ - static char buff[16]; - - sprintf(buff, "%d,%x", __irq_pil(irq), (unsigned int)__irq_ino(irq)); - return buff; -} - #define NR_IRQS 16 #define irq_canonicalize(irq) (irq) diff --git a/sound/sparc/amd7930.c b/sound/sparc/amd7930.c index 55493340f467..dfe9bac7fa32 100644 --- a/sound/sparc/amd7930.c +++ b/sound/sparc/amd7930.c @@ -977,9 +977,9 @@ static int __init snd_amd7930_create(struct snd_card *card, if (request_irq(irq_prop->pri, snd_amd7930_interrupt, SA_INTERRUPT | SA_SHIRQ, "amd7930", amd)) { - snd_printk("amd7930-%d: Unable to grab IRQ %s\n", + snd_printk("amd7930-%d: Unable to grab IRQ %d\n", dev, - __irq_itoa(irq_prop->pri)); + irq_prop->pri); snd_amd7930_free(amd); return -EBUSY; } @@ -1063,11 +1063,11 @@ static int __init amd7930_attach(int prom_node, struct sbus_dev *sdev) strcpy(card->driver, "AMD7930"); strcpy(card->shortname, "Sun AMD7930"); - sprintf(card->longname, "%s at 0x%02lx:0x%08lx, irq %s", + sprintf(card->longname, "%s at 0x%02lx:0x%08lx, irq %d", card->shortname, rp->flags & 0xffL, rp->start, - __irq_itoa(irq_prop.pri)); + irq_prop.pri); if ((err = snd_amd7930_create(card, sdev, rp, reg_prop.reg_size, &irq_prop, dev, &amd)) < 0) diff --git a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c index 8804f26ddb3a..b3efc9aa2916 100644 --- a/sound/sparc/cs4231.c +++ b/sound/sparc/cs4231.c @@ -2003,9 +2003,8 @@ static int __init snd_cs4231_sbus_create(struct snd_card *card, if (request_irq(sdev->irqs[0], snd_cs4231_sbus_interrupt, SA_SHIRQ, "cs4231", chip)) { - snd_printdd("cs4231-%d: Unable to grab SBUS IRQ %s\n", - dev, - __irq_itoa(sdev->irqs[0])); + snd_printdd("cs4231-%d: Unable to grab SBUS IRQ %d\n", + dev, sdev->irqs[0]); snd_cs4231_sbus_free(chip); return -EBUSY; } @@ -2038,11 +2037,11 @@ static int __init cs4231_sbus_attach(struct sbus_dev *sdev) if (err) return err; - sprintf(card->longname, "%s at 0x%02lx:0x%08lx, irq %s", + sprintf(card->longname, "%s at 0x%02lx:0x%08lx, irq %d", card->shortname, rp->flags & 0xffL, rp->start, - __irq_itoa(sdev->irqs[0])); + sdev->irqs[0]); if ((err = snd_cs4231_sbus_create(card, sdev, dev, &cp)) < 0) { snd_card_free(card); @@ -2244,10 +2243,10 @@ static int __init cs4231_ebus_attach(struct linux_ebus_device *edev) if (err) return err; - sprintf(card->longname, "%s at 0x%lx, irq %s", + sprintf(card->longname, "%s at 0x%lx, irq %d", card->shortname, edev->resource[0].start, - __irq_itoa(edev->irqs[0])); + edev->irqs[0]); if ((err = snd_cs4231_ebus_create(card, edev, dev, &chip)) < 0) { snd_card_free(card); diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c index 2164b7d290c7..e622d08215c9 100644 --- a/sound/sparc/dbri.c +++ b/sound/sparc/dbri.c @@ -2645,9 +2645,9 @@ static int __init dbri_attach(int prom_node, struct sbus_dev *sdev) strcpy(card->driver, "DBRI"); strcpy(card->shortname, "Sun DBRI"); rp = &sdev->resource[0]; - sprintf(card->longname, "%s at 0x%02lx:0x%08lx, irq %s", + sprintf(card->longname, "%s at 0x%02lx:0x%08lx, irq %d", card->shortname, - rp->flags & 0xffL, rp->start, __irq_itoa(irq.pri)); + rp->flags & 0xffL, rp->start, irq.pri); if ((err = snd_dbri_create(card, sdev, &irq, dev)) < 0) { snd_card_free(card); -- cgit v1.2.3 From 37cdcd9e82108f9b899f1631f66ade2e45738a6e Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 20 Jun 2006 01:21:57 -0700 Subject: [SPARC64]: Kill ino_bucket->pil And reuse that struct member for virt_irq, which will be used in future changesets for the implementation of mapping between real and virtual IRQ numbers. This nicely kills off a ton of SBUS and PCI controller PIL assignment code which is no longer necessary. Signed-off-by: David S. Miller --- arch/sparc64/kernel/devices.c | 2 +- arch/sparc64/kernel/irq.c | 70 ++++++++++---------------- arch/sparc64/kernel/pci_psycho.c | 77 +---------------------------- arch/sparc64/kernel/pci_sabre.c | 81 +----------------------------- arch/sparc64/kernel/pci_schizo.c | 104 +-------------------------------------- arch/sparc64/kernel/pci_sun4v.c | 32 +----------- arch/sparc64/kernel/sbus.c | 47 ++---------------- include/asm-sparc64/irq.h | 11 ++--- 8 files changed, 43 insertions(+), 381 deletions(-) (limited to 'include') diff --git a/arch/sparc64/kernel/devices.c b/arch/sparc64/kernel/devices.c index 007e8922cd16..0684899d998b 100644 --- a/arch/sparc64/kernel/devices.c +++ b/arch/sparc64/kernel/devices.c @@ -157,7 +157,7 @@ unsigned int sun4v_vdev_device_interrupt(unsigned int dev_node) return 0; } - return sun4v_build_irq(sun4v_vdev_devhandle, irq, 5, 0); + return sun4v_build_irq(sun4v_vdev_devhandle, irq, 0); } static const char *cpu_mid_prop(void) diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index ad134bbc151c..f2668f2bed9c 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c @@ -70,7 +70,7 @@ struct ino_bucket ivector_table[NUM_IVECS] __attribute__ ((aligned (SMP_CACHE_BY */ #define irq_work(__cpu) &(trap_block[(__cpu)].irq_worklist) -static struct irqaction *irq_action[NR_IRQS+1]; +static struct irqaction *irq_action[NR_IRQS]; /* This only synchronizes entities which modify IRQ handler * state and some selected user-level spots that want to @@ -116,12 +116,9 @@ int show_interrupts(struct seq_file *p, void *v) kstat_cpu(j).irqs[i]); } #endif - seq_printf(p, " %s:%lx", action->name, - get_ino_in_irqaction(action)); - for (action = action->next; action; action = action->next) { - seq_printf(p, ", %s:%lx", action->name, - get_ino_in_irqaction(action)); - } + seq_printf(p, " %s", action->name); + for (action = action->next; action; action = action->next) + seq_printf(p, ", %s", action->name); seq_putc(p, '\n'); } out_unlock: @@ -245,48 +242,47 @@ void disable_irq(unsigned int irq) } } -static void build_irq_error(const char *msg, unsigned int ino, int pil, int inofixup, +static void build_irq_error(const char *msg, unsigned int ino, int inofixup, unsigned long iclr, unsigned long imap, struct ino_bucket *bucket) { - prom_printf("IRQ: INO %04x (%d:%016lx:%016lx) --> " - "(%d:%d:%016lx:%016lx), halting...\n", - ino, bucket->pil, bucket->iclr, bucket->imap, - pil, inofixup, iclr, imap); + prom_printf("IRQ: INO %04x (%016lx:%016lx) --> " + "(%d:%016lx:%016lx), halting...\n", + ino, bucket->iclr, bucket->imap, + inofixup, iclr, imap); prom_halt(); } -unsigned int build_irq(int pil, int inofixup, unsigned long iclr, unsigned long imap) +unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap) { struct ino_bucket *bucket; int ino; - BUG_ON(pil == 0); BUG_ON(tlb_type == hypervisor); /* RULE: Both must be specified in all other cases. */ if (iclr == 0UL || imap == 0UL) { - prom_printf("Invalid build_irq %d %d %016lx %016lx\n", - pil, inofixup, iclr, imap); + prom_printf("Invalid build_irq %d %016lx %016lx\n", + inofixup, iclr, imap); prom_halt(); } ino = (upa_readl(imap) & (IMAP_IGN | IMAP_INO)) + inofixup; if (ino > NUM_IVECS) { - prom_printf("Invalid INO %04x (%d:%d:%016lx:%016lx)\n", - ino, pil, inofixup, iclr, imap); + prom_printf("Invalid INO %04x (%d:%016lx:%016lx)\n", + ino, inofixup, iclr, imap); prom_halt(); } bucket = &ivector_table[ino]; if (bucket->flags & IBF_ACTIVE) build_irq_error("IRQ: Trying to build active INO bucket.\n", - ino, pil, inofixup, iclr, imap, bucket); + ino, inofixup, iclr, imap, bucket); if (bucket->irq_info) { if (bucket->imap != imap || bucket->iclr != iclr) build_irq_error("IRQ: Trying to reinit INO bucket.\n", - ino, pil, inofixup, iclr, imap, bucket); + ino, inofixup, iclr, imap, bucket); goto out; } @@ -302,14 +298,13 @@ unsigned int build_irq(int pil, int inofixup, unsigned long iclr, unsigned long */ bucket->imap = imap; bucket->iclr = iclr; - bucket->pil = pil; bucket->flags = 0; out: return __irq(bucket); } -unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino, int pil, unsigned char flags) +unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino, unsigned char flags) { struct ino_bucket *bucket; unsigned long sysino; @@ -328,7 +323,6 @@ unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino, int pil, unsign bucket->imap = ~0UL - sysino; bucket->iclr = ~0UL - sysino; - bucket->pil = pil; bucket->flags = flags; bucket->irq_info = kzalloc(sizeof(struct irq_desc), GFP_ATOMIC); @@ -356,16 +350,12 @@ static void atomic_bucket_insert(struct ino_bucket *bucket) static int check_irq_sharing(int pil, unsigned long irqflags) { - struct irqaction *action, *tmp; + struct irqaction *action; action = *(irq_action + pil); if (action) { - if ((action->flags & SA_SHIRQ) && (irqflags & SA_SHIRQ)) { - for (tmp = action; tmp->next; tmp = tmp->next) - ; - } else { + if (!(action->flags & SA_SHIRQ) || !(irqflags & SA_SHIRQ)) return -EBUSY; - } } return 0; } @@ -425,12 +415,12 @@ int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_ * installing a new handler, but is this really a problem, * only the sysadmin is able to do this. */ - rand_initialize_irq(irq); + rand_initialize_irq(PIL_DEVICE_IRQ); } spin_lock_irqsave(&irq_action_lock, flags); - if (check_irq_sharing(bucket->pil, irqflags)) { + if (check_irq_sharing(PIL_DEVICE_IRQ, irqflags)) { spin_unlock_irqrestore(&irq_action_lock, flags); return -EBUSY; } @@ -454,7 +444,7 @@ int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_ put_ino_in_irqaction(action, irq); put_smpaff_in_irqaction(action, CPU_MASK_NONE); - append_irq_action(bucket->pil, action); + append_irq_action(PIL_DEVICE_IRQ, action); enable_irq(irq); @@ -478,16 +468,15 @@ EXPORT_SYMBOL(request_irq); static struct irqaction *unlink_irq_action(unsigned int irq, void *dev_id) { - struct ino_bucket *bucket = __bucket(irq); struct irqaction *action, **pp; - pp = irq_action + bucket->pil; + pp = irq_action + PIL_DEVICE_IRQ; action = *pp; if (unlikely(!action)) return NULL; if (unlikely(!action->handler)) { - printk("Freeing free IRQ %d\n", bucket->pil); + printk("Freeing free IRQ %d\n", PIL_DEVICE_IRQ); return NULL; } @@ -648,7 +637,7 @@ static void process_bucket(struct ino_bucket *bp, struct pt_regs *regs) /* Test and add entropy */ if (random & SA_SAMPLE_RANDOM) - add_interrupt_randomness(bp->pil); + add_interrupt_randomness(PIL_DEVICE_IRQ); out: bp->flags &= ~IBF_INPROGRESS; } @@ -691,7 +680,7 @@ void handler_irq(int irq, struct pt_regs *regs) while (bp) { struct ino_bucket *nbp = __bucket(bp->irq_chain); - kstat_this_cpu.irqs[bp->pil]++; + kstat_this_cpu.irqs[bp->virt_irq]++; bp->irq_chain = 0; process_bucket(bp, regs); @@ -817,16 +806,9 @@ static void distribute_irqs(void) spin_lock_irqsave(&irq_action_lock, flags); cpu = 0; - /* - * Skip the timer at [0], and very rare error/power intrs at [15]. - * Also level [12], it causes problems on Ex000 systems. - */ for (level = 1; level < NR_IRQS; level++) { struct irqaction *p = irq_action[level]; - if (level == 12) - continue; - while(p) { cpu = retarget_one_irq(p, cpu); p = p->next; diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c index d17878b145c2..5743e1316a93 100644 --- a/arch/sparc64/kernel/pci_psycho.c +++ b/arch/sparc64/kernel/pci_psycho.c @@ -276,74 +276,6 @@ static unsigned long __onboard_imap_off[] = { ((ino & 0x20) ? (PSYCHO_ICLR_SCSI + (((ino) & 0x1f) << 3)) : \ (PSYCHO_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3))) -/* PCI PSYCHO INO number to Sparc PIL level. */ -static unsigned char psycho_pil_table[] = { -/*0x00*/0, 0, 0, 0, /* PCI A slot 0 Int A, B, C, D */ -/*0x04*/0, 0, 0, 0, /* PCI A slot 1 Int A, B, C, D */ -/*0x08*/0, 0, 0, 0, /* PCI A slot 2 Int A, B, C, D */ -/*0x0c*/0, 0, 0, 0, /* PCI A slot 3 Int A, B, C, D */ -/*0x10*/0, 0, 0, 0, /* PCI B slot 0 Int A, B, C, D */ -/*0x14*/0, 0, 0, 0, /* PCI B slot 1 Int A, B, C, D */ -/*0x18*/0, 0, 0, 0, /* PCI B slot 2 Int A, B, C, D */ -/*0x1c*/0, 0, 0, 0, /* PCI B slot 3 Int A, B, C, D */ -/*0x20*/5, /* SCSI */ -/*0x21*/5, /* Ethernet */ -/*0x22*/8, /* Parallel Port */ -/*0x23*/13, /* Audio Record */ -/*0x24*/14, /* Audio Playback */ -/*0x25*/15, /* PowerFail */ -/*0x26*/5, /* second SCSI */ -/*0x27*/11, /* Floppy */ -/*0x28*/5, /* Spare Hardware */ -/*0x29*/9, /* Keyboard */ -/*0x2a*/5, /* Mouse */ -/*0x2b*/12, /* Serial */ -/*0x2c*/10, /* Timer 0 */ -/*0x2d*/11, /* Timer 1 */ -/*0x2e*/15, /* Uncorrectable ECC */ -/*0x2f*/15, /* Correctable ECC */ -/*0x30*/15, /* PCI Bus A Error */ -/*0x31*/15, /* PCI Bus B Error */ -/*0x32*/15, /* Power Management */ -}; - -static int psycho_ino_to_pil(struct pci_dev *pdev, unsigned int ino) -{ - int ret; - - ret = psycho_pil_table[ino]; - if (ret == 0 && pdev == NULL) { - ret = 5; - } else if (ret == 0) { - switch ((pdev->class >> 16) & 0xff) { - case PCI_BASE_CLASS_STORAGE: - ret = 5; - break; - - case PCI_BASE_CLASS_NETWORK: - ret = 6; - break; - - case PCI_BASE_CLASS_DISPLAY: - ret = 9; - break; - - case PCI_BASE_CLASS_MULTIMEDIA: - case PCI_BASE_CLASS_MEMORY: - case PCI_BASE_CLASS_BRIDGE: - case PCI_BASE_CLASS_SERIAL: - ret = 10; - break; - - default: - ret = 5; - break; - }; - } - - return ret; -} - static unsigned int psycho_irq_build(struct pci_pbm_info *pbm, struct pci_dev *pdev, unsigned int ino) @@ -351,7 +283,7 @@ static unsigned int psycho_irq_build(struct pci_pbm_info *pbm, struct ino_bucket *bucket; unsigned long imap, iclr; unsigned long imap_off, iclr_off; - int pil, inofixup = 0; + int inofixup = 0; ino &= PCI_IRQ_INO; if (ino < PSYCHO_ONBOARD_IRQ_BASE) { @@ -367,11 +299,6 @@ static unsigned int psycho_irq_build(struct pci_pbm_info *pbm, } /* Now build the IRQ bucket. */ - pil = psycho_ino_to_pil(pdev, ino); - - if (PIL_RESERVED(pil)) - BUG(); - imap = pbm->controller_regs + imap_off; imap += 4; @@ -382,7 +309,7 @@ static unsigned int psycho_irq_build(struct pci_pbm_info *pbm, if ((ino & 0x20) == 0) inofixup = ino & 0x03; - bucket = __bucket(build_irq(pil, inofixup, iclr, imap)); + bucket = __bucket(build_irq(inofixup, iclr, imap)); bucket->flags |= IBF_PCI; return __irq(bucket); diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index f67bb7f078cf..caa7aeed5d14 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c @@ -523,78 +523,6 @@ static unsigned long __onboard_imap_off[] = { ((ino & 0x20) ? (SABRE_ICLR_SCSI + (((ino) & 0x1f) << 3)) : \ (SABRE_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3))) -/* PCI SABRE INO number to Sparc PIL level. */ -static unsigned char sabre_pil_table[] = { -/*0x00*/0, 0, 0, 0, /* PCI A slot 0 Int A, B, C, D */ -/*0x04*/0, 0, 0, 0, /* PCI A slot 1 Int A, B, C, D */ -/*0x08*/0, 0, 0, 0, /* PCI A slot 2 Int A, B, C, D */ -/*0x0c*/0, 0, 0, 0, /* PCI A slot 3 Int A, B, C, D */ -/*0x10*/0, 0, 0, 0, /* PCI B slot 0 Int A, B, C, D */ -/*0x14*/0, 0, 0, 0, /* PCI B slot 1 Int A, B, C, D */ -/*0x18*/0, 0, 0, 0, /* PCI B slot 2 Int A, B, C, D */ -/*0x1c*/0, 0, 0, 0, /* PCI B slot 3 Int A, B, C, D */ -/*0x20*/5, /* SCSI */ -/*0x21*/5, /* Ethernet */ -/*0x22*/8, /* Parallel Port */ -/*0x23*/13, /* Audio Record */ -/*0x24*/14, /* Audio Playback */ -/*0x25*/15, /* PowerFail */ -/*0x26*/5, /* second SCSI */ -/*0x27*/11, /* Floppy */ -/*0x28*/5, /* Spare Hardware */ -/*0x29*/9, /* Keyboard */ -/*0x2a*/5, /* Mouse */ -/*0x2b*/12, /* Serial */ -/*0x2c*/10, /* Timer 0 */ -/*0x2d*/11, /* Timer 1 */ -/*0x2e*/15, /* Uncorrectable ECC */ -/*0x2f*/15, /* Correctable ECC */ -/*0x30*/15, /* PCI Bus A Error */ -/*0x31*/15, /* PCI Bus B Error */ -/*0x32*/15, /* Power Management */ -}; - -static int sabre_ino_to_pil(struct pci_dev *pdev, unsigned int ino) -{ - int ret; - - if (pdev && - pdev->vendor == PCI_VENDOR_ID_SUN && - pdev->device == PCI_DEVICE_ID_SUN_RIO_USB) - return 9; - - ret = sabre_pil_table[ino]; - if (ret == 0 && pdev == NULL) { - ret = 5; - } else if (ret == 0) { - switch ((pdev->class >> 16) & 0xff) { - case PCI_BASE_CLASS_STORAGE: - ret = 5; - break; - - case PCI_BASE_CLASS_NETWORK: - ret = 6; - break; - - case PCI_BASE_CLASS_DISPLAY: - ret = 9; - break; - - case PCI_BASE_CLASS_MULTIMEDIA: - case PCI_BASE_CLASS_MEMORY: - case PCI_BASE_CLASS_BRIDGE: - case PCI_BASE_CLASS_SERIAL: - ret = 10; - break; - - default: - ret = 5; - break; - }; - } - return ret; -} - /* When a device lives behind a bridge deeper in the PCI bus topology * than APB, a special sequence must run to make sure all pending DMA * transfers at the time of IRQ delivery are visible in the coherency @@ -619,7 +547,7 @@ static unsigned int sabre_irq_build(struct pci_pbm_info *pbm, struct ino_bucket *bucket; unsigned long imap, iclr; unsigned long imap_off, iclr_off; - int pil, inofixup = 0; + int inofixup = 0; ino &= PCI_IRQ_INO; if (ino < SABRE_ONBOARD_IRQ_BASE) { @@ -635,11 +563,6 @@ static unsigned int sabre_irq_build(struct pci_pbm_info *pbm, } /* Now build the IRQ bucket. */ - pil = sabre_ino_to_pil(pdev, ino); - - if (PIL_RESERVED(pil)) - BUG(); - imap = pbm->controller_regs + imap_off; imap += 4; @@ -650,7 +573,7 @@ static unsigned int sabre_irq_build(struct pci_pbm_info *pbm, if ((ino & 0x20) == 0) inofixup = ino & 0x03; - bucket = __bucket(build_irq(pil, inofixup, iclr, imap)); + bucket = __bucket(build_irq(inofixup, iclr, imap)); bucket->flags |= IBF_PCI; if (pdev) { diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c index 7fe4de03ac2e..ca49ef08236d 100644 --- a/arch/sparc64/kernel/pci_schizo.c +++ b/arch/sparc64/kernel/pci_schizo.c @@ -232,101 +232,6 @@ static unsigned long schizo_iclr_offset(unsigned long ino) return SCHIZO_ICLR_BASE + (ino * 8UL); } -/* PCI SCHIZO INO number to Sparc PIL level. This table only matters for - * INOs which will not have an associated PCI device struct, ie. onboard - * EBUS devices and PCI controller internal error interrupts. - */ -static unsigned char schizo_pil_table[] = { -/*0x00*/0, 0, 0, 0, /* PCI slot 0 Int A, B, C, D */ -/*0x04*/0, 0, 0, 0, /* PCI slot 1 Int A, B, C, D */ -/*0x08*/0, 0, 0, 0, /* PCI slot 2 Int A, B, C, D */ -/*0x0c*/0, 0, 0, 0, /* PCI slot 3 Int A, B, C, D */ -/*0x10*/0, 0, 0, 0, /* PCI slot 4 Int A, B, C, D */ -/*0x14*/0, 0, 0, 0, /* PCI slot 5 Int A, B, C, D */ -/*0x18*/5, /* SCSI */ -/*0x19*/5, /* second SCSI */ -/*0x1a*/0, /* UNKNOWN */ -/*0x1b*/0, /* UNKNOWN */ -/*0x1c*/8, /* Parallel */ -/*0x1d*/5, /* Ethernet */ -/*0x1e*/8, /* Firewire-1394 */ -/*0x1f*/9, /* USB */ -/*0x20*/13, /* Audio Record */ -/*0x21*/14, /* Audio Playback */ -/*0x22*/12, /* Serial */ -/*0x23*/5, /* EBUS I2C */ -/*0x24*/10, /* RTC Clock */ -/*0x25*/11, /* Floppy */ -/*0x26*/0, /* UNKNOWN */ -/*0x27*/0, /* UNKNOWN */ -/*0x28*/0, /* UNKNOWN */ -/*0x29*/0, /* UNKNOWN */ -/*0x2a*/10, /* UPA 1 */ -/*0x2b*/10, /* UPA 2 */ -/*0x2c*/0, /* UNKNOWN */ -/*0x2d*/0, /* UNKNOWN */ -/*0x2e*/0, /* UNKNOWN */ -/*0x2f*/0, /* UNKNOWN */ -/*0x30*/15, /* Uncorrectable ECC */ -/*0x31*/15, /* Correctable ECC */ -/*0x32*/15, /* PCI Bus A Error */ -/*0x33*/15, /* PCI Bus B Error */ -/*0x34*/15, /* Safari Bus Error */ -/*0x35*/0, /* Reserved */ -/*0x36*/0, /* Reserved */ -/*0x37*/0, /* Reserved */ -/*0x38*/0, /* Reserved for NewLink */ -/*0x39*/0, /* Reserved for NewLink */ -/*0x3a*/0, /* Reserved for NewLink */ -/*0x3b*/0, /* Reserved for NewLink */ -/*0x3c*/0, /* Reserved for NewLink */ -/*0x3d*/0, /* Reserved for NewLink */ -/*0x3e*/0, /* Reserved for NewLink */ -/*0x3f*/0, /* Reserved for NewLink */ -}; - -static int schizo_ino_to_pil(struct pci_dev *pdev, unsigned int ino) -{ - int ret; - - if (pdev && - pdev->vendor == PCI_VENDOR_ID_SUN && - pdev->device == PCI_DEVICE_ID_SUN_RIO_USB) - return 9; - - ret = schizo_pil_table[ino]; - if (ret == 0 && pdev == NULL) { - ret = 5; - } else if (ret == 0) { - switch ((pdev->class >> 16) & 0xff) { - case PCI_BASE_CLASS_STORAGE: - ret = 5; - break; - - case PCI_BASE_CLASS_NETWORK: - ret = 6; - break; - - case PCI_BASE_CLASS_DISPLAY: - ret = 9; - break; - - case PCI_BASE_CLASS_MULTIMEDIA: - case PCI_BASE_CLASS_MEMORY: - case PCI_BASE_CLASS_BRIDGE: - case PCI_BASE_CLASS_SERIAL: - ret = 10; - break; - - default: - ret = 5; - break; - }; - } - - return ret; -} - static void tomatillo_wsync_handler(struct ino_bucket *bucket, void *_arg1, void *_arg2) { unsigned long sync_reg = (unsigned long) _arg2; @@ -372,17 +277,12 @@ static unsigned int schizo_irq_build(struct pci_pbm_info *pbm, struct ino_bucket *bucket; unsigned long imap, iclr; unsigned long imap_off, iclr_off; - int pil, ign_fixup; + int ign_fixup; ino &= PCI_IRQ_INO; imap_off = schizo_imap_offset(ino); /* Now build the IRQ bucket. */ - pil = schizo_ino_to_pil(pdev, ino); - - if (PIL_RESERVED(pil)) - BUG(); - imap = pbm->pbm_regs + imap_off; imap += 4; @@ -405,7 +305,7 @@ static unsigned int schizo_irq_build(struct pci_pbm_info *pbm, ign_fixup = (1 << 6); } - bucket = __bucket(build_irq(pil, ign_fixup, iclr, imap)); + bucket = __bucket(build_irq(ign_fixup, iclr, imap)); bucket->flags |= IBF_PCI; if (pdev && pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO) { diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index 0c0895202970..b97c81ba8835 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c @@ -843,38 +843,8 @@ static unsigned int pci_sun4v_irq_build(struct pci_pbm_info *pbm, unsigned int devino) { u32 devhandle = pbm->devhandle; - int pil; - pil = 5; - if (pdev) { - switch ((pdev->class >> 16) & 0xff) { - case PCI_BASE_CLASS_STORAGE: - pil = 5; - break; - - case PCI_BASE_CLASS_NETWORK: - pil = 6; - break; - - case PCI_BASE_CLASS_DISPLAY: - pil = 9; - break; - - case PCI_BASE_CLASS_MULTIMEDIA: - case PCI_BASE_CLASS_MEMORY: - case PCI_BASE_CLASS_BRIDGE: - case PCI_BASE_CLASS_SERIAL: - pil = 10; - break; - - default: - pil = 5; - break; - }; - } - BUG_ON(PIL_RESERVED(pil)); - - return sun4v_build_irq(devhandle, devino, pil, IBF_PCI); + return sun4v_build_irq(devhandle, devino, IBF_PCI); } static void pci_sun4v_base_address_update(struct pci_dev *pdev, int resource) diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c index 1d6ffdeabd4c..8812417247d4 100644 --- a/arch/sparc64/kernel/sbus.c +++ b/arch/sparc64/kernel/sbus.c @@ -691,36 +691,6 @@ void sbus_set_sbus64(struct sbus_dev *sdev, int bursts) upa_writeq(val, cfg_reg); } -/* SBUS SYSIO INO number to Sparc PIL level. */ -static unsigned char sysio_ino_to_pil[] = { - 0, 5, 5, 7, 5, 7, 8, 9, /* SBUS slot 0 */ - 0, 5, 5, 7, 5, 7, 8, 9, /* SBUS slot 1 */ - 0, 5, 5, 7, 5, 7, 8, 9, /* SBUS slot 2 */ - 0, 5, 5, 7, 5, 7, 8, 9, /* SBUS slot 3 */ - 5, /* Onboard SCSI */ - 5, /* Onboard Ethernet */ -/*XXX*/ 8, /* Onboard BPP */ - 0, /* Bogon */ - 13, /* Audio */ -/*XXX*/15, /* PowerFail */ - 0, /* Bogon */ - 0, /* Bogon */ - 12, /* Zilog Serial Channels (incl. Keyboard/Mouse lines) */ - 11, /* Floppy */ - 0, /* Spare Hardware (bogon for now) */ - 0, /* Keyboard (bogon for now) */ - 0, /* Mouse (bogon for now) */ - 0, /* Serial (bogon for now) */ - 0, 0, /* Bogon, Bogon */ - 10, /* Timer 0 */ - 11, /* Timer 1 */ - 0, 0, /* Bogon, Bogon */ - 15, /* Uncorrectable SBUS Error */ - 15, /* Correctable SBUS Error */ - 15, /* SBUS Error */ -/*XXX*/ 0, /* Power Management (bogon for now) */ -}; - /* INO number to IMAP register offset for SYSIO external IRQ's. * This should conform to both Sunfire/Wildfire server and Fusion * desktop designs. @@ -812,21 +782,12 @@ unsigned int sbus_build_irq(void *buscookie, unsigned int ino) struct sbus_iommu *iommu = sbus->iommu; unsigned long reg_base = iommu->sbus_control_reg - 0x2000UL; unsigned long imap, iclr; - int pil, sbus_level = 0; - - pil = sysio_ino_to_pil[ino]; - if (!pil) { - printk("sbus_irq_build: Bad SYSIO INO[%x]\n", ino); - panic("Bad SYSIO IRQ translations..."); - } - - if (PIL_RESERVED(pil)) - BUG(); + int sbus_level = 0; imap = sysio_irq_offsets[ino]; if (imap == ((unsigned long)-1)) { - prom_printf("get_irq_translations: Bad SYSIO INO[%x] cpu[%d]\n", - ino, pil); + prom_printf("get_irq_translations: Bad SYSIO INO[%x]\n", + ino); prom_halt(); } imap += reg_base; @@ -860,7 +821,7 @@ unsigned int sbus_build_irq(void *buscookie, unsigned int ino) iclr += ((unsigned long)sbus_level - 1UL) * 8UL; } - return build_irq(pil, sbus_level, iclr, imap); + return build_irq(sbus_level, iclr, imap); } /* Error interrupt handling. */ diff --git a/include/asm-sparc64/irq.h b/include/asm-sparc64/irq.h index bbdf89e6faa4..d66c7cd820c2 100644 --- a/include/asm-sparc64/irq.h +++ b/include/asm-sparc64/irq.h @@ -37,14 +37,14 @@ struct irq_desc { * line. Keep this in mind please. */ struct ino_bucket { - /* Next handler in per-CPU PIL worklist. We know that + /* Next handler in per-CPU IRQ worklist. We know that * bucket pointers have the high 32-bits clear, so to * save space we only store the bits we need. */ /*0x00*/unsigned int irq_chain; - /* PIL to schedule this IVEC at. */ -/*0x04*/unsigned char pil; + /* Virtual interrupt number assigned to this INO. */ +/*0x04*/unsigned char virt_irq; /* If an IVEC arrives while irq_info is NULL, we * set this to notify request_irq() about the event. @@ -95,7 +95,6 @@ extern struct ino_bucket ivector_table[NUM_IVECS]; #define __irq_ino(irq) \ (((struct ino_bucket *)(unsigned long)(irq)) - &ivector_table[0]) -#define __irq_pil(irq) ((struct ino_bucket *)(unsigned long)(irq))->pil #define __bucket(irq) ((struct ino_bucket *)(unsigned long)(irq)) #define __irq(bucket) ((unsigned int)(unsigned long)(bucket)) @@ -105,8 +104,8 @@ extern struct ino_bucket ivector_table[NUM_IVECS]; extern void disable_irq(unsigned int); #define disable_irq_nosync disable_irq extern void enable_irq(unsigned int); -extern unsigned int build_irq(int pil, int inofixup, unsigned long iclr, unsigned long imap); -extern unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino, int pil, unsigned char flags); +extern unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap); +extern unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino, unsigned char flags); extern unsigned int sbus_build_irq(void *sbus, unsigned int ino); static __inline__ void set_softint(unsigned long bits) -- cgit v1.2.3 From 8047e247c899f80c33a23ad7e9e250224f0d26a5 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 20 Jun 2006 01:22:35 -0700 Subject: [SPARC64]: Virtualize IRQ numbers. Inspired by PowerPC XICS interrupt support code. All IRQs are virtualized in order to keep NR_IRQS from needing to be too large. Interrupts on sparc64 are arbitrary 11-bit values, but we don't need to define NR_IRQS to 2048 if we virtualize the IRQs. As PCI and SBUS controller drivers build device IRQs, we divy out virtual IRQ numbers incrementally starting at 1. Zero is a special virtual IRQ used for the timer interrupt. So device drivers all see virtual IRQs, and all the normal interfaces such as request_irq(), enable_irq(), etc. translate that into a real IRQ number in order to configure the IRQ. At this point knowledge of the struct ino_bucket is almost entirely contained within arch/sparc64/kernel/irq.c There are a few small bits in the PCI controller drivers that need to be swept away before we can remove ino_bucket's definition out of asm-sparc64/irq.h and privately into kernel/irq.c Signed-off-by: David S. Miller --- arch/sparc64/kernel/irq.c | 263 ++++++++++++++++++++++++++------------- arch/sparc64/kernel/pci_psycho.c | 6 +- arch/sparc64/kernel/pci_sabre.c | 18 +-- arch/sparc64/kernel/pci_schizo.c | 86 ++++++------- arch/sparc64/kernel/sbus.c | 2 +- include/asm-sparc64/irq.h | 13 +- 6 files changed, 242 insertions(+), 146 deletions(-) (limited to 'include') diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index f2668f2bed9c..49ad9cd0f8c8 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c @@ -70,7 +70,10 @@ struct ino_bucket ivector_table[NUM_IVECS] __attribute__ ((aligned (SMP_CACHE_BY */ #define irq_work(__cpu) &(trap_block[(__cpu)].irq_worklist) -static struct irqaction *irq_action[NR_IRQS]; +static struct irqaction timer_irq_action = { + .name = "timer", +}; +static struct irqaction *irq_action[NR_IRQS] = { &timer_irq_action, }; /* This only synchronizes entities which modify IRQ handler * state and some selected user-level spots that want to @@ -79,6 +82,59 @@ static struct irqaction *irq_action[NR_IRQS]; */ static DEFINE_SPINLOCK(irq_action_lock); +static unsigned int virt_to_real_irq_table[NR_IRQS]; +static unsigned char virt_irq_cur = 1; + +static unsigned char virt_irq_alloc(unsigned int real_irq) +{ + unsigned char ent; + + BUILD_BUG_ON(NR_IRQS >= 256); + + ent = virt_irq_cur; + if (ent >= NR_IRQS) { + printk(KERN_ERR "IRQ: Out of virtual IRQs.\n"); + return 0; + } + + virt_irq_cur = ent + 1; + virt_to_real_irq_table[ent] = real_irq; + + return ent; +} + +#if 0 /* Currently unused. */ +static unsigned char real_to_virt_irq(unsigned int real_irq) +{ + struct ino_bucket *bucket = __bucket(real_irq); + + return bucket->virt_irq; +} +#endif + +static unsigned int virt_to_real_irq(unsigned char virt_irq) +{ + return virt_to_real_irq_table[virt_irq]; +} + +void irq_install_pre_handler(int virt_irq, + void (*func)(struct ino_bucket *, void *, void *), + void *arg1, void *arg2) +{ + unsigned int real_irq = virt_to_real_irq(virt_irq); + struct ino_bucket *bucket; + struct irq_desc *d; + + if (unlikely(!real_irq)) + return; + + bucket = __bucket(real_irq); + d = bucket->irq_info; + d->pre_handler = func; + d->pre_handler_arg1 = arg1; + d->pre_handler_arg2 = arg2; +} + static void register_irq_proc (unsigned int irq); /* @@ -164,14 +220,18 @@ static unsigned int sun4u_compute_tid(unsigned long imap, unsigned long cpuid) return tid; } -/* Now these are always passed a true fully specified sun4u INO. */ -void enable_irq(unsigned int irq) +void enable_irq(unsigned int virt_irq) { - struct ino_bucket *bucket = __bucket(irq); + unsigned int real_irq = virt_to_real_irq(virt_irq); + struct ino_bucket *bucket; unsigned long imap, cpuid; + if (unlikely(!real_irq)) + return; + + bucket = __bucket(real_irq); imap = bucket->imap; - if (imap == 0UL) + if (unlikely(imap == 0UL)) return; preempt_disable(); @@ -182,7 +242,7 @@ void enable_irq(unsigned int irq) cpuid = real_hard_smp_processor_id(); if (tlb_type == hypervisor) { - unsigned int ino = __irq_ino(irq); + unsigned int ino = __irq_ino(real_irq); int err; err = sun4v_intr_settarget(ino, cpuid); @@ -211,34 +271,39 @@ void enable_irq(unsigned int irq) preempt_enable(); } -/* This now gets passed true ino's as well. */ -void disable_irq(unsigned int irq) +void disable_irq(unsigned int virt_irq) { - struct ino_bucket *bucket = __bucket(irq); + unsigned int real_irq = virt_to_real_irq(virt_irq); + struct ino_bucket *bucket; unsigned long imap; + if (unlikely(!real_irq)) + return; + + bucket = __bucket(real_irq); imap = bucket->imap; - if (imap != 0UL) { - if (tlb_type == hypervisor) { - unsigned int ino = __irq_ino(irq); - int err; - - err = sun4v_intr_setenabled(ino, HV_INTR_DISABLED); - if (err != HV_EOK) - printk("sun4v_intr_setenabled(%x): " - "err(%d)\n", ino, err); - } else { - u32 tmp; - - /* NOTE: We do not want to futz with the IRQ clear registers - * and move the state to IDLE, the SCSI code does call - * disable_irq() to assure atomicity in the queue cmd - * SCSI adapter driver code. Thus we'd lose interrupts. - */ - tmp = upa_readl(imap); - tmp &= ~IMAP_VALID; - upa_writel(tmp, imap); - } + if (unlikely(imap == 0UL)) + return; + + if (tlb_type == hypervisor) { + unsigned int ino = __irq_ino(real_irq); + int err; + + err = sun4v_intr_setenabled(ino, HV_INTR_DISABLED); + if (err != HV_EOK) + printk("sun4v_intr_setenabled(%x): " + "err(%d)\n", ino, err); + } else { + u32 tmp; + + /* NOTE: We do not want to futz with the IRQ clear registers + * and move the state to IDLE, the SCSI code does call + * disable_irq() to assure atomicity in the queue cmd + * SCSI adapter driver code. Thus we'd lose interrupts. + */ + tmp = upa_readl(imap); + tmp &= ~IMAP_VALID; + upa_writel(tmp, imap); } } @@ -253,14 +318,14 @@ static void build_irq_error(const char *msg, unsigned int ino, int inofixup, prom_halt(); } -unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap) +unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap, unsigned char flags) { struct ino_bucket *bucket; int ino; BUG_ON(tlb_type == hypervisor); - /* RULE: Both must be specified in all other cases. */ + /* RULE: Both must be specified. */ if (iclr == 0UL || imap == 0UL) { prom_printf("Invalid build_irq %d %016lx %016lx\n", inofixup, iclr, imap); @@ -298,10 +363,12 @@ unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap) */ bucket->imap = imap; bucket->iclr = iclr; - bucket->flags = 0; + if (!bucket->virt_irq) + bucket->virt_irq = virt_irq_alloc(__irq(bucket)); + bucket->flags = flags; out: - return __irq(bucket); + return bucket->virt_irq; } unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino, unsigned char flags) @@ -322,7 +389,8 @@ unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino, unsigned char f */ bucket->imap = ~0UL - sysino; bucket->iclr = ~0UL - sysino; - + if (!bucket->virt_irq) + bucket->virt_irq = virt_irq_alloc(__irq(bucket)); bucket->flags = flags; bucket->irq_info = kzalloc(sizeof(struct irq_desc), GFP_ATOMIC); @@ -331,7 +399,7 @@ unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino, unsigned char f prom_halt(); } - return __irq(bucket); + return bucket->virt_irq; } static void atomic_bucket_insert(struct ino_bucket *bucket) @@ -390,37 +458,42 @@ static struct irqaction *get_action_slot(struct ino_bucket *bucket) return NULL; } -int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), +int request_irq(unsigned int virt_irq, + irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long irqflags, const char *name, void *dev_id) { struct irqaction *action; - struct ino_bucket *bucket = __bucket(irq); + struct ino_bucket *bucket; unsigned long flags; + unsigned int real_irq; int pending = 0; + real_irq = virt_to_real_irq(virt_irq); + if (unlikely(!real_irq)) + return -EINVAL; + if (unlikely(!handler)) return -EINVAL; + bucket = __bucket(real_irq); if (unlikely(!bucket->irq_info)) return -ENODEV; if (irqflags & SA_SAMPLE_RANDOM) { /* - * This function might sleep, we want to call it first, - * outside of the atomic block. In SA_STATIC_ALLOC case, - * random driver's kmalloc will fail, but it is safe. - * If already initialized, random driver will not reinit. - * Yes, this might clear the entropy pool if the wrong - * driver is attempted to be loaded, without actually - * installing a new handler, but is this really a problem, - * only the sysadmin is able to do this. - */ - rand_initialize_irq(PIL_DEVICE_IRQ); + * This function might sleep, we want to call it first, + * outside of the atomic block. + * Yes, this might clear the entropy pool if the wrong + * driver is attempted to be loaded, without actually + * installing a new handler, but is this really a problem, + * only the sysadmin is able to do this. + */ + rand_initialize_irq(virt_irq); } spin_lock_irqsave(&irq_action_lock, flags); - if (check_irq_sharing(PIL_DEVICE_IRQ, irqflags)) { + if (check_irq_sharing(virt_irq, irqflags)) { spin_unlock_irqrestore(&irq_action_lock, flags); return -EBUSY; } @@ -441,12 +514,12 @@ int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_ action->name = name; action->next = NULL; action->dev_id = dev_id; - put_ino_in_irqaction(action, irq); + put_ino_in_irqaction(action, __irq_ino(real_irq)); put_smpaff_in_irqaction(action, CPU_MASK_NONE); - append_irq_action(PIL_DEVICE_IRQ, action); + append_irq_action(virt_irq, action); - enable_irq(irq); + enable_irq(virt_irq); /* We ate the IVEC already, this makes sure it does not get lost. */ if (pending) { @@ -456,7 +529,7 @@ int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_ spin_unlock_irqrestore(&irq_action_lock, flags); - register_irq_proc(__irq_ino(irq)); + register_irq_proc(virt_irq); #ifdef CONFIG_SMP distribute_irqs(); @@ -466,17 +539,17 @@ int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_ EXPORT_SYMBOL(request_irq); -static struct irqaction *unlink_irq_action(unsigned int irq, void *dev_id) +static struct irqaction *unlink_irq_action(unsigned int virt_irq, void *dev_id) { struct irqaction *action, **pp; - pp = irq_action + PIL_DEVICE_IRQ; + pp = irq_action + virt_irq; action = *pp; if (unlikely(!action)) return NULL; if (unlikely(!action->handler)) { - printk("Freeing free IRQ %d\n", PIL_DEVICE_IRQ); + printk("Freeing free IRQ %d\n", virt_irq); return NULL; } @@ -491,28 +564,33 @@ static struct irqaction *unlink_irq_action(unsigned int irq, void *dev_id) return action; } -void free_irq(unsigned int irq, void *dev_id) +void free_irq(unsigned int virt_irq, void *dev_id) { struct irqaction *action; struct ino_bucket *bucket; struct irq_desc *desc; unsigned long flags; + unsigned int real_irq; int ent, i; + real_irq = virt_to_real_irq(virt_irq); + if (unlikely(!real_irq)) + return; + spin_lock_irqsave(&irq_action_lock, flags); - action = unlink_irq_action(irq, dev_id); + action = unlink_irq_action(virt_irq, dev_id); spin_unlock_irqrestore(&irq_action_lock, flags); if (unlikely(!action)) return; - synchronize_irq(irq); + synchronize_irq(virt_irq); spin_lock_irqsave(&irq_action_lock, flags); - bucket = __bucket(irq); + bucket = __bucket(real_irq); desc = bucket->irq_info; for (i = 0; i < MAX_IRQ_DESC_ACTION; i++) { @@ -545,7 +623,7 @@ void free_irq(unsigned int irq, void *dev_id) * the same IMAP are active. */ if (ent == NUM_IVECS) - disable_irq(irq); + disable_irq(virt_irq); } spin_unlock_irqrestore(&irq_action_lock, flags); @@ -554,10 +632,15 @@ void free_irq(unsigned int irq, void *dev_id) EXPORT_SYMBOL(free_irq); #ifdef CONFIG_SMP -void synchronize_irq(unsigned int irq) +void synchronize_irq(unsigned int virt_irq) { - struct ino_bucket *bucket = __bucket(irq); + unsigned int real_irq = virt_to_real_irq(virt_irq); + struct ino_bucket *bucket; + + if (unlikely(!real_irq)) + return; + bucket = __bucket(real_irq); #if 0 /* The following is how I wish I could implement this. * Unfortunately the ICLR registers are read-only, you can @@ -616,7 +699,7 @@ static void process_bucket(struct ino_bucket *bp, struct pt_regs *regs) action_mask &= ~mask; - if (p->handler(__irq(bp), p->dev_id, regs) == IRQ_HANDLED) + if (p->handler(bp->virt_irq, p->dev_id, regs) == IRQ_HANDLED) random |= p->flags; if (!action_mask) @@ -637,7 +720,7 @@ static void process_bucket(struct ino_bucket *bp, struct pt_regs *regs) /* Test and add entropy */ if (random & SA_SAMPLE_RANDOM) - add_interrupt_randomness(PIL_DEVICE_IRQ); + add_interrupt_randomness(bp->virt_irq); out: bp->flags &= ~IBF_INPROGRESS; } @@ -657,7 +740,7 @@ void timer_irq(int irq, struct pt_regs *regs) clear_softint(clr_mask); irq_enter(); - kstat_this_cpu.irqs[irq]++; + kstat_this_cpu.irqs[0]++; timer_interrupt(irq, NULL, regs); irq_exit(); } @@ -1022,13 +1105,13 @@ void __init init_IRQ(void) : "g1"); } -static struct proc_dir_entry * root_irq_dir; -static struct proc_dir_entry * irq_dir [NUM_IVECS]; +static struct proc_dir_entry *root_irq_dir; +static struct proc_dir_entry *irq_dir[NR_IRQS]; #ifdef CONFIG_SMP -static int irq_affinity_read_proc (char *page, char **start, off_t off, - int count, int *eof, void *data) +static int irq_affinity_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) { struct ino_bucket *bp = ivector_table + (long)data; struct irq_desc *desc = bp->irq_info; @@ -1047,11 +1130,20 @@ static int irq_affinity_read_proc (char *page, char **start, off_t off, return len; } -static inline void set_intr_affinity(int irq, cpumask_t hw_aff) +static inline void set_intr_affinity(int virt_irq, cpumask_t hw_aff) { - struct ino_bucket *bp = ivector_table + irq; - struct irq_desc *desc = bp->irq_info; - struct irqaction *ap = desc->action; + struct ino_bucket *bp; + struct irq_desc *desc; + struct irqaction *ap; + unsigned int real_irq; + + real_irq = virt_to_real_irq(virt_irq); + if (unlikely(!real_irq)) + return; + + bp = __bucket(real_irq); + desc = bp->irq_info; + ap = desc->action; /* Users specify affinity in terms of hw cpu ids. * As soon as we do this, handler_irq() might see and take action. @@ -1060,13 +1152,16 @@ static inline void set_intr_affinity(int irq, cpumask_t hw_aff) /* Migration is simply done by the next cpu to service this * interrupt. + * + * XXX Broken, this doesn't happen anymore... */ } -static int irq_affinity_write_proc (struct file *file, const char __user *buffer, - unsigned long count, void *data) +static int irq_affinity_write_proc(struct file *file, + const char __user *buffer, + unsigned long count, void *data) { - int irq = (long) data, full_count = count, err; + int virt_irq = (long) data, full_count = count, err; cpumask_t new_value; err = cpumask_parse(buffer, count, new_value); @@ -1080,7 +1175,7 @@ static int irq_affinity_write_proc (struct file *file, const char __user *buffer if (cpus_empty(new_value)) return -EINVAL; - set_intr_affinity(irq, new_value); + set_intr_affinity(virt_irq, new_value); return full_count; } @@ -1089,18 +1184,18 @@ static int irq_affinity_write_proc (struct file *file, const char __user *buffer #define MAX_NAMELEN 10 -static void register_irq_proc (unsigned int irq) +static void register_irq_proc(unsigned int virt_irq) { char name [MAX_NAMELEN]; - if (!root_irq_dir || irq_dir[irq]) + if (!root_irq_dir || irq_dir[virt_irq]) return; memset(name, 0, MAX_NAMELEN); - sprintf(name, "%x", irq); + sprintf(name, "%d", virt_irq); /* create /proc/irq/1234 */ - irq_dir[irq] = proc_mkdir(name, root_irq_dir); + irq_dir[virt_irq] = proc_mkdir(name, root_irq_dir); #ifdef CONFIG_SMP /* XXX SMP affinity not supported on starfire yet. */ @@ -1112,7 +1207,7 @@ static void register_irq_proc (unsigned int irq) if (entry) { entry->nlink = 1; - entry->data = (void *)(long)irq; + entry->data = (void *)(long)virt_irq; entry->read_proc = irq_affinity_read_proc; entry->write_proc = irq_affinity_write_proc; } @@ -1120,7 +1215,7 @@ static void register_irq_proc (unsigned int irq) #endif } -void init_irq_proc (void) +void init_irq_proc(void) { /* create /proc/irq */ root_irq_dir = proc_mkdir("irq", NULL); diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c index 5743e1316a93..f2d1097f541d 100644 --- a/arch/sparc64/kernel/pci_psycho.c +++ b/arch/sparc64/kernel/pci_psycho.c @@ -280,7 +280,6 @@ static unsigned int psycho_irq_build(struct pci_pbm_info *pbm, struct pci_dev *pdev, unsigned int ino) { - struct ino_bucket *bucket; unsigned long imap, iclr; unsigned long imap_off, iclr_off; int inofixup = 0; @@ -309,10 +308,7 @@ static unsigned int psycho_irq_build(struct pci_pbm_info *pbm, if ((ino & 0x20) == 0) inofixup = ino & 0x03; - bucket = __bucket(build_irq(inofixup, iclr, imap)); - bucket->flags |= IBF_PCI; - - return __irq(bucket); + return build_irq(inofixup, iclr, imap, IBF_PCI); } /* PSYCHO error handling support. */ diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index caa7aeed5d14..846c1205aa9a 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c @@ -544,10 +544,10 @@ static unsigned int sabre_irq_build(struct pci_pbm_info *pbm, struct pci_dev *pdev, unsigned int ino) { - struct ino_bucket *bucket; unsigned long imap, iclr; unsigned long imap_off, iclr_off; int inofixup = 0; + int virt_irq; ino &= PCI_IRQ_INO; if (ino < SABRE_ONBOARD_IRQ_BASE) { @@ -573,23 +573,23 @@ static unsigned int sabre_irq_build(struct pci_pbm_info *pbm, if ((ino & 0x20) == 0) inofixup = ino & 0x03; - bucket = __bucket(build_irq(inofixup, iclr, imap)); - bucket->flags |= IBF_PCI; + virt_irq = build_irq(inofixup, iclr, imap, IBF_PCI); if (pdev) { struct pcidev_cookie *pcp = pdev->sysdata; if (pdev->bus->number != pcp->pbm->pci_first_busno) { struct pci_controller_info *p = pcp->pbm->parent; - struct irq_desc *d = bucket->irq_info; - d->pre_handler = sabre_wsync_handler; - d->pre_handler_arg1 = pdev; - d->pre_handler_arg2 = (void *) - p->pbm_A.controller_regs + SABRE_WRSYNC; + irq_install_pre_handler(virt_irq, + sabre_wsync_handler, + pdev, + (void *) + p->pbm_A.controller_regs + + SABRE_WRSYNC); } } - return __irq(bucket); + return virt_irq; } /* SABRE error handling support. */ diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c index ca49ef08236d..0c400b5fa5bd 100644 --- a/arch/sparc64/kernel/pci_schizo.c +++ b/arch/sparc64/kernel/pci_schizo.c @@ -270,25 +270,33 @@ static void tomatillo_wsync_handler(struct ino_bucket *bucket, void *_arg1, void } } +static unsigned long schizo_ino_to_iclr(struct pci_pbm_info *pbm, + unsigned int ino) +{ + ino &= PCI_IRQ_INO; + return pbm->pbm_regs + schizo_iclr_offset(ino) + 4; +} + +static unsigned long schizo_ino_to_imap(struct pci_pbm_info *pbm, + unsigned int ino) +{ + ino &= PCI_IRQ_INO; + return pbm->pbm_regs + schizo_imap_offset(ino) + 4; +} + static unsigned int schizo_irq_build(struct pci_pbm_info *pbm, struct pci_dev *pdev, unsigned int ino) { - struct ino_bucket *bucket; unsigned long imap, iclr; - unsigned long imap_off, iclr_off; int ign_fixup; + int virt_irq; ino &= PCI_IRQ_INO; - imap_off = schizo_imap_offset(ino); /* Now build the IRQ bucket. */ - imap = pbm->pbm_regs + imap_off; - imap += 4; - - iclr_off = schizo_iclr_offset(ino); - iclr = pbm->pbm_regs + iclr_off; - iclr += 4; + imap = schizo_ino_to_imap(pbm, ino); + iclr = schizo_ino_to_iclr(pbm, ino); /* On Schizo, no inofixup occurs. This is because each * INO has it's own IMAP register. On Psycho and Sabre @@ -305,19 +313,17 @@ static unsigned int schizo_irq_build(struct pci_pbm_info *pbm, ign_fixup = (1 << 6); } - bucket = __bucket(build_irq(ign_fixup, iclr, imap)); - bucket->flags |= IBF_PCI; + virt_irq = build_irq(ign_fixup, iclr, imap, IBF_PCI); if (pdev && pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO) { - struct irq_desc *p = bucket->irq_info; - - p->pre_handler = tomatillo_wsync_handler; - p->pre_handler_arg1 = ((pbm->chip_version <= 4) ? - (void *) 1 : (void *) 0); - p->pre_handler_arg2 = (void *) pbm->sync_reg; + irq_install_pre_handler(virt_irq, + tomatillo_wsync_handler, + ((pbm->chip_version <= 4) ? + (void *) 1 : (void *) 0), + (void *) pbm->sync_reg); } - return __irq(bucket); + return virt_irq; } /* SCHIZO error handling support. */ @@ -358,7 +364,6 @@ struct pci_pbm_info *pbm_for_ino(struct pci_controller_info *p, u32 ino) static void schizo_clear_other_err_intr(struct pci_controller_info *p, int irq) { struct pci_pbm_info *pbm; - struct ino_bucket *bucket; unsigned long iclr; /* Do not clear the interrupt for the other PCI bus. @@ -376,11 +381,11 @@ static void schizo_clear_other_err_intr(struct pci_controller_info *p, int irq) else pbm = &p->pbm_A; - irq = schizo_irq_build(pbm, NULL, - (pbm->portid << 6) | (irq & IMAP_INO)); - bucket = __bucket(irq); - iclr = bucket->iclr; + schizo_irq_build(pbm, NULL, + (pbm->portid << 6) | (irq & IMAP_INO)); + iclr = schizo_ino_to_iclr(pbm, + (pbm->portid << 6) | (irq & IMAP_INO)); upa_writel(ICLR_IDLE, iclr); } @@ -1125,7 +1130,6 @@ static void tomatillo_register_error_handlers(struct pci_controller_info *p) { struct pci_pbm_info *pbm; unsigned int irq; - struct ino_bucket *bucket; u64 tmp, err_mask, err_no_mask; /* Build IRQs and register handlers. */ @@ -1137,8 +1141,7 @@ static void tomatillo_register_error_handlers(struct pci_controller_info *p) pbm->name); prom_halt(); } - bucket = __bucket(irq); - tmp = upa_readl(bucket->imap); + tmp = upa_readl(schizo_ino_to_imap(pbm, (pbm->portid << 6) | SCHIZO_UE_INO)); upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_UE_INO) + 4)); @@ -1150,8 +1153,7 @@ static void tomatillo_register_error_handlers(struct pci_controller_info *p) pbm->name); prom_halt(); } - bucket = __bucket(irq); - tmp = upa_readl(bucket->imap); + tmp = upa_readl(schizo_ino_to_imap(pbm, (pbm->portid << 6) | SCHIZO_CE_INO)); upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_CE_INO) + 4)); @@ -1164,8 +1166,8 @@ static void tomatillo_register_error_handlers(struct pci_controller_info *p) pbm->name); prom_halt(); } - bucket = __bucket(irq); - tmp = upa_readl(bucket->imap); + tmp = upa_readl(schizo_ino_to_imap(pbm, ((pbm->portid << 6) | + SCHIZO_PCIERR_A_INO))); upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_PCIERR_A_INO) + 4)); @@ -1178,8 +1180,8 @@ static void tomatillo_register_error_handlers(struct pci_controller_info *p) pbm->name); prom_halt(); } - bucket = __bucket(irq); - tmp = upa_readl(bucket->imap); + tmp = upa_readl(schizo_ino_to_imap(pbm, ((pbm->portid << 6) | + SCHIZO_PCIERR_B_INO))); upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_PCIERR_B_INO) + 4)); @@ -1191,8 +1193,8 @@ static void tomatillo_register_error_handlers(struct pci_controller_info *p) pbm->name); prom_halt(); } - bucket = __bucket(irq); - tmp = upa_readl(bucket->imap); + tmp = upa_readl(schizo_ino_to_imap(pbm, ((pbm->portid << 6) | + SCHIZO_SERR_INO))); upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_SERR_INO) + 4)); @@ -1263,7 +1265,6 @@ static void schizo_register_error_handlers(struct pci_controller_info *p) { struct pci_pbm_info *pbm; unsigned int irq; - struct ino_bucket *bucket; u64 tmp, err_mask, err_no_mask; /* Build IRQs and register handlers. */ @@ -1275,8 +1276,7 @@ static void schizo_register_error_handlers(struct pci_controller_info *p) pbm->name); prom_halt(); } - bucket = __bucket(irq); - tmp = upa_readl(bucket->imap); + tmp = upa_readl(schizo_ino_to_imap(pbm, (pbm->portid << 6) | SCHIZO_UE_INO)); upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_UE_INO) + 4)); pbm = pbm_for_ino(p, SCHIZO_CE_INO); @@ -1287,8 +1287,7 @@ static void schizo_register_error_handlers(struct pci_controller_info *p) pbm->name); prom_halt(); } - bucket = __bucket(irq); - tmp = upa_readl(bucket->imap); + tmp = upa_readl(schizo_ino_to_imap(pbm, (pbm->portid << 6) | SCHIZO_CE_INO)); upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_CE_INO) + 4)); pbm = pbm_for_ino(p, SCHIZO_PCIERR_A_INO); @@ -1299,8 +1298,7 @@ static void schizo_register_error_handlers(struct pci_controller_info *p) pbm->name); prom_halt(); } - bucket = __bucket(irq); - tmp = upa_readl(bucket->imap); + tmp = upa_readl(schizo_ino_to_imap(pbm, (pbm->portid << 6) | SCHIZO_PCIERR_A_INO)); upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_PCIERR_A_INO) + 4)); pbm = pbm_for_ino(p, SCHIZO_PCIERR_B_INO); @@ -1311,8 +1309,7 @@ static void schizo_register_error_handlers(struct pci_controller_info *p) pbm->name); prom_halt(); } - bucket = __bucket(irq); - tmp = upa_readl(bucket->imap); + tmp = upa_readl(schizo_ino_to_imap(pbm, (pbm->portid << 6) | SCHIZO_PCIERR_B_INO)); upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_PCIERR_B_INO) + 4)); pbm = pbm_for_ino(p, SCHIZO_SERR_INO); @@ -1323,8 +1320,7 @@ static void schizo_register_error_handlers(struct pci_controller_info *p) pbm->name); prom_halt(); } - bucket = __bucket(irq); - tmp = upa_readl(bucket->imap); + tmp = upa_readl(schizo_ino_to_imap(pbm, (pbm->portid << 6) | SCHIZO_SERR_INO)); upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_SERR_INO) + 4)); /* Enable UE and CE interrupts for controller. */ diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c index 8812417247d4..5544cf5d38b2 100644 --- a/arch/sparc64/kernel/sbus.c +++ b/arch/sparc64/kernel/sbus.c @@ -821,7 +821,7 @@ unsigned int sbus_build_irq(void *buscookie, unsigned int ino) iclr += ((unsigned long)sbus_level - 1UL) * 8UL; } - return build_irq(sbus_level, iclr, imap); + return build_irq(sbus_level, iclr, imap, 0); } /* Error interrupt handling. */ diff --git a/include/asm-sparc64/irq.h b/include/asm-sparc64/irq.h index d66c7cd820c2..9edcd90495f7 100644 --- a/include/asm-sparc64/irq.h +++ b/include/asm-sparc64/irq.h @@ -98,13 +98,22 @@ extern struct ino_bucket ivector_table[NUM_IVECS]; #define __bucket(irq) ((struct ino_bucket *)(unsigned long)(irq)) #define __irq(bucket) ((unsigned int)(unsigned long)(bucket)) -#define NR_IRQS 16 +/* The largest number of unique interrupt sources we support. + * If this needs to ever be larger than 255, you need to change + * the type of ino_bucket->virt_irq as appropriate. + * + * ino_bucket->virt_irq allocation is made during {sun4v_,}build_irq(). + */ +#define NR_IRQS 255 +extern void irq_install_pre_handler(int virt_irq, + void (*func)(struct ino_bucket *, void *, void *), + void *arg1, void *arg2); #define irq_canonicalize(irq) (irq) extern void disable_irq(unsigned int); #define disable_irq_nosync disable_irq extern void enable_irq(unsigned int); -extern unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap); +extern unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap, unsigned char flags); extern unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino, unsigned char flags); extern unsigned int sbus_build_irq(void *sbus, unsigned int ino); -- cgit v1.2.3 From e18e2a00efc8352c131eb8d5a460149fb5776f1c Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 20 Jun 2006 01:23:32 -0700 Subject: [SPARC64]: Move over to GENERIC_HARDIRQS. This is the long overdue conversion of sparc64 over to the generic IRQ layer. The kernel image is slightly larger, but the BSS is ~60K smaller due to the reduced size of struct ino_bucket. A lot of IRQ implementation details, including ino_bucket, were moved out of asm-sparc64/irq.h and are now private to arch/sparc64/kernel/irq.c, and most of the code in irq.c totally disappeared. One thing that's different at the moment is IRQ distribution, we do it at enable_irq() time. If the cpu mask is ALL then we round-robin using a global rotating cpu counter, else we pick the first cpu in the mask to support single cpu targetting. This is similar to what powerpc's XICS IRQ support code does. This works fine on my UP SB1000, and the SMP build goes fine and runs on that machine, but lots of testing on different setups is needed. Signed-off-by: David S. Miller --- arch/sparc64/Kconfig | 4 + arch/sparc64/kernel/devices.c | 2 +- arch/sparc64/kernel/entry.S | 2 +- arch/sparc64/kernel/irq.c | 957 +++++++++++------------------------- arch/sparc64/kernel/pci.c | 38 -- arch/sparc64/kernel/pci_psycho.c | 2 +- arch/sparc64/kernel/pci_sabre.c | 4 +- arch/sparc64/kernel/pci_schizo.c | 6 +- arch/sparc64/kernel/pci_sun4v.c | 2 +- arch/sparc64/kernel/sbus.c | 2 +- arch/sparc64/kernel/sparc64_ksyms.c | 4 - arch/sparc64/kernel/sun4v_ivec.S | 2 +- include/asm-sparc64/hardirq.h | 2 + include/asm-sparc64/hw_irq.h | 2 +- include/asm-sparc64/irq.h | 78 +-- 15 files changed, 305 insertions(+), 802 deletions(-) (limited to 'include') diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig index 43a66f5407f4..a7a111db25b2 100644 --- a/arch/sparc64/Kconfig +++ b/arch/sparc64/Kconfig @@ -87,6 +87,10 @@ config SYSVIPC_COMPAT depends on COMPAT && SYSVIPC default y +config GENERIC_HARDIRQS + bool + default y + menu "General machine setup" config SMP diff --git a/arch/sparc64/kernel/devices.c b/arch/sparc64/kernel/devices.c index 0684899d998b..0dd95ae50e12 100644 --- a/arch/sparc64/kernel/devices.c +++ b/arch/sparc64/kernel/devices.c @@ -157,7 +157,7 @@ unsigned int sun4v_vdev_device_interrupt(unsigned int dev_node) return 0; } - return sun4v_build_irq(sun4v_vdev_devhandle, irq, 0); + return sun4v_build_irq(sun4v_vdev_devhandle, irq); } static const char *cpu_mid_prop(void) diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S index c87365e59e71..be85ce2a4ad9 100644 --- a/arch/sparc64/kernel/entry.S +++ b/arch/sparc64/kernel/entry.S @@ -432,7 +432,7 @@ do_ivec: membar #Sync sethi %hi(ivector_table), %g2 - sllx %g3, 5, %g3 + sllx %g3, 3, %g3 or %g2, %lo(ivector_table), %g2 add %g2, %g3, %g3 diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index 49ad9cd0f8c8..a8c9dc8d1958 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -42,10 +43,6 @@ #include #include -#ifdef CONFIG_SMP -static void distribute_irqs(void); -#endif - /* UPA nodes send interrupt packet to UltraSparc with first data reg * value low 5 (7 on Starfire) bits holding the IRQ identifier being * delivered. We must translate this into a non-vector IRQ so we can @@ -57,10 +54,29 @@ static void distribute_irqs(void); * The IVEC handler does not need to act atomically, the PIL dispatch * code uses CAS to get an atomic snapshot of the list and clear it * at the same time. + * + * If you make changes to ino_bucket, please update hand coded assembler + * of the vectored interrupt trap handler(s) in entry.S and sun4v_ivec.S */ +struct ino_bucket { + /* Next handler in per-CPU IRQ worklist. We know that + * bucket pointers have the high 32-bits clear, so to + * save space we only store the bits we need. + */ +/*0x00*/unsigned int irq_chain; + /* Virtual interrupt number assigned to this INO. */ +/*0x04*/unsigned int virt_irq; +}; + +#define NUM_IVECS (IMAP_INR + 1) struct ino_bucket ivector_table[NUM_IVECS] __attribute__ ((aligned (SMP_CACHE_BYTES))); +#define __irq_ino(irq) \ + (((struct ino_bucket *)(unsigned long)(irq)) - &ivector_table[0]) +#define __bucket(irq) ((struct ino_bucket *)(unsigned long)(irq)) +#define __irq(bucket) ((unsigned int)(unsigned long)(bucket)) + /* This has to be in the main kernel image, it cannot be * turned into per-cpu data. The reason is that the main * kernel image is locked into the TLB and this structure @@ -70,18 +86,6 @@ struct ino_bucket ivector_table[NUM_IVECS] __attribute__ ((aligned (SMP_CACHE_BY */ #define irq_work(__cpu) &(trap_block[(__cpu)].irq_worklist) -static struct irqaction timer_irq_action = { - .name = "timer", -}; -static struct irqaction *irq_action[NR_IRQS] = { &timer_irq_action, }; - -/* This only synchronizes entities which modify IRQ handler - * state and some selected user-level spots that want to - * read things in the table. IRQ handler processing orders - * its' accesses such that no locking is needed. - */ -static DEFINE_SPINLOCK(irq_action_lock); - static unsigned int virt_to_real_irq_table[NR_IRQS]; static unsigned char virt_irq_cur = 1; @@ -117,69 +121,45 @@ static unsigned int virt_to_real_irq(unsigned char virt_irq) return virt_to_real_irq_table[virt_irq]; } -void irq_install_pre_handler(int virt_irq, - void (*func)(struct ino_bucket *, void *, void *), - void *arg1, void *arg2) -{ - unsigned int real_irq = virt_to_real_irq(virt_irq); - struct ino_bucket *bucket; - struct irq_desc *d; - - if (unlikely(!real_irq)) - return; - - bucket = __bucket(real_irq); - d = bucket->irq_info; - d->pre_handler = func; - d->pre_handler_arg1 = arg1; - d->pre_handler_arg2 = arg2; -} - -static void register_irq_proc (unsigned int irq); - /* - * Upper 2b of irqaction->flags holds the ino. - * irqaction->mask holds the smp affinity information. + * /proc/interrupts printing: */ -#define put_ino_in_irqaction(action, irq) \ - action->flags &= 0xffffffffffffUL; \ - action->flags |= __irq_ino(irq) << 48; - -#define get_ino_in_irqaction(action) (action->flags >> 48) - -#define put_smpaff_in_irqaction(action, smpaff) (action)->mask = (smpaff) -#define get_smpaff_in_irqaction(action) ((action)->mask) int show_interrupts(struct seq_file *p, void *v) { + int i = *(loff_t *) v, j; + struct irqaction * action; unsigned long flags; - int i = *(loff_t *) v; - struct irqaction *action; -#ifdef CONFIG_SMP - int j; -#endif - spin_lock_irqsave(&irq_action_lock, flags); - if (i <= NR_IRQS) { - if (!(action = *(i + irq_action))) - goto out_unlock; - seq_printf(p, "%3d: ", i); + if (i == 0) { + seq_printf(p, " "); + for_each_online_cpu(j) + seq_printf(p, "CPU%d ",j); + seq_putc(p, '\n'); + } + + if (i < NR_IRQS) { + spin_lock_irqsave(&irq_desc[i].lock, flags); + action = irq_desc[i].action; + if (!action) + goto skip; + seq_printf(p, "%3d: ",i); #ifndef CONFIG_SMP seq_printf(p, "%10u ", kstat_irqs(i)); #else - for_each_online_cpu(j) { - seq_printf(p, "%10u ", - kstat_cpu(j).irqs[i]); - } + for_each_online_cpu(j) + seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); #endif - seq_printf(p, " %s", action->name); - for (action = action->next; action; action = action->next) + seq_printf(p, " %9s", irq_desc[i].handler->typename); + seq_printf(p, " %s", action->name); + + for (action=action->next; action; action = action->next) seq_printf(p, ", %s", action->name); + seq_putc(p, '\n'); +skip: + spin_unlock_irqrestore(&irq_desc[i].lock, flags); } -out_unlock: - spin_unlock_irqrestore(&irq_action_lock, flags); - return 0; } @@ -220,509 +200,321 @@ static unsigned int sun4u_compute_tid(unsigned long imap, unsigned long cpuid) return tid; } -void enable_irq(unsigned int virt_irq) -{ - unsigned int real_irq = virt_to_real_irq(virt_irq); - struct ino_bucket *bucket; - unsigned long imap, cpuid; - - if (unlikely(!real_irq)) - return; +struct irq_handler_data { + unsigned long iclr; + unsigned long imap; - bucket = __bucket(real_irq); - imap = bucket->imap; - if (unlikely(imap == 0UL)) - return; - - preempt_disable(); - - /* This gets the physical processor ID, even on uniprocessor, - * so we can always program the interrupt target correctly. - */ - cpuid = real_hard_smp_processor_id(); - - if (tlb_type == hypervisor) { - unsigned int ino = __irq_ino(real_irq); - int err; - - err = sun4v_intr_settarget(ino, cpuid); - if (err != HV_EOK) - printk("sun4v_intr_settarget(%x,%lu): err(%d)\n", - ino, cpuid, err); - err = sun4v_intr_setenabled(ino, HV_INTR_ENABLED); - if (err != HV_EOK) - printk("sun4v_intr_setenabled(%x): err(%d)\n", - ino, err); - } else { - unsigned int tid = sun4u_compute_tid(imap, cpuid); - - /* NOTE NOTE NOTE, IGN and INO are read-only, IGN is a product - * of this SYSIO's preconfigured IGN in the SYSIO Control - * Register, the hardware just mirrors that value here. - * However for Graphics and UPA Slave devices the full - * IMAP_INR field can be set by the programmer here. - * - * Things like FFB can now be handled via the new IRQ - * mechanism. - */ - upa_writel(tid | IMAP_VALID, imap); - } - - preempt_enable(); -} + void (*pre_handler)(unsigned int, void *, void *); + void *pre_handler_arg1; + void *pre_handler_arg2; +}; -void disable_irq(unsigned int virt_irq) +static inline struct ino_bucket *virt_irq_to_bucket(unsigned int virt_irq) { unsigned int real_irq = virt_to_real_irq(virt_irq); - struct ino_bucket *bucket; - unsigned long imap; + struct ino_bucket *bucket = NULL; - if (unlikely(!real_irq)) - return; - - bucket = __bucket(real_irq); - imap = bucket->imap; - if (unlikely(imap == 0UL)) - return; - - if (tlb_type == hypervisor) { - unsigned int ino = __irq_ino(real_irq); - int err; + if (likely(real_irq)) + bucket = __bucket(real_irq); - err = sun4v_intr_setenabled(ino, HV_INTR_DISABLED); - if (err != HV_EOK) - printk("sun4v_intr_setenabled(%x): " - "err(%d)\n", ino, err); - } else { - u32 tmp; - - /* NOTE: We do not want to futz with the IRQ clear registers - * and move the state to IDLE, the SCSI code does call - * disable_irq() to assure atomicity in the queue cmd - * SCSI adapter driver code. Thus we'd lose interrupts. - */ - tmp = upa_readl(imap); - tmp &= ~IMAP_VALID; - upa_writel(tmp, imap); - } + return bucket; } -static void build_irq_error(const char *msg, unsigned int ino, int inofixup, - unsigned long iclr, unsigned long imap, - struct ino_bucket *bucket) +#ifdef CONFIG_SMP +static int irq_choose_cpu(unsigned int virt_irq) { - prom_printf("IRQ: INO %04x (%016lx:%016lx) --> " - "(%d:%016lx:%016lx), halting...\n", - ino, bucket->iclr, bucket->imap, - inofixup, iclr, imap); - prom_halt(); -} + cpumask_t mask = irq_affinity[virt_irq]; + int cpuid; -unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap, unsigned char flags) -{ - struct ino_bucket *bucket; - int ino; + if (cpus_equal(mask, CPU_MASK_ALL)) { + static int irq_rover; + static DEFINE_SPINLOCK(irq_rover_lock); + unsigned long flags; - BUG_ON(tlb_type == hypervisor); + /* Round-robin distribution... */ + do_round_robin: + spin_lock_irqsave(&irq_rover_lock, flags); - /* RULE: Both must be specified. */ - if (iclr == 0UL || imap == 0UL) { - prom_printf("Invalid build_irq %d %016lx %016lx\n", - inofixup, iclr, imap); - prom_halt(); - } - - ino = (upa_readl(imap) & (IMAP_IGN | IMAP_INO)) + inofixup; - if (ino > NUM_IVECS) { - prom_printf("Invalid INO %04x (%d:%016lx:%016lx)\n", - ino, inofixup, iclr, imap); - prom_halt(); - } + while (!cpu_online(irq_rover)) { + if (++irq_rover >= NR_CPUS) + irq_rover = 0; + } + cpuid = irq_rover; + do { + if (++irq_rover >= NR_CPUS) + irq_rover = 0; + } while (!cpu_online(irq_rover)); - bucket = &ivector_table[ino]; - if (bucket->flags & IBF_ACTIVE) - build_irq_error("IRQ: Trying to build active INO bucket.\n", - ino, inofixup, iclr, imap, bucket); + spin_unlock_irqrestore(&irq_rover_lock, flags); + } else { + cpumask_t tmp; - if (bucket->irq_info) { - if (bucket->imap != imap || bucket->iclr != iclr) - build_irq_error("IRQ: Trying to reinit INO bucket.\n", - ino, inofixup, iclr, imap, bucket); + cpus_and(tmp, cpu_online_map, mask); - goto out; - } + if (cpus_empty(tmp)) + goto do_round_robin; - bucket->irq_info = kzalloc(sizeof(struct irq_desc), GFP_ATOMIC); - if (!bucket->irq_info) { - prom_printf("IRQ: Error, kmalloc(irq_desc) failed.\n"); - prom_halt(); + cpuid = first_cpu(tmp); } - /* Ok, looks good, set it up. Don't touch the irq_chain or - * the pending flag. - */ - bucket->imap = imap; - bucket->iclr = iclr; - if (!bucket->virt_irq) - bucket->virt_irq = virt_irq_alloc(__irq(bucket)); - bucket->flags = flags; - -out: - return bucket->virt_irq; + return cpuid; +} +#else +static int irq_choose_cpu(unsigned int virt_irq) +{ + return real_hard_smp_processor_id(); } +#endif -unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino, unsigned char flags) +static void sun4u_irq_enable(unsigned int virt_irq) { - struct ino_bucket *bucket; - unsigned long sysino; + irq_desc_t *desc = irq_desc + virt_irq; + struct irq_handler_data *data = desc->handler_data; - sysino = sun4v_devino_to_sysino(devhandle, devino); + if (likely(data)) { + unsigned long cpuid, imap; + unsigned int tid; - bucket = &ivector_table[sysino]; + cpuid = irq_choose_cpu(virt_irq); + imap = data->imap; - /* Catch accidental accesses to these things. IMAP/ICLR handling - * is done by hypervisor calls on sun4v platforms, not by direct - * register accesses. - * - * But we need to make them look unique for the disable_irq() logic - * in free_irq(). - */ - bucket->imap = ~0UL - sysino; - bucket->iclr = ~0UL - sysino; - if (!bucket->virt_irq) - bucket->virt_irq = virt_irq_alloc(__irq(bucket)); - bucket->flags = flags; + tid = sun4u_compute_tid(imap, cpuid); - bucket->irq_info = kzalloc(sizeof(struct irq_desc), GFP_ATOMIC); - if (!bucket->irq_info) { - prom_printf("IRQ: Error, kmalloc(irq_desc) failed.\n"); - prom_halt(); + upa_writel(tid | IMAP_VALID, imap); } - - return bucket->virt_irq; } -static void atomic_bucket_insert(struct ino_bucket *bucket) +static void sun4u_irq_disable(unsigned int virt_irq) { - unsigned long pstate; - unsigned int *ent; + irq_desc_t *desc = irq_desc + virt_irq; + struct irq_handler_data *data = desc->handler_data; - __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate)); - __asm__ __volatile__("wrpr %0, %1, %%pstate" - : : "r" (pstate), "i" (PSTATE_IE)); - ent = irq_work(smp_processor_id()); - bucket->irq_chain = *ent; - *ent = __irq(bucket); - __asm__ __volatile__("wrpr %0, 0x0, %%pstate" : : "r" (pstate)); -} + if (likely(data)) { + unsigned long imap = data->imap; + u32 tmp = upa_readl(imap); -static int check_irq_sharing(int pil, unsigned long irqflags) -{ - struct irqaction *action; - - action = *(irq_action + pil); - if (action) { - if (!(action->flags & SA_SHIRQ) || !(irqflags & SA_SHIRQ)) - return -EBUSY; + tmp &= ~IMAP_VALID; + upa_writel(tmp, imap); } - return 0; } -static void append_irq_action(int pil, struct irqaction *action) +static void sun4u_irq_end(unsigned int virt_irq) { - struct irqaction **pp = irq_action + pil; + irq_desc_t *desc = irq_desc + virt_irq; + struct irq_handler_data *data = desc->handler_data; - while (*pp) - pp = &((*pp)->next); - *pp = action; + if (likely(data)) + upa_writel(ICLR_IDLE, data->iclr); } -static struct irqaction *get_action_slot(struct ino_bucket *bucket) +static void sun4v_irq_enable(unsigned int virt_irq) { - struct irq_desc *desc = bucket->irq_info; - int max_irq, i; + struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq); + unsigned int ino = bucket - &ivector_table[0]; - max_irq = 1; - if (bucket->flags & IBF_PCI) - max_irq = MAX_IRQ_DESC_ACTION; - for (i = 0; i < max_irq; i++) { - struct irqaction *p = &desc->action[i]; - u32 mask = (1 << i); + if (likely(bucket)) { + unsigned long cpuid; + int err; - if (desc->action_active_mask & mask) - continue; + cpuid = irq_choose_cpu(virt_irq); - desc->action_active_mask |= mask; - return p; + err = sun4v_intr_settarget(ino, cpuid); + if (err != HV_EOK) + printk("sun4v_intr_settarget(%x,%lu): err(%d)\n", + ino, cpuid, err); + err = sun4v_intr_setenabled(ino, HV_INTR_ENABLED); + if (err != HV_EOK) + printk("sun4v_intr_setenabled(%x): err(%d)\n", + ino, err); } - return NULL; } -int request_irq(unsigned int virt_irq, - irqreturn_t (*handler)(int, void *, struct pt_regs *), - unsigned long irqflags, const char *name, void *dev_id) +static void sun4v_irq_disable(unsigned int virt_irq) { - struct irqaction *action; - struct ino_bucket *bucket; - unsigned long flags; - unsigned int real_irq; - int pending = 0; - - real_irq = virt_to_real_irq(virt_irq); - if (unlikely(!real_irq)) - return -EINVAL; - - if (unlikely(!handler)) - return -EINVAL; - - bucket = __bucket(real_irq); - if (unlikely(!bucket->irq_info)) - return -ENODEV; - - if (irqflags & SA_SAMPLE_RANDOM) { - /* - * This function might sleep, we want to call it first, - * outside of the atomic block. - * Yes, this might clear the entropy pool if the wrong - * driver is attempted to be loaded, without actually - * installing a new handler, but is this really a problem, - * only the sysadmin is able to do this. - */ - rand_initialize_irq(virt_irq); - } - - spin_lock_irqsave(&irq_action_lock, flags); + struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq); + unsigned int ino = bucket - &ivector_table[0]; - if (check_irq_sharing(virt_irq, irqflags)) { - spin_unlock_irqrestore(&irq_action_lock, flags); - return -EBUSY; - } + if (likely(bucket)) { + int err; - action = get_action_slot(bucket); - if (!action) { - spin_unlock_irqrestore(&irq_action_lock, flags); - return -ENOMEM; + err = sun4v_intr_setenabled(ino, HV_INTR_DISABLED); + if (err != HV_EOK) + printk("sun4v_intr_setenabled(%x): " + "err(%d)\n", ino, err); } +} - bucket->flags |= IBF_ACTIVE; - pending = bucket->pending; - if (pending) - bucket->pending = 0; - - action->handler = handler; - action->flags = irqflags; - action->name = name; - action->next = NULL; - action->dev_id = dev_id; - put_ino_in_irqaction(action, __irq_ino(real_irq)); - put_smpaff_in_irqaction(action, CPU_MASK_NONE); - - append_irq_action(virt_irq, action); +static void sun4v_irq_end(unsigned int virt_irq) +{ + struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq); + unsigned int ino = bucket - &ivector_table[0]; - enable_irq(virt_irq); + if (likely(bucket)) { + int err; - /* We ate the IVEC already, this makes sure it does not get lost. */ - if (pending) { - atomic_bucket_insert(bucket); - set_softint(1 << PIL_DEVICE_IRQ); + err = sun4v_intr_setstate(ino, HV_INTR_STATE_IDLE); + if (err != HV_EOK) + printk("sun4v_intr_setstate(%x): " + "err(%d)\n", ino, err); } - - spin_unlock_irqrestore(&irq_action_lock, flags); - - register_irq_proc(virt_irq); - -#ifdef CONFIG_SMP - distribute_irqs(); -#endif - return 0; } -EXPORT_SYMBOL(request_irq); - -static struct irqaction *unlink_irq_action(unsigned int virt_irq, void *dev_id) +static void run_pre_handler(unsigned int virt_irq) { - struct irqaction *action, **pp; - - pp = irq_action + virt_irq; - action = *pp; - if (unlikely(!action)) - return NULL; + struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq); + irq_desc_t *desc = irq_desc + virt_irq; + struct irq_handler_data *data = desc->handler_data; - if (unlikely(!action->handler)) { - printk("Freeing free IRQ %d\n", virt_irq); - return NULL; + if (likely(data->pre_handler)) { + data->pre_handler(__irq_ino(__irq(bucket)), + data->pre_handler_arg1, + data->pre_handler_arg2); } - - while (action && action->dev_id != dev_id) { - pp = &action->next; - action = *pp; - } - - if (likely(action)) - *pp = action->next; - - return action; } -void free_irq(unsigned int virt_irq, void *dev_id) -{ - struct irqaction *action; - struct ino_bucket *bucket; - struct irq_desc *desc; - unsigned long flags; - unsigned int real_irq; - int ent, i; - - real_irq = virt_to_real_irq(virt_irq); - if (unlikely(!real_irq)) - return; +static struct hw_interrupt_type sun4u_irq = { + .typename = "sun4u", + .enable = sun4u_irq_enable, + .disable = sun4u_irq_disable, + .end = sun4u_irq_end, +}; - spin_lock_irqsave(&irq_action_lock, flags); +static struct hw_interrupt_type sun4u_irq_ack = { + .typename = "sun4u+ack", + .enable = sun4u_irq_enable, + .disable = sun4u_irq_disable, + .ack = run_pre_handler, + .end = sun4u_irq_end, +}; - action = unlink_irq_action(virt_irq, dev_id); +static struct hw_interrupt_type sun4v_irq = { + .typename = "sun4v", + .enable = sun4v_irq_enable, + .disable = sun4v_irq_disable, + .end = sun4v_irq_end, +}; - spin_unlock_irqrestore(&irq_action_lock, flags); +static struct hw_interrupt_type sun4v_irq_ack = { + .typename = "sun4v+ack", + .enable = sun4v_irq_enable, + .disable = sun4v_irq_disable, + .ack = run_pre_handler, + .end = sun4v_irq_end, +}; - if (unlikely(!action)) - return; +void irq_install_pre_handler(int virt_irq, + void (*func)(unsigned int, void *, void *), + void *arg1, void *arg2) +{ + irq_desc_t *desc = irq_desc + virt_irq; + struct irq_handler_data *data = desc->handler_data; - synchronize_irq(virt_irq); + data->pre_handler = func; + data->pre_handler_arg1 = arg1; + data->pre_handler_arg2 = arg2; - spin_lock_irqsave(&irq_action_lock, flags); + desc->handler = (desc->handler == &sun4u_irq ? + &sun4u_irq_ack : &sun4v_irq_ack); +} - bucket = __bucket(real_irq); - desc = bucket->irq_info; +unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap) +{ + struct ino_bucket *bucket; + struct irq_handler_data *data; + irq_desc_t *desc; + int ino; - for (i = 0; i < MAX_IRQ_DESC_ACTION; i++) { - struct irqaction *p = &desc->action[i]; + BUG_ON(tlb_type == hypervisor); - if (p == action) { - desc->action_active_mask &= ~(1 << i); - break; - } + ino = (upa_readl(imap) & (IMAP_IGN | IMAP_INO)) + inofixup; + bucket = &ivector_table[ino]; + if (!bucket->virt_irq) { + bucket->virt_irq = virt_irq_alloc(__irq(bucket)); + irq_desc[bucket->virt_irq].handler = &sun4u_irq; } - if (!desc->action_active_mask) { - unsigned long imap = bucket->imap; - - /* This unique interrupt source is now inactive. */ - bucket->flags &= ~IBF_ACTIVE; - - /* See if any other buckets share this bucket's IMAP - * and are still active. - */ - for (ent = 0; ent < NUM_IVECS; ent++) { - struct ino_bucket *bp = &ivector_table[ent]; - if (bp != bucket && - bp->imap == imap && - (bp->flags & IBF_ACTIVE) != 0) - break; - } + desc = irq_desc + bucket->virt_irq; + if (unlikely(desc->handler_data)) + goto out; - /* Only disable when no other sub-irq levels of - * the same IMAP are active. - */ - if (ent == NUM_IVECS) - disable_irq(virt_irq); + data = kzalloc(sizeof(struct irq_handler_data), GFP_ATOMIC); + if (unlikely(!data)) { + prom_printf("IRQ: kzalloc(irq_handler_data) failed.\n"); + prom_halt(); } + desc->handler_data = data; - spin_unlock_irqrestore(&irq_action_lock, flags); -} + data->imap = imap; + data->iclr = iclr; -EXPORT_SYMBOL(free_irq); +out: + return bucket->virt_irq; +} -#ifdef CONFIG_SMP -void synchronize_irq(unsigned int virt_irq) +unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino) { - unsigned int real_irq = virt_to_real_irq(virt_irq); struct ino_bucket *bucket; + struct irq_handler_data *data; + unsigned long sysino; + irq_desc_t *desc; - if (unlikely(!real_irq)) - return; + BUG_ON(tlb_type != hypervisor); - bucket = __bucket(real_irq); -#if 0 - /* The following is how I wish I could implement this. - * Unfortunately the ICLR registers are read-only, you can - * only write ICLR_foo values to them. To get the current - * IRQ status you would need to get at the IRQ diag registers - * in the PCI/SBUS controller and the layout of those vary - * from one controller to the next, sigh... -DaveM - */ - unsigned long iclr = bucket->iclr; - - while (1) { - u32 tmp = upa_readl(iclr); - - if (tmp == ICLR_TRANSMIT || - tmp == ICLR_PENDING) { - cpu_relax(); - continue; - } - break; + sysino = sun4v_devino_to_sysino(devhandle, devino); + bucket = &ivector_table[sysino]; + if (!bucket->virt_irq) { + bucket->virt_irq = virt_irq_alloc(__irq(bucket)); + irq_desc[bucket->virt_irq].handler = &sun4v_irq; } -#else - /* So we have to do this with a INPROGRESS bit just like x86. */ - while (bucket->flags & IBF_INPROGRESS) - cpu_relax(); -#endif -} -#endif /* CONFIG_SMP */ - -static void process_bucket(struct ino_bucket *bp, struct pt_regs *regs) -{ - struct irq_desc *desc = bp->irq_info; - unsigned char flags = bp->flags; - u32 action_mask, i; - int random; - - bp->flags |= IBF_INPROGRESS; - if (unlikely(!(flags & IBF_ACTIVE))) { - bp->pending = 1; + desc = irq_desc + bucket->virt_irq; + if (unlikely(desc->handler_data)) goto out; - } - - if (desc->pre_handler) - desc->pre_handler(bp, - desc->pre_handler_arg1, - desc->pre_handler_arg2); - action_mask = desc->action_active_mask; - random = 0; - for (i = 0; i < MAX_IRQ_DESC_ACTION; i++) { - struct irqaction *p = &desc->action[i]; - u32 mask = (1 << i); + data = kzalloc(sizeof(struct irq_handler_data), GFP_ATOMIC); + if (unlikely(!data)) { + prom_printf("IRQ: kzalloc(irq_handler_data) failed.\n"); + prom_halt(); + } + desc->handler_data = data; - if (!(action_mask & mask)) - continue; + /* Catch accidental accesses to these things. IMAP/ICLR handling + * is done by hypervisor calls on sun4v platforms, not by direct + * register accesses. + */ + data->imap = ~0UL; + data->iclr = ~0UL; - action_mask &= ~mask; +out: + return bucket->virt_irq; +} - if (p->handler(bp->virt_irq, p->dev_id, regs) == IRQ_HANDLED) - random |= p->flags; +void hw_resend_irq(struct hw_interrupt_type *handler, unsigned int virt_irq) +{ + struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq); + unsigned long pstate; + unsigned int *ent; - if (!action_mask) - break; - } + __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate)); + __asm__ __volatile__("wrpr %0, %1, %%pstate" + : : "r" (pstate), "i" (PSTATE_IE)); + ent = irq_work(smp_processor_id()); + bucket->irq_chain = *ent; + *ent = __irq(bucket); + set_softint(1 << PIL_DEVICE_IRQ); + __asm__ __volatile__("wrpr %0, 0x0, %%pstate" : : "r" (pstate)); +} - if (tlb_type == hypervisor) { - unsigned int ino = __irq_ino(bp); - int err; +void ack_bad_irq(unsigned int virt_irq) +{ + struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq); + unsigned int ino = 0xdeadbeef; - err = sun4v_intr_setstate(ino, HV_INTR_STATE_IDLE); - if (err != HV_EOK) - printk("sun4v_intr_setstate(%x): " - "err(%d)\n", ino, err); - } else { - upa_writel(ICLR_IDLE, bp->iclr); - } + if (bucket) + ino = bucket - &ivector_table[0]; - /* Test and add entropy */ - if (random & SA_SAMPLE_RANDOM) - add_interrupt_randomness(bp->virt_irq); -out: - bp->flags &= ~IBF_INPROGRESS; + printk(KERN_CRIT "Unexpected IRQ from ino[%x] virt_irq[%u]\n", + ino, virt_irq); } #ifndef CONFIG_SMP @@ -740,35 +532,33 @@ void timer_irq(int irq, struct pt_regs *regs) clear_softint(clr_mask); irq_enter(); + kstat_this_cpu.irqs[0]++; timer_interrupt(irq, NULL, regs); + irq_exit(); } #endif void handler_irq(int irq, struct pt_regs *regs) { - struct ino_bucket *bp; - int cpu = smp_processor_id(); + struct ino_bucket *bucket; - /* XXX at this point we should be able to assert that - * XXX irq is PIL_DEVICE_IRQ... - */ clear_softint(1 << irq); irq_enter(); /* Sliiiick... */ - bp = __bucket(xchg32(irq_work(cpu), 0)); - while (bp) { - struct ino_bucket *nbp = __bucket(bp->irq_chain); + bucket = __bucket(xchg32(irq_work(smp_processor_id()), 0)); + while (bucket) { + struct ino_bucket *next = __bucket(bucket->irq_chain); - kstat_this_cpu.irqs[bp->virt_irq]++; + bucket->irq_chain = 0; + __do_IRQ(bucket->virt_irq, regs); - bp->irq_chain = 0; - process_bucket(bp, regs); - bp = nbp; + bucket = next; } + irq_exit(); } @@ -833,74 +623,6 @@ main_interrupt: EXPORT_SYMBOL(sparc_floppy_irq); #endif -/* We really don't need these at all on the Sparc. We only have - * stubs here because they are exported to modules. - */ -unsigned long probe_irq_on(void) -{ - return 0; -} - -EXPORT_SYMBOL(probe_irq_on); - -int probe_irq_off(unsigned long mask) -{ - return 0; -} - -EXPORT_SYMBOL(probe_irq_off); - -#ifdef CONFIG_SMP -static int retarget_one_irq(struct irqaction *p, int goal_cpu) -{ - struct ino_bucket *bucket = get_ino_in_irqaction(p) + ivector_table; - - while (!cpu_online(goal_cpu)) { - if (++goal_cpu >= NR_CPUS) - goal_cpu = 0; - } - - if (tlb_type == hypervisor) { - unsigned int ino = __irq_ino(bucket); - - sun4v_intr_settarget(ino, goal_cpu); - sun4v_intr_setenabled(ino, HV_INTR_ENABLED); - } else { - unsigned long imap = bucket->imap; - unsigned int tid = sun4u_compute_tid(imap, goal_cpu); - - upa_writel(tid | IMAP_VALID, imap); - } - - do { - if (++goal_cpu >= NR_CPUS) - goal_cpu = 0; - } while (!cpu_online(goal_cpu)); - - return goal_cpu; -} - -/* Called from request_irq. */ -static void distribute_irqs(void) -{ - unsigned long flags; - int cpu, level; - - spin_lock_irqsave(&irq_action_lock, flags); - cpu = 0; - - for (level = 1; level < NR_IRQS; level++) { - struct irqaction *p = irq_action[level]; - - while(p) { - cpu = retarget_one_irq(p, cpu); - p = p->next; - } - } - spin_unlock_irqrestore(&irq_action_lock, flags); -} -#endif - struct sun5_timer { u64 count0; u64 limit0; @@ -1076,6 +798,10 @@ void __cpuinit sun4v_init_mondo_queues(int use_bootmem, int cpu, int alloc, int } } +static struct irqaction timer_irq_action = { + .name = "timer", +}; + /* Only invoked on boot processor. */ void __init init_IRQ(void) { @@ -1103,121 +829,6 @@ void __init init_IRQ(void) : /* No outputs */ : "i" (PSTATE_IE) : "g1"); -} -static struct proc_dir_entry *root_irq_dir; -static struct proc_dir_entry *irq_dir[NR_IRQS]; - -#ifdef CONFIG_SMP - -static int irq_affinity_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - struct ino_bucket *bp = ivector_table + (long)data; - struct irq_desc *desc = bp->irq_info; - struct irqaction *ap = desc->action; - cpumask_t mask; - int len; - - mask = get_smpaff_in_irqaction(ap); - if (cpus_empty(mask)) - mask = cpu_online_map; - - len = cpumask_scnprintf(page, count, mask); - if (count - len < 2) - return -EINVAL; - len += sprintf(page + len, "\n"); - return len; + irq_desc[0].action = &timer_irq_action; } - -static inline void set_intr_affinity(int virt_irq, cpumask_t hw_aff) -{ - struct ino_bucket *bp; - struct irq_desc *desc; - struct irqaction *ap; - unsigned int real_irq; - - real_irq = virt_to_real_irq(virt_irq); - if (unlikely(!real_irq)) - return; - - bp = __bucket(real_irq); - desc = bp->irq_info; - ap = desc->action; - - /* Users specify affinity in terms of hw cpu ids. - * As soon as we do this, handler_irq() might see and take action. - */ - put_smpaff_in_irqaction(ap, hw_aff); - - /* Migration is simply done by the next cpu to service this - * interrupt. - * - * XXX Broken, this doesn't happen anymore... - */ -} - -static int irq_affinity_write_proc(struct file *file, - const char __user *buffer, - unsigned long count, void *data) -{ - int virt_irq = (long) data, full_count = count, err; - cpumask_t new_value; - - err = cpumask_parse(buffer, count, new_value); - - /* - * Do not allow disabling IRQs completely - it's a too easy - * way to make the system unusable accidentally :-) At least - * one online CPU still has to be targeted. - */ - cpus_and(new_value, new_value, cpu_online_map); - if (cpus_empty(new_value)) - return -EINVAL; - - set_intr_affinity(virt_irq, new_value); - - return full_count; -} - -#endif - -#define MAX_NAMELEN 10 - -static void register_irq_proc(unsigned int virt_irq) -{ - char name [MAX_NAMELEN]; - - if (!root_irq_dir || irq_dir[virt_irq]) - return; - - memset(name, 0, MAX_NAMELEN); - sprintf(name, "%d", virt_irq); - - /* create /proc/irq/1234 */ - irq_dir[virt_irq] = proc_mkdir(name, root_irq_dir); - -#ifdef CONFIG_SMP - /* XXX SMP affinity not supported on starfire yet. */ - if (this_is_starfire == 0) { - struct proc_dir_entry *entry; - - /* create /proc/irq/1234/smp_affinity */ - entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]); - - if (entry) { - entry->nlink = 1; - entry->data = (void *)(long)virt_irq; - entry->read_proc = irq_affinity_read_proc; - entry->write_proc = irq_affinity_write_proc; - } - } -#endif -} - -void init_irq_proc(void) -{ - /* create /proc/irq */ - root_irq_dir = proc_mkdir("irq", NULL); -} - diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c index f97ddeb105ac..9472580a4319 100644 --- a/arch/sparc64/kernel/pci.c +++ b/arch/sparc64/kernel/pci.c @@ -47,12 +47,6 @@ struct pci_controller_info *pci_controller_root = NULL; /* Each PCI controller found gets a unique index. */ int pci_num_controllers = 0; -/* At boot time the user can give the kernel a command - * line option which controls if and how PCI devices - * are reordered at PCI bus probing time. - */ -int pci_device_reorder = 0; - volatile int pci_poke_in_progress; volatile int pci_poke_cpu = -1; volatile int pci_poke_faulted; @@ -316,27 +310,6 @@ static void __init pci_scan_each_controller_bus(void) p->scan_bus(p); } -/* Reorder the pci_dev chain, so that onboard devices come first - * and then come the pluggable cards. - */ -static void __init pci_reorder_devs(void) -{ - struct list_head *pci_onboard = &pci_devices; - struct list_head *walk = pci_onboard->next; - - while (walk != pci_onboard) { - struct pci_dev *pdev = pci_dev_g(walk); - struct list_head *walk_next = walk->next; - - if (pdev->irq && (__irq_ino(pdev->irq) & 0x20)) { - list_del(walk); - list_add(walk, pci_onboard); - } - - walk = walk_next; - } -} - extern void clock_probe(void); extern void power_init(void); @@ -348,9 +321,6 @@ static int __init pcibios_init(void) pci_scan_each_controller_bus(); - if (pci_device_reorder) - pci_reorder_devs(); - isa_init(); ebus_init(); clock_probe(); @@ -441,14 +411,6 @@ EXPORT_SYMBOL(pcibios_bus_to_resource); char * __init pcibios_setup(char *str) { - if (!strcmp(str, "onboardfirst")) { - pci_device_reorder = 1; - return NULL; - } - if (!strcmp(str, "noreorder")) { - pci_device_reorder = 0; - return NULL; - } return str; } diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c index f2d1097f541d..24db22aa9728 100644 --- a/arch/sparc64/kernel/pci_psycho.c +++ b/arch/sparc64/kernel/pci_psycho.c @@ -308,7 +308,7 @@ static unsigned int psycho_irq_build(struct pci_pbm_info *pbm, if ((ino & 0x20) == 0) inofixup = ino & 0x03; - return build_irq(inofixup, iclr, imap, IBF_PCI); + return build_irq(inofixup, iclr, imap); } /* PSYCHO error handling support. */ diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index 846c1205aa9a..b7d997b55f0a 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c @@ -530,7 +530,7 @@ static unsigned long __onboard_imap_off[] = { * side of the non-APB bridge, then perform a read of Sabre's DMA * write-sync register. */ -static void sabre_wsync_handler(struct ino_bucket *bucket, void *_arg1, void *_arg2) +static void sabre_wsync_handler(unsigned int ino, void *_arg1, void *_arg2) { struct pci_dev *pdev = _arg1; unsigned long sync_reg = (unsigned long) _arg2; @@ -573,7 +573,7 @@ static unsigned int sabre_irq_build(struct pci_pbm_info *pbm, if ((ino & 0x20) == 0) inofixup = ino & 0x03; - virt_irq = build_irq(inofixup, iclr, imap, IBF_PCI); + virt_irq = build_irq(inofixup, iclr, imap); if (pdev) { struct pcidev_cookie *pcp = pdev->sysdata; diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c index 0c400b5fa5bd..cc662e915d32 100644 --- a/arch/sparc64/kernel/pci_schizo.c +++ b/arch/sparc64/kernel/pci_schizo.c @@ -232,10 +232,10 @@ static unsigned long schizo_iclr_offset(unsigned long ino) return SCHIZO_ICLR_BASE + (ino * 8UL); } -static void tomatillo_wsync_handler(struct ino_bucket *bucket, void *_arg1, void *_arg2) +static void tomatillo_wsync_handler(unsigned int ino, void *_arg1, void *_arg2) { unsigned long sync_reg = (unsigned long) _arg2; - u64 mask = 1UL << (__irq_ino(__irq(bucket)) & IMAP_INO); + u64 mask = 1UL << (ino & IMAP_INO); u64 val; int limit; @@ -313,7 +313,7 @@ static unsigned int schizo_irq_build(struct pci_pbm_info *pbm, ign_fixup = (1 << 6); } - virt_irq = build_irq(ign_fixup, iclr, imap, IBF_PCI); + virt_irq = build_irq(ign_fixup, iclr, imap); if (pdev && pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO) { irq_install_pre_handler(virt_irq, diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index b97c81ba8835..5419480edf41 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c @@ -844,7 +844,7 @@ static unsigned int pci_sun4v_irq_build(struct pci_pbm_info *pbm, { u32 devhandle = pbm->devhandle; - return sun4v_build_irq(devhandle, devino, IBF_PCI); + return sun4v_build_irq(devhandle, devino); } static void pci_sun4v_base_address_update(struct pci_dev *pdev, int resource) diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c index 5544cf5d38b2..8812417247d4 100644 --- a/arch/sparc64/kernel/sbus.c +++ b/arch/sparc64/kernel/sbus.c @@ -821,7 +821,7 @@ unsigned int sbus_build_irq(void *buscookie, unsigned int ino) iclr += ((unsigned long)sbus_level - 1UL) * 8UL; } - return build_irq(sbus_level, iclr, imap, 0); + return build_irq(sbus_level, iclr, imap); } /* Error interrupt handling. */ diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c index 38e569f786dd..af72bf5c3db1 100644 --- a/arch/sparc64/kernel/sparc64_ksyms.c +++ b/arch/sparc64/kernel/sparc64_ksyms.c @@ -175,10 +175,6 @@ EXPORT_SYMBOL(set_bit); EXPORT_SYMBOL(clear_bit); EXPORT_SYMBOL(change_bit); -EXPORT_SYMBOL(ivector_table); -EXPORT_SYMBOL(enable_irq); -EXPORT_SYMBOL(disable_irq); - EXPORT_SYMBOL(__flushw_user); EXPORT_SYMBOL(tlb_type); diff --git a/arch/sparc64/kernel/sun4v_ivec.S b/arch/sparc64/kernel/sun4v_ivec.S index f70e4774649d..49703c3c5769 100644 --- a/arch/sparc64/kernel/sun4v_ivec.S +++ b/arch/sparc64/kernel/sun4v_ivec.S @@ -103,7 +103,7 @@ sun4v_dev_mondo: /* Get &ivector_table[IVEC] into %g4. */ sethi %hi(ivector_table), %g4 - sllx %g3, 5, %g3 + sllx %g3, 3, %g3 or %g4, %lo(ivector_table), %g4 add %g4, %g3, %g4 diff --git a/include/asm-sparc64/hardirq.h b/include/asm-sparc64/hardirq.h index f0cf71376ec5..7c29fd1a87aa 100644 --- a/include/asm-sparc64/hardirq.h +++ b/include/asm-sparc64/hardirq.h @@ -12,6 +12,8 @@ #define local_softirq_pending() \ (local_cpu_data().__softirq_pending) +void ack_bad_irq(unsigned int irq); + #define HARDIRQ_BITS 8 #endif /* !(__SPARC64_HARDIRQ_H) */ diff --git a/include/asm-sparc64/hw_irq.h b/include/asm-sparc64/hw_irq.h index 153cae2ddaee..599b3b073450 100644 --- a/include/asm-sparc64/hw_irq.h +++ b/include/asm-sparc64/hw_irq.h @@ -1,6 +1,6 @@ #ifndef __ASM_SPARC64_HW_IRQ_H #define __ASM_SPARC64_HW_IRQ_H -/* Dummy include. */ +extern void hw_resend_irq(struct hw_interrupt_type *handler, unsigned int virt_irq); #endif diff --git a/include/asm-sparc64/irq.h b/include/asm-sparc64/irq.h index 9edcd90495f7..77a4f63cba7a 100644 --- a/include/asm-sparc64/irq.h +++ b/include/asm-sparc64/irq.h @@ -16,58 +16,6 @@ #include #include -struct ino_bucket; - -#define MAX_IRQ_DESC_ACTION 4 - -struct irq_desc { - void (*pre_handler)(struct ino_bucket *, void *, void *); - void *pre_handler_arg1; - void *pre_handler_arg2; - u32 action_active_mask; - struct irqaction action[MAX_IRQ_DESC_ACTION]; -}; - -/* You should not mess with this directly. That's the job of irq.c. - * - * If you make changes here, please update hand coded assembler of - * the vectored interrupt trap handler in entry.S -DaveM - * - * This is currently one DCACHE line, two buckets per L2 cache - * line. Keep this in mind please. - */ -struct ino_bucket { - /* Next handler in per-CPU IRQ worklist. We know that - * bucket pointers have the high 32-bits clear, so to - * save space we only store the bits we need. - */ -/*0x00*/unsigned int irq_chain; - - /* Virtual interrupt number assigned to this INO. */ -/*0x04*/unsigned char virt_irq; - - /* If an IVEC arrives while irq_info is NULL, we - * set this to notify request_irq() about the event. - */ -/*0x05*/unsigned char pending; - - /* Miscellaneous flags. */ -/*0x06*/unsigned char flags; - - /* Currently unused. */ -/*0x07*/unsigned char __pad; - - /* Reference to IRQ descriptor for this bucket. */ -/*0x08*/struct irq_desc *irq_info; - - /* Sun5 Interrupt Clear Register. */ -/*0x10*/unsigned long iclr; - - /* Sun5 Interrupt Mapping Register. */ -/*0x18*/unsigned long imap; - -}; - /* IMAP/ICLR register defines */ #define IMAP_VALID 0x80000000 /* IRQ Enabled */ #define IMAP_TID_UPA 0x7c000000 /* UPA TargetID */ @@ -85,19 +33,6 @@ struct ino_bucket { #define ICLR_TRANSMIT 0x00000001 /* Transmit state */ #define ICLR_PENDING 0x00000003 /* Pending state */ -/* Only 8-bits are available, be careful. -DaveM */ -#define IBF_PCI 0x02 /* PSYCHO/SABRE/SCHIZO PCI interrupt. */ -#define IBF_ACTIVE 0x04 /* Interrupt is active and has a handler.*/ -#define IBF_INPROGRESS 0x10 /* IRQ is being serviced. */ - -#define NUM_IVECS (IMAP_INR + 1) -extern struct ino_bucket ivector_table[NUM_IVECS]; - -#define __irq_ino(irq) \ - (((struct ino_bucket *)(unsigned long)(irq)) - &ivector_table[0]) -#define __bucket(irq) ((struct ino_bucket *)(unsigned long)(irq)) -#define __irq(bucket) ((unsigned int)(unsigned long)(bucket)) - /* The largest number of unique interrupt sources we support. * If this needs to ever be larger than 255, you need to change * the type of ino_bucket->virt_irq as appropriate. @@ -107,14 +42,11 @@ extern struct ino_bucket ivector_table[NUM_IVECS]; #define NR_IRQS 255 extern void irq_install_pre_handler(int virt_irq, - void (*func)(struct ino_bucket *, void *, void *), + void (*func)(unsigned int, void *, void *), void *arg1, void *arg2); #define irq_canonicalize(irq) (irq) -extern void disable_irq(unsigned int); -#define disable_irq_nosync disable_irq -extern void enable_irq(unsigned int); -extern unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap, unsigned char flags); -extern unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino, unsigned char flags); +extern unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap); +extern unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino); extern unsigned int sbus_build_irq(void *sbus, unsigned int ino); static __inline__ void set_softint(unsigned long bits) @@ -140,8 +72,4 @@ static __inline__ unsigned long get_softint(void) return retval; } -struct irqaction; -struct pt_regs; -int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *); - #endif -- cgit v1.2.3 From e6fea6a5e30efef56dee2b8455fde0811922055b Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Tue, 20 Jun 2006 19:26:41 +0100 Subject: [ARM] 3602/1: ixp23xx: fix two typos Patch from Lennert Buytenhek Fix two typos in include/asm-arm/arch-ixp23xx. Signed-off-by: Lennert Buytenhek Signed-off-by: Russell King --- include/asm-arm/arch-ixp23xx/entry-macro.S | 2 +- include/asm-arm/arch-ixp23xx/ixp23xx.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/asm-arm/arch-ixp23xx/entry-macro.S b/include/asm-arm/arch-ixp23xx/entry-macro.S index 0ef4e6016ac4..867761677b57 100644 --- a/include/asm-arm/arch-ixp23xx/entry-macro.S +++ b/include/asm-arm/arch-ixp23xx/entry-macro.S @@ -8,7 +8,7 @@ .macro get_irqnr_and_base, irqnr, irqstat, base, tmp ldr \irqnr, =(IXP23XX_INTC_VIRT + IXP23XX_INTR_IRQ_ENC_ST_OFFSET) ldr \irqnr, [\irqnr] @ get interrupt number - cmp \irqnr, #0x0 @ suprious interrupt ? + cmp \irqnr, #0x0 @ spurious interrupt ? movne \irqnr, \irqnr, lsr #2 @ skip unwanted low order bits subne \irqnr, \irqnr, #1 @ convert to 0 based diff --git a/include/asm-arm/arch-ixp23xx/ixp23xx.h b/include/asm-arm/arch-ixp23xx/ixp23xx.h index e49e1ca61b1a..01efdbd1180f 100644 --- a/include/asm-arm/arch-ixp23xx/ixp23xx.h +++ b/include/asm-arm/arch-ixp23xx/ixp23xx.h @@ -251,7 +251,7 @@ * CAP CSRs. ****************************************************************************/ #define IXP23XX_GLOBAL_REG(x) ((volatile unsigned long *)(IXP23XX_CAP_CSR_VIRT + 0x4a00 + (x))) -#define IXP23XX_PROD_IDG IXP23XX_GLOBAL_REG(0x00) +#define IXP23XX_PRODUCT_ID IXP23XX_GLOBAL_REG(0x00) #define IXP23XX_MISC_CONTROL IXP23XX_GLOBAL_REG(0x04) #define IXP23XX_MSF_CLK_CNTRL IXP23XX_GLOBAL_REG(0x08) #define IXP23XX_RESET0 IXP23XX_GLOBAL_REG(0x0c) -- cgit v1.2.3 From c322e24b40b83bbdfa7c269bc0105e76a39e627f Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Tue, 20 Jun 2006 19:26:42 +0100 Subject: [ARM] 3606/1: PXA27x SSP Register definitions Patch from Liam Girdwood This patch adds some new PXA27x SSP port registers and also fixes the SSP slots per frame macro Changes:- o SSCR0_SlotPerFrm fixed o Added SSP port TSA, RSA, TSS and ACD registers Signed-off-by: Liam Girdwood Signed-off-by: Russell King --- include/asm-arm/arch-pxa/pxa-regs.h | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/asm-arm/arch-pxa/pxa-regs.h b/include/asm-arm/arch-pxa/pxa-regs.h index c8f53a71c076..7c1aefd99d54 100644 --- a/include/asm-arm/arch-pxa/pxa-regs.h +++ b/include/asm-arm/arch-pxa/pxa-regs.h @@ -1626,7 +1626,7 @@ #define SSCR0_RIM (1 << 22) /* Receive FIFO overrrun interrupt mask */ #define SSCR0_TUM (1 << 23) /* Transmit FIFO underrun interrupt mask */ #define SSCR0_FRDC (0x07000000) /* Frame rate divider control (mask) */ -#define SSCR0_SlotsPerFrm(c) ((x) - 1) /* Time slots per frame [1..8] */ +#define SSCR0_SlotsPerFrm(x) ((x) - 1) /* Time slots per frame [1..8] */ #define SSCR0_ADC (1 << 30) /* Audio clock select */ #define SSCR0_MOD (1 << 31) /* Mode (normal or network) */ #endif @@ -1707,6 +1707,10 @@ #if defined (CONFIG_PXA27x) #define SSTO_P1 __REG(0x41000028) /* SSP Port 1 Time Out Register */ #define SSPSP_P1 __REG(0x4100002C) /* SSP Port 1 Programmable Serial Protocol */ +#define SSTSA_P1 __REG(0x41000030) /* SSP Port 1 Tx Timeslot Active */ +#define SSRSA_P1 __REG(0x41000034) /* SSP Port 1 Rx Timeslot Active */ +#define SSTSS_P1 __REG(0x41000038) /* SSP Port 1 Timeslot Status */ +#define SSACD_P1 __REG(0x4100003C) /* SSP Port 1 Audio Clock Divider */ #define SSCR0_P2 __REG(0x41700000) /* SSP Port 2 Control Register 0 */ #define SSCR1_P2 __REG(0x41700004) /* SSP Port 2 Control Register 1 */ #define SSSR_P2 __REG(0x41700008) /* SSP Port 2 Status Register */ @@ -1714,6 +1718,10 @@ #define SSDR_P2 __REG(0x41700010) /* (Write / Read) SSP Port 2 Data Write Register/SSP Data Read Register */ #define SSTO_P2 __REG(0x41700028) /* SSP Port 2 Time Out Register */ #define SSPSP_P2 __REG(0x4170002C) /* SSP Port 2 Programmable Serial Protocol */ +#define SSTSA_P2 __REG(0x41700030) /* SSP Port 2 Tx Timeslot Active */ +#define SSRSA_P2 __REG(0x41700034) /* SSP Port 2 Rx Timeslot Active */ +#define SSTSS_P2 __REG(0x41700038) /* SSP Port 2 Timeslot Status */ +#define SSACD_P2 __REG(0x4170003C) /* SSP Port 2 Audio Clock Divider */ #define SSCR0_P3 __REG(0x41900000) /* SSP Port 3 Control Register 0 */ #define SSCR1_P3 __REG(0x41900004) /* SSP Port 3 Control Register 1 */ #define SSSR_P3 __REG(0x41900008) /* SSP Port 3 Status Register */ @@ -1721,6 +1729,10 @@ #define SSDR_P3 __REG(0x41900010) /* (Write / Read) SSP Port 3 Data Write Register/SSP Data Read Register */ #define SSTO_P3 __REG(0x41900028) /* SSP Port 3 Time Out Register */ #define SSPSP_P3 __REG(0x4190002C) /* SSP Port 3 Programmable Serial Protocol */ +#define SSTSA_P3 __REG(0x41900030) /* SSP Port 3 Tx Timeslot Active */ +#define SSRSA_P3 __REG(0x41900034) /* SSP Port 3 Rx Timeslot Active */ +#define SSTSS_P3 __REG(0x41900038) /* SSP Port 3 Timeslot Status */ +#define SSACD_P3 __REG(0x4190003C) /* SSP Port 3 Audio Clock Divider */ #else /* PXA255 (only port 2) and PXA26x ports*/ #define SSTO_P1 __REG(0x41000028) /* SSP Port 1 Time Out Register */ #define SSPSP_P1 __REG(0x4100002C) /* SSP Port 1 Programmable Serial Protocol */ @@ -1747,6 +1759,10 @@ #define SSDR_P(x) (*(((x) == 1) ? &SSDR_P1 : ((x) == 2) ? &SSDR_P2 : ((x) == 3) ? &SSDR_P3 : NULL)) #define SSTO_P(x) (*(((x) == 1) ? &SSTO_P1 : ((x) == 2) ? &SSTO_P2 : ((x) == 3) ? &SSTO_P3 : NULL)) #define SSPSP_P(x) (*(((x) == 1) ? &SSPSP_P1 : ((x) == 2) ? &SSPSP_P2 : ((x) == 3) ? &SSPSP_P3 : NULL)) +#define SSTSA_P(x) (*(((x) == 1) ? &SSTSA_P1 : ((x) == 2) ? &SSTSA_P2 : ((x) == 3) ? &SSTSA_P3 : NULL)) +#define SSRSA_P(x) (*(((x) == 1) ? &SSRSA_P1 : ((x) == 2) ? &SSRSA_P2 : ((x) == 3) ? &SSRSA_P3 : NULL)) +#define SSTSS_P(x) (*(((x) == 1) ? &SSTSS_P1 : ((x) == 2) ? &SSTSS_P2 : ((x) == 3) ? &SSTSS_P3 : NULL)) +#define SSACD_P(x) (*(((x) == 1) ? &SSACD_P1 : ((x) == 2) ? &SSACD_P2 : ((x) == 3) ? &SSACD_P3 : NULL)) /* * MultiMediaCard (MMC) controller -- cgit v1.2.3 From d6bdbb8ef3e4a9cafc747e1444b4908f9f2f548d Mon Sep 17 00:00:00 2001 From: Andrew Victor Date: Tue, 20 Jun 2006 19:27:34 +0100 Subject: [ARM] 3603/1: AT91RM9200 remove old files Patch from Andrew Victor This patch removes the now unnecessary include/asm-arm/arch-at91rm9200/pio.h file. The pin configuration is now handled in the platform-device setup code (arch/arm/mach-at91rm9200/devices.c). Signed-off-by: Andrew Victor Signed-off-by: Russell King --- include/asm-arm/arch-at91rm9200/pio.h | 115 ---------------------------------- 1 file changed, 115 deletions(-) delete mode 100644 include/asm-arm/arch-at91rm9200/pio.h (limited to 'include') diff --git a/include/asm-arm/arch-at91rm9200/pio.h b/include/asm-arm/arch-at91rm9200/pio.h deleted file mode 100644 index a89501b4a703..000000000000 --- a/include/asm-arm/arch-at91rm9200/pio.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * include/asm-arm/arch-at91rm9200/pio.h - * - * Copyright (C) 2003 SAN People - * - * 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. - * - */ - -#ifndef __ASM_ARCH_PIO_H -#define __ASM_ARCH_PIO_H - -#include - -static inline void AT91_CfgPIO_USART0(void) { - at91_sys_write(AT91_PIOA + PIO_PDR, AT91_PA17_TXD0 | AT91_PA18_RXD0 | AT91_PA20_CTS0); - - /* - * Errata #39 - RTS0 is not internally connected to PA21. We need to drive - * the pin manually. Default is off (RTS is active low). - */ - at91_sys_write(AT91_PIOA + PIO_PER, AT91_PA21_RTS0); - at91_sys_write(AT91_PIOA + PIO_OER, AT91_PA21_RTS0); - at91_sys_write(AT91_PIOA + PIO_SODR, AT91_PA21_RTS0); -} - -static inline void AT91_CfgPIO_USART1(void) { - at91_sys_write(AT91_PIOB + PIO_PDR, AT91_PB18_RI1 | AT91_PB19_DTR1 - | AT91_PB20_TXD1 | AT91_PB21_RXD1 | AT91_PB23_DCD1 - | AT91_PB24_CTS1 | AT91_PB25_DSR1 | AT91_PB26_RTS1); -} - -static inline void AT91_CfgPIO_USART2(void) { - at91_sys_write(AT91_PIOA + PIO_PDR, AT91_PA22_RXD2 | AT91_PA23_TXD2); -} - -static inline void AT91_CfgPIO_USART3(void) { - at91_sys_write(AT91_PIOA + PIO_PDR, AT91_PA5_TXD3 | AT91_PA6_RXD3); - at91_sys_write(AT91_PIOA + PIO_BSR, AT91_PA5_TXD3 | AT91_PA6_RXD3); -} - -static inline void AT91_CfgPIO_DBGU(void) { - at91_sys_write(AT91_PIOA + PIO_PDR, AT91_PA31_DTXD | AT91_PA30_DRXD); -} - -/* - * Enable the Two-Wire interface. - */ -static inline void AT91_CfgPIO_TWI(void) { - at91_sys_write(AT91_PIOA + PIO_PDR, AT91_PA25_TWD | AT91_PA26_TWCK); - at91_sys_write(AT91_PIOA + PIO_ASR, AT91_PA25_TWD | AT91_PA26_TWCK); - at91_sys_write(AT91_PIOA + PIO_MDER, AT91_PA25_TWD | AT91_PA26_TWCK); /* open drain */ -} - -/* - * Enable the Serial Peripheral Interface. - */ -static inline void AT91_CfgPIO_SPI(void) { - at91_sys_write(AT91_PIOA + PIO_PDR, AT91_PA0_MISO | AT91_PA1_MOSI | AT91_PA2_SPCK); -} - -static inline void AT91_CfgPIO_SPI_CS0(void) { - at91_sys_write(AT91_PIOA + PIO_PDR, AT91_PA3_NPCS0); -} - -static inline void AT91_CfgPIO_SPI_CS1(void) { - at91_sys_write(AT91_PIOA + PIO_PDR, AT91_PA4_NPCS1); -} - -static inline void AT91_CfgPIO_SPI_CS2(void) { - at91_sys_write(AT91_PIOA + PIO_PDR, AT91_PA5_NPCS2); -} - -static inline void AT91_CfgPIO_SPI_CS3(void) { - at91_sys_write(AT91_PIOA + PIO_PDR, AT91_PA6_NPCS3); -} - -/* - * Select the DataFlash card. - */ -static inline void AT91_CfgPIO_DataFlashCard(void) { - at91_sys_write(AT91_PIOB + PIO_PER, AT91_PIO_P(7)); - at91_sys_write(AT91_PIOB + PIO_OER, AT91_PIO_P(7)); - at91_sys_write(AT91_PIOB + PIO_CODR, AT91_PIO_P(7)); -} - -/* - * Enable NAND Flash (SmartMedia) interface. - */ -static inline void AT91_CfgPIO_SmartMedia(void) { - /* enable PC0=SMCE, PC1=SMOE, PC3=SMWE, A21=CLE, A22=ALE */ - at91_sys_write(AT91_PIOC + PIO_ASR, AT91_PC0_BFCK | AT91_PC1_BFRDY_SMOE | AT91_PC3_BFBAA_SMWE); - at91_sys_write(AT91_PIOC + PIO_PDR, AT91_PC0_BFCK | AT91_PC1_BFRDY_SMOE | AT91_PC3_BFBAA_SMWE); - - /* Configure PC2 as input (signal READY of the SmartMedia) */ - at91_sys_write(AT91_PIOC + PIO_PER, AT91_PC2_BFAVD); /* enable direct output enable */ - at91_sys_write(AT91_PIOC + PIO_ODR, AT91_PC2_BFAVD); /* disable output */ - - /* Configure PB1 as input (signal Card Detect of the SmartMedia) */ - at91_sys_write(AT91_PIOB + PIO_PER, AT91_PIO_P(1)); /* enable direct output enable */ - at91_sys_write(AT91_PIOB + PIO_ODR, AT91_PIO_P(1)); /* disable output */ -} - -static inline int AT91_PIO_SmartMedia_RDY(void) { - return (at91_sys_read(AT91_PIOC + PIO_PDSR) & AT91_PIO_P(2)) ? 1 : 0; -} - -static inline int AT91_PIO_SmartMedia_CardDetect(void) { - return (at91_sys_read(AT91_PIOB + PIO_PDSR) & AT91_PIO_P(1)) ? 1 : 0; -} - -#endif -- cgit v1.2.3 From 907d6deb625cd7ff5fea3ef4b20dfb6c1c19c3ee Mon Sep 17 00:00:00 2001 From: Andrew Victor Date: Tue, 20 Jun 2006 19:30:19 +0100 Subject: [ARM] 3605/1: AT91RM9200 Power Management Patch from Andrew Victor This patch adds the core Power Management support for the AT91RM9200 processor. It will support suspend-to-RAM and standby modes. The suspend-to-RAM functionality is not 100% complete. The code that needs to be execute from the internal SRAM to restore the system is outstanding. For now we just fall through to Standby mode. The AT91-specific at91_suspend_entering_slow_clock() function will eventually be replaced by clk_must_disable() once that functionality is added to mainline clock API. Patch from David Brownell. Signed-off-by: Andrew Victor Signed-off-by: Russell King --- arch/arm/mach-at91rm9200/generic.h | 7 + arch/arm/mach-at91rm9200/pm.c | 225 +++++++++++++++++++++++++++++++++ include/asm-arm/arch-at91rm9200/gpio.h | 5 + 3 files changed, 237 insertions(+) create mode 100644 arch/arm/mach-at91rm9200/pm.c (limited to 'include') diff --git a/arch/arm/mach-at91rm9200/generic.h b/arch/arm/mach-at91rm9200/generic.h index 9bd541eba0a0..f0d969d7d874 100644 --- a/arch/arm/mach-at91rm9200/generic.h +++ b/arch/arm/mach-at91rm9200/generic.h @@ -16,3 +16,10 @@ extern struct sys_timer at91rm9200_timer; extern void __init at91rm9200_map_io(void); extern int __init at91_clock_init(unsigned long main_clock); +struct device; +extern void __init at91_clock_associate(const char *id, struct device *dev, const char *func); + + /* Power Management */ +extern void at91_irq_suspend(void); +extern void at91_irq_resume(void); + diff --git a/arch/arm/mach-at91rm9200/pm.c b/arch/arm/mach-at91rm9200/pm.c new file mode 100644 index 000000000000..47e5480feb7e --- /dev/null +++ b/arch/arm/mach-at91rm9200/pm.c @@ -0,0 +1,225 @@ +/* + * arch/arm/mach-at91rm9200/pm.c + * AT91 Power Management + * + * Copyright (C) 2005 David Brownell + * + * 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 +#include +#include +#include +#include +#include + +#include + +#include "generic.h" + + +static int at91_pm_valid_state(suspend_state_t state) +{ + switch (state) { + case PM_SUSPEND_ON: + case PM_SUSPEND_STANDBY: + case PM_SUSPEND_MEM: + return 1; + + default: + return 0; + } +} + + +static suspend_state_t target_state; + +/* + * Called after processes are frozen, but before we shutdown devices. + */ +static int at91_pm_prepare(suspend_state_t state) +{ + target_state = state; + return 0; +} + +/* + * Verify that all the clocks are correct before entering + * slow-clock mode. + */ +static int at91_pm_verify_clocks(void) +{ + unsigned long scsr; + int i; + + scsr = at91_sys_read(AT91_PMC_SCSR); + + /* USB must not be using PLLB */ + if ((scsr & (AT91_PMC_UHP | AT91_PMC_UDP)) != 0) { + pr_debug("AT91: PM - Suspend-to-RAM with USB still active\n"); + return 0; + } + +#ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS + /* PCK0..PCK3 must be disabled, or configured to use clk32k */ + for (i = 0; i < 4; i++) { + u32 css; + + if ((scsr & (AT91_PMC_PCK0 << i)) == 0) + continue; + + css = at91_sys_read(AT91_PMC_PCKR(i)) & AT91_PMC_CSS; + if (css != AT91_PMC_CSS_SLOW) { + pr_debug("AT91: PM - Suspend-to-RAM with PCK%d src %d\n", i, css); + return 0; + } + } +#endif + + return 1; +} + +/* + * Call this from platform driver suspend() to see how deeply to suspend. + * For example, some controllers (like OHCI) need one of the PLL clocks + * in order to act as a wakeup source, and those are not available when + * going into slow clock mode. + * + * REVISIT: generalize as clk_will_be_available(clk)? Other platforms have + * the very same problem (but not using at91 main_clk), and it'd be better + * to add one generic API rather than lots of platform-specific ones. + */ +int at91_suspend_entering_slow_clock(void) +{ + return (target_state == PM_SUSPEND_MEM); +} +EXPORT_SYMBOL(at91_suspend_entering_slow_clock); + + +static void (*slow_clock)(void); + + + +static int at91_pm_enter(suspend_state_t state) +{ + at91_gpio_suspend(); + at91_irq_suspend(); + + pr_debug("AT91: PM - wake mask %08x, pm state %d\n", + /* remember all the always-wake irqs */ + (at91_sys_read(AT91_PMC_PCSR) + | (1 << AT91_ID_FIQ) + | (1 << AT91_ID_SYS) + | (1 << AT91_ID_IRQ0) + | (1 << AT91_ID_IRQ1) + | (1 << AT91_ID_IRQ2) + | (1 << AT91_ID_IRQ3) + | (1 << AT91_ID_IRQ4) + | (1 << AT91_ID_IRQ5) + | (1 << AT91_ID_IRQ6)) + & at91_sys_read(AT91_AIC_IMR), + state); + + switch (state) { + /* + * Suspend-to-RAM is like STANDBY plus slow clock mode, so + * drivers must suspend more deeply: only the master clock + * controller may be using the main oscillator. + */ + case PM_SUSPEND_MEM: + /* + * Ensure that clocks are in a valid state. + */ + if (!at91_pm_verify_clocks()) + goto error; + + /* + * Enter slow clock mode by switching over to clk32k and + * turning off the main oscillator; reverse on wakeup. + */ + if (slow_clock) { + slow_clock(); + break; + } else { + /* DEVELOPMENT ONLY */ + pr_info("AT91: PM - no slow clock mode yet ...\n"); + /* FALLTHROUGH leaving master clock alone */ + } + + /* + * STANDBY mode has *all* drivers suspended; ignores irqs not + * marked as 'wakeup' event sources; and reduces DRAM power. + * But otherwise it's identical to PM_SUSPEND_ON: cpu idle, and + * nothing fancy done with main or cpu clocks. + */ + case PM_SUSPEND_STANDBY: + /* + * NOTE: the Wait-for-Interrupt instruction needs to be + * in icache so the SDRAM stays in self-refresh mode until + * the wakeup IRQ occurs. + */ + asm("b 1f; .align 5; 1:"); + asm("mcr p15, 0, r0, c7, c10, 4"); /* drain write buffer */ + at91_sys_write(AT91_SDRAMC_SRR, 1); /* self-refresh mode */ + /* fall though to next state */ + + case PM_SUSPEND_ON: + asm("mcr p15, 0, r0, c7, c0, 4"); /* wait for interrupt */ + break; + + default: + pr_debug("AT91: PM - bogus suspend state %d\n", state); + goto error; + } + + pr_debug("AT91: PM - wakeup %08x\n", + at91_sys_read(AT91_AIC_IPR) & at91_sys_read(AT91_AIC_IMR)); + +error: + target_state = PM_SUSPEND_ON; + at91_irq_resume(); + at91_gpio_resume(); + return 0; +} + + +static struct pm_ops at91_pm_ops ={ + .pm_disk_mode = 0, + .valid = at91_pm_valid_state, + .prepare = at91_pm_prepare, + .enter = at91_pm_enter, +}; + +static int __init at91_pm_init(void) +{ + printk("AT91: Power Management\n"); + +#ifdef CONFIG_AT91_PM_SLOW_CLOCK + /* REVISIT allocations of SRAM should be dynamically managed. + * FIQ handlers and other components will want SRAM/TCM too... + */ + slow_clock = (void *) (AT91_VA_BASE_SRAM + (3 * SZ_4K)); + memcpy(slow_clock, at91rm9200_slow_clock, at91rm9200_slow_clock_sz); +#endif + + /* Disable SDRAM low-power mode. Cannot be used with self-refresh. */ + at91_sys_write(AT91_SDRAMC_LPR, 0); + + pm_set_ops(&at91_pm_ops); + + return 0; +} +arch_initcall(at91_pm_init); diff --git a/include/asm-arm/arch-at91rm9200/gpio.h b/include/asm-arm/arch-at91rm9200/gpio.h index 6176ab2dc417..dbde1baaf251 100644 --- a/include/asm-arm/arch-at91rm9200/gpio.h +++ b/include/asm-arm/arch-at91rm9200/gpio.h @@ -13,6 +13,8 @@ #ifndef __ASM_ARCH_AT91RM9200_GPIO_H #define __ASM_ARCH_AT91RM9200_GPIO_H +#include + #define PIN_BASE NR_AIC_IRQS #define PQFP_GPIO_BANKS 3 /* PQFP package has 3 banks */ @@ -188,6 +190,9 @@ extern int at91_set_multi_drive(unsigned pin, int is_on); /* callable at any time */ extern int at91_set_gpio_value(unsigned pin, int value); extern int at91_get_gpio_value(unsigned pin); + +extern void at91_gpio_suspend(void); +extern void at91_gpio_resume(void); #endif #endif -- cgit v1.2.3 From 5c3fddced9f62f4b175ce400bb96b23f47626e50 Mon Sep 17 00:00:00 2001 From: Andrew Victor Date: Tue, 20 Jun 2006 19:30:20 +0100 Subject: [ARM] 3607/1: AT91RM9200 misc fixes Patch from Andrew Victor This final patch includes some general fixes. 1. Link in pm.o if CONFIG_PM is enabled. [Should have been included in patch 3605/1]. 2. Use __raw_readl()/__raw_writel() when accessing System Peripheral registers. 3. Removed some unnecessary includes Signed-off-by: Andrew Victor Signed-off-by: Russell King --- arch/arm/mach-at91rm9200/Makefile | 7 +++++++ include/asm-arm/arch-at91rm9200/hardware.h | 4 ++-- include/asm-arm/arch-at91rm9200/io.h | 1 - include/asm-arm/arch-at91rm9200/irqs.h | 2 -- 4 files changed, 9 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/arch/arm/mach-at91rm9200/Makefile b/arch/arm/mach-at91rm9200/Makefile index c8f544b789c0..81ebc6684ad2 100644 --- a/arch/arm/mach-at91rm9200/Makefile +++ b/arch/arm/mach-at91rm9200/Makefile @@ -7,6 +7,8 @@ obj-m := obj-n := obj- := +obj-$(CONFIG_PM) += pm.o + # Board-specific support obj-$(CONFIG_ARCH_AT91RM9200DK) += board-dk.o obj-$(CONFIG_MACH_AT91RM9200EK) += board-ek.o @@ -28,3 +30,8 @@ obj-$(CONFIG_LEDS) += $(led-y) # VGA support #obj-$(CONFIG_FB_S1D13XXX) += ics1523.o + + +ifeq ($(CONFIG_PM_DEBUG),y) +CFLAGS_pm.o += -DDEBUG +endif diff --git a/include/asm-arm/arch-at91rm9200/hardware.h b/include/asm-arm/arch-at91rm9200/hardware.h index 87f40df57140..235d39d91107 100644 --- a/include/asm-arm/arch-at91rm9200/hardware.h +++ b/include/asm-arm/arch-at91rm9200/hardware.h @@ -84,14 +84,14 @@ static inline unsigned int at91_sys_read(unsigned int reg_offset) { void __iomem *addr = (void __iomem *)AT91_VA_BASE_SYS; - return readl(addr + reg_offset); + return __raw_readl(addr + reg_offset); } static inline void at91_sys_write(unsigned int reg_offset, unsigned long value) { void __iomem *addr = (void __iomem *)AT91_VA_BASE_SYS; - writel(value, addr + reg_offset); + __raw_writel(value, addr + reg_offset); } #endif diff --git a/include/asm-arm/arch-at91rm9200/io.h b/include/asm-arm/arch-at91rm9200/io.h index 23e670d85c9d..88fd1bebcef3 100644 --- a/include/asm-arm/arch-at91rm9200/io.h +++ b/include/asm-arm/arch-at91rm9200/io.h @@ -21,7 +21,6 @@ #ifndef __ASM_ARCH_IO_H #define __ASM_ARCH_IO_H -#include #include #define IO_SPACE_LIMIT 0xFFFFFFFF diff --git a/include/asm-arm/arch-at91rm9200/irqs.h b/include/asm-arm/arch-at91rm9200/irqs.h index 27b0497f1b36..2dc93b174a8f 100644 --- a/include/asm-arm/arch-at91rm9200/irqs.h +++ b/include/asm-arm/arch-at91rm9200/irqs.h @@ -37,8 +37,6 @@ * symbols in gpio.h for ones handled indirectly as GPIOs. * We make provision for 4 banks of GPIO. */ -#include - #define NR_IRQS (NR_AIC_IRQS + (4 * 32)) -- cgit v1.2.3 From 55c20c0af7fe7d5d09af4addfafcfe3bdc500f5d Mon Sep 17 00:00:00 2001 From: Andrew Victor Date: Tue, 20 Jun 2006 19:31:39 +0100 Subject: [ARM] 3599/1: AT91RM9200 remove global variables Patch from Andrew Victor This patch removes some now unnecessary global variables - at91_master_clock, at91_serial_map, at91_console_port. Signed-off-by: Andrew Victor Signed-off-by: Russell King --- arch/arm/mach-at91rm9200/clock.c | 5 +---- arch/arm/mach-at91rm9200/common.c | 11 ----------- include/asm-arm/arch-at91rm9200/board.h | 7 ------- 3 files changed, 1 insertion(+), 22 deletions(-) (limited to 'include') diff --git a/arch/arm/mach-at91rm9200/clock.c b/arch/arm/mach-at91rm9200/clock.c index 30042d2bac5f..fe71b834899b 100644 --- a/arch/arm/mach-at91rm9200/clock.c +++ b/arch/arm/mach-at91rm9200/clock.c @@ -28,10 +28,10 @@ #include #include -#include /* for master clock global */ #include "generic.h" + /* * There's a lot more which can be done with clocks, including cpufreq * integration, slow clock mode support (for system suspend), letting @@ -722,9 +722,6 @@ int __init at91_clock_init(unsigned long main_clock) (unsigned) main_clock / 1000000, ((unsigned) main_clock % 1000000) / 1000); - /* FIXME get rid of master_clock global */ - at91_master_clock = mck.rate_hz; - #ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS /* establish PCK0..PCK3 parentage */ for (tmp = 0; tmp < ARRAY_SIZE(clock_list); tmp++) { diff --git a/arch/arm/mach-at91rm9200/common.c b/arch/arm/mach-at91rm9200/common.c index 40d29a73b5c5..1da68966e77f 100644 --- a/arch/arm/mach-at91rm9200/common.c +++ b/arch/arm/mach-at91rm9200/common.c @@ -108,14 +108,3 @@ void __init at91rm9200_map_io(void) iotable_init(at91rm9200_io_desc, ARRAY_SIZE(at91rm9200_io_desc)); } - -unsigned long at91_master_clock; - -EXPORT_SYMBOL(at91_master_clock); - - -int at91_serial_map[AT91_NR_UART]; -int at91_console_port; - -EXPORT_SYMBOL(at91_serial_map); -EXPORT_SYMBOL(at91_console_port); diff --git a/include/asm-arm/arch-at91rm9200/board.h b/include/asm-arm/arch-at91rm9200/board.h index 587948d56753..1fdd70b23809 100644 --- a/include/asm-arm/arch-at91rm9200/board.h +++ b/include/asm-arm/arch-at91rm9200/board.h @@ -31,13 +31,6 @@ #ifndef __ASM_ARCH_BOARD_H #define __ASM_ARCH_BOARD_H - /* Clocks */ -extern unsigned long at91_master_clock; - - /* Serial Port */ -extern int at91_serial_map[AT91_NR_UART]; -extern int at91_console_port; - #include #include #include -- cgit v1.2.3 From ea75ee9ab8835ece099589c729574aa8aa94c0a6 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 20 Jun 2006 19:53:16 +0100 Subject: [ARM] Include asm/hardware.h not asm/arch/hardware.h Signed-off-by: Russell King --- arch/arm/mach-at91rm9200/board-carmeva.c | 2 +- arch/arm/mach-at91rm9200/board-csb337.c | 2 +- arch/arm/mach-at91rm9200/board-csb637.c | 2 +- arch/arm/mach-at91rm9200/board-dk.c | 2 +- arch/arm/mach-at91rm9200/board-eb9200.c | 2 +- arch/arm/mach-at91rm9200/board-ek.c | 2 +- arch/arm/mach-at91rm9200/board-kafa.c | 2 +- arch/arm/mach-at91rm9200/board-kb9202.c | 2 +- arch/arm/mach-at91rm9200/clock.c | 2 +- arch/arm/mach-at91rm9200/common.c | 2 +- arch/arm/mach-at91rm9200/devices.c | 2 +- arch/arm/mach-at91rm9200/gpio.c | 2 +- arch/arm/mach-netx/fb.c | 2 +- arch/arm/mach-pnx4008/serial.c | 2 +- include/asm-arm/arch-at91rm9200/memory.h | 2 +- include/asm-arm/arch-at91rm9200/system.h | 2 +- include/asm-arm/arch-at91rm9200/timex.h | 2 +- include/asm-arm/arch-at91rm9200/uncompress.h | 2 +- 18 files changed, 18 insertions(+), 18 deletions(-) (limited to 'include') diff --git a/arch/arm/mach-at91rm9200/board-carmeva.c b/arch/arm/mach-at91rm9200/board-carmeva.c index 9183cb75ccd0..2c138b542ebe 100644 --- a/arch/arm/mach-at91rm9200/board-carmeva.c +++ b/arch/arm/mach-at91rm9200/board-carmeva.c @@ -35,7 +35,7 @@ #include #include -#include +#include #include #include diff --git a/arch/arm/mach-at91rm9200/board-csb337.c b/arch/arm/mach-at91rm9200/board-csb337.c index 3b9de181ae32..e94645d77f7a 100644 --- a/arch/arm/mach-at91rm9200/board-csb337.c +++ b/arch/arm/mach-at91rm9200/board-csb337.c @@ -35,7 +35,7 @@ #include #include -#include +#include #include #include diff --git a/arch/arm/mach-at91rm9200/board-csb637.c b/arch/arm/mach-at91rm9200/board-csb637.c index 2c4470d110da..67d5f7786cdb 100644 --- a/arch/arm/mach-at91rm9200/board-csb637.c +++ b/arch/arm/mach-at91rm9200/board-csb637.c @@ -34,7 +34,7 @@ #include #include -#include +#include #include #include diff --git a/arch/arm/mach-at91rm9200/board-dk.c b/arch/arm/mach-at91rm9200/board-dk.c index eb02ca95be79..48d7390fa584 100644 --- a/arch/arm/mach-at91rm9200/board-dk.c +++ b/arch/arm/mach-at91rm9200/board-dk.c @@ -38,7 +38,7 @@ #include #include -#include +#include #include #include diff --git a/arch/arm/mach-at91rm9200/board-eb9200.c b/arch/arm/mach-at91rm9200/board-eb9200.c index c7e4546a262d..a3e2df968a66 100644 --- a/arch/arm/mach-at91rm9200/board-eb9200.c +++ b/arch/arm/mach-at91rm9200/board-eb9200.c @@ -35,7 +35,7 @@ #include #include -#include +#include #include #include diff --git a/arch/arm/mach-at91rm9200/board-ek.c b/arch/arm/mach-at91rm9200/board-ek.c index 4d7468e42679..72202ed830ad 100644 --- a/arch/arm/mach-at91rm9200/board-ek.c +++ b/arch/arm/mach-at91rm9200/board-ek.c @@ -38,7 +38,7 @@ #include #include -#include +#include #include #include diff --git a/arch/arm/mach-at91rm9200/board-kafa.c b/arch/arm/mach-at91rm9200/board-kafa.c index 35d459fdfcf1..bf760c5e0c46 100644 --- a/arch/arm/mach-at91rm9200/board-kafa.c +++ b/arch/arm/mach-at91rm9200/board-kafa.c @@ -34,7 +34,7 @@ #include #include -#include +#include #include #include diff --git a/arch/arm/mach-at91rm9200/board-kb9202.c b/arch/arm/mach-at91rm9200/board-kb9202.c index 6ba65ef48809..f06d2b54cc9a 100644 --- a/arch/arm/mach-at91rm9200/board-kb9202.c +++ b/arch/arm/mach-at91rm9200/board-kb9202.c @@ -35,7 +35,7 @@ #include #include -#include +#include #include #include diff --git a/arch/arm/mach-at91rm9200/clock.c b/arch/arm/mach-at91rm9200/clock.c index fe71b834899b..edc2cc837ae6 100644 --- a/arch/arm/mach-at91rm9200/clock.c +++ b/arch/arm/mach-at91rm9200/clock.c @@ -27,7 +27,7 @@ #include #include -#include +#include #include "generic.h" diff --git a/arch/arm/mach-at91rm9200/common.c b/arch/arm/mach-at91rm9200/common.c index 1da68966e77f..e836f8537a1d 100644 --- a/arch/arm/mach-at91rm9200/common.c +++ b/arch/arm/mach-at91rm9200/common.c @@ -16,7 +16,7 @@ #include #include -#include +#include #include "generic.h" static struct map_desc at91rm9200_io_desc[] __initdata = { diff --git a/arch/arm/mach-at91rm9200/devices.c b/arch/arm/mach-at91rm9200/devices.c index bf753e306a3a..1cf85d231baa 100644 --- a/arch/arm/mach-at91rm9200/devices.c +++ b/arch/arm/mach-at91rm9200/devices.c @@ -16,7 +16,7 @@ #include #include -#include +#include #include #include diff --git a/arch/arm/mach-at91rm9200/gpio.c b/arch/arm/mach-at91rm9200/gpio.c index 3430ea054662..83c34747087b 100644 --- a/arch/arm/mach-at91rm9200/gpio.c +++ b/arch/arm/mach-at91rm9200/gpio.c @@ -16,7 +16,7 @@ #include #include -#include +#include #include static const u32 pio_controller_offset[4] = { diff --git a/arch/arm/mach-netx/fb.c b/arch/arm/mach-netx/fb.c index e169b683e4de..ef0ab6115c0b 100644 --- a/arch/arm/mach-netx/fb.c +++ b/arch/arm/mach-netx/fb.c @@ -24,7 +24,7 @@ #include #include -#include +#include struct clk {}; diff --git a/arch/arm/mach-pnx4008/serial.c b/arch/arm/mach-pnx4008/serial.c index 2e1e04cc048c..10322384e45d 100644 --- a/arch/arm/mach-pnx4008/serial.c +++ b/arch/arm/mach-pnx4008/serial.c @@ -16,7 +16,7 @@ #include #include -#include +#include #include #include diff --git a/include/asm-arm/arch-at91rm9200/memory.h b/include/asm-arm/arch-at91rm9200/memory.h index 462f1f0ad67c..3c327c404373 100644 --- a/include/asm-arm/arch-at91rm9200/memory.h +++ b/include/asm-arm/arch-at91rm9200/memory.h @@ -21,7 +21,7 @@ #ifndef __ASM_ARCH_MEMORY_H #define __ASM_ARCH_MEMORY_H -#include +#include #define PHYS_OFFSET (AT91_SDRAM_BASE) diff --git a/include/asm-arm/arch-at91rm9200/system.h b/include/asm-arm/arch-at91rm9200/system.h index 945e66507a78..8a2ff472e4cf 100644 --- a/include/asm-arm/arch-at91rm9200/system.h +++ b/include/asm-arm/arch-at91rm9200/system.h @@ -21,7 +21,7 @@ #ifndef __ASM_ARCH_SYSTEM_H #define __ASM_ARCH_SYSTEM_H -#include +#include static inline void arch_idle(void) { diff --git a/include/asm-arm/arch-at91rm9200/timex.h b/include/asm-arm/arch-at91rm9200/timex.h index 3f112dd12587..88687cefe6eb 100644 --- a/include/asm-arm/arch-at91rm9200/timex.h +++ b/include/asm-arm/arch-at91rm9200/timex.h @@ -21,7 +21,7 @@ #ifndef __ASM_ARCH_TIMEX_H #define __ASM_ARCH_TIMEX_H -#include +#include #define CLOCK_TICK_RATE (AT91_SLOW_CLOCK) diff --git a/include/asm-arm/arch-at91rm9200/uncompress.h b/include/asm-arm/arch-at91rm9200/uncompress.h index 7b38497c24b5..ec7811ab0a52 100644 --- a/include/asm-arm/arch-at91rm9200/uncompress.h +++ b/include/asm-arm/arch-at91rm9200/uncompress.h @@ -21,7 +21,7 @@ #ifndef __ASM_ARCH_UNCOMPRESS_H #define __ASM_ARCH_UNCOMPRESS_H -#include +#include /* * The following code assumes the serial port has already been -- cgit v1.2.3 From 4af6fee18822d012a15b4c9b8992e1f2793dfe0b Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Tue, 20 Jun 2006 21:30:44 +0100 Subject: [ARM] 3610/1: Make reboot work on Versatile Patch from Deepak Saxena This patch makes soft reboot work on the Versatile board. Thanks to Catalin Marinas @ ARM for pointing out the proper way to do this. Signed-off-by: Deepak Saxena Signed-off-by: Russell King --- arch/arm/Kconfig | 112 ++++++++++++++++---------------- include/asm-arm/arch-versatile/system.h | 16 ++--- 2 files changed, 63 insertions(+), 65 deletions(-) (limited to 'include') diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index dfb97fe045d0..1b7e5c2e90ef 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -93,15 +93,49 @@ choice prompt "ARM system type" default ARCH_VERSATILE +config ARCH_AAEC2000 + bool "Agilent AAEC-2000 based" + select ARM_AMBA + help + This enables support for systems based on the Agilent AAEC-2000 + +config ARCH_INTEGRATOR + bool "ARM Ltd. Integrator family" + select ARM_AMBA + select ICST525 + help + Support for ARM's Integrator platform. + +config ARCH_REALVIEW + bool "ARM Ltd. RealView family" + select ARM_AMBA + select ICST307 + help + This enables support for ARM Ltd RealView boards. + +config ARCH_VERSATILE + bool "ARM Ltd. Versatile family" + select ARM_AMBA + select ARM_VIC + select ICST307 + help + This enables support for ARM Ltd Versatile board. + +config ARCH_AT91RM9200 + bool "Atmel AT91RM9200" + help + Say Y here if you intend to run this kernel on an Atmel + AT91RM9200-based board. + config ARCH_CLPS7500 - bool "Cirrus-CL-PS7500FE" + bool "Cirrus CL-PS7500FE" select TIMER_ACORN select ISA help Support for the Cirrus Logic PS7500FE system-on-a-chip. config ARCH_CLPS711X - bool "CLPS711x/EP721x-based" + bool "Cirrus Logic CLPS711x/EP721x-based" help Support for Cirrus Logic 711x/721x based boards. @@ -135,12 +169,22 @@ config ARCH_FOOTBRIDGE Support for systems based on the DC21285 companion chip ("FootBridge"), such as the Simtec CATS and the Rebel NetWinder. -config ARCH_INTEGRATOR - bool "Integrator" - select ARM_AMBA - select ICST525 +config ARCH_NETX + bool "Hilscher NetX based" + select ARM_VIC help - Support for ARM's Integrator platform. + This enables support for systems based on the Hilscher NetX Soc + +config ARCH_H720X + bool "Hynix HMS720x-based" + select ISA_DMA_API + help + This enables support for systems based on the Hynix HMS720x + +config ARCH_IMX + bool "IMX" + help + Support for Motorola's i.MX family of processors (MX1, MXL). config ARCH_IOP3XX bool "IOP3xx-based" @@ -178,6 +222,11 @@ config ARCH_L7200 If you have any questions or comments about the Linux kernel port to this board, send e-mail to . +config ARCH_PNX4008 + bool "Philips Nexperia PNX4008 Mobile" + help + This enables support for Philips PNX4008 mobile platform. + config ARCH_PXA bool "PXA2xx-based" select ARCH_MTD_XIP @@ -232,55 +281,6 @@ config ARCH_OMAP help Support for TI's OMAP platform (OMAP1 and OMAP2). -config ARCH_VERSATILE - bool "Versatile" - select ARM_AMBA - select ARM_VIC - select ICST307 - help - This enables support for ARM Ltd Versatile board. - -config ARCH_REALVIEW - bool "RealView" - select ARM_AMBA - select ICST307 - help - This enables support for ARM Ltd RealView boards. - -config ARCH_IMX - bool "IMX" - help - Support for Motorola's i.MX family of processors (MX1, MXL). - -config ARCH_H720X - bool "Hynix-HMS720x-based" - select ISA_DMA_API - help - This enables support for systems based on the Hynix HMS720x - -config ARCH_AAEC2000 - bool "Agilent AAEC-2000 based" - select ARM_AMBA - help - This enables support for systems based on the Agilent AAEC-2000 - -config ARCH_AT91RM9200 - bool "AT91RM9200" - help - Say Y here if you intend to run this kernel on an Atmel - AT91RM9200-based board. - -config ARCH_PNX4008 - bool "Philips Nexperia PNX4008 Mobile" - help - This enables support for Philips PNX4008 mobile platform. - -config ARCH_NETX - bool "Hilscher NetX based" - select ARM_VIC - help - This enables support for systems based on the Hilscher NetX Soc - endchoice source "arch/arm/mach-clps711x/Kconfig" diff --git a/include/asm-arm/arch-versatile/system.h b/include/asm-arm/arch-versatile/system.h index 8889a189739f..71c6254c0d9b 100644 --- a/include/asm-arm/arch-versatile/system.h +++ b/include/asm-arm/arch-versatile/system.h @@ -36,16 +36,14 @@ static inline void arch_idle(void) static inline void arch_reset(char mode) { - unsigned int hdr_ctrl = (IO_ADDRESS(VERSATILE_SYS_BASE) + VERSATILE_SYS_RESETCTL_OFFSET); - unsigned int val; + u32 val; - /* - * To reset, we hit the on-board reset register - * in the system FPGA - */ - val = __raw_readl(hdr_ctrl); - val |= VERSATILE_SYS_CTRL_RESET_CONFIGCLR; - __raw_writel(val, hdr_ctrl); + val = __raw_readl(IO_ADDRESS(VERSATILE_SYS_RESETCTL)) & ~0x7; + val |= 0x105; + + __raw_writel(0xa05f, IO_ADDRESS(VERSATILE_SYS_LOCK)); + __raw_writel(val, IO_ADDRESS(VERSATILE_SYS_RESETCTL)); + __raw_writel(0, IO_ADDRESS(VERSATILE_SYS_LOCK)); } #endif -- cgit v1.2.3 From 2eec0e0842ef747027eb9181d5f50d7157184d57 Mon Sep 17 00:00:00 2001 From: Cedric Le Goater Date: Mon, 19 Jun 2006 21:10:44 -0700 Subject: [PATCH] s390: add __raw_writeq required by __iowrite64_copy It also adds all the related quad routines. Signed-off-by: Cedric Le Goater Acked-by: Heiko Carstens Cc: Martin Schwidefsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-s390/io.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'include') diff --git a/include/asm-s390/io.h b/include/asm-s390/io.h index b05825dd16d7..d4614b35f423 100644 --- a/include/asm-s390/io.h +++ b/include/asm-s390/io.h @@ -86,20 +86,25 @@ extern void iounmap(void *addr); #define readb(addr) (*(volatile unsigned char *) __io_virt(addr)) #define readw(addr) (*(volatile unsigned short *) __io_virt(addr)) #define readl(addr) (*(volatile unsigned int *) __io_virt(addr)) +#define readq(addr) (*(volatile unsigned long long *) __io_virt(addr)) #define readb_relaxed(addr) readb(addr) #define readw_relaxed(addr) readw(addr) #define readl_relaxed(addr) readl(addr) +#define readq_relaxed(addr) readq(addr) #define __raw_readb readb #define __raw_readw readw #define __raw_readl readl +#define __raw_readq readq #define writeb(b,addr) (*(volatile unsigned char *) __io_virt(addr) = (b)) #define writew(b,addr) (*(volatile unsigned short *) __io_virt(addr) = (b)) #define writel(b,addr) (*(volatile unsigned int *) __io_virt(addr) = (b)) +#define writeq(b,addr) (*(volatile unsigned long long *) __io_virt(addr) = (b)) #define __raw_writeb writeb #define __raw_writew writew #define __raw_writel writel +#define __raw_writeq writeq #define memset_io(a,b,c) memset(__io_virt(a),(b),(c)) #define memcpy_fromio(a,b,c) memcpy((a),__io_virt(b),(c)) -- cgit v1.2.3 From 22ae813b85df7c0b0fc7c8d6f336d6a9f566ff97 Mon Sep 17 00:00:00 2001 From: Brice Goglin Date: Tue, 20 Jun 2006 20:03:02 -0700 Subject: [PATCH] add __iowrite64_copy Introduce __iowrite64_copy. It will be used by the Myri-10G Ethernet driver to post requests to the NIC. This driver will be submitted soon. __iowrite64_copy copies to I/O memory in units of 64 bits when possible (on 64 bit architectures). It reverts to __iowrite32_copy on 32 bit architectures. Signed-off-by: Brice Goglin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/io.h | 1 + lib/iomap_copy.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) (limited to 'include') diff --git a/include/linux/io.h b/include/linux/io.h index 85533ec5aaa1..420e2fdf26f6 100644 --- a/include/linux/io.h +++ b/include/linux/io.h @@ -21,5 +21,6 @@ #include void __iowrite32_copy(void __iomem *to, const void *from, size_t count); +void __iowrite64_copy(void __iomem *to, const void *from, size_t count); #endif /* _LINUX_IO_H */ diff --git a/lib/iomap_copy.c b/lib/iomap_copy.c index 351045f4f63c..864fc5ea398c 100644 --- a/lib/iomap_copy.c +++ b/lib/iomap_copy.c @@ -40,3 +40,31 @@ void __attribute__((weak)) __iowrite32_copy(void __iomem *to, __raw_writel(*src++, dst++); } EXPORT_SYMBOL_GPL(__iowrite32_copy); + +/** + * __iowrite64_copy - copy data to MMIO space, in 64-bit or 32-bit units + * @to: destination, in MMIO space (must be 64-bit aligned) + * @from: source (must be 64-bit aligned) + * @count: number of 64-bit quantities to copy + * + * Copy data from kernel space to MMIO space, in units of 32 or 64 bits at a + * time. Order of access is not guaranteed, nor is a memory barrier + * performed afterwards. + */ +void __attribute__((weak)) __iowrite64_copy(void __iomem *to, + const void *from, + size_t count) +{ +#ifdef CONFIG_64BIT + u64 __iomem *dst = to; + const u64 *src = from; + const u64 *end = src + count; + + while (src < end) + __raw_writeq(*src++, dst++); +#else + __iowrite32_copy(to, from, count * 2); +#endif +} + +EXPORT_SYMBOL_GPL(__iowrite64_copy); -- cgit v1.2.3 From 6b543404058a5ffdca8c48e95e0b8a69bb4bdba9 Mon Sep 17 00:00:00 2001 From: Jon Loeliger Date: Sat, 17 Jun 2006 17:52:51 -0500 Subject: [POWERPC] Add 8641 Register space and IRQ definitions. Signed-off-by: Jeff Brown Signed-off-by: Xianghua Xiao Signed-off-by: Jon Loeliger Signed-off-by: Paul Mackerras --- include/asm-powerpc/immap_86xx.h | 199 +++++++++++++++++++++++++++++++++++++++ include/asm-powerpc/irq.h | 86 +++++++++++++++++ include/asm-powerpc/mpc86xx.h | 47 +++++++++ 3 files changed, 332 insertions(+) create mode 100644 include/asm-powerpc/immap_86xx.h create mode 100644 include/asm-powerpc/mpc86xx.h (limited to 'include') diff --git a/include/asm-powerpc/immap_86xx.h b/include/asm-powerpc/immap_86xx.h new file mode 100644 index 000000000000..d905b6622268 --- /dev/null +++ b/include/asm-powerpc/immap_86xx.h @@ -0,0 +1,199 @@ +/* + * MPC86xx Internal Memory Map + * + * Author: Jeff Brown + * + * Copyright 2004 Freescale Semiconductor, Inc + * + * 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. + * + */ + +#ifndef __ASM_POWERPC_IMMAP_86XX_H__ +#define __ASM_POWERPC_IMMAP_86XX_H__ +#ifdef __KERNEL__ + +/* Eventually this should define all the IO block registers in 86xx */ + +/* PCI Registers */ +typedef struct ccsr_pci { + uint cfg_addr; /* 0x.000 - PCI Configuration Address Register */ + uint cfg_data; /* 0x.004 - PCI Configuration Data Register */ + uint int_ack; /* 0x.008 - PCI Interrupt Acknowledge Register */ + char res1[3060]; + uint potar0; /* 0x.c00 - PCI Outbound Transaction Address Register 0 */ + uint potear0; /* 0x.c04 - PCI Outbound Translation Extended Address Register 0 */ + uint powbar0; /* 0x.c08 - PCI Outbound Window Base Address Register 0 */ + char res2[4]; + uint powar0; /* 0x.c10 - PCI Outbound Window Attributes Register 0 */ + char res3[12]; + uint potar1; /* 0x.c20 - PCI Outbound Transaction Address Register 1 */ + uint potear1; /* 0x.c24 - PCI Outbound Translation Extended Address Register 1 */ + uint powbar1; /* 0x.c28 - PCI Outbound Window Base Address Register 1 */ + char res4[4]; + uint powar1; /* 0x.c30 - PCI Outbound Window Attributes Register 1 */ + char res5[12]; + uint potar2; /* 0x.c40 - PCI Outbound Transaction Address Register 2 */ + uint potear2; /* 0x.c44 - PCI Outbound Translation Extended Address Register 2 */ + uint powbar2; /* 0x.c48 - PCI Outbound Window Base Address Register 2 */ + char res6[4]; + uint powar2; /* 0x.c50 - PCI Outbound Window Attributes Register 2 */ + char res7[12]; + uint potar3; /* 0x.c60 - PCI Outbound Transaction Address Register 3 */ + uint potear3; /* 0x.c64 - PCI Outbound Translation Extended Address Register 3 */ + uint powbar3; /* 0x.c68 - PCI Outbound Window Base Address Register 3 */ + char res8[4]; + uint powar3; /* 0x.c70 - PCI Outbound Window Attributes Register 3 */ + char res9[12]; + uint potar4; /* 0x.c80 - PCI Outbound Transaction Address Register 4 */ + uint potear4; /* 0x.c84 - PCI Outbound Translation Extended Address Register 4 */ + uint powbar4; /* 0x.c88 - PCI Outbound Window Base Address Register 4 */ + char res10[4]; + uint powar4; /* 0x.c90 - PCI Outbound Window Attributes Register 4 */ + char res11[268]; + uint pitar3; /* 0x.da0 - PCI Inbound Translation Address Register 3 */ + char res12[4]; + uint piwbar3; /* 0x.da8 - PCI Inbound Window Base Address Register 3 */ + uint piwbear3; /* 0x.dac - PCI Inbound Window Base Extended Address Register 3 */ + uint piwar3; /* 0x.db0 - PCI Inbound Window Attributes Register 3 */ + char res13[12]; + uint pitar2; /* 0x.dc0 - PCI Inbound Translation Address Register 2 */ + char res14[4]; + uint piwbar2; /* 0x.dc8 - PCI Inbound Window Base Address Register 2 */ + uint piwbear2; /* 0x.dcc - PCI Inbound Window Base Extended Address Register 2 */ + uint piwar2; /* 0x.dd0 - PCI Inbound Window Attributes Register 2 */ + char res15[12]; + uint pitar1; /* 0x.de0 - PCI Inbound Translation Address Register 1 */ + char res16[4]; + uint piwbar1; /* 0x.de8 - PCI Inbound Window Base Address Register 1 */ + char res17[4]; + uint piwar1; /* 0x.df0 - PCI Inbound Window Attributes Register 1 */ + char res18[12]; + uint err_dr; /* 0x.e00 - PCI Error Detect Register */ + uint err_cap_dr; /* 0x.e04 - PCI Error Capture Disable Register */ + uint err_en; /* 0x.e08 - PCI Error Enable Register */ + uint err_attrib; /* 0x.e0c - PCI Error Attributes Capture Register */ + uint err_addr; /* 0x.e10 - PCI Error Address Capture Register */ + uint err_ext_addr; /* 0x.e14 - PCI Error Extended Address Capture Register */ + uint err_dl; /* 0x.e18 - PCI Error Data Low Capture Register */ + uint err_dh; /* 0x.e1c - PCI Error Data High Capture Register */ + uint gas_timr; /* 0x.e20 - PCI Gasket Timer Register */ + uint pci_timr; /* 0x.e24 - PCI Timer Register */ + char res19[472]; +} ccsr_pci_t; + +/* PCI Express Registers */ +typedef struct ccsr_pex { + uint pex_config_addr; /* 0x.000 - PCI Express Configuration Address Register */ + uint pex_config_data; /* 0x.004 - PCI Express Configuration Data Register */ + char res1[4]; + uint pex_otb_cpl_tor; /* 0x.00c - PCI Express Outbound completion timeout register */ + uint pex_conf_tor; /* 0x.010 - PCI Express configuration timeout register */ + char res2[12]; + uint pex_pme_mes_dr; /* 0x.020 - PCI Express PME and message detect register */ + uint pex_pme_mes_disr; /* 0x.024 - PCI Express PME and message disable register */ + uint pex_pme_mes_ier; /* 0x.028 - PCI Express PME and message interrupt enable register */ + uint pex_pmcr; /* 0x.02c - PCI Express power management command register */ + char res3[3024]; + uint pexotar0; /* 0x.c00 - PCI Express outbound translation address register 0 */ + uint pexotear0; /* 0x.c04 - PCI Express outbound translation extended address register 0*/ + char res4[8]; + uint pexowar0; /* 0x.c10 - PCI Express outbound window attributes register 0*/ + char res5[12]; + uint pexotar1; /* 0x.c20 - PCI Express outbound translation address register 1 */ + uint pexotear1; /* 0x.c24 - PCI Express outbound translation extended address register 1*/ + uint pexowbar1; /* 0x.c28 - PCI Express outbound window base address register 1*/ + char res6[4]; + uint pexowar1; /* 0x.c30 - PCI Express outbound window attributes register 1*/ + char res7[12]; + uint pexotar2; /* 0x.c40 - PCI Express outbound translation address register 2 */ + uint pexotear2; /* 0x.c44 - PCI Express outbound translation extended address register 2*/ + uint pexowbar2; /* 0x.c48 - PCI Express outbound window base address register 2*/ + char res8[4]; + uint pexowar2; /* 0x.c50 - PCI Express outbound window attributes register 2*/ + char res9[12]; + uint pexotar3; /* 0x.c60 - PCI Express outbound translation address register 3 */ + uint pexotear3; /* 0x.c64 - PCI Express outbound translation extended address register 3*/ + uint pexowbar3; /* 0x.c68 - PCI Express outbound window base address register 3*/ + char res10[4]; + uint pexowar3; /* 0x.c70 - PCI Express outbound window attributes register 3*/ + char res11[12]; + uint pexotar4; /* 0x.c80 - PCI Express outbound translation address register 4 */ + uint pexotear4; /* 0x.c84 - PCI Express outbound translation extended address register 4*/ + uint pexowbar4; /* 0x.c88 - PCI Express outbound window base address register 4*/ + char res12[4]; + uint pexowar4; /* 0x.c90 - PCI Express outbound window attributes register 4*/ + char res13[12]; + char res14[256]; + uint pexitar3; /* 0x.da0 - PCI Express inbound translation address register 3 */ + char res15[4]; + uint pexiwbar3; /* 0x.da8 - PCI Express inbound window base address register 3 */ + uint pexiwbear3; /* 0x.dac - PCI Express inbound window base extended address register 3 */ + uint pexiwar3; /* 0x.db0 - PCI Express inbound window attributes register 3 */ + char res16[12]; + uint pexitar2; /* 0x.dc0 - PCI Express inbound translation address register 2 */ + char res17[4]; + uint pexiwbar2; /* 0x.dc8 - PCI Express inbound window base address register 2 */ + uint pexiwbear2; /* 0x.dcc - PCI Express inbound window base extended address register 2 */ + uint pexiwar2; /* 0x.dd0 - PCI Express inbound window attributes register 2 */ + char res18[12]; + uint pexitar1; /* 0x.de0 - PCI Express inbound translation address register 2 */ + char res19[4]; + uint pexiwbar1; /* 0x.de8 - PCI Express inbound window base address register 2 */ + uint pexiwbear1; /* 0x.dec - PCI Express inbound window base extended address register 2 */ + uint pexiwar1; /* 0x.df0 - PCI Express inbound window attributes register 2 */ + char res20[12]; + uint pex_err_dr; /* 0x.e00 - PCI Express error detect register */ + char res21[4]; + uint pex_err_en; /* 0x.e08 - PCI Express error interrupt enable register */ + char res22[4]; + uint pex_err_disr; /* 0x.e10 - PCI Express error disable register */ + char res23[12]; + uint pex_err_cap_stat; /* 0x.e20 - PCI Express error capture status register */ + char res24[4]; + uint pex_err_cap_r0; /* 0x.e28 - PCI Express error capture register 0 */ + uint pex_err_cap_r1; /* 0x.e2c - PCI Express error capture register 0 */ + uint pex_err_cap_r2; /* 0x.e30 - PCI Express error capture register 0 */ + uint pex_err_cap_r3; /* 0x.e34 - PCI Express error capture register 0 */ +} ccsr_pex_t; + +/* Global Utility Registers */ +typedef struct ccsr_guts { + uint porpllsr; /* 0x.0000 - POR PLL Ratio Status Register */ + uint porbmsr; /* 0x.0004 - POR Boot Mode Status Register */ + uint porimpscr; /* 0x.0008 - POR I/O Impedance Status and Control Register */ + uint pordevsr; /* 0x.000c - POR I/O Device Status Register */ + uint pordbgmsr; /* 0x.0010 - POR Debug Mode Status Register */ + char res1[12]; + uint gpporcr; /* 0x.0020 - General-Purpose POR Configuration Register */ + char res2[12]; + uint gpiocr; /* 0x.0030 - GPIO Control Register */ + char res3[12]; + uint gpoutdr; /* 0x.0040 - General-Purpose Output Data Register */ + char res4[12]; + uint gpindr; /* 0x.0050 - General-Purpose Input Data Register */ + char res5[12]; + uint pmuxcr; /* 0x.0060 - Alternate Function Signal Multiplex Control */ + char res6[12]; + uint devdisr; /* 0x.0070 - Device Disable Control */ + char res7[12]; + uint powmgtcsr; /* 0x.0080 - Power Management Status and Control Register */ + char res8[12]; + uint mcpsumr; /* 0x.0090 - Machine Check Summary Register */ + char res9[12]; + uint pvr; /* 0x.00a0 - Processor Version Register */ + uint svr; /* 0x.00a4 - System Version Register */ + char res10[3416]; + uint clkocr; /* 0x.0e00 - Clock Out Select Register */ + char res11[12]; + uint ddrdllcr; /* 0x.0e10 - DDR DLL Control Register */ + char res12[12]; + uint lbcdllcr; /* 0x.0e20 - LBC DLL Control Register */ + char res13[61916]; +} ccsr_guts_t; + +#endif /* __ASM_POWERPC_IMMAP_86XX_H__ */ +#endif /* __KERNEL__ */ diff --git a/include/asm-powerpc/irq.h b/include/asm-powerpc/irq.h index 7bc6d73b2823..7a762096f196 100644 --- a/include/asm-powerpc/irq.h +++ b/include/asm-powerpc/irq.h @@ -348,6 +348,92 @@ extern u64 ppc64_interrupt_controller; #define SIU_INT_PC1 ((uint)0x3e+CPM_IRQ_OFFSET) #define SIU_INT_PC0 ((uint)0x3f+CPM_IRQ_OFFSET) +#elif defined(CONFIG_PPC_86xx) +#include + +#define NR_EPIC_INTS 48 +#ifndef NR_8259_INTS +#define NR_8259_INTS 16 /*ULI 1575 can route 12 interrupts */ +#endif +#define NUM_8259_INTERRUPTS NR_8259_INTS + +#ifndef I8259_OFFSET +#define I8259_OFFSET 0 +#endif + +#define NR_IRQS 256 + +/* Internal IRQs on MPC86xx OpenPIC */ + +#ifndef MPC86xx_OPENPIC_IRQ_OFFSET +#define MPC86xx_OPENPIC_IRQ_OFFSET NR_8259_INTS +#endif + +/* The 48 internal sources */ +#define MPC86xx_IRQ_NULL ( 0 + MPC86xx_OPENPIC_IRQ_OFFSET) +#define MPC86xx_IRQ_MCM ( 1 + MPC86xx_OPENPIC_IRQ_OFFSET) +#define MPC86xx_IRQ_DDR ( 2 + MPC86xx_OPENPIC_IRQ_OFFSET) +#define MPC86xx_IRQ_LBC ( 3 + MPC86xx_OPENPIC_IRQ_OFFSET) +#define MPC86xx_IRQ_DMA0 ( 4 + MPC86xx_OPENPIC_IRQ_OFFSET) +#define MPC86xx_IRQ_DMA1 ( 5 + MPC86xx_OPENPIC_IRQ_OFFSET) +#define MPC86xx_IRQ_DMA2 ( 6 + MPC86xx_OPENPIC_IRQ_OFFSET) +#define MPC86xx_IRQ_DMA3 ( 7 + MPC86xx_OPENPIC_IRQ_OFFSET) + +/* no 10,11 */ +#define MPC86xx_IRQ_UART2 (12 + MPC86xx_OPENPIC_IRQ_OFFSET) +#define MPC86xx_IRQ_TSEC1_TX (13 + MPC86xx_OPENPIC_IRQ_OFFSET) +#define MPC86xx_IRQ_TSEC1_RX (14 + MPC86xx_OPENPIC_IRQ_OFFSET) +#define MPC86xx_IRQ_TSEC3_TX (15 + MPC86xx_OPENPIC_IRQ_OFFSET) +#define MPC86xx_IRQ_TSEC3_RX (16 + MPC86xx_OPENPIC_IRQ_OFFSET) +#define MPC86xx_IRQ_TSEC3_ERROR (17 + MPC86xx_OPENPIC_IRQ_OFFSET) +#define MPC86xx_IRQ_TSEC1_ERROR (18 + MPC86xx_OPENPIC_IRQ_OFFSET) +#define MPC86xx_IRQ_TSEC2_TX (19 + MPC86xx_OPENPIC_IRQ_OFFSET) +#define MPC86xx_IRQ_TSEC2_RX (20 + MPC86xx_OPENPIC_IRQ_OFFSET) +#define MPC86xx_IRQ_TSEC4_TX (21 + MPC86xx_OPENPIC_IRQ_OFFSET) +#define MPC86xx_IRQ_TSEC4_RX (22 + MPC86xx_OPENPIC_IRQ_OFFSET) +#define MPC86xx_IRQ_TSEC4_ERROR (23 + MPC86xx_OPENPIC_IRQ_OFFSET) +#define MPC86xx_IRQ_TSEC2_ERROR (24 + MPC86xx_OPENPIC_IRQ_OFFSET) +/* no 25 */ +#define MPC86xx_IRQ_UART1 (26 + MPC86xx_OPENPIC_IRQ_OFFSET) +#define MPC86xx_IRQ_IIC (27 + MPC86xx_OPENPIC_IRQ_OFFSET) +#define MPC86xx_IRQ_PERFMON (28 + MPC86xx_OPENPIC_IRQ_OFFSET) +/* no 29,30,31 */ +#define MPC86xx_IRQ_SRIO_ERROR (32 + MPC86xx_OPENPIC_IRQ_OFFSET) +#define MPC86xx_IRQ_SRIO_OUT_BELL (33 + MPC86xx_OPENPIC_IRQ_OFFSET) +#define MPC86xx_IRQ_SRIO_IN_BELL (34 + MPC86xx_OPENPIC_IRQ_OFFSET) +/* no 35,36 */ +#define MPC86xx_IRQ_SRIO_OUT_MSG1 (37 + MPC86xx_OPENPIC_IRQ_OFFSET) +#define MPC86xx_IRQ_SRIO_IN_MSG1 (38 + MPC86xx_OPENPIC_IRQ_OFFSET) +#define MPC86xx_IRQ_SRIO_OUT_MSG2 (39 + MPC86xx_OPENPIC_IRQ_OFFSET) +#define MPC86xx_IRQ_SRIO_IN_MSG2 (40 + MPC86xx_OPENPIC_IRQ_OFFSET) + +/* The 12 external interrupt lines */ +#define MPC86xx_IRQ_EXT_BASE 48 +#define MPC86xx_IRQ_EXT0 (0 + MPC86xx_IRQ_EXT_BASE \ + + MPC86xx_OPENPIC_IRQ_OFFSET) +#define MPC86xx_IRQ_EXT1 (1 + MPC86xx_IRQ_EXT_BASE \ + + MPC86xx_OPENPIC_IRQ_OFFSET) +#define MPC86xx_IRQ_EXT2 (2 + MPC86xx_IRQ_EXT_BASE \ + + MPC86xx_OPENPIC_IRQ_OFFSET) +#define MPC86xx_IRQ_EXT3 (3 + MPC86xx_IRQ_EXT_BASE \ + + MPC86xx_OPENPIC_IRQ_OFFSET) +#define MPC86xx_IRQ_EXT4 (4 + MPC86xx_IRQ_EXT_BASE \ + + MPC86xx_OPENPIC_IRQ_OFFSET) +#define MPC86xx_IRQ_EXT5 (5 + MPC86xx_IRQ_EXT_BASE \ + + MPC86xx_OPENPIC_IRQ_OFFSET) +#define MPC86xx_IRQ_EXT6 (6 + MPC86xx_IRQ_EXT_BASE \ + + MPC86xx_OPENPIC_IRQ_OFFSET) +#define MPC86xx_IRQ_EXT7 (7 + MPC86xx_IRQ_EXT_BASE \ + + MPC86xx_OPENPIC_IRQ_OFFSET) +#define MPC86xx_IRQ_EXT8 (8 + MPC86xx_IRQ_EXT_BASE \ + + MPC86xx_OPENPIC_IRQ_OFFSET) +#define MPC86xx_IRQ_EXT9 (9 + MPC86xx_IRQ_EXT_BASE \ + + MPC86xx_OPENPIC_IRQ_OFFSET) +#define MPC86xx_IRQ_EXT10 (10 + MPC86xx_IRQ_EXT_BASE \ + + MPC86xx_OPENPIC_IRQ_OFFSET) +#define MPC86xx_IRQ_EXT11 (11 + MPC86xx_IRQ_EXT_BASE \ + + MPC86xx_OPENPIC_IRQ_OFFSET) + #else /* CONFIG_40x + CONFIG_8xx */ /* * this is the # irq's for all ppc arch's (pmac/chrp/prep) diff --git a/include/asm-powerpc/mpc86xx.h b/include/asm-powerpc/mpc86xx.h new file mode 100644 index 000000000000..d0a6718d188b --- /dev/null +++ b/include/asm-powerpc/mpc86xx.h @@ -0,0 +1,47 @@ +/* + * MPC86xx definitions + * + * Author: Jeff Brown + * + * Copyright 2004 Freescale Semiconductor, Inc + * + * 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. + */ + +#ifdef __KERNEL__ +#ifndef __ASM_POWERPC_MPC86xx_H__ +#define __ASM_POWERPC_MPC86xx_H__ + +#include +#include + +#ifdef CONFIG_PPC_86xx + +#ifdef CONFIG_MPC8641_HPCN +#include +#endif + +#define _IO_BASE isa_io_base +#define _ISA_MEM_BASE isa_mem_base +#ifdef CONFIG_PCI +#define PCI_DRAM_OFFSET pci_dram_offset +#else +#define PCI_DRAM_OFFSET 0 +#endif + +#define CPU0_BOOT_RELEASE 0x01000000 +#define CPU1_BOOT_RELEASE 0x02000000 +#define CPU_ALL_RELEASED (CPU0_BOOT_RELEASE | CPU1_BOOT_RELEASE) +#define MCM_PORT_CONFIG_OFFSET 0x1010 + +/* Offset from CCSRBAR */ +#define MPC86xx_OPENPIC_OFFSET (0x40000) +#define MPC86xx_MCM_OFFSET (0x00000) +#define MPC86xx_MCM_SIZE (0x02000) + +#endif /* CONFIG_PPC_86xx */ +#endif /* __ASM_POWERPC_MPC86xx_H__ */ +#endif /* __KERNEL__ */ -- cgit v1.2.3 From acf7d76827a577059636e949079021e6af6dd702 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 19 Jun 2006 20:33:16 +0200 Subject: [POWERPC] cell: add RAS support This is a first version of support for the Cell BE "Reliability, Availability and Serviceability" features. It doesn't yet handle some of the RAS interrupts (the ones described in iic_is/iic_irr), I'm still working on a proper way to expose these. They are essentially a cascaded controller by themselves (sic !) though I may just handle them locally to the iic driver. I need also to sync with David Erb on the way he hooked in the performance monitor interrupt. So that's all for 2.6.17 and I'll do more work on that with my rework of the powerpc interrupt layer that I'm hacking on at the moment. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/configs/cell_defconfig | 1 + arch/powerpc/kernel/head_64.S | 29 +++++++ arch/powerpc/kernel/prom.c | 43 +++++++++++ arch/powerpc/platforms/cell/Kconfig | 4 + arch/powerpc/platforms/cell/Makefile | 3 +- arch/powerpc/platforms/cell/cbe_regs.c | 128 +++++++++++++++++++++++++++++++ arch/powerpc/platforms/cell/cbe_regs.h | 129 ++++++++++++++++++++++++++++++++ arch/powerpc/platforms/cell/interrupt.c | 37 +++------ arch/powerpc/platforms/cell/pervasive.c | 104 ++++++------------------- arch/powerpc/platforms/cell/pervasive.h | 37 +-------- arch/powerpc/platforms/cell/ras.c | 112 +++++++++++++++++++++++++++ arch/powerpc/platforms/cell/ras.h | 9 +++ arch/powerpc/platforms/cell/setup.c | 10 ++- include/asm-powerpc/prom.h | 3 + include/asm-powerpc/reg.h | 2 + 15 files changed, 505 insertions(+), 146 deletions(-) create mode 100644 arch/powerpc/platforms/cell/cbe_regs.c create mode 100644 arch/powerpc/platforms/cell/cbe_regs.h create mode 100644 arch/powerpc/platforms/cell/ras.c create mode 100644 arch/powerpc/platforms/cell/ras.h (limited to 'include') diff --git a/arch/powerpc/configs/cell_defconfig b/arch/powerpc/configs/cell_defconfig index dbe421dc3c11..5b8599d03f16 100644 --- a/arch/powerpc/configs/cell_defconfig +++ b/arch/powerpc/configs/cell_defconfig @@ -133,6 +133,7 @@ CONFIG_CELL_IIC=y # CONFIG_SPU_FS=m CONFIG_SPUFS_MMAP=y +CONFIG_CBE_RAS=y # # Kernel options diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index b7d140430a41..831acbdf2592 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -316,6 +316,21 @@ label##_pSeries: \ mtspr SPRN_SPRG1,r13; /* save r13 */ \ EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common) +#define HSTD_EXCEPTION_PSERIES(n, label) \ + . = n; \ + .globl label##_pSeries; \ +label##_pSeries: \ + HMT_MEDIUM; \ + mtspr SPRN_SPRG1,r20; /* save r20 */ \ + mfspr r20,SPRN_HSRR0; /* copy HSRR0 to SRR0 */ \ + mtspr SPRN_SRR0,r20; \ + mfspr r20,SPRN_HSRR1; /* copy HSRR0 to SRR0 */ \ + mtspr SPRN_SRR1,r20; \ + mfspr r20,SPRN_SPRG1; /* restore r20 */ \ + mtspr SPRN_SPRG1,r13; /* save r13 */ \ + EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common) + + #define STD_EXCEPTION_ISERIES(n, label, area) \ .globl label##_iSeries; \ label##_iSeries: \ @@ -544,8 +559,17 @@ system_call_pSeries: STD_EXCEPTION_PSERIES(0xf20, altivec_unavailable) +#ifdef CONFIG_CBE_RAS + HSTD_EXCEPTION_PSERIES(0x1200, cbe_system_error) +#endif /* CONFIG_CBE_RAS */ STD_EXCEPTION_PSERIES(0x1300, instruction_breakpoint) +#ifdef CONFIG_CBE_RAS + HSTD_EXCEPTION_PSERIES(0x1600, cbe_maintenance) +#endif /* CONFIG_CBE_RAS */ STD_EXCEPTION_PSERIES(0x1700, altivec_assist) +#ifdef CONFIG_CBE_RAS + HSTD_EXCEPTION_PSERIES(0x1800, cbe_thermal) +#endif /* CONFIG_CBE_RAS */ . = 0x3000 @@ -827,6 +851,11 @@ machine_check_common: #else STD_EXCEPTION_COMMON(0x1700, altivec_assist, .unknown_exception) #endif +#ifdef CONFIG_CBE_RAS + STD_EXCEPTION_COMMON(0x1200, cbe_system_error, .cbe_system_error_exception) + STD_EXCEPTION_COMMON(0x1600, cbe_maintenance, .cbe_maintenance_exception) + STD_EXCEPTION_COMMON(0x1800, cbe_thermal, .cbe_thermal_exception) +#endif /* CONFIG_CBE_RAS */ /* * Here we have detected that the kernel stack pointer is bad. diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 629023240ece..483455c5bb02 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -2105,3 +2105,46 @@ int prom_update_property(struct device_node *np, return 0; } + +/* Find the device node for a given logical cpu number, also returns the cpu + * local thread number (index in ibm,interrupt-server#s) if relevant and + * asked for (non NULL) + */ +struct device_node *of_get_cpu_node(int cpu, unsigned int *thread) +{ + int hardid; + struct device_node *np; + + hardid = get_hard_smp_processor_id(cpu); + + for_each_node_by_type(np, "cpu") { + u32 *intserv; + unsigned int plen, t; + + /* Check for ibm,ppc-interrupt-server#s. If it doesn't exist + * fallback to "reg" property and assume no threads + */ + intserv = (u32 *)get_property(np, "ibm,ppc-interrupt-server#s", + &plen); + if (intserv == NULL) { + u32 *reg = (u32 *)get_property(np, "reg", NULL); + if (reg == NULL) + continue; + if (*reg == hardid) { + if (thread) + *thread = 0; + return np; + } + } else { + plen /= sizeof(u32); + for (t = 0; t < plen; t++) { + if (hardid == intserv[t]) { + if (thread) + *thread = t; + return np; + } + } + } + } + return NULL; +} diff --git a/arch/powerpc/platforms/cell/Kconfig b/arch/powerpc/platforms/cell/Kconfig index 6a02d51086c8..00b83db2ce73 100644 --- a/arch/powerpc/platforms/cell/Kconfig +++ b/arch/powerpc/platforms/cell/Kconfig @@ -16,4 +16,8 @@ config SPUFS_MMAP select MEMORY_HOTPLUG default y +config CBE_RAS + bool "RAS features for bare metal Cell BE" + default y + endmenu diff --git a/arch/powerpc/platforms/cell/Makefile b/arch/powerpc/platforms/cell/Makefile index e570bad06394..6b11f6adca08 100644 --- a/arch/powerpc/platforms/cell/Makefile +++ b/arch/powerpc/platforms/cell/Makefile @@ -1,5 +1,6 @@ obj-y += interrupt.o iommu.o setup.o spider-pic.o -obj-y += pervasive.o +obj-y += cbe_regs.o pervasive.o +obj-$(CONFIG_CBE_RAS) += ras.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_SPU_FS) += spu-base.o spufs/ diff --git a/arch/powerpc/platforms/cell/cbe_regs.c b/arch/powerpc/platforms/cell/cbe_regs.c new file mode 100644 index 000000000000..2dfde61c8412 --- /dev/null +++ b/arch/powerpc/platforms/cell/cbe_regs.c @@ -0,0 +1,128 @@ +/* + * cbe_regs.c + * + * Accessor routines for the various MMIO register blocks of the CBE + * + * (c) 2006 Benjamin Herrenschmidt , IBM Corp. + */ + + +#include +#include +#include + +#include +#include +#include +#include + +#include "cbe_regs.h" + +#define MAX_CBE 2 + +/* + * Current implementation uses "cpu" nodes. We build our own mapping + * array of cpu numbers to cpu nodes locally for now to allow interrupt + * time code to have a fast path rather than call of_get_cpu_node(). If + * we implement cpu hotplug, we'll have to install an appropriate norifier + * in order to release references to the cpu going away + */ +static struct cbe_regs_map +{ + struct device_node *cpu_node; + struct cbe_pmd_regs __iomem *pmd_regs; + struct cbe_iic_regs __iomem *iic_regs; +} cbe_regs_maps[MAX_CBE]; +static int cbe_regs_map_count; + +static struct cbe_thread_map +{ + struct device_node *cpu_node; + struct cbe_regs_map *regs; +} cbe_thread_map[NR_CPUS]; + +static struct cbe_regs_map *cbe_find_map(struct device_node *np) +{ + int i; + + for (i = 0; i < cbe_regs_map_count; i++) + if (cbe_regs_maps[i].cpu_node == np) + return &cbe_regs_maps[i]; + return NULL; +} + +struct cbe_pmd_regs __iomem *cbe_get_pmd_regs(struct device_node *np) +{ + struct cbe_regs_map *map = cbe_find_map(np); + if (map == NULL) + return NULL; + return map->pmd_regs; +} + +struct cbe_pmd_regs __iomem *cbe_get_cpu_pmd_regs(int cpu) +{ + struct cbe_regs_map *map = cbe_thread_map[cpu].regs; + if (map == NULL) + return NULL; + return map->pmd_regs; +} + + +struct cbe_iic_regs __iomem *cbe_get_iic_regs(struct device_node *np) +{ + struct cbe_regs_map *map = cbe_find_map(np); + if (map == NULL) + return NULL; + return map->iic_regs; +} +struct cbe_iic_regs __iomem *cbe_get_cpu_iic_regs(int cpu) +{ + struct cbe_regs_map *map = cbe_thread_map[cpu].regs; + if (map == NULL) + return NULL; + return map->iic_regs; +} + +void __init cbe_regs_init(void) +{ + int i; + struct device_node *cpu; + + /* Build local fast map of CPUs */ + for_each_cpu(i) + cbe_thread_map[i].cpu_node = of_get_cpu_node(i, NULL); + + /* Find maps for each device tree CPU */ + for_each_node_by_type(cpu, "cpu") { + struct cbe_regs_map *map = &cbe_regs_maps[cbe_regs_map_count++]; + + /* That hack must die die die ! */ + struct address_prop { + unsigned long address; + unsigned int len; + } __attribute__((packed)) *prop; + + + if (cbe_regs_map_count > MAX_CBE) { + printk(KERN_ERR "cbe_regs: More BE chips than supported" + "!\n"); + cbe_regs_map_count--; + return; + } + map->cpu_node = cpu; + for_each_cpu(i) + if (cbe_thread_map[i].cpu_node == cpu) + cbe_thread_map[i].regs = map; + + prop = (struct address_prop *)get_property(cpu, "pervasive", + NULL); + if (prop != NULL) + map->pmd_regs = ioremap(prop->address, prop->len); + + prop = (struct address_prop *)get_property(cpu, "iic", + NULL); + if (prop != NULL) + map->iic_regs = ioremap(prop->address, prop->len); + } +} + diff --git a/arch/powerpc/platforms/cell/cbe_regs.h b/arch/powerpc/platforms/cell/cbe_regs.h new file mode 100644 index 000000000000..e76e4a6af5bc --- /dev/null +++ b/arch/powerpc/platforms/cell/cbe_regs.h @@ -0,0 +1,129 @@ +/* + * cbe_regs.h + * + * This file is intended to hold the various register definitions for CBE + * on-chip system devices (memory controller, IO controller, etc...) + * + * (c) 2006 Benjamin Herrenschmidt , IBM Corp. + */ + +#ifndef CBE_REGS_H +#define CBE_REGS_H + +/* + * + * Some HID register definitions + * + */ + +/* CBE specific HID0 bits */ +#define HID0_CBE_THERM_WAKEUP 0x0000020000000000ul +#define HID0_CBE_SYSERR_WAKEUP 0x0000008000000000ul +#define HID0_CBE_THERM_INT_EN 0x0000000400000000ul +#define HID0_CBE_SYSERR_INT_EN 0x0000000200000000ul + + +/* + * + * Pervasive unit register definitions + * + */ + +struct cbe_pmd_regs { + u8 pad_0x0000_0x0800[0x0800 - 0x0000]; /* 0x0000 */ + + /* Thermal Sensor Registers */ + u64 ts_ctsr1; /* 0x0800 */ + u64 ts_ctsr2; /* 0x0808 */ + u64 ts_mtsr1; /* 0x0810 */ + u64 ts_mtsr2; /* 0x0818 */ + u64 ts_itr1; /* 0x0820 */ + u64 ts_itr2; /* 0x0828 */ + u64 ts_gitr; /* 0x0830 */ + u64 ts_isr; /* 0x0838 */ + u64 ts_imr; /* 0x0840 */ + u64 tm_cr1; /* 0x0848 */ + u64 tm_cr2; /* 0x0850 */ + u64 tm_simr; /* 0x0858 */ + u64 tm_tpr; /* 0x0860 */ + u64 tm_str1; /* 0x0868 */ + u64 tm_str2; /* 0x0870 */ + u64 tm_tsr; /* 0x0878 */ + + /* Power Management */ + u64 pm_control; /* 0x0880 */ +#define CBE_PMD_PAUSE_ZERO_CONTROL 0x10000 + u64 pm_status; /* 0x0888 */ + + /* Time Base Register */ + u64 tbr; /* 0x0890 */ + + u8 pad_0x0898_0x0c00 [0x0c00 - 0x0898]; /* 0x0898 */ + + /* Fault Isolation Registers */ + u64 checkstop_fir; /* 0x0c00 */ + u64 recoverable_fir; + u64 spec_att_mchk_fir; + u64 fir_mode_reg; + u64 fir_enable_mask; + + u8 pad_0x0c28_0x1000 [0x1000 - 0x0c28]; /* 0x0c28 */ +}; + +extern struct cbe_pmd_regs __iomem *cbe_get_pmd_regs(struct device_node *np); +extern struct cbe_pmd_regs __iomem *cbe_get_cpu_pmd_regs(int cpu); + +/* + * + * IIC unit register definitions + * + */ + +struct cbe_iic_pending_bits { + u32 data; + u8 flags; + u8 class; + u8 source; + u8 prio; +}; + +#define CBE_IIC_IRQ_VALID 0x80 +#define CBE_IIC_IRQ_IPI 0x40 + +struct cbe_iic_thread_regs { + struct cbe_iic_pending_bits pending; + struct cbe_iic_pending_bits pending_destr; + u64 generate; + u64 prio; +}; + +struct cbe_iic_regs { + u8 pad_0x0000_0x0400[0x0400 - 0x0000]; /* 0x0000 */ + + /* IIC interrupt registers */ + struct cbe_iic_thread_regs thread[2]; /* 0x0400 */ + u64 iic_ir; /* 0x0440 */ + u64 iic_is; /* 0x0448 */ + + u8 pad_0x0450_0x0500[0x0500 - 0x0450]; /* 0x0450 */ + + /* IOC FIR */ + u64 ioc_fir_reset; /* 0x0500 */ + u64 ioc_fir_set; + u64 ioc_checkstop_enable; + u64 ioc_fir_error_mask; + u64 ioc_syserr_enable; + u64 ioc_fir; + + u8 pad_0x0530_0x1000[0x1000 - 0x0530]; /* 0x0530 */ +}; + +extern struct cbe_iic_regs __iomem *cbe_get_iic_regs(struct device_node *np); +extern struct cbe_iic_regs __iomem *cbe_get_cpu_iic_regs(int cpu); + + +/* Init this module early */ +extern void cbe_regs_init(void); + + +#endif /* CBE_REGS_H */ diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c index 978be1c30c1b..0a707bcabef6 100644 --- a/arch/powerpc/platforms/cell/interrupt.c +++ b/arch/powerpc/platforms/cell/interrupt.c @@ -33,29 +33,10 @@ #include #include "interrupt.h" - -struct iic_pending_bits { - u32 data; - u8 flags; - u8 class; - u8 source; - u8 prio; -}; - -enum iic_pending_flags { - IIC_VALID = 0x80, - IIC_IPI = 0x40, -}; - -struct iic_regs { - struct iic_pending_bits pending; - struct iic_pending_bits pending_destr; - u64 generate; - u64 prio; -}; +#include "cbe_regs.h" struct iic { - struct iic_regs __iomem *regs; + struct cbe_iic_thread_regs __iomem *regs; u8 target_id; }; @@ -115,7 +96,7 @@ static struct hw_interrupt_type iic_pic = { .end = iic_end, }; -static int iic_external_get_irq(struct iic_pending_bits pending) +static int iic_external_get_irq(struct cbe_iic_pending_bits pending) { int irq; unsigned char node, unit; @@ -168,15 +149,15 @@ int iic_get_irq(struct pt_regs *regs) { struct iic *iic; int irq; - struct iic_pending_bits pending; + struct cbe_iic_pending_bits pending; iic = &__get_cpu_var(iic); *(unsigned long *) &pending = in_be64((unsigned long __iomem *) &iic->regs->pending_destr); irq = -1; - if (pending.flags & IIC_VALID) { - if (pending.flags & IIC_IPI) { + if (pending.flags & CBE_IIC_IRQ_VALID) { + if (pending.flags & CBE_IIC_IRQ_IPI) { irq = IIC_IPI_OFFSET + (pending.prio >> 4); /* if (irq > 0x80) @@ -226,7 +207,7 @@ static int setup_iic_hardcoded(void) regs += 0x20; printk(KERN_INFO "IIC for CPU %d at %lx\n", cpu, regs); - iic->regs = ioremap(regs, sizeof(struct iic_regs)); + iic->regs = ioremap(regs, sizeof(struct cbe_iic_thread_regs)); iic->target_id = (nodeid << 4) + ((cpu & 1) ? 0xf : 0xe); } @@ -267,12 +248,12 @@ static int setup_iic(void) } iic = &per_cpu(iic, np[0]); - iic->regs = ioremap(regs[0], sizeof(struct iic_regs)); + iic->regs = ioremap(regs[0], sizeof(struct cbe_iic_thread_regs)); iic->target_id = ((np[0] & 2) << 3) + ((np[0] & 1) ? 0xf : 0xe); printk("IIC for CPU %d at %lx mapped to %p\n", np[0], regs[0], iic->regs); iic = &per_cpu(iic, np[1]); - iic->regs = ioremap(regs[2], sizeof(struct iic_regs)); + iic->regs = ioremap(regs[2], sizeof(struct cbe_iic_thread_regs)); iic->target_id = ((np[1] & 2) << 3) + ((np[1] & 1) ? 0xf : 0xe); printk("IIC for CPU %d at %lx mapped to %p\n", np[1], regs[2], iic->regs); diff --git a/arch/powerpc/platforms/cell/pervasive.c b/arch/powerpc/platforms/cell/pervasive.c index 7eed8c624517..695ac4e1617e 100644 --- a/arch/powerpc/platforms/cell/pervasive.c +++ b/arch/powerpc/platforms/cell/pervasive.c @@ -37,36 +37,28 @@ #include #include "pervasive.h" +#include "cbe_regs.h" static DEFINE_SPINLOCK(cbe_pervasive_lock); -struct cbe_pervasive { - struct pmd_regs __iomem *regs; - unsigned int thread; -}; - -/* can't use per_cpu from setup_arch */ -static struct cbe_pervasive cbe_pervasive[NR_CPUS]; static void __init cbe_enable_pause_zero(void) { unsigned long thread_switch_control; unsigned long temp_register; - struct cbe_pervasive *p; - int thread; + struct cbe_pmd_regs __iomem *pregs; spin_lock_irq(&cbe_pervasive_lock); - p = &cbe_pervasive[smp_processor_id()]; - - if (!cbe_pervasive->regs) + pregs = cbe_get_cpu_pmd_regs(smp_processor_id()); + if (pregs == NULL) goto out; pr_debug("Power Management: CPU %d\n", smp_processor_id()); /* Enable Pause(0) control bit */ - temp_register = in_be64(&p->regs->pm_control); + temp_register = in_be64(&pregs->pm_control); - out_be64(&p->regs->pm_control, - temp_register|PMD_PAUSE_ZERO_CONTROL); + out_be64(&pregs->pm_control, + temp_register | CBE_PMD_PAUSE_ZERO_CONTROL); /* Enable DEC and EE interrupt request */ thread_switch_control = mfspr(SPRN_TSC_CELL); @@ -75,25 +67,16 @@ static void __init cbe_enable_pause_zero(void) switch ((mfspr(SPRN_CTRLF) & CTRL_CT)) { case CTRL_CT0: thread_switch_control |= TSC_CELL_DEC_ENABLE_0; - thread = 0; break; case CTRL_CT1: thread_switch_control |= TSC_CELL_DEC_ENABLE_1; - thread = 1; break; default: printk(KERN_WARNING "%s: unknown configuration\n", __FUNCTION__); - thread = -1; break; } - if (p->thread != thread) - printk(KERN_WARNING "%s: device tree inconsistant, " - "cpu %i: %d/%d\n", __FUNCTION__, - smp_processor_id(), - p->thread, thread); - mtspr(SPRN_TSC_CELL, thread_switch_control); out: @@ -104,6 +87,11 @@ static void cbe_idle(void) { unsigned long ctrl; + /* Why do we do that on every idle ? Couldn't that be done once for + * all or do we lose the state some way ? Also, the pm_control + * register setting, that can't be set once at boot ? We really want + * to move that away in order to implement a simple powersave + */ cbe_enable_pause_zero(); while (1) { @@ -152,8 +140,15 @@ static int cbe_system_reset_exception(struct pt_regs *regs) timer_interrupt(regs); break; case SRR1_WAKEMT: - /* no action required */ break; +#ifdef CONFIG_CBE_RAS + case SRR1_WAKESYSERR: + cbe_system_error_exception(regs); + break; + case SRR1_WAKETHERM: + cbe_thermal_exception(regs); + break; +#endif /* CONFIG_CBE_RAS */ default: /* do system reset */ return 0; @@ -162,68 +157,11 @@ static int cbe_system_reset_exception(struct pt_regs *regs) return 1; } -static int __init cbe_find_pmd_mmio(int cpu, struct cbe_pervasive *p) -{ - struct device_node *node; - unsigned int *int_servers; - char *addr; - unsigned long real_address; - unsigned int size; - - struct pmd_regs __iomem *pmd_mmio_area; - int hardid, thread; - int proplen; - - pmd_mmio_area = NULL; - hardid = get_hard_smp_processor_id(cpu); - for (node = NULL; (node = of_find_node_by_type(node, "cpu"));) { - int_servers = (void *) get_property(node, - "ibm,ppc-interrupt-server#s", &proplen); - if (!int_servers) { - printk(KERN_WARNING "%s misses " - "ibm,ppc-interrupt-server#s property", - node->full_name); - continue; - } - for (thread = 0; thread < proplen / sizeof (int); thread++) { - if (hardid == int_servers[thread]) { - addr = get_property(node, "pervasive", NULL); - goto found; - } - } - } - - printk(KERN_WARNING "%s: CPU %d not found\n", __FUNCTION__, cpu); - return -EINVAL; - -found: - real_address = *(unsigned long*) addr; - addr += sizeof (unsigned long); - size = *(unsigned int*) addr; - - pr_debug("pervasive area for CPU %d at %lx, size %x\n", - cpu, real_address, size); - p->regs = ioremap(real_address, size); - p->thread = thread; - return 0; -} - -void __init cell_pervasive_init(void) +void __init cbe_pervasive_init(void) { - struct cbe_pervasive *p; - int cpu; - int ret; - if (!cpu_has_feature(CPU_FTR_PAUSE_ZERO)) return; - for_each_possible_cpu(cpu) { - p = &cbe_pervasive[cpu]; - ret = cbe_find_pmd_mmio(cpu, p); - if (ret) - return; - } - ppc_md.idle_loop = cbe_idle; ppc_md.system_reset_exception = cbe_system_reset_exception; } diff --git a/arch/powerpc/platforms/cell/pervasive.h b/arch/powerpc/platforms/cell/pervasive.h index da1fb85ca3e8..7b50947f8044 100644 --- a/arch/powerpc/platforms/cell/pervasive.h +++ b/arch/powerpc/platforms/cell/pervasive.h @@ -25,38 +25,9 @@ #ifndef PERVASIVE_H #define PERVASIVE_H -struct pmd_regs { - u8 pad_0x0000_0x0800[0x0800 - 0x0000]; /* 0x0000 */ - - /* Thermal Sensor Registers */ - u64 ts_ctsr1; /* 0x0800 */ - u64 ts_ctsr2; /* 0x0808 */ - u64 ts_mtsr1; /* 0x0810 */ - u64 ts_mtsr2; /* 0x0818 */ - u64 ts_itr1; /* 0x0820 */ - u64 ts_itr2; /* 0x0828 */ - u64 ts_gitr; /* 0x0830 */ - u64 ts_isr; /* 0x0838 */ - u64 ts_imr; /* 0x0840 */ - u64 tm_cr1; /* 0x0848 */ - u64 tm_cr2; /* 0x0850 */ - u64 tm_simr; /* 0x0858 */ - u64 tm_tpr; /* 0x0860 */ - u64 tm_str1; /* 0x0868 */ - u64 tm_str2; /* 0x0870 */ - u64 tm_tsr; /* 0x0878 */ - - /* Power Management */ - u64 pm_control; /* 0x0880 */ -#define PMD_PAUSE_ZERO_CONTROL 0x10000 - u64 pm_status; /* 0x0888 */ - - /* Time Base Register */ - u64 tbr; /* 0x0890 */ - - u8 pad_0x0898_0x1000 [0x1000 - 0x0898]; /* 0x0898 */ -}; - -void __init cell_pervasive_init(void); +extern void cbe_pervasive_init(void); +extern void cbe_system_error_exception(struct pt_regs *regs); +extern void cbe_maintenance_exception(struct pt_regs *regs); +extern void cbe_thermal_exception(struct pt_regs *regs); #endif diff --git a/arch/powerpc/platforms/cell/ras.c b/arch/powerpc/platforms/cell/ras.c new file mode 100644 index 000000000000..033ad6e2827b --- /dev/null +++ b/arch/powerpc/platforms/cell/ras.c @@ -0,0 +1,112 @@ +#define DEBUG + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "ras.h" +#include "cbe_regs.h" + + +static void dump_fir(int cpu) +{ + struct cbe_pmd_regs __iomem *pregs = cbe_get_cpu_pmd_regs(cpu); + struct cbe_iic_regs __iomem *iregs = cbe_get_cpu_iic_regs(cpu); + + if (pregs == NULL) + return; + + /* Todo: do some nicer parsing of bits and based on them go down + * to other sub-units FIRs and not only IIC + */ + printk(KERN_ERR "Global Checkstop FIR : 0x%016lx\n", + in_be64(&pregs->checkstop_fir)); + printk(KERN_ERR "Global Recoverable FIR : 0x%016lx\n", + in_be64(&pregs->checkstop_fir)); + printk(KERN_ERR "Global MachineCheck FIR : 0x%016lx\n", + in_be64(&pregs->spec_att_mchk_fir)); + + if (iregs == NULL) + return; + printk(KERN_ERR "IOC FIR : 0x%016lx\n", + in_be64(&iregs->ioc_fir)); + +} + +void cbe_system_error_exception(struct pt_regs *regs) +{ + int cpu = smp_processor_id(); + + printk(KERN_ERR "System Error Interrupt on CPU %d !\n", cpu); + dump_fir(cpu); + dump_stack(); +} + +void cbe_maintenance_exception(struct pt_regs *regs) +{ + int cpu = smp_processor_id(); + + /* + * Nothing implemented for the maintenance interrupt at this point + */ + + printk(KERN_ERR "Unhandled Maintenance interrupt on CPU %d !\n", cpu); + dump_stack(); +} + +void cbe_thermal_exception(struct pt_regs *regs) +{ + int cpu = smp_processor_id(); + + /* + * Nothing implemented for the thermal interrupt at this point + */ + + printk(KERN_ERR "Unhandled Thermal interrupt on CPU %d !\n", cpu); + dump_stack(); +} + +static int cbe_machine_check_handler(struct pt_regs *regs) +{ + int cpu = smp_processor_id(); + + printk(KERN_ERR "Machine Check Interrupt on CPU %d !\n", cpu); + dump_fir(cpu); + + /* No recovery from this code now, lets continue */ + return 0; +} + +void __init cbe_ras_init(void) +{ + unsigned long hid0; + + /* + * Enable System Error & thermal interrupts and wakeup conditions + */ + + hid0 = mfspr(SPRN_HID0); + hid0 |= HID0_CBE_THERM_INT_EN | HID0_CBE_THERM_WAKEUP | + HID0_CBE_SYSERR_INT_EN | HID0_CBE_SYSERR_WAKEUP; + mtspr(SPRN_HID0, hid0); + mb(); + + /* + * Install machine check handler. Leave setting of precise mode to + * what the firmware did for now + */ + ppc_md.machine_check_exception = cbe_machine_check_handler; + mb(); + + /* + * For now, we assume that IOC_FIR is already set to forward some + * error conditions to the System Error handler. If that is not true + * then it will have to be fixed up here. + */ +} diff --git a/arch/powerpc/platforms/cell/ras.h b/arch/powerpc/platforms/cell/ras.h new file mode 100644 index 000000000000..eb7ee54c82a0 --- /dev/null +++ b/arch/powerpc/platforms/cell/ras.h @@ -0,0 +1,9 @@ +#ifndef RAS_H +#define RAS_H + +extern void cbe_system_error_exception(struct pt_regs *regs); +extern void cbe_maintenance_exception(struct pt_regs *regs); +extern void cbe_thermal_exception(struct pt_regs *regs); +extern void cbe_ras_init(void); + +#endif /* RAS_H */ diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c index fd3e5609e3e0..eb8ab9bbf744 100644 --- a/arch/powerpc/platforms/cell/setup.c +++ b/arch/powerpc/platforms/cell/setup.c @@ -52,7 +52,9 @@ #include "interrupt.h" #include "iommu.h" +#include "cbe_regs.h" #include "pervasive.h" +#include "ras.h" #ifdef DEBUG #define DBG(fmt...) udbg_printf(fmt) @@ -82,6 +84,12 @@ static void __init cell_setup_arch(void) ppc_md.init_IRQ = iic_init_IRQ; ppc_md.get_irq = iic_get_irq; + cbe_regs_init(); + +#ifdef CONFIG_CBE_RAS + cbe_ras_init(); +#endif + #ifdef CONFIG_SMP smp_init_cell(); #endif @@ -98,7 +106,7 @@ static void __init cell_setup_arch(void) init_pci_config_tokens(); find_and_init_phbs(); spider_init_IRQ(); - cell_pervasive_init(); + cbe_pervasive_init(); #ifdef CONFIG_DUMMY_CONSOLE conswitchp = &dummy_con; #endif diff --git a/include/asm-powerpc/prom.h b/include/asm-powerpc/prom.h index c79d58ab7441..8bdcd5178302 100644 --- a/include/asm-powerpc/prom.h +++ b/include/asm-powerpc/prom.h @@ -238,5 +238,8 @@ void of_parse_dma_window(struct device_node *dn, unsigned char *dma_window_prop, extern void kdump_move_device_tree(void); +/* CPU OF node matching */ +struct device_node *of_get_cpu_node(int cpu, unsigned int *thread); + #endif /* __KERNEL__ */ #endif /* _POWERPC_PROM_H */ diff --git a/include/asm-powerpc/reg.h b/include/asm-powerpc/reg.h index f2ed7577aa35..cf73475a0c69 100644 --- a/include/asm-powerpc/reg.h +++ b/include/asm-powerpc/reg.h @@ -386,6 +386,8 @@ #define SRR1_WAKEMT 0x00280000 /* mtctrl */ #define SRR1_WAKEDEC 0x00180000 /* Decrementer interrupt */ #define SRR1_WAKETHERM 0x00100000 /* Thermal management interrupt */ +#define SPRN_HSRR0 0x13A /* Save/Restore Register 0 */ +#define SPRN_HSRR1 0x13B /* Save/Restore Register 1 */ #ifndef SPRN_SVR #define SPRN_SVR 0x11E /* System Version Register */ -- cgit v1.2.3 From 1d64093f6627a7eef1ed0fe005463f0a5ea25a5f Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Mon, 19 Jun 2006 20:33:19 +0200 Subject: [POWERPC] cell: register SPUs as sysdevs SPUs are registered as system devices, exposing attributes through sysfs. Since the sysdev includes a kref, we can remove the one in struct spu (it isn't used at the moment anyway). Currently only the interrupt source and numa node attributes are added. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spu_base.c | 54 ++++++++++++++++++++++++++++++++++ include/asm-powerpc/spu.h | 5 ++-- 2 files changed, 57 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index ad141fe8d52d..d5877aacc3b6 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c @@ -649,6 +649,46 @@ out: return ret; } +struct sysdev_class spu_sysdev_class = { + set_kset_name("spu") +}; + +static ssize_t spu_show_isrc(struct sys_device *sysdev, char *buf) +{ + struct spu *spu = container_of(sysdev, struct spu, sysdev); + return sprintf(buf, "%d\n", spu->isrc); + +} +static SYSDEV_ATTR(isrc, 0400, spu_show_isrc, NULL); + +extern int attach_sysdev_to_node(struct sys_device *dev, int nid); + +static int spu_create_sysdev(struct spu *spu) +{ + int ret; + + spu->sysdev.id = spu->number; + spu->sysdev.cls = &spu_sysdev_class; + ret = sysdev_register(&spu->sysdev); + if (ret) { + printk(KERN_ERR "Can't register SPU %d with sysfs\n", + spu->number); + return ret; + } + + sysdev_create_file(&spu->sysdev, &attr_isrc); + sysfs_add_device_to_node(&spu->sysdev, spu->nid); + + return 0; +} + +static void spu_destroy_sysdev(struct spu *spu) +{ + sysdev_remove_file(&spu->sysdev, &attr_isrc); + sysfs_remove_device_from_node(&spu->sysdev, spu->nid); + sysdev_unregister(&spu->sysdev); +} + static int __init create_spu(struct device_node *spe) { struct spu *spu; @@ -695,6 +735,10 @@ static int __init create_spu(struct device_node *spe) if (ret) goto out_unmap; + ret = spu_create_sysdev(spu); + if (ret) + goto out_free_irqs; + list_add(&spu->list, &spu_list); mutex_unlock(&spu_mutex); @@ -703,6 +747,9 @@ static int __init create_spu(struct device_node *spe) spu->problem, spu->priv1, spu->priv2, spu->number); goto out; +out_free_irqs: + spu_free_irqs(spu); + out_unmap: mutex_unlock(&spu_mutex); spu_unmap(spu); @@ -716,6 +763,7 @@ static void destroy_spu(struct spu *spu) { list_del_init(&spu->list); + spu_destroy_sysdev(spu); spu_free_irqs(spu); spu_unmap(spu); kfree(spu); @@ -728,6 +776,7 @@ static void cleanup_spu_base(void) list_for_each_entry_safe(spu, tmp, &spu_list, list) destroy_spu(spu); mutex_unlock(&spu_mutex); + sysdev_class_unregister(&spu_sysdev_class); } module_exit(cleanup_spu_base); @@ -736,6 +785,11 @@ static int __init init_spu_base(void) struct device_node *node; int ret; + /* create sysdev class for spus */ + ret = sysdev_class_register(&spu_sysdev_class); + if (ret) + return ret; + ret = -ENODEV; for (node = of_find_node_by_type(NULL, "spe"); node; node = of_find_node_by_type(node, "spe")) { diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h index 7cfcff3ef027..946489929eb2 100644 --- a/include/asm-powerpc/spu.h +++ b/include/asm-powerpc/spu.h @@ -25,8 +25,8 @@ #ifdef __KERNEL__ #include -#include #include +#include #define LS_SIZE (256 * 1024) #define LS_ADDR_MASK (LS_SIZE - 1) @@ -123,7 +123,6 @@ struct spu { u64 flags; u64 dar; u64 dsisr; - struct kref kref; size_t ls_size; unsigned int slb_replace; struct mm_struct *mm; @@ -144,6 +143,8 @@ struct spu { char irq_c0[8]; char irq_c1[8]; char irq_c2[8]; + + struct sys_device sysdev; }; struct spu *spu_alloc(void); -- cgit v1.2.3 From 540270d82db943855538cea5d0c790e7e669dda0 Mon Sep 17 00:00:00 2001 From: Geoff Levand Date: Mon, 19 Jun 2006 20:33:29 +0200 Subject: [POWERPC] spufs: further abstract priv1 register access To support muti-platform binaries the spu hypervisor accessor routines must have runtime binding. I removed the existing statically linked routines in spu.h and spu_priv1_mmio.c and created new accessor routines in spu_priv1.h that operate indirectly through an ops struct spu_priv1_ops. spu_priv1_mmio.c contains the instance of the accessor routines for running on raw hardware. Signed-off-by: Geoff Levand Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/setup.c | 4 + arch/powerpc/platforms/cell/spu_base.c | 5 + arch/powerpc/platforms/cell/spu_priv1_mmio.c | 104 +++++++++------ arch/powerpc/platforms/cell/spufs/hw_ops.c | 1 + arch/powerpc/platforms/cell/spufs/switch.c | 1 + include/asm-powerpc/spu.h | 23 ---- include/asm-powerpc/spu_priv1.h | 182 +++++++++++++++++++++++++++ 7 files changed, 256 insertions(+), 64 deletions(-) create mode 100644 include/asm-powerpc/spu_priv1.h (limited to 'include') diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c index eb8ab9bbf744..3d1831d331e5 100644 --- a/arch/powerpc/platforms/cell/setup.c +++ b/arch/powerpc/platforms/cell/setup.c @@ -49,6 +49,7 @@ #include #include #include +#include #include "interrupt.h" #include "iommu.h" @@ -83,6 +84,9 @@ static void __init cell_setup_arch(void) { ppc_md.init_IRQ = iic_init_IRQ; ppc_md.get_irq = iic_get_irq; +#ifdef CONFIG_SPU_BASE + spu_priv1_ops = &spu_priv1_mmio_ops; +#endif cbe_regs_init(); diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index eb367dd89a7d..c3bb7299c4b5 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c @@ -34,10 +34,15 @@ #include #include #include +#include #include #include "interrupt.h" +const struct spu_priv1_ops *spu_priv1_ops; + +EXPORT_SYMBOL_GPL(spu_priv1_ops); + static int __spu_trap_invalid_dma(struct spu *spu) { pr_debug("%s\n", __FUNCTION__); diff --git a/arch/powerpc/platforms/cell/spu_priv1_mmio.c b/arch/powerpc/platforms/cell/spu_priv1_mmio.c index b2656421c7b5..abe8a84925d2 100644 --- a/arch/powerpc/platforms/cell/spu_priv1_mmio.c +++ b/arch/powerpc/platforms/cell/spu_priv1_mmio.c @@ -1,133 +1,155 @@ /* - * access to SPU privileged registers + * spu hypervisor abstraction for direct hardware access. + * + * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 + * Copyright 2006 Sony Corp. + * + * 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; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + #include #include #include +#include -void spu_int_mask_and(struct spu *spu, int class, u64 mask) +static void int_mask_and(struct spu *spu, int class, u64 mask) { u64 old_mask; old_mask = in_be64(&spu->priv1->int_mask_RW[class]); out_be64(&spu->priv1->int_mask_RW[class], old_mask & mask); } -EXPORT_SYMBOL_GPL(spu_int_mask_and); -void spu_int_mask_or(struct spu *spu, int class, u64 mask) +static void int_mask_or(struct spu *spu, int class, u64 mask) { u64 old_mask; old_mask = in_be64(&spu->priv1->int_mask_RW[class]); out_be64(&spu->priv1->int_mask_RW[class], old_mask | mask); } -EXPORT_SYMBOL_GPL(spu_int_mask_or); -void spu_int_mask_set(struct spu *spu, int class, u64 mask) +static void int_mask_set(struct spu *spu, int class, u64 mask) { out_be64(&spu->priv1->int_mask_RW[class], mask); } -EXPORT_SYMBOL_GPL(spu_int_mask_set); -u64 spu_int_mask_get(struct spu *spu, int class) +static u64 int_mask_get(struct spu *spu, int class) { return in_be64(&spu->priv1->int_mask_RW[class]); } -EXPORT_SYMBOL_GPL(spu_int_mask_get); -void spu_int_stat_clear(struct spu *spu, int class, u64 stat) +static void int_stat_clear(struct spu *spu, int class, u64 stat) { out_be64(&spu->priv1->int_stat_RW[class], stat); } -EXPORT_SYMBOL_GPL(spu_int_stat_clear); -u64 spu_int_stat_get(struct spu *spu, int class) +static u64 int_stat_get(struct spu *spu, int class) { return in_be64(&spu->priv1->int_stat_RW[class]); } -EXPORT_SYMBOL_GPL(spu_int_stat_get); -void spu_int_route_set(struct spu *spu, u64 route) +static void int_route_set(struct spu *spu, u64 route) { out_be64(&spu->priv1->int_route_RW, route); } -EXPORT_SYMBOL_GPL(spu_int_route_set); -u64 spu_mfc_dar_get(struct spu *spu) +static u64 mfc_dar_get(struct spu *spu) { return in_be64(&spu->priv1->mfc_dar_RW); } -EXPORT_SYMBOL_GPL(spu_mfc_dar_get); -u64 spu_mfc_dsisr_get(struct spu *spu) +static u64 mfc_dsisr_get(struct spu *spu) { return in_be64(&spu->priv1->mfc_dsisr_RW); } -EXPORT_SYMBOL_GPL(spu_mfc_dsisr_get); -void spu_mfc_dsisr_set(struct spu *spu, u64 dsisr) +static void mfc_dsisr_set(struct spu *spu, u64 dsisr) { out_be64(&spu->priv1->mfc_dsisr_RW, dsisr); } -EXPORT_SYMBOL_GPL(spu_mfc_dsisr_set); -void spu_mfc_sdr_set(struct spu *spu, u64 sdr) +static void mfc_sdr_set(struct spu *spu, u64 sdr) { out_be64(&spu->priv1->mfc_sdr_RW, sdr); } -EXPORT_SYMBOL_GPL(spu_mfc_sdr_set); -void spu_mfc_sr1_set(struct spu *spu, u64 sr1) +static void mfc_sr1_set(struct spu *spu, u64 sr1) { out_be64(&spu->priv1->mfc_sr1_RW, sr1); } -EXPORT_SYMBOL_GPL(spu_mfc_sr1_set); -u64 spu_mfc_sr1_get(struct spu *spu) +static u64 mfc_sr1_get(struct spu *spu) { return in_be64(&spu->priv1->mfc_sr1_RW); } -EXPORT_SYMBOL_GPL(spu_mfc_sr1_get); -void spu_mfc_tclass_id_set(struct spu *spu, u64 tclass_id) +static void mfc_tclass_id_set(struct spu *spu, u64 tclass_id) { out_be64(&spu->priv1->mfc_tclass_id_RW, tclass_id); } -EXPORT_SYMBOL_GPL(spu_mfc_tclass_id_set); -u64 spu_mfc_tclass_id_get(struct spu *spu) +static u64 mfc_tclass_id_get(struct spu *spu) { return in_be64(&spu->priv1->mfc_tclass_id_RW); } -EXPORT_SYMBOL_GPL(spu_mfc_tclass_id_get); -void spu_tlb_invalidate(struct spu *spu) +static void tlb_invalidate(struct spu *spu) { out_be64(&spu->priv1->tlb_invalidate_entry_W, 0ul); } -EXPORT_SYMBOL_GPL(spu_tlb_invalidate); -void spu_resource_allocation_groupID_set(struct spu *spu, u64 id) +static void resource_allocation_groupID_set(struct spu *spu, u64 id) { out_be64(&spu->priv1->resource_allocation_groupID_RW, id); } -EXPORT_SYMBOL_GPL(spu_resource_allocation_groupID_set); -u64 spu_resource_allocation_groupID_get(struct spu *spu) +static u64 resource_allocation_groupID_get(struct spu *spu) { return in_be64(&spu->priv1->resource_allocation_groupID_RW); } -EXPORT_SYMBOL_GPL(spu_resource_allocation_groupID_get); -void spu_resource_allocation_enable_set(struct spu *spu, u64 enable) +static void resource_allocation_enable_set(struct spu *spu, u64 enable) { out_be64(&spu->priv1->resource_allocation_enable_RW, enable); } -EXPORT_SYMBOL_GPL(spu_resource_allocation_enable_set); -u64 spu_resource_allocation_enable_get(struct spu *spu) +static u64 resource_allocation_enable_get(struct spu *spu) { return in_be64(&spu->priv1->resource_allocation_enable_RW); } -EXPORT_SYMBOL_GPL(spu_resource_allocation_enable_get); + +const struct spu_priv1_ops spu_priv1_mmio_ops = +{ + .int_mask_and = int_mask_and, + .int_mask_or = int_mask_or, + .int_mask_set = int_mask_set, + .int_mask_get = int_mask_get, + .int_stat_clear = int_stat_clear, + .int_stat_get = int_stat_get, + .int_route_set = int_route_set, + .mfc_dar_get = mfc_dar_get, + .mfc_dsisr_get = mfc_dsisr_get, + .mfc_dsisr_set = mfc_dsisr_set, + .mfc_sdr_set = mfc_sdr_set, + .mfc_sr1_set = mfc_sr1_set, + .mfc_sr1_get = mfc_sr1_get, + .mfc_tclass_id_set = mfc_tclass_id_set, + .mfc_tclass_id_get = mfc_tclass_id_get, + .tlb_invalidate = tlb_invalidate, + .resource_allocation_groupID_set = resource_allocation_groupID_set, + .resource_allocation_groupID_get = resource_allocation_groupID_get, + .resource_allocation_enable_set = resource_allocation_enable_set, + .resource_allocation_enable_get = resource_allocation_enable_get, +}; diff --git a/arch/powerpc/platforms/cell/spufs/hw_ops.c b/arch/powerpc/platforms/cell/spufs/hw_ops.c index a13a8b5a014d..ede2cac46b6d 100644 --- a/arch/powerpc/platforms/cell/spufs/hw_ops.c +++ b/arch/powerpc/platforms/cell/spufs/hw_ops.c @@ -32,6 +32,7 @@ #include #include +#include #include #include #include "spufs.h" diff --git a/arch/powerpc/platforms/cell/spufs/switch.c b/arch/powerpc/platforms/cell/spufs/switch.c index 85bea06e798b..2dae062a9aec 100644 --- a/arch/powerpc/platforms/cell/spufs/switch.c +++ b/arch/powerpc/platforms/cell/spufs/switch.c @@ -46,6 +46,7 @@ #include #include +#include #include #include diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h index 946489929eb2..c7812e92f683 100644 --- a/include/asm-powerpc/spu.h +++ b/include/asm-powerpc/spu.h @@ -183,29 +183,6 @@ static inline void unregister_spu_syscalls(struct spufs_calls *calls) #endif /* MODULE */ -/* access to priv1 registers */ -void spu_int_mask_and(struct spu *spu, int class, u64 mask); -void spu_int_mask_or(struct spu *spu, int class, u64 mask); -void spu_int_mask_set(struct spu *spu, int class, u64 mask); -u64 spu_int_mask_get(struct spu *spu, int class); -void spu_int_stat_clear(struct spu *spu, int class, u64 stat); -u64 spu_int_stat_get(struct spu *spu, int class); -void spu_int_route_set(struct spu *spu, u64 route); -u64 spu_mfc_dar_get(struct spu *spu); -u64 spu_mfc_dsisr_get(struct spu *spu); -void spu_mfc_dsisr_set(struct spu *spu, u64 dsisr); -void spu_mfc_sdr_set(struct spu *spu, u64 sdr); -void spu_mfc_sr1_set(struct spu *spu, u64 sr1); -u64 spu_mfc_sr1_get(struct spu *spu); -void spu_mfc_tclass_id_set(struct spu *spu, u64 tclass_id); -u64 spu_mfc_tclass_id_get(struct spu *spu); -void spu_tlb_invalidate(struct spu *spu); -void spu_resource_allocation_groupID_set(struct spu *spu, u64 id); -u64 spu_resource_allocation_groupID_get(struct spu *spu); -void spu_resource_allocation_enable_set(struct spu *spu, u64 enable); -u64 spu_resource_allocation_enable_get(struct spu *spu); - - /* * This defines the Local Store, Problem Area and Privlege Area of an SPU. */ diff --git a/include/asm-powerpc/spu_priv1.h b/include/asm-powerpc/spu_priv1.h new file mode 100644 index 000000000000..cb87d1f7e9bc --- /dev/null +++ b/include/asm-powerpc/spu_priv1.h @@ -0,0 +1,182 @@ +/* + * Defines an spu hypervisor abstraction layer. + * + * Copyright 2006 Sony Corp. + * + * 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; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if !defined(_SPU_PRIV1_H) +#define _SPU_PRIV1_H +#if defined(__KERNEL__) + +struct spu; + +/* access to priv1 registers */ + +struct spu_priv1_ops +{ + void (*int_mask_and) (struct spu *spu, int class, u64 mask); + void (*int_mask_or) (struct spu *spu, int class, u64 mask); + void (*int_mask_set) (struct spu *spu, int class, u64 mask); + u64 (*int_mask_get) (struct spu *spu, int class); + void (*int_stat_clear) (struct spu *spu, int class, u64 stat); + u64 (*int_stat_get) (struct spu *spu, int class); + void (*int_route_set) (struct spu *spu, u64 route); + u64 (*mfc_dar_get) (struct spu *spu); + u64 (*mfc_dsisr_get) (struct spu *spu); + void (*mfc_dsisr_set) (struct spu *spu, u64 dsisr); + void (*mfc_sdr_set) (struct spu *spu, u64 sdr); + void (*mfc_sr1_set) (struct spu *spu, u64 sr1); + u64 (*mfc_sr1_get) (struct spu *spu); + void (*mfc_tclass_id_set) (struct spu *spu, u64 tclass_id); + u64 (*mfc_tclass_id_get) (struct spu *spu); + void (*tlb_invalidate) (struct spu *spu); + void (*resource_allocation_groupID_set) (struct spu *spu, u64 id); + u64 (*resource_allocation_groupID_get) (struct spu *spu); + void (*resource_allocation_enable_set) (struct spu *spu, u64 enable); + u64 (*resource_allocation_enable_get) (struct spu *spu); +}; + +extern const struct spu_priv1_ops* spu_priv1_ops; + +static inline void +spu_int_mask_and (struct spu *spu, int class, u64 mask) +{ + spu_priv1_ops->int_mask_and(spu, class, mask); +} + +static inline void +spu_int_mask_or (struct spu *spu, int class, u64 mask) +{ + spu_priv1_ops->int_mask_or(spu, class, mask); +} + +static inline void +spu_int_mask_set (struct spu *spu, int class, u64 mask) +{ + spu_priv1_ops->int_mask_set(spu, class, mask); +} + +static inline u64 +spu_int_mask_get (struct spu *spu, int class) +{ + return spu_priv1_ops->int_mask_get(spu, class); +} + +static inline void +spu_int_stat_clear (struct spu *spu, int class, u64 stat) +{ + spu_priv1_ops->int_stat_clear(spu, class, stat); +} + +static inline u64 +spu_int_stat_get (struct spu *spu, int class) +{ + return spu_priv1_ops->int_stat_get (spu, class); +} + +static inline void +spu_int_route_set (struct spu *spu, u64 route) +{ + spu_priv1_ops->int_stat_get(spu, route); +} + +static inline u64 +spu_mfc_dar_get (struct spu *spu) +{ + return spu_priv1_ops->mfc_dar_get(spu); +} + +static inline u64 +spu_mfc_dsisr_get (struct spu *spu) +{ + return spu_priv1_ops->mfc_dsisr_get(spu); +} + +static inline void +spu_mfc_dsisr_set (struct spu *spu, u64 dsisr) +{ + spu_priv1_ops->mfc_dsisr_set(spu, dsisr); +} + +static inline void +spu_mfc_sdr_set (struct spu *spu, u64 sdr) +{ + spu_priv1_ops->mfc_sdr_set(spu, sdr); +} + +static inline void +spu_mfc_sr1_set (struct spu *spu, u64 sr1) +{ + spu_priv1_ops->mfc_sr1_set(spu, sr1); +} + +static inline u64 +spu_mfc_sr1_get (struct spu *spu) +{ + return spu_priv1_ops->mfc_sr1_get(spu); +} + +static inline void +spu_mfc_tclass_id_set (struct spu *spu, u64 tclass_id) +{ + spu_priv1_ops->mfc_tclass_id_set(spu, tclass_id); +} + +static inline u64 +spu_mfc_tclass_id_get (struct spu *spu) +{ + return spu_priv1_ops->mfc_tclass_id_get(spu); +} + +static inline void +spu_tlb_invalidate (struct spu *spu) +{ + spu_priv1_ops->tlb_invalidate(spu); +} + +static inline void +spu_resource_allocation_groupID_set (struct spu *spu, u64 id) +{ + spu_priv1_ops->resource_allocation_groupID_set(spu, id); +} + +static inline u64 +spu_resource_allocation_groupID_get (struct spu *spu) +{ + return spu_priv1_ops->resource_allocation_groupID_get(spu); +} + +static inline void +spu_resource_allocation_enable_set (struct spu *spu, u64 enable) +{ + spu_priv1_ops->resource_allocation_enable_set(spu, enable); +} + +static inline u64 +spu_resource_allocation_enable_get (struct spu *spu) +{ + return spu_priv1_ops->resource_allocation_enable_get(spu); +} + +/* The declarations folowing are put here for convenience + * and only intended to be used by the platform setup code + * for initializing spu_priv1_ops. + */ + +extern const struct spu_priv1_ops spu_priv1_mmio_ops; + +#endif /* __KERNEL__ */ +#endif -- cgit v1.2.3 From a91942ae7ebd518006dcbeb2a1d7b147253c080e Mon Sep 17 00:00:00 2001 From: Geoff Levand Date: Mon, 19 Jun 2006 20:33:30 +0200 Subject: [POWERPC] spufs: fix spu irq affinity setting This changes the hypervisor abstraction of setting cpu affinity to a higher level to avoid platform dependent interrupt controller routines. I replaced spu_priv1_ops:spu_int_route_set() with a new routine spu_priv1_ops:spu_cpu_affinity_set(). As a by-product, this change eliminated what looked like an existing bug in the set affinity code where spu_int_route_set() mistakenly called int_stat_get(). Signed-off-by: Geoff Levand Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spu_base.c | 8 -------- arch/powerpc/platforms/cell/spu_priv1_mmio.c | 8 ++++++-- arch/powerpc/platforms/cell/spufs/sched.c | 3 ++- include/asm-powerpc/spu_priv1.h | 6 +++--- 4 files changed, 11 insertions(+), 14 deletions(-) (limited to 'include') diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index c3bb7299c4b5..8ca22394e4d3 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c @@ -522,14 +522,6 @@ int spu_irq_class_1_bottom(struct spu *spu) return ret; } -void spu_irq_setaffinity(struct spu *spu, int cpu) -{ - u64 target = iic_get_target_id(cpu); - u64 route = target << 48 | target << 32 | target << 16; - spu_int_route_set(spu, route); -} -EXPORT_SYMBOL_GPL(spu_irq_setaffinity); - static int __init find_spu_node_id(struct device_node *spe) { unsigned int *id; diff --git a/arch/powerpc/platforms/cell/spu_priv1_mmio.c b/arch/powerpc/platforms/cell/spu_priv1_mmio.c index abe8a84925d2..71b69f0a1a48 100644 --- a/arch/powerpc/platforms/cell/spu_priv1_mmio.c +++ b/arch/powerpc/platforms/cell/spu_priv1_mmio.c @@ -24,6 +24,8 @@ #include #include +#include "interrupt.h" + static void int_mask_and(struct spu *spu, int class, u64 mask) { u64 old_mask; @@ -60,8 +62,10 @@ static u64 int_stat_get(struct spu *spu, int class) return in_be64(&spu->priv1->int_stat_RW[class]); } -static void int_route_set(struct spu *spu, u64 route) +static void cpu_affinity_set(struct spu *spu, int cpu) { + u64 target = iic_get_target_id(cpu); + u64 route = target << 48 | target << 32 | target << 16; out_be64(&spu->priv1->int_route_RW, route); } @@ -138,7 +142,7 @@ const struct spu_priv1_ops spu_priv1_mmio_ops = .int_mask_get = int_mask_get, .int_stat_clear = int_stat_clear, .int_stat_get = int_stat_get, - .int_route_set = int_route_set, + .cpu_affinity_set = cpu_affinity_set, .mfc_dar_get = mfc_dar_get, .mfc_dsisr_get = mfc_dsisr_get, .mfc_dsisr_set = mfc_dsisr_set, diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index bf652cd77000..3dcc5d8d66b9 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c @@ -43,6 +43,7 @@ #include #include #include +#include #include "spufs.h" #define SPU_MIN_TIMESLICE (100 * HZ / 1000) @@ -363,7 +364,7 @@ int spu_activate(struct spu_context *ctx, u64 flags) * We're likely to wait for interrupts on the same * CPU that we are now on, so send them here. */ - spu_irq_setaffinity(spu, raw_smp_processor_id()); + spu_cpu_affinity_set(spu, raw_smp_processor_id()); put_active_spu(spu); return 0; } diff --git a/include/asm-powerpc/spu_priv1.h b/include/asm-powerpc/spu_priv1.h index cb87d1f7e9bc..300c458b6d06 100644 --- a/include/asm-powerpc/spu_priv1.h +++ b/include/asm-powerpc/spu_priv1.h @@ -33,7 +33,7 @@ struct spu_priv1_ops u64 (*int_mask_get) (struct spu *spu, int class); void (*int_stat_clear) (struct spu *spu, int class, u64 stat); u64 (*int_stat_get) (struct spu *spu, int class); - void (*int_route_set) (struct spu *spu, u64 route); + void (*cpu_affinity_set) (struct spu *spu, int cpu); u64 (*mfc_dar_get) (struct spu *spu); u64 (*mfc_dsisr_get) (struct spu *spu); void (*mfc_dsisr_set) (struct spu *spu, u64 dsisr); @@ -88,9 +88,9 @@ spu_int_stat_get (struct spu *spu, int class) } static inline void -spu_int_route_set (struct spu *spu, u64 route) +spu_cpu_affinity_set (struct spu *spu, int cpu) { - spu_priv1_ops->int_stat_get(spu, route); + spu_priv1_ops->cpu_affinity_set(spu, cpu); } static inline u64 -- cgit v1.2.3 From 2eabbbd33ec39f690005aa186c57476598edc6b3 Mon Sep 17 00:00:00 2001 From: Masato Noguchi Date: Mon, 19 Jun 2006 20:33:31 +0200 Subject: [POWERPC] spufs: remove stop_code from struct spu This patch remove 'stop_code' -- discarded member of struct spu. It is written at initialize and interrupt, but never read in current implementation. Signed-off-by: Masato Noguchi Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spu_base.c | 2 -- arch/powerpc/platforms/cell/spufs/switch.c | 1 - include/asm-powerpc/spu.h | 1 - 3 files changed, 4 deletions(-) (limited to 'include') diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index 8ca22394e4d3..249a0af4cc99 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c @@ -160,7 +160,6 @@ static int __spu_trap_mailbox(struct spu *spu) static int __spu_trap_stop(struct spu *spu) { pr_debug("%s\n", __FUNCTION__); - spu->stop_code = in_be32(&spu->problem->spu_status_R); if (spu->stop_callback) spu->stop_callback(spu); return 0; @@ -169,7 +168,6 @@ static int __spu_trap_stop(struct spu *spu) static int __spu_trap_halt(struct spu *spu) { pr_debug("%s\n", __FUNCTION__); - spu->stop_code = in_be32(&spu->problem->spu_status_R); if (spu->stop_callback) spu->stop_callback(spu); return 0; diff --git a/arch/powerpc/platforms/cell/spufs/switch.c b/arch/powerpc/platforms/cell/spufs/switch.c index 2dae062a9aec..b30e55dab832 100644 --- a/arch/powerpc/platforms/cell/spufs/switch.c +++ b/arch/powerpc/platforms/cell/spufs/switch.c @@ -2109,7 +2109,6 @@ int spu_restore(struct spu_state *new, struct spu *spu) acquire_spu_lock(spu); harvest(NULL, spu); - spu->stop_code = 0; spu->dar = 0; spu->dsisr = 0; spu->slb_replace = 0; diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h index c7812e92f683..c0290f9d20bd 100644 --- a/include/asm-powerpc/spu.h +++ b/include/asm-powerpc/spu.h @@ -134,7 +134,6 @@ struct spu { int class_0_pending; spinlock_t register_lock; - u32 stop_code; void (* wbox_callback)(struct spu *spu); void (* ibox_callback)(struct spu *spu); void (* stop_callback)(struct spu *spu); -- cgit v1.2.3 From 379507181a1e330d4f5b0fabe61cd43eccf09763 Mon Sep 17 00:00:00 2001 From: "arnd@arndb.de" Date: Mon, 19 Jun 2006 20:33:35 +0200 Subject: [POWERPC] spufs: one more fix for 64k pages The SPU context save/restore code is currently built for a 4k page size and we provide a _shipped version of it since most people don't have the spu toolchain that is needed to rebuild that code. This patch hardcodes the data structures to a 64k page alignment, which also guarantees 4k alignment but unfortunately wastes 60k of memory per SPU context that is created in the running system. We will follow up on this with another patch to reduce that overhead or maybe redo the context save/restore logic to do this part entirely different, but for now it should make experimental systems work with either page size. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/Makefile | 9 +- .../cell/spufs/spu_restore_dump.h_shipped | 1122 ++++++++++++++++---- .../platforms/cell/spufs/spu_save_dump.h_shipped | 922 ++++++++++++---- include/asm-powerpc/spu_csa.h | 13 +- 4 files changed, 1651 insertions(+), 415 deletions(-) (limited to 'include') diff --git a/arch/powerpc/platforms/cell/spufs/Makefile b/arch/powerpc/platforms/cell/spufs/Makefile index e3c4482be3be..bb5dc634272c 100644 --- a/arch/powerpc/platforms/cell/spufs/Makefile +++ b/arch/powerpc/platforms/cell/spufs/Makefile @@ -10,8 +10,10 @@ SPU_CC := $(SPU_CROSS)gcc SPU_AS := $(SPU_CROSS)gcc SPU_LD := $(SPU_CROSS)ld SPU_OBJCOPY := $(SPU_CROSS)objcopy -SPU_CFLAGS := -O2 -Wall -I$(srctree)/include -I$(objtree)/include2 -SPU_AFLAGS := -c -D__ASSEMBLY__ -I$(srctree)/include -I$(objtree)/include2 +SPU_CFLAGS := -O2 -Wall -I$(srctree)/include \ + -I$(objtree)/include2 -D__KERNEL__ +SPU_AFLAGS := -c -D__ASSEMBLY__ -I$(srctree)/include \ + -I$(objtree)/include2 -D__KERNEL__ SPU_LDFLAGS := -N -Ttext=0x0 $(obj)/switch.o: $(obj)/spu_save_dump.h $(obj)/spu_restore_dump.h @@ -48,7 +50,8 @@ cmd_hexdump = ( \ echo " * Hex-dump auto generated from $*.c." ; \ echo " * Do not edit!" ; \ echo " */" ; \ - echo "static unsigned int $*_code[] __page_aligned = {" ; \ + echo "static unsigned int $*_code[] " \ + "__attribute__((__aligned__(128))) = {" ; \ hexdump -v -e '"0x" 4/1 "%02x" "," "\n"' $< ; \ echo "};" ; \ ) > $@ diff --git a/arch/powerpc/platforms/cell/spufs/spu_restore_dump.h_shipped b/arch/powerpc/platforms/cell/spufs/spu_restore_dump.h_shipped index 1b2355ff7036..15183d209b58 100644 --- a/arch/powerpc/platforms/cell/spufs/spu_restore_dump.h_shipped +++ b/arch/powerpc/platforms/cell/spufs/spu_restore_dump.h_shipped @@ -3,229 +3,901 @@ * Hex-dump auto generated from spu_restore.c. * Do not edit! */ -static unsigned int spu_restore_code[] __page_aligned = { -0x40800000, 0x409ff801, 0x24000080, 0x24fd8081, -0x1cd80081, 0x33001180, 0x42030003, 0x33800284, -0x1c010204, 0x40200000, 0x40200000, 0x40200000, -0x34000190, 0x34004191, 0x34008192, 0x3400c193, -0x141fc205, 0x23fffd84, 0x1c100183, 0x217ffa85, -0x3080a000, 0x3080a201, 0x3080a402, 0x3080a603, -0x3080a804, 0x3080aa05, 0x3080ac06, 0x3080ae07, -0x3080b008, 0x3080b209, 0x3080b40a, 0x3080b60b, -0x3080b80c, 0x3080ba0d, 0x3080bc0e, 0x3080be0f, -0x00003ffc, 0x00000000, 0x00000000, 0x00000000, -0x01a00182, 0x3ec00083, 0xb0a14103, 0x01a00204, -0x3ec10082, 0x4202800e, 0x04000703, 0xb0a14202, -0x21a00803, 0x3fbf028d, 0x3f20068d, 0x3fbe0682, -0x3fe30102, 0x21a00882, 0x3f82028f, 0x3fe3078f, -0x3fbf0784, 0x3f200204, 0x3fbe0204, 0x3fe30204, -0x04000203, 0x21a00903, 0x40848002, 0x21a00982, -0x40800003, 0x21a00a03, 0x40802002, 0x21a00a82, -0x21a00083, 0x40800082, 0x21a00b02, 0x10002818, -0x40a80002, 0x32800007, 0x4207000c, 0x18008208, -0x40a0000b, 0x4080020a, 0x40800709, 0x00200000, -0x42070002, 0x3ac30384, 0x1cffc489, 0x00200000, -0x18008383, 0x38830382, 0x4cffc486, 0x3ac28185, -0xb0408584, 0x28830382, 0x1c020387, 0x38828182, -0xb0408405, 0x1802c408, 0x28828182, 0x217ff886, -0x04000583, 0x21a00803, 0x3fbe0682, 0x3fe30102, -0x04000106, 0x21a00886, 0x04000603, 0x21a00903, -0x40803c02, 0x21a00982, 0x40800003, 0x04000184, -0x21a00a04, 0x40802202, 0x21a00a82, 0x42028005, -0x34208702, 0x21002282, 0x21a00804, 0x21a00886, -0x3fbf0782, 0x3f200102, 0x3fbe0102, 0x3fe30102, -0x21a00902, 0x40804003, 0x21a00983, 0x21a00a04, -0x40805a02, 0x21a00a82, 0x40800083, 0x21a00b83, -0x01a00c02, 0x01a00d83, 0x3420c282, 0x21a00e02, -0x34210283, 0x21a00f03, 0x34200284, 0x77400200, -0x3421c282, 0x21a00702, 0x34218283, 0x21a00083, -0x34214282, 0x21a00b02, 0x4200480c, 0x00200000, -0x1c010286, 0x34220284, 0x34220302, 0x0f608203, -0x5c024204, 0x3b81810b, 0x42013c02, 0x00200000, -0x18008185, 0x38808183, 0x3b814182, 0x21004e84, -0x4020007f, 0x35000100, 0x000004e0, 0x000002a0, -0x000002e8, 0x00000428, 0x00000360, 0x000002e8, -0x000004a0, 0x00000468, 0x000003c8, 0x00000360, -0x409ffe02, 0x30801203, 0x40800204, 0x3ec40085, -0x10009c09, 0x3ac10606, 0xb060c105, 0x4020007f, -0x4020007f, 0x20801203, 0x38810602, 0xb0408586, -0x28810602, 0x32004180, 0x34204702, 0x21a00382, -0x4020007f, 0x327fdc80, 0x409ffe02, 0x30801203, -0x40800204, 0x3ec40087, 0x40800405, 0x00200000, -0x40800606, 0x3ac10608, 0x3ac14609, 0x3ac1860a, -0xb060c107, 0x20801203, 0x41004003, 0x38810602, -0x4020007f, 0xb0408188, 0x4020007f, 0x28810602, -0x41201002, 0x38814603, 0x10009c09, 0xb060c109, -0x4020007f, 0x28814603, 0x41193f83, 0x38818602, -0x60ffc003, 0xb040818a, 0x28818602, 0x32003080, -0x409ffe02, 0x30801203, 0x40800204, 0x3ec40087, -0x41201008, 0x10009c14, 0x40800405, 0x3ac10609, -0x40800606, 0x3ac1460a, 0xb060c107, 0x3ac1860b, -0x20801203, 0x38810602, 0xb0408409, 0x28810602, -0x38814603, 0xb060c40a, 0x4020007f, 0x28814603, -0x41193f83, 0x38818602, 0x60ffc003, 0xb040818b, -0x28818602, 0x32002380, 0x409ffe02, 0x30801204, -0x40800205, 0x3ec40083, 0x40800406, 0x3ac14607, -0x3ac18608, 0xb0810103, 0x41004002, 0x20801204, -0x4020007f, 0x38814603, 0x10009c0b, 0xb060c107, -0x4020007f, 0x4020007f, 0x28814603, 0x38818602, -0x4020007f, 0x4020007f, 0xb0408588, 0x28818602, -0x4020007f, 0x32001780, 0x409ffe02, 0x1000640e, -0x40800204, 0x30801203, 0x40800405, 0x3ec40087, -0x40800606, 0x3ac10608, 0x3ac14609, 0x3ac1860a, -0xb060c107, 0x20801203, 0x413d8003, 0x38810602, -0x4020007f, 0x327fd780, 0x409ffe02, 0x10007f0c, -0x40800205, 0x30801204, 0x40800406, 0x3ec40083, -0x3ac14607, 0x3ac18608, 0xb0810103, 0x413d8002, -0x20801204, 0x38814603, 0x4020007f, 0x327feb80, -0x409ffe02, 0x30801203, 0x40800204, 0x3ec40087, -0x40800405, 0x1000650a, 0x40800606, 0x3ac10608, -0x3ac14609, 0x3ac1860a, 0xb060c107, 0x20801203, -0x38810602, 0xb0408588, 0x4020007f, 0x327fc980, -0x00400000, 0x40800003, 0x4020007f, 0x35000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, +static unsigned int spu_restore_code[] __attribute__((__aligned__(128))) = { +0x40800000, +0x409ff801, +0x24000080, +0x24fd8081, +0x1cd80081, +0x33001180, +0x42030003, +0x33800284, +0x1c010204, +0x40200000, +0x40200000, +0x40200000, +0x34000190, +0x34004191, +0x34008192, +0x3400c193, +0x141fc205, +0x23fffd84, +0x1c100183, +0x217ffa85, +0x3080a000, +0x3080a201, +0x3080a402, +0x3080a603, +0x3080a804, +0x3080aa05, +0x3080ac06, +0x3080ae07, +0x3080b008, +0x3080b209, +0x3080b40a, +0x3080b60b, +0x3080b80c, +0x3080ba0d, +0x3080bc0e, +0x3080be0f, +0x00003ffc, +0x00000000, +0x00000000, +0x00000000, +0x01a00182, +0x3ec00083, +0xb0a14103, +0x01a00204, +0x3ec10082, +0x4202800e, +0x04000703, +0xb0a14202, +0x21a00803, +0x3fbf028d, +0x3f20068d, +0x3fbe0682, +0x3fe30102, +0x21a00882, +0x3f82028f, +0x3fe3078f, +0x3fbf0784, +0x3f200204, +0x3fbe0204, +0x3fe30204, +0x04000203, +0x21a00903, +0x40848002, +0x21a00982, +0x40800003, +0x21a00a03, +0x40802002, +0x21a00a82, +0x21a00083, +0x40800082, +0x21a00b02, +0x10002818, +0x42a00002, +0x32800007, +0x4207000c, +0x18008208, +0x40a0000b, +0x4080020a, +0x40800709, +0x00200000, +0x42070002, +0x3ac30384, +0x1cffc489, +0x00200000, +0x18008383, +0x38830382, +0x4cffc486, +0x3ac28185, +0xb0408584, +0x28830382, +0x1c020387, +0x38828182, +0xb0408405, +0x1802c408, +0x28828182, +0x217ff886, +0x04000583, +0x21a00803, +0x3fbe0682, +0x3fe30102, +0x04000106, +0x21a00886, +0x04000603, +0x21a00903, +0x40803c02, +0x21a00982, +0x40800003, +0x04000184, +0x21a00a04, +0x40802202, +0x21a00a82, +0x42028005, +0x34208702, +0x21002282, +0x21a00804, +0x21a00886, +0x3fbf0782, +0x3f200102, +0x3fbe0102, +0x3fe30102, +0x21a00902, +0x40804003, +0x21a00983, +0x21a00a04, +0x40805a02, +0x21a00a82, +0x40800083, +0x21a00b83, +0x01a00c02, +0x01a00d83, +0x3420c282, +0x21a00e02, +0x34210283, +0x21a00f03, +0x34200284, +0x77400200, +0x3421c282, +0x21a00702, +0x34218283, +0x21a00083, +0x34214282, +0x21a00b02, +0x4200480c, +0x00200000, +0x1c010286, +0x34220284, +0x34220302, +0x0f608203, +0x5c024204, +0x3b81810b, +0x42013c02, +0x00200000, +0x18008185, +0x38808183, +0x3b814182, +0x21004e84, +0x4020007f, +0x35000100, +0x000004e0, +0x000002a0, +0x000002e8, +0x00000428, +0x00000360, +0x000002e8, +0x000004a0, +0x00000468, +0x000003c8, +0x00000360, +0x409ffe02, +0x30801203, +0x40800204, +0x3ec40085, +0x10009c09, +0x3ac10606, +0xb060c105, +0x4020007f, +0x4020007f, +0x20801203, +0x38810602, +0xb0408586, +0x28810602, +0x32004180, +0x34204702, +0x21a00382, +0x4020007f, +0x327fdc80, +0x409ffe02, +0x30801203, +0x40800204, +0x3ec40087, +0x40800405, +0x00200000, +0x40800606, +0x3ac10608, +0x3ac14609, +0x3ac1860a, +0xb060c107, +0x20801203, +0x41004003, +0x38810602, +0x4020007f, +0xb0408188, +0x4020007f, +0x28810602, +0x41201002, +0x38814603, +0x10009c09, +0xb060c109, +0x4020007f, +0x28814603, +0x41193f83, +0x38818602, +0x60ffc003, +0xb040818a, +0x28818602, +0x32003080, +0x409ffe02, +0x30801203, +0x40800204, +0x3ec40087, +0x41201008, +0x10009c14, +0x40800405, +0x3ac10609, +0x40800606, +0x3ac1460a, +0xb060c107, +0x3ac1860b, +0x20801203, +0x38810602, +0xb0408409, +0x28810602, +0x38814603, +0xb060c40a, +0x4020007f, +0x28814603, +0x41193f83, +0x38818602, +0x60ffc003, +0xb040818b, +0x28818602, +0x32002380, +0x409ffe02, +0x30801204, +0x40800205, +0x3ec40083, +0x40800406, +0x3ac14607, +0x3ac18608, +0xb0810103, +0x41004002, +0x20801204, +0x4020007f, +0x38814603, +0x10009c0b, +0xb060c107, +0x4020007f, +0x4020007f, +0x28814603, +0x38818602, +0x4020007f, +0x4020007f, +0xb0408588, +0x28818602, +0x4020007f, +0x32001780, +0x409ffe02, +0x1000640e, +0x40800204, +0x30801203, +0x40800405, +0x3ec40087, +0x40800606, +0x3ac10608, +0x3ac14609, +0x3ac1860a, +0xb060c107, +0x20801203, +0x413d8003, +0x38810602, +0x4020007f, +0x327fd780, +0x409ffe02, +0x10007f0c, +0x40800205, +0x30801204, +0x40800406, +0x3ec40083, +0x3ac14607, +0x3ac18608, +0xb0810103, +0x413d8002, +0x20801204, +0x38814603, +0x4020007f, +0x327feb80, +0x409ffe02, +0x30801203, +0x40800204, +0x3ec40087, +0x40800405, +0x1000650a, +0x40800606, +0x3ac10608, +0x3ac14609, +0x3ac1860a, +0xb060c107, +0x20801203, +0x38810602, +0xb0408588, +0x4020007f, +0x327fc980, +0x00400000, +0x40800003, +0x4020007f, +0x35000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, }; diff --git a/arch/powerpc/platforms/cell/spufs/spu_save_dump.h_shipped b/arch/powerpc/platforms/cell/spufs/spu_save_dump.h_shipped index 39e54003f1df..b9f81ac8a632 100644 --- a/arch/powerpc/platforms/cell/spufs/spu_save_dump.h_shipped +++ b/arch/powerpc/platforms/cell/spufs/spu_save_dump.h_shipped @@ -3,189 +3,741 @@ * Hex-dump auto generated from spu_save.c. * Do not edit! */ -static unsigned int spu_save_code[] __page_aligned = { -0x20805000, 0x20805201, 0x20805402, 0x20805603, -0x20805804, 0x20805a05, 0x20805c06, 0x20805e07, -0x20806008, 0x20806209, 0x2080640a, 0x2080660b, -0x2080680c, 0x20806a0d, 0x20806c0e, 0x20806e0f, -0x4201c003, 0x33800184, 0x1c010204, 0x40200000, -0x24000190, 0x24004191, 0x24008192, 0x2400c193, -0x141fc205, 0x23fffd84, 0x1c100183, 0x217ffb85, -0x40800000, 0x409ff801, 0x24000080, 0x24fd8081, -0x1cd80081, 0x33000180, 0x00000000, 0x00000000, -0x01a00182, 0x3ec00083, 0xb1c38103, 0x01a00204, -0x3ec10082, 0x4201400d, 0xb1c38202, 0x01a00583, -0x34218682, 0x3ed80684, 0xb0408184, 0x24218682, -0x01a00603, 0x00200000, 0x34214682, 0x3ed40684, -0xb0408184, 0x40800003, 0x24214682, 0x21a00083, -0x40800082, 0x21a00b02, 0x4020007f, 0x1000251e, -0x40a80002, 0x32800008, 0x4205c00c, 0x00200000, -0x40a0000b, 0x3f82070f, 0x4080020a, 0x40800709, -0x3fe3078f, 0x3fbf0783, 0x3f200183, 0x3fbe0183, -0x3fe30187, 0x18008387, 0x4205c002, 0x3ac30404, -0x1cffc489, 0x00200000, 0x18008403, 0x38830402, -0x4cffc486, 0x3ac28185, 0xb0408584, 0x28830402, -0x1c020408, 0x38828182, 0xb0408385, 0x1802c387, -0x28828182, 0x217ff886, 0x04000582, 0x32800007, -0x21a00802, 0x3fbf0705, 0x3f200285, 0x3fbe0285, -0x3fe30285, 0x21a00885, 0x04000603, 0x21a00903, -0x40803c02, 0x21a00982, 0x04000386, 0x21a00a06, -0x40801202, 0x21a00a82, 0x73000003, 0x24200683, -0x01a00404, 0x00200000, 0x34204682, 0x3ec40683, -0xb0408203, 0x24204682, 0x01a00783, 0x00200000, -0x3421c682, 0x3edc0684, 0xb0408184, 0x2421c682, -0x21a00806, 0x21a00885, 0x3fbf0784, 0x3f200204, -0x3fbe0204, 0x3fe30204, 0x21a00904, 0x40804002, -0x21a00982, 0x21a00a06, 0x40805a02, 0x21a00a82, -0x04000683, 0x21a00803, 0x21a00885, 0x21a00904, -0x40848002, 0x21a00982, 0x21a00a06, 0x40801002, -0x21a00a82, 0x21a00a06, 0x40806602, 0x00200000, -0x35800009, 0x21a00a82, 0x40800083, 0x21a00b83, -0x01a00c02, 0x01a00d83, 0x00003ffb, 0x40800003, -0x4020007f, 0x35000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, +static unsigned int spu_save_code[] __attribute__((__aligned__(128))) = { +0x20805000, +0x20805201, +0x20805402, +0x20805603, +0x20805804, +0x20805a05, +0x20805c06, +0x20805e07, +0x20806008, +0x20806209, +0x2080640a, +0x2080660b, +0x2080680c, +0x20806a0d, +0x20806c0e, +0x20806e0f, +0x4201c003, +0x33800184, +0x1c010204, +0x40200000, +0x24000190, +0x24004191, +0x24008192, +0x2400c193, +0x141fc205, +0x23fffd84, +0x1c100183, +0x217ffb85, +0x40800000, +0x409ff801, +0x24000080, +0x24fd8081, +0x1cd80081, +0x33000180, +0x00000000, +0x00000000, +0x01a00182, +0x3ec00083, +0xb1c38103, +0x01a00204, +0x3ec10082, +0x4201400d, +0xb1c38202, +0x01a00583, +0x34218682, +0x3ed80684, +0xb0408184, +0x24218682, +0x01a00603, +0x00200000, +0x34214682, +0x3ed40684, +0xb0408184, +0x40800003, +0x24214682, +0x21a00083, +0x40800082, +0x21a00b02, +0x4020007f, +0x1000251e, +0x42a00002, +0x32800008, +0x4205c00c, +0x00200000, +0x40a0000b, +0x3f82070f, +0x4080020a, +0x40800709, +0x3fe3078f, +0x3fbf0783, +0x3f200183, +0x3fbe0183, +0x3fe30187, +0x18008387, +0x4205c002, +0x3ac30404, +0x1cffc489, +0x00200000, +0x18008403, +0x38830402, +0x4cffc486, +0x3ac28185, +0xb0408584, +0x28830402, +0x1c020408, +0x38828182, +0xb0408385, +0x1802c387, +0x28828182, +0x217ff886, +0x04000582, +0x32800007, +0x21a00802, +0x3fbf0705, +0x3f200285, +0x3fbe0285, +0x3fe30285, +0x21a00885, +0x04000603, +0x21a00903, +0x40803c02, +0x21a00982, +0x04000386, +0x21a00a06, +0x40801202, +0x21a00a82, +0x73000003, +0x24200683, +0x01a00404, +0x00200000, +0x34204682, +0x3ec40683, +0xb0408203, +0x24204682, +0x01a00783, +0x00200000, +0x3421c682, +0x3edc0684, +0xb0408184, +0x2421c682, +0x21a00806, +0x21a00885, +0x3fbf0784, +0x3f200204, +0x3fbe0204, +0x3fe30204, +0x21a00904, +0x40804002, +0x21a00982, +0x21a00a06, +0x40805a02, +0x21a00a82, +0x04000683, +0x21a00803, +0x21a00885, +0x21a00904, +0x40848002, +0x21a00982, +0x21a00a06, +0x40801002, +0x21a00a82, +0x21a00a06, +0x40806602, +0x00200000, +0x35800009, +0x21a00a82, +0x40800083, +0x21a00b83, +0x01a00c02, +0x01a00d83, +0x00003ffb, +0x40800003, +0x4020007f, +0x35000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, }; diff --git a/include/asm-powerpc/spu_csa.h b/include/asm-powerpc/spu_csa.h index ba18d7d4dde2..964c2d38ccb7 100644 --- a/include/asm-powerpc/spu_csa.h +++ b/include/asm-powerpc/spu_csa.h @@ -86,10 +86,18 @@ struct spu_lscsa { struct spu_reg128 event_mask; struct spu_reg128 srr0; struct spu_reg128 stopped_status; - struct spu_reg128 pad[119]; /* 'ls' must be page-aligned. */ - unsigned char ls[LS_SIZE]; + + /* + * 'ls' must be page-aligned on all configurations. + * Since we don't want to rely on having the spu-gcc + * installed to build the kernel and this structure + * is used in the SPU-side code, make it 64k-page + * aligned for now. + */ + unsigned char ls[LS_SIZE] __attribute__((aligned(65536))); }; +#ifndef __SPU__ /* * struct spu_problem_collapsed - condensed problem state area, w/o pads. */ @@ -250,6 +258,7 @@ extern int spu_restore(struct spu_state *new, struct spu *spu); extern int spu_switch(struct spu_state *prev, struct spu_state *new, struct spu *spu); +#endif /* !__SPU__ */ #endif /* __KERNEL__ */ #endif /* !__ASSEMBLY__ */ #endif /* _SPU_CSA_H_ */ -- cgit v1.2.3 From 868ea0c9256b658b14603e1ad7361b81b92ccacd Mon Sep 17 00:00:00 2001 From: "Mark A. Greer" Date: Tue, 20 Jun 2006 14:15:36 -0700 Subject: [POWERPC] mpic: add support for serial mode interrupts On Tue, Jun 20, 2006 at 02:01:26PM +1000, Benjamin Herrenschmidt wrote: > On Mon, 2006-06-19 at 13:08 -0700, Mark A. Greer wrote: > > MPC10x-style interrupt controllers have a serial mode that allows > > several interrupts to be clocked in through one INT signal. > > > > This patch adds the software support for that mode. > > You hard code the clock ratio... why not add a separate call to be > called after mpic_init, > something like mpic_set_serial_int(int mpic, int enable, int > clock_ratio) ? How's this? -- MPC10x-style interrupt controllers have a serial mode that allows several interrupts to be clocked in through one INT signal. This patch adds the software support for that mode. Signed-off-by: Mark A. Greer -- arch/powerpc/sysdev/mpic.c | 20 ++++++++++++++++++++ include/asm-powerpc/mpic.h | 10 ++++++++++ 2 files changed, 30 insertions(+) -- Signed-off-by: Paul Mackerras --- arch/powerpc/sysdev/mpic.c | 20 ++++++++++++++++++++ include/asm-powerpc/mpic.h | 10 ++++++++++ 2 files changed, 30 insertions(+) (limited to 'include') diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 7dcdfcb3c984..bffe50d02c99 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -829,7 +829,27 @@ void __init mpic_init(struct mpic *mpic) mpic_cpu_write(MPIC_CPU_CURRENT_TASK_PRI, 0); } +void __init mpic_set_clk_ratio(struct mpic *mpic, u32 clock_ratio) +{ + u32 v; + + v = mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1); + v &= ~MPIC_GREG_GLOBAL_CONF_1_CLK_RATIO_MASK; + v |= MPIC_GREG_GLOBAL_CONF_1_CLK_RATIO(clock_ratio); + mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1, v); +} +void __init mpic_set_serial_int(struct mpic *mpic, int enable) +{ + u32 v; + + v = mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1); + if (enable) + v |= MPIC_GREG_GLOBAL_CONF_1_SIE; + else + v &= ~MPIC_GREG_GLOBAL_CONF_1_SIE; + mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1, v); +} void mpic_irq_set_priority(unsigned int irq, unsigned int pri) { diff --git a/include/asm-powerpc/mpic.h b/include/asm-powerpc/mpic.h index 6b9e78142f4f..f0d22ac34b96 100644 --- a/include/asm-powerpc/mpic.h +++ b/include/asm-powerpc/mpic.h @@ -22,6 +22,10 @@ #define MPIC_GREG_GCONF_8259_PTHROU_DIS 0x20000000 #define MPIC_GREG_GCONF_BASE_MASK 0x000fffff #define MPIC_GREG_GLOBAL_CONF_1 0x00030 +#define MPIC_GREG_GLOBAL_CONF_1_SIE 0x08000000 +#define MPIC_GREG_GLOBAL_CONF_1_CLK_RATIO_MASK 0x70000000 +#define MPIC_GREG_GLOBAL_CONF_1_CLK_RATIO(r) \ + (((r) << 28) & MPIC_GREG_GLOBAL_CONF_1_CLK_RATIO_MASK) #define MPIC_GREG_VENDOR_0 0x00040 #define MPIC_GREG_VENDOR_1 0x00050 #define MPIC_GREG_VENDOR_2 0x00060 @@ -284,6 +288,12 @@ extern int mpic_get_one_irq(struct mpic *mpic, struct pt_regs *regs); /* This one gets to the primary mpic */ extern int mpic_get_irq(struct pt_regs *regs); +/* Set the EPIC clock ratio */ +void mpic_set_clk_ratio(struct mpic *mpic, u32 clock_ratio); + +/* Enable/Disable EPIC serial interrupt mode */ +void mpic_set_serial_int(struct mpic *mpic, int enable); + /* global mpic for pSeries */ extern struct mpic *pSeries_mpic; -- cgit v1.2.3 From 72abd54035a3d71fd8f02596e659257e8bba16ca Mon Sep 17 00:00:00 2001 From: Andreas Schwab Date: Mon, 19 Jun 2006 22:45:04 +0200 Subject: [POWERPC] Unify ppc syscall tables Avoid duplication of the syscall table for the cell platform. Based on an idea from David Woodhouse. Signed-off-by: Andreas Schwab Acked-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/systbl.S | 311 +-------------------------- arch/powerpc/platforms/cell/spu_callbacks.c | 314 ++-------------------------- include/asm-powerpc/systbl.h | 306 +++++++++++++++++++++++++++ 3 files changed, 324 insertions(+), 607 deletions(-) create mode 100644 include/asm-powerpc/systbl.h (limited to 'include') diff --git a/arch/powerpc/kernel/systbl.S b/arch/powerpc/kernel/systbl.S index 26ed1f5ef16e..ee75ccf1a802 100644 --- a/arch/powerpc/kernel/systbl.S +++ b/arch/powerpc/kernel/systbl.S @@ -32,6 +32,10 @@ #define SYS32ONLY(func) .long sys_##func #define SYSX(f, f3264, f32) .long f32 #endif +#define SYSCALL_SPU(func) SYSCALL(func) +#define COMPAT_SYS_SPU(func) COMPAT_SYS(func) +#define PPC_SYS_SPU(func) PPC_SYS(func) +#define SYSX_SPU(f, f3264, f32) SYSX(f, f3264, f32) #ifdef CONFIG_PPC64 #define sys_sigpending sys_ni_syscall @@ -39,309 +43,4 @@ #endif _GLOBAL(sys_call_table) -SYSCALL(restart_syscall) -SYSCALL(exit) -PPC_SYS(fork) -SYSCALL(read) -SYSCALL(write) -COMPAT_SYS(open) -SYSCALL(close) -COMPAT_SYS(waitpid) -COMPAT_SYS(creat) -SYSCALL(link) -SYSCALL(unlink) -COMPAT_SYS(execve) -SYSCALL(chdir) -COMPAT_SYS(time) -SYSCALL(mknod) -SYSCALL(chmod) -SYSCALL(lchown) -SYSCALL(ni_syscall) -OLDSYS(stat) -SYSX(sys_lseek,ppc32_lseek,sys_lseek) -SYSCALL(getpid) -COMPAT_SYS(mount) -SYSX(sys_ni_syscall,sys_oldumount,sys_oldumount) -SYSCALL(setuid) -SYSCALL(getuid) -COMPAT_SYS(stime) -COMPAT_SYS(ptrace) -SYSCALL(alarm) -OLDSYS(fstat) -COMPAT_SYS(pause) -COMPAT_SYS(utime) -SYSCALL(ni_syscall) -SYSCALL(ni_syscall) -COMPAT_SYS(access) -COMPAT_SYS(nice) -SYSCALL(ni_syscall) -SYSCALL(sync) -COMPAT_SYS(kill) -SYSCALL(rename) -COMPAT_SYS(mkdir) -SYSCALL(rmdir) -SYSCALL(dup) -SYSCALL(pipe) -COMPAT_SYS(times) -SYSCALL(ni_syscall) -SYSCALL(brk) -SYSCALL(setgid) -SYSCALL(getgid) -SYSCALL(signal) -SYSCALL(geteuid) -SYSCALL(getegid) -SYSCALL(acct) -SYSCALL(umount) -SYSCALL(ni_syscall) -COMPAT_SYS(ioctl) -COMPAT_SYS(fcntl) -SYSCALL(ni_syscall) -COMPAT_SYS(setpgid) -SYSCALL(ni_syscall) -SYSX(sys_ni_syscall,sys_olduname, sys_olduname) -COMPAT_SYS(umask) -SYSCALL(chroot) -SYSCALL(ustat) -SYSCALL(dup2) -SYSCALL(getppid) -SYSCALL(getpgrp) -SYSCALL(setsid) -SYS32ONLY(sigaction) -SYSCALL(sgetmask) -COMPAT_SYS(ssetmask) -SYSCALL(setreuid) -SYSCALL(setregid) -SYS32ONLY(sigsuspend) -COMPAT_SYS(sigpending) -COMPAT_SYS(sethostname) -COMPAT_SYS(setrlimit) -COMPAT_SYS(old_getrlimit) -COMPAT_SYS(getrusage) -COMPAT_SYS(gettimeofday) -COMPAT_SYS(settimeofday) -COMPAT_SYS(getgroups) -COMPAT_SYS(setgroups) -SYSX(sys_ni_syscall,sys_ni_syscall,ppc_select) -SYSCALL(symlink) -OLDSYS(lstat) -COMPAT_SYS(readlink) -SYSCALL(uselib) -SYSCALL(swapon) -SYSCALL(reboot) -SYSX(sys_ni_syscall,old32_readdir,old_readdir) -SYSCALL(mmap) -SYSCALL(munmap) -SYSCALL(truncate) -SYSCALL(ftruncate) -SYSCALL(fchmod) -SYSCALL(fchown) -COMPAT_SYS(getpriority) -COMPAT_SYS(setpriority) -SYSCALL(ni_syscall) -COMPAT_SYS(statfs) -COMPAT_SYS(fstatfs) -SYSCALL(ni_syscall) -COMPAT_SYS(socketcall) -COMPAT_SYS(syslog) -COMPAT_SYS(setitimer) -COMPAT_SYS(getitimer) -COMPAT_SYS(newstat) -COMPAT_SYS(newlstat) -COMPAT_SYS(newfstat) -SYSX(sys_ni_syscall,sys_uname,sys_uname) -SYSCALL(ni_syscall) -SYSCALL(vhangup) -SYSCALL(ni_syscall) -SYSCALL(ni_syscall) -COMPAT_SYS(wait4) -SYSCALL(swapoff) -COMPAT_SYS(sysinfo) -COMPAT_SYS(ipc) -SYSCALL(fsync) -SYS32ONLY(sigreturn) -PPC_SYS(clone) -COMPAT_SYS(setdomainname) -PPC_SYS(newuname) -SYSCALL(ni_syscall) -COMPAT_SYS(adjtimex) -SYSCALL(mprotect) -SYSX(sys_ni_syscall,compat_sys_sigprocmask,sys_sigprocmask) -SYSCALL(ni_syscall) -SYSCALL(init_module) -SYSCALL(delete_module) -SYSCALL(ni_syscall) -SYSCALL(quotactl) -COMPAT_SYS(getpgid) -SYSCALL(fchdir) -SYSCALL(bdflush) -COMPAT_SYS(sysfs) -SYSX(ppc64_personality,ppc64_personality,sys_personality) -SYSCALL(ni_syscall) -SYSCALL(setfsuid) -SYSCALL(setfsgid) -SYSCALL(llseek) -COMPAT_SYS(getdents) -SYSX(sys_select,ppc32_select,ppc_select) -SYSCALL(flock) -SYSCALL(msync) -COMPAT_SYS(readv) -COMPAT_SYS(writev) -COMPAT_SYS(getsid) -SYSCALL(fdatasync) -COMPAT_SYS(sysctl) -SYSCALL(mlock) -SYSCALL(munlock) -SYSCALL(mlockall) -SYSCALL(munlockall) -COMPAT_SYS(sched_setparam) -COMPAT_SYS(sched_getparam) -COMPAT_SYS(sched_setscheduler) -COMPAT_SYS(sched_getscheduler) -SYSCALL(sched_yield) -COMPAT_SYS(sched_get_priority_max) -COMPAT_SYS(sched_get_priority_min) -COMPAT_SYS(sched_rr_get_interval) -COMPAT_SYS(nanosleep) -SYSCALL(mremap) -SYSCALL(setresuid) -SYSCALL(getresuid) -SYSCALL(ni_syscall) -SYSCALL(poll) -COMPAT_SYS(nfsservctl) -SYSCALL(setresgid) -SYSCALL(getresgid) -COMPAT_SYS(prctl) -COMPAT_SYS(rt_sigreturn) -COMPAT_SYS(rt_sigaction) -COMPAT_SYS(rt_sigprocmask) -COMPAT_SYS(rt_sigpending) -COMPAT_SYS(rt_sigtimedwait) -COMPAT_SYS(rt_sigqueueinfo) -COMPAT_SYS(rt_sigsuspend) -COMPAT_SYS(pread64) -COMPAT_SYS(pwrite64) -SYSCALL(chown) -SYSCALL(getcwd) -SYSCALL(capget) -SYSCALL(capset) -COMPAT_SYS(sigaltstack) -SYSX(sys_sendfile64,compat_sys_sendfile,sys_sendfile) -SYSCALL(ni_syscall) -SYSCALL(ni_syscall) -PPC_SYS(vfork) -COMPAT_SYS(getrlimit) -COMPAT_SYS(readahead) -SYS32ONLY(mmap2) -SYS32ONLY(truncate64) -SYS32ONLY(ftruncate64) -SYSX(sys_ni_syscall,sys_stat64,sys_stat64) -SYSX(sys_ni_syscall,sys_lstat64,sys_lstat64) -SYSX(sys_ni_syscall,sys_fstat64,sys_fstat64) -SYSCALL(pciconfig_read) -SYSCALL(pciconfig_write) -SYSCALL(pciconfig_iobase) -SYSCALL(ni_syscall) -SYSCALL(getdents64) -SYSCALL(pivot_root) -SYSX(sys_ni_syscall,compat_sys_fcntl64,sys_fcntl64) -SYSCALL(madvise) -SYSCALL(mincore) -SYSCALL(gettid) -SYSCALL(tkill) -SYSCALL(setxattr) -SYSCALL(lsetxattr) -SYSCALL(fsetxattr) -SYSCALL(getxattr) -SYSCALL(lgetxattr) -SYSCALL(fgetxattr) -SYSCALL(listxattr) -SYSCALL(llistxattr) -SYSCALL(flistxattr) -SYSCALL(removexattr) -SYSCALL(lremovexattr) -SYSCALL(fremovexattr) -COMPAT_SYS(futex) -COMPAT_SYS(sched_setaffinity) -COMPAT_SYS(sched_getaffinity) -SYSCALL(ni_syscall) -SYSCALL(ni_syscall) -SYS32ONLY(sendfile64) -COMPAT_SYS(io_setup) -SYSCALL(io_destroy) -COMPAT_SYS(io_getevents) -COMPAT_SYS(io_submit) -SYSCALL(io_cancel) -SYSCALL(set_tid_address) -SYSX(sys_fadvise64,ppc32_fadvise64,sys_fadvise64) -SYSCALL(exit_group) -SYSX(sys_lookup_dcookie,ppc32_lookup_dcookie,sys_lookup_dcookie) -SYSCALL(epoll_create) -SYSCALL(epoll_ctl) -SYSCALL(epoll_wait) -SYSCALL(remap_file_pages) -SYSX(sys_timer_create,compat_sys_timer_create,sys_timer_create) -COMPAT_SYS(timer_settime) -COMPAT_SYS(timer_gettime) -SYSCALL(timer_getoverrun) -SYSCALL(timer_delete) -COMPAT_SYS(clock_settime) -COMPAT_SYS(clock_gettime) -COMPAT_SYS(clock_getres) -COMPAT_SYS(clock_nanosleep) -SYSX(ppc64_swapcontext,ppc32_swapcontext,ppc_swapcontext) -COMPAT_SYS(tgkill) -COMPAT_SYS(utimes) -COMPAT_SYS(statfs64) -COMPAT_SYS(fstatfs64) -SYSX(sys_ni_syscall, ppc_fadvise64_64, ppc_fadvise64_64) -PPC_SYS(rtas) -OLDSYS(debug_setcontext) -SYSCALL(ni_syscall) -SYSCALL(ni_syscall) -COMPAT_SYS(mbind) -COMPAT_SYS(get_mempolicy) -COMPAT_SYS(set_mempolicy) -COMPAT_SYS(mq_open) -SYSCALL(mq_unlink) -COMPAT_SYS(mq_timedsend) -COMPAT_SYS(mq_timedreceive) -COMPAT_SYS(mq_notify) -COMPAT_SYS(mq_getsetattr) -COMPAT_SYS(kexec_load) -COMPAT_SYS(add_key) -COMPAT_SYS(request_key) -COMPAT_SYS(keyctl) -COMPAT_SYS(waitid) -COMPAT_SYS(ioprio_set) -COMPAT_SYS(ioprio_get) -SYSCALL(inotify_init) -SYSCALL(inotify_add_watch) -SYSCALL(inotify_rm_watch) -SYSCALL(spu_run) -SYSCALL(spu_create) -COMPAT_SYS(pselect6) -COMPAT_SYS(ppoll) -SYSCALL(unshare) -SYSCALL(splice) -SYSCALL(tee) -SYSCALL(vmsplice) -COMPAT_SYS(openat) -SYSCALL(mkdirat) -SYSCALL(mknodat) -SYSCALL(fchownat) -COMPAT_SYS(futimesat) -SYSX(sys_newfstatat, sys_fstatat64, sys_fstatat64) -SYSCALL(unlinkat) -SYSCALL(renameat) -SYSCALL(linkat) -SYSCALL(symlinkat) -SYSCALL(readlinkat) -SYSCALL(fchmodat) -SYSCALL(faccessat) -COMPAT_SYS(get_robust_list) -COMPAT_SYS(set_robust_list) - -/* - * please add new calls to arch/powerpc/platforms/cell/spu_callbacks.c - * as well when appropriate. - */ +#include diff --git a/arch/powerpc/platforms/cell/spu_callbacks.c b/arch/powerpc/platforms/cell/spu_callbacks.c index b47fcc5ddb78..47ec3be3edcd 100644 --- a/arch/powerpc/platforms/cell/spu_callbacks.c +++ b/arch/powerpc/platforms/cell/spu_callbacks.c @@ -34,307 +34,19 @@ */ void *spu_syscall_table[] = { - [__NR_restart_syscall] sys_ni_syscall, /* sys_restart_syscall */ - [__NR_exit] sys_ni_syscall, /* sys_exit */ - [__NR_fork] sys_ni_syscall, /* ppc_fork */ - [__NR_read] sys_read, - [__NR_write] sys_write, - [__NR_open] sys_open, - [__NR_close] sys_close, - [__NR_waitpid] sys_waitpid, - [__NR_creat] sys_creat, - [__NR_link] sys_link, - [__NR_unlink] sys_unlink, - [__NR_execve] sys_ni_syscall, /* sys_execve */ - [__NR_chdir] sys_chdir, - [__NR_time] sys_time, - [__NR_mknod] sys_mknod, - [__NR_chmod] sys_chmod, - [__NR_lchown] sys_lchown, - [__NR_break] sys_ni_syscall, - [__NR_oldstat] sys_ni_syscall, - [__NR_lseek] sys_lseek, - [__NR_getpid] sys_getpid, - [__NR_mount] sys_ni_syscall, /* sys_mount */ - [__NR_umount] sys_ni_syscall, - [__NR_setuid] sys_setuid, - [__NR_getuid] sys_getuid, - [__NR_stime] sys_stime, - [__NR_ptrace] sys_ni_syscall, /* sys_ptrace */ - [__NR_alarm] sys_alarm, - [__NR_oldfstat] sys_ni_syscall, - [__NR_pause] sys_ni_syscall, /* sys_pause */ - [__NR_utime] sys_ni_syscall, /* sys_utime */ - [__NR_stty] sys_ni_syscall, - [__NR_gtty] sys_ni_syscall, - [__NR_access] sys_access, - [__NR_nice] sys_nice, - [__NR_ftime] sys_ni_syscall, - [__NR_sync] sys_sync, - [__NR_kill] sys_kill, - [__NR_rename] sys_rename, - [__NR_mkdir] sys_mkdir, - [__NR_rmdir] sys_rmdir, - [__NR_dup] sys_dup, - [__NR_pipe] sys_pipe, - [__NR_times] sys_times, - [__NR_prof] sys_ni_syscall, - [__NR_brk] sys_brk, - [__NR_setgid] sys_setgid, - [__NR_getgid] sys_getgid, - [__NR_signal] sys_ni_syscall, /* sys_signal */ - [__NR_geteuid] sys_geteuid, - [__NR_getegid] sys_getegid, - [__NR_acct] sys_ni_syscall, /* sys_acct */ - [__NR_umount2] sys_ni_syscall, /* sys_umount */ - [__NR_lock] sys_ni_syscall, - [__NR_ioctl] sys_ioctl, - [__NR_fcntl] sys_fcntl, - [__NR_mpx] sys_ni_syscall, - [__NR_setpgid] sys_setpgid, - [__NR_ulimit] sys_ni_syscall, - [__NR_oldolduname] sys_ni_syscall, - [__NR_umask] sys_umask, - [__NR_chroot] sys_chroot, - [__NR_ustat] sys_ni_syscall, /* sys_ustat */ - [__NR_dup2] sys_dup2, - [__NR_getppid] sys_getppid, - [__NR_getpgrp] sys_getpgrp, - [__NR_setsid] sys_setsid, - [__NR_sigaction] sys_ni_syscall, - [__NR_sgetmask] sys_sgetmask, - [__NR_ssetmask] sys_ssetmask, - [__NR_setreuid] sys_setreuid, - [__NR_setregid] sys_setregid, - [__NR_sigsuspend] sys_ni_syscall, - [__NR_sigpending] sys_ni_syscall, - [__NR_sethostname] sys_sethostname, - [__NR_setrlimit] sys_setrlimit, - [__NR_getrlimit] sys_ni_syscall, - [__NR_getrusage] sys_getrusage, - [__NR_gettimeofday] sys_gettimeofday, - [__NR_settimeofday] sys_settimeofday, - [__NR_getgroups] sys_getgroups, - [__NR_setgroups] sys_setgroups, - [__NR_select] sys_ni_syscall, - [__NR_symlink] sys_symlink, - [__NR_oldlstat] sys_ni_syscall, - [__NR_readlink] sys_readlink, - [__NR_uselib] sys_ni_syscall, /* sys_uselib */ - [__NR_swapon] sys_ni_syscall, /* sys_swapon */ - [__NR_reboot] sys_ni_syscall, /* sys_reboot */ - [__NR_readdir] sys_ni_syscall, - [__NR_mmap] sys_mmap, - [__NR_munmap] sys_munmap, - [__NR_truncate] sys_truncate, - [__NR_ftruncate] sys_ftruncate, - [__NR_fchmod] sys_fchmod, - [__NR_fchown] sys_fchown, - [__NR_getpriority] sys_getpriority, - [__NR_setpriority] sys_setpriority, - [__NR_profil] sys_ni_syscall, - [__NR_statfs] sys_ni_syscall, /* sys_statfs */ - [__NR_fstatfs] sys_ni_syscall, /* sys_fstatfs */ - [__NR_ioperm] sys_ni_syscall, - [__NR_socketcall] sys_socketcall, - [__NR_syslog] sys_syslog, - [__NR_setitimer] sys_setitimer, - [__NR_getitimer] sys_getitimer, - [__NR_stat] sys_newstat, - [__NR_lstat] sys_newlstat, - [__NR_fstat] sys_newfstat, - [__NR_olduname] sys_ni_syscall, - [__NR_iopl] sys_ni_syscall, - [__NR_vhangup] sys_vhangup, - [__NR_idle] sys_ni_syscall, - [__NR_vm86] sys_ni_syscall, - [__NR_wait4] sys_wait4, - [__NR_swapoff] sys_ni_syscall, /* sys_swapoff */ - [__NR_sysinfo] sys_sysinfo, - [__NR_ipc] sys_ni_syscall, /* sys_ipc */ - [__NR_fsync] sys_fsync, - [__NR_sigreturn] sys_ni_syscall, - [__NR_clone] sys_ni_syscall, /* ppc_clone */ - [__NR_setdomainname] sys_setdomainname, - [__NR_uname] ppc_newuname, - [__NR_modify_ldt] sys_ni_syscall, - [__NR_adjtimex] sys_adjtimex, - [__NR_mprotect] sys_mprotect, - [__NR_sigprocmask] sys_ni_syscall, - [__NR_create_module] sys_ni_syscall, - [__NR_init_module] sys_ni_syscall, /* sys_init_module */ - [__NR_delete_module] sys_ni_syscall, /* sys_delete_module */ - [__NR_get_kernel_syms] sys_ni_syscall, - [__NR_quotactl] sys_ni_syscall, /* sys_quotactl */ - [__NR_getpgid] sys_getpgid, - [__NR_fchdir] sys_fchdir, - [__NR_bdflush] sys_bdflush, - [__NR_sysfs] sys_ni_syscall, /* sys_sysfs */ - [__NR_personality] ppc64_personality, - [__NR_afs_syscall] sys_ni_syscall, - [__NR_setfsuid] sys_setfsuid, - [__NR_setfsgid] sys_setfsgid, - [__NR__llseek] sys_llseek, - [__NR_getdents] sys_getdents, - [__NR__newselect] sys_select, - [__NR_flock] sys_flock, - [__NR_msync] sys_msync, - [__NR_readv] sys_readv, - [__NR_writev] sys_writev, - [__NR_getsid] sys_getsid, - [__NR_fdatasync] sys_fdatasync, - [__NR__sysctl] sys_ni_syscall, /* sys_sysctl */ - [__NR_mlock] sys_mlock, - [__NR_munlock] sys_munlock, - [__NR_mlockall] sys_mlockall, - [__NR_munlockall] sys_munlockall, - [__NR_sched_setparam] sys_sched_setparam, - [__NR_sched_getparam] sys_sched_getparam, - [__NR_sched_setscheduler] sys_sched_setscheduler, - [__NR_sched_getscheduler] sys_sched_getscheduler, - [__NR_sched_yield] sys_sched_yield, - [__NR_sched_get_priority_max] sys_sched_get_priority_max, - [__NR_sched_get_priority_min] sys_sched_get_priority_min, - [__NR_sched_rr_get_interval] sys_sched_rr_get_interval, - [__NR_nanosleep] sys_nanosleep, - [__NR_mremap] sys_mremap, - [__NR_setresuid] sys_setresuid, - [__NR_getresuid] sys_getresuid, - [__NR_query_module] sys_ni_syscall, - [__NR_poll] sys_poll, - [__NR_nfsservctl] sys_ni_syscall, /* sys_nfsservctl */ - [__NR_setresgid] sys_setresgid, - [__NR_getresgid] sys_getresgid, - [__NR_prctl] sys_prctl, - [__NR_rt_sigreturn] sys_ni_syscall, /* ppc64_rt_sigreturn */ - [__NR_rt_sigaction] sys_ni_syscall, /* sys_rt_sigaction */ - [__NR_rt_sigprocmask] sys_ni_syscall, /* sys_rt_sigprocmask */ - [__NR_rt_sigpending] sys_ni_syscall, /* sys_rt_sigpending */ - [__NR_rt_sigtimedwait] sys_ni_syscall, /* sys_rt_sigtimedwait */ - [__NR_rt_sigqueueinfo] sys_ni_syscall, /* sys_rt_sigqueueinfo */ - [__NR_rt_sigsuspend] sys_ni_syscall, /* sys_rt_sigsuspend */ - [__NR_pread64] sys_pread64, - [__NR_pwrite64] sys_pwrite64, - [__NR_chown] sys_chown, - [__NR_getcwd] sys_getcwd, - [__NR_capget] sys_capget, - [__NR_capset] sys_capset, - [__NR_sigaltstack] sys_ni_syscall, /* sys_sigaltstack */ - [__NR_sendfile] sys_sendfile64, - [__NR_getpmsg] sys_ni_syscall, - [__NR_putpmsg] sys_ni_syscall, - [__NR_vfork] sys_ni_syscall, /* ppc_vfork */ - [__NR_ugetrlimit] sys_getrlimit, - [__NR_readahead] sys_readahead, - [192] sys_ni_syscall, - [193] sys_ni_syscall, - [194] sys_ni_syscall, - [195] sys_ni_syscall, - [196] sys_ni_syscall, - [197] sys_ni_syscall, - [__NR_pciconfig_read] sys_ni_syscall, /* sys_pciconfig_read */ - [__NR_pciconfig_write] sys_ni_syscall, /* sys_pciconfig_write */ - [__NR_pciconfig_iobase] sys_ni_syscall, /* sys_pciconfig_iobase */ - [__NR_multiplexer] sys_ni_syscall, - [__NR_getdents64] sys_getdents64, - [__NR_pivot_root] sys_pivot_root, - [204] sys_ni_syscall, - [__NR_madvise] sys_madvise, - [__NR_mincore] sys_mincore, - [__NR_gettid] sys_gettid, - [__NR_tkill] sys_tkill, - [__NR_setxattr] sys_setxattr, - [__NR_lsetxattr] sys_lsetxattr, - [__NR_fsetxattr] sys_fsetxattr, - [__NR_getxattr] sys_getxattr, - [__NR_lgetxattr] sys_lgetxattr, - [__NR_fgetxattr] sys_fgetxattr, - [__NR_listxattr] sys_listxattr, - [__NR_llistxattr] sys_llistxattr, - [__NR_flistxattr] sys_flistxattr, - [__NR_removexattr] sys_removexattr, - [__NR_lremovexattr] sys_lremovexattr, - [__NR_fremovexattr] sys_fremovexattr, - [__NR_futex] sys_futex, - [__NR_sched_setaffinity] sys_sched_setaffinity, - [__NR_sched_getaffinity] sys_sched_getaffinity, - [224] sys_ni_syscall, - [__NR_tuxcall] sys_ni_syscall, - [226] sys_ni_syscall, - [__NR_io_setup] sys_io_setup, - [__NR_io_destroy] sys_io_destroy, - [__NR_io_getevents] sys_io_getevents, - [__NR_io_submit] sys_io_submit, - [__NR_io_cancel] sys_io_cancel, - [__NR_set_tid_address] sys_ni_syscall, /* sys_set_tid_address */ - [__NR_fadvise64] sys_fadvise64, - [__NR_exit_group] sys_ni_syscall, /* sys_exit_group */ - [__NR_lookup_dcookie] sys_ni_syscall, /* sys_lookup_dcookie */ - [__NR_epoll_create] sys_epoll_create, - [__NR_epoll_ctl] sys_epoll_ctl, - [__NR_epoll_wait] sys_epoll_wait, - [__NR_remap_file_pages] sys_remap_file_pages, - [__NR_timer_create] sys_timer_create, - [__NR_timer_settime] sys_timer_settime, - [__NR_timer_gettime] sys_timer_gettime, - [__NR_timer_getoverrun] sys_timer_getoverrun, - [__NR_timer_delete] sys_timer_delete, - [__NR_clock_settime] sys_clock_settime, - [__NR_clock_gettime] sys_clock_gettime, - [__NR_clock_getres] sys_clock_getres, - [__NR_clock_nanosleep] sys_clock_nanosleep, - [__NR_swapcontext] sys_ni_syscall, /* ppc64_swapcontext */ - [__NR_tgkill] sys_tgkill, - [__NR_utimes] sys_utimes, - [__NR_statfs64] sys_statfs64, - [__NR_fstatfs64] sys_fstatfs64, - [254] sys_ni_syscall, - [__NR_rtas] ppc_rtas, - [256] sys_ni_syscall, - [257] sys_ni_syscall, - [258] sys_ni_syscall, - [__NR_mbind] sys_ni_syscall, /* sys_mbind */ - [__NR_get_mempolicy] sys_ni_syscall, /* sys_get_mempolicy */ - [__NR_set_mempolicy] sys_ni_syscall, /* sys_set_mempolicy */ - [__NR_mq_open] sys_ni_syscall, /* sys_mq_open */ - [__NR_mq_unlink] sys_ni_syscall, /* sys_mq_unlink */ - [__NR_mq_timedsend] sys_ni_syscall, /* sys_mq_timedsend */ - [__NR_mq_timedreceive] sys_ni_syscall, /* sys_mq_timedreceive */ - [__NR_mq_notify] sys_ni_syscall, /* sys_mq_notify */ - [__NR_mq_getsetattr] sys_ni_syscall, /* sys_mq_getsetattr */ - [__NR_kexec_load] sys_ni_syscall, /* sys_kexec_load */ - [__NR_add_key] sys_ni_syscall, /* sys_add_key */ - [__NR_request_key] sys_ni_syscall, /* sys_request_key */ - [__NR_keyctl] sys_ni_syscall, /* sys_keyctl */ - [__NR_waitid] sys_ni_syscall, /* sys_waitid */ - [__NR_ioprio_set] sys_ni_syscall, /* sys_ioprio_set */ - [__NR_ioprio_get] sys_ni_syscall, /* sys_ioprio_get */ - [__NR_inotify_init] sys_ni_syscall, /* sys_inotify_init */ - [__NR_inotify_add_watch] sys_ni_syscall, /* sys_inotify_add_watch */ - [__NR_inotify_rm_watch] sys_ni_syscall, /* sys_inotify_rm_watch */ - [__NR_spu_run] sys_ni_syscall, /* sys_spu_run */ - [__NR_spu_create] sys_ni_syscall, /* sys_spu_create */ - [__NR_pselect6] sys_ni_syscall, /* sys_pselect */ - [__NR_ppoll] sys_ni_syscall, /* sys_ppoll */ - [__NR_unshare] sys_unshare, - [__NR_splice] sys_splice, - [__NR_tee] sys_tee, - [__NR_vmsplice] sys_vmsplice, - [__NR_openat] sys_openat, - [__NR_mkdirat] sys_mkdirat, - [__NR_mknodat] sys_mknodat, - [__NR_fchownat] sys_fchownat, - [__NR_futimesat] sys_futimesat, - [__NR_newfstatat] sys_newfstatat, - [__NR_unlinkat] sys_unlinkat, - [__NR_renameat] sys_renameat, - [__NR_linkat] sys_linkat, - [__NR_symlinkat] sys_symlinkat, - [__NR_readlinkat] sys_readlinkat, - [__NR_fchmodat] sys_fchmodat, - [__NR_faccessat] sys_faccessat, - [__NR_get_robust_list] sys_get_robust_list, - [__NR_set_robust_list] sys_set_robust_list, +#define SYSCALL(func) sys_ni_syscall, +#define COMPAT_SYS(func) sys_ni_syscall, +#define PPC_SYS(func) sys_ni_syscall, +#define OLDSYS(func) sys_ni_syscall, +#define SYS32ONLY(func) sys_ni_syscall, +#define SYSX(f, f3264, f32) sys_ni_syscall, + +#define SYSCALL_SPU(func) sys_##func, +#define COMPAT_SYS_SPU(func) sys_##func, +#define PPC_SYS_SPU(func) ppc_##func, +#define SYSX_SPU(f, f3264, f32) f, + +#include }; long spu_sys_callback(struct spu_syscall_block *s) diff --git a/include/asm-powerpc/systbl.h b/include/asm-powerpc/systbl.h new file mode 100644 index 000000000000..eac85ce101b6 --- /dev/null +++ b/include/asm-powerpc/systbl.h @@ -0,0 +1,306 @@ +/* + * List of powerpc syscalls. For the meaning of the _SPU suffix see + * arch/powerpc/platforms/cell/spu_callbacks.c + */ + +SYSCALL(restart_syscall) +SYSCALL(exit) +PPC_SYS(fork) +SYSCALL_SPU(read) +SYSCALL_SPU(write) +COMPAT_SYS_SPU(open) +SYSCALL_SPU(close) +COMPAT_SYS_SPU(waitpid) +COMPAT_SYS_SPU(creat) +SYSCALL_SPU(link) +SYSCALL_SPU(unlink) +COMPAT_SYS(execve) +SYSCALL_SPU(chdir) +COMPAT_SYS_SPU(time) +SYSCALL_SPU(mknod) +SYSCALL_SPU(chmod) +SYSCALL_SPU(lchown) +SYSCALL(ni_syscall) +OLDSYS(stat) +SYSX_SPU(sys_lseek,ppc32_lseek,sys_lseek) +SYSCALL_SPU(getpid) +COMPAT_SYS(mount) +SYSX(sys_ni_syscall,sys_oldumount,sys_oldumount) +SYSCALL_SPU(setuid) +SYSCALL_SPU(getuid) +COMPAT_SYS_SPU(stime) +COMPAT_SYS(ptrace) +SYSCALL_SPU(alarm) +OLDSYS(fstat) +COMPAT_SYS(pause) +COMPAT_SYS(utime) +SYSCALL(ni_syscall) +SYSCALL(ni_syscall) +COMPAT_SYS_SPU(access) +COMPAT_SYS_SPU(nice) +SYSCALL(ni_syscall) +SYSCALL_SPU(sync) +COMPAT_SYS_SPU(kill) +SYSCALL_SPU(rename) +COMPAT_SYS_SPU(mkdir) +SYSCALL_SPU(rmdir) +SYSCALL_SPU(dup) +SYSCALL_SPU(pipe) +COMPAT_SYS_SPU(times) +SYSCALL(ni_syscall) +SYSCALL_SPU(brk) +SYSCALL_SPU(setgid) +SYSCALL_SPU(getgid) +SYSCALL(signal) +SYSCALL_SPU(geteuid) +SYSCALL_SPU(getegid) +SYSCALL(acct) +SYSCALL(umount) +SYSCALL(ni_syscall) +COMPAT_SYS_SPU(ioctl) +COMPAT_SYS_SPU(fcntl) +SYSCALL(ni_syscall) +COMPAT_SYS_SPU(setpgid) +SYSCALL(ni_syscall) +SYSX(sys_ni_syscall,sys_olduname, sys_olduname) +COMPAT_SYS_SPU(umask) +SYSCALL_SPU(chroot) +SYSCALL(ustat) +SYSCALL_SPU(dup2) +SYSCALL_SPU(getppid) +SYSCALL_SPU(getpgrp) +SYSCALL_SPU(setsid) +SYS32ONLY(sigaction) +SYSCALL_SPU(sgetmask) +COMPAT_SYS_SPU(ssetmask) +SYSCALL_SPU(setreuid) +SYSCALL_SPU(setregid) +SYS32ONLY(sigsuspend) +COMPAT_SYS(sigpending) +COMPAT_SYS_SPU(sethostname) +COMPAT_SYS_SPU(setrlimit) +COMPAT_SYS(old_getrlimit) +COMPAT_SYS_SPU(getrusage) +COMPAT_SYS_SPU(gettimeofday) +COMPAT_SYS_SPU(settimeofday) +COMPAT_SYS_SPU(getgroups) +COMPAT_SYS_SPU(setgroups) +SYSX(sys_ni_syscall,sys_ni_syscall,ppc_select) +SYSCALL_SPU(symlink) +OLDSYS(lstat) +COMPAT_SYS_SPU(readlink) +SYSCALL(uselib) +SYSCALL(swapon) +SYSCALL(reboot) +SYSX(sys_ni_syscall,old32_readdir,old_readdir) +SYSCALL_SPU(mmap) +SYSCALL_SPU(munmap) +SYSCALL_SPU(truncate) +SYSCALL_SPU(ftruncate) +SYSCALL_SPU(fchmod) +SYSCALL_SPU(fchown) +COMPAT_SYS_SPU(getpriority) +COMPAT_SYS_SPU(setpriority) +SYSCALL(ni_syscall) +COMPAT_SYS(statfs) +COMPAT_SYS(fstatfs) +SYSCALL(ni_syscall) +COMPAT_SYS_SPU(socketcall) +COMPAT_SYS_SPU(syslog) +COMPAT_SYS_SPU(setitimer) +COMPAT_SYS_SPU(getitimer) +COMPAT_SYS_SPU(newstat) +COMPAT_SYS_SPU(newlstat) +COMPAT_SYS_SPU(newfstat) +SYSX(sys_ni_syscall,sys_uname,sys_uname) +SYSCALL(ni_syscall) +SYSCALL_SPU(vhangup) +SYSCALL(ni_syscall) +SYSCALL(ni_syscall) +COMPAT_SYS_SPU(wait4) +SYSCALL(swapoff) +COMPAT_SYS_SPU(sysinfo) +COMPAT_SYS(ipc) +SYSCALL_SPU(fsync) +SYS32ONLY(sigreturn) +PPC_SYS(clone) +COMPAT_SYS_SPU(setdomainname) +PPC_SYS_SPU(newuname) +SYSCALL(ni_syscall) +COMPAT_SYS_SPU(adjtimex) +SYSCALL_SPU(mprotect) +SYSX(sys_ni_syscall,compat_sys_sigprocmask,sys_sigprocmask) +SYSCALL(ni_syscall) +SYSCALL(init_module) +SYSCALL(delete_module) +SYSCALL(ni_syscall) +SYSCALL(quotactl) +COMPAT_SYS_SPU(getpgid) +SYSCALL_SPU(fchdir) +SYSCALL_SPU(bdflush) +COMPAT_SYS(sysfs) +SYSX_SPU(ppc64_personality,ppc64_personality,sys_personality) +SYSCALL(ni_syscall) +SYSCALL_SPU(setfsuid) +SYSCALL_SPU(setfsgid) +SYSCALL_SPU(llseek) +COMPAT_SYS_SPU(getdents) +SYSX_SPU(sys_select,ppc32_select,ppc_select) +SYSCALL_SPU(flock) +SYSCALL_SPU(msync) +COMPAT_SYS_SPU(readv) +COMPAT_SYS_SPU(writev) +COMPAT_SYS_SPU(getsid) +SYSCALL_SPU(fdatasync) +COMPAT_SYS(sysctl) +SYSCALL_SPU(mlock) +SYSCALL_SPU(munlock) +SYSCALL_SPU(mlockall) +SYSCALL_SPU(munlockall) +COMPAT_SYS_SPU(sched_setparam) +COMPAT_SYS_SPU(sched_getparam) +COMPAT_SYS_SPU(sched_setscheduler) +COMPAT_SYS_SPU(sched_getscheduler) +SYSCALL_SPU(sched_yield) +COMPAT_SYS_SPU(sched_get_priority_max) +COMPAT_SYS_SPU(sched_get_priority_min) +COMPAT_SYS_SPU(sched_rr_get_interval) +COMPAT_SYS_SPU(nanosleep) +SYSCALL_SPU(mremap) +SYSCALL_SPU(setresuid) +SYSCALL_SPU(getresuid) +SYSCALL(ni_syscall) +SYSCALL_SPU(poll) +COMPAT_SYS(nfsservctl) +SYSCALL_SPU(setresgid) +SYSCALL_SPU(getresgid) +COMPAT_SYS_SPU(prctl) +COMPAT_SYS(rt_sigreturn) +COMPAT_SYS(rt_sigaction) +COMPAT_SYS(rt_sigprocmask) +COMPAT_SYS(rt_sigpending) +COMPAT_SYS(rt_sigtimedwait) +COMPAT_SYS(rt_sigqueueinfo) +COMPAT_SYS(rt_sigsuspend) +COMPAT_SYS_SPU(pread64) +COMPAT_SYS_SPU(pwrite64) +SYSCALL_SPU(chown) +SYSCALL_SPU(getcwd) +SYSCALL_SPU(capget) +SYSCALL_SPU(capset) +COMPAT_SYS(sigaltstack) +SYSX_SPU(sys_sendfile64,compat_sys_sendfile,sys_sendfile) +SYSCALL(ni_syscall) +SYSCALL(ni_syscall) +PPC_SYS(vfork) +COMPAT_SYS_SPU(getrlimit) +COMPAT_SYS_SPU(readahead) +SYS32ONLY(mmap2) +SYS32ONLY(truncate64) +SYS32ONLY(ftruncate64) +SYSX(sys_ni_syscall,sys_stat64,sys_stat64) +SYSX(sys_ni_syscall,sys_lstat64,sys_lstat64) +SYSX(sys_ni_syscall,sys_fstat64,sys_fstat64) +SYSCALL(pciconfig_read) +SYSCALL(pciconfig_write) +SYSCALL(pciconfig_iobase) +SYSCALL(ni_syscall) +SYSCALL_SPU(getdents64) +SYSCALL_SPU(pivot_root) +SYSX(sys_ni_syscall,compat_sys_fcntl64,sys_fcntl64) +SYSCALL_SPU(madvise) +SYSCALL_SPU(mincore) +SYSCALL_SPU(gettid) +SYSCALL_SPU(tkill) +SYSCALL_SPU(setxattr) +SYSCALL_SPU(lsetxattr) +SYSCALL_SPU(fsetxattr) +SYSCALL_SPU(getxattr) +SYSCALL_SPU(lgetxattr) +SYSCALL_SPU(fgetxattr) +SYSCALL_SPU(listxattr) +SYSCALL_SPU(llistxattr) +SYSCALL_SPU(flistxattr) +SYSCALL_SPU(removexattr) +SYSCALL_SPU(lremovexattr) +SYSCALL_SPU(fremovexattr) +COMPAT_SYS_SPU(futex) +COMPAT_SYS_SPU(sched_setaffinity) +COMPAT_SYS_SPU(sched_getaffinity) +SYSCALL(ni_syscall) +SYSCALL(ni_syscall) +SYS32ONLY(sendfile64) +COMPAT_SYS_SPU(io_setup) +SYSCALL_SPU(io_destroy) +COMPAT_SYS_SPU(io_getevents) +COMPAT_SYS_SPU(io_submit) +SYSCALL_SPU(io_cancel) +SYSCALL(set_tid_address) +SYSX_SPU(sys_fadvise64,ppc32_fadvise64,sys_fadvise64) +SYSCALL(exit_group) +SYSX(sys_lookup_dcookie,ppc32_lookup_dcookie,sys_lookup_dcookie) +SYSCALL_SPU(epoll_create) +SYSCALL_SPU(epoll_ctl) +SYSCALL_SPU(epoll_wait) +SYSCALL_SPU(remap_file_pages) +SYSX_SPU(sys_timer_create,compat_sys_timer_create,sys_timer_create) +COMPAT_SYS_SPU(timer_settime) +COMPAT_SYS_SPU(timer_gettime) +SYSCALL_SPU(timer_getoverrun) +SYSCALL_SPU(timer_delete) +COMPAT_SYS_SPU(clock_settime) +COMPAT_SYS_SPU(clock_gettime) +COMPAT_SYS_SPU(clock_getres) +COMPAT_SYS_SPU(clock_nanosleep) +SYSX(ppc64_swapcontext,ppc32_swapcontext,ppc_swapcontext) +COMPAT_SYS_SPU(tgkill) +COMPAT_SYS_SPU(utimes) +COMPAT_SYS_SPU(statfs64) +COMPAT_SYS_SPU(fstatfs64) +SYSX(sys_ni_syscall, ppc_fadvise64_64, ppc_fadvise64_64) +PPC_SYS_SPU(rtas) +OLDSYS(debug_setcontext) +SYSCALL(ni_syscall) +SYSCALL(ni_syscall) +COMPAT_SYS(mbind) +COMPAT_SYS(get_mempolicy) +COMPAT_SYS(set_mempolicy) +COMPAT_SYS(mq_open) +SYSCALL(mq_unlink) +COMPAT_SYS(mq_timedsend) +COMPAT_SYS(mq_timedreceive) +COMPAT_SYS(mq_notify) +COMPAT_SYS(mq_getsetattr) +COMPAT_SYS(kexec_load) +COMPAT_SYS(add_key) +COMPAT_SYS(request_key) +COMPAT_SYS(keyctl) +COMPAT_SYS(waitid) +COMPAT_SYS(ioprio_set) +COMPAT_SYS(ioprio_get) +SYSCALL(inotify_init) +SYSCALL(inotify_add_watch) +SYSCALL(inotify_rm_watch) +SYSCALL(spu_run) +SYSCALL(spu_create) +COMPAT_SYS(pselect6) +COMPAT_SYS(ppoll) +SYSCALL_SPU(unshare) +SYSCALL_SPU(splice) +SYSCALL_SPU(tee) +SYSCALL_SPU(vmsplice) +COMPAT_SYS_SPU(openat) +SYSCALL_SPU(mkdirat) +SYSCALL_SPU(mknodat) +SYSCALL_SPU(fchownat) +COMPAT_SYS_SPU(futimesat) +SYSX_SPU(sys_newfstatat, sys_fstatat64, sys_fstatat64) +SYSCALL_SPU(unlinkat) +SYSCALL_SPU(renameat) +SYSCALL_SPU(linkat) +SYSCALL_SPU(symlinkat) +SYSCALL_SPU(readlinkat) +SYSCALL_SPU(fchmodat) +SYSCALL_SPU(faccessat) +COMPAT_SYS_SPU(get_robust_list) +COMPAT_SYS_SPU(set_robust_list) -- cgit v1.2.3 From ddf5f75a16b3e7460ffee881795aa168dffcd0cf Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 20 Jun 2006 02:30:33 +0200 Subject: [POWERPC] disable floating point exceptions for init Floating point exceptions should not be enabled by default, as this setting impacts the performance on some CPUs, in particular the Cell BE. Since the bits are inherited from parent processes, the place to change the default is the thread struct used for init. glibc sets this up correctly per thread in its fesetenv function, so user space should not be impacted by this setting. None of the other common libc implementations (uClibc, dietlibc, newlib, klibc) has support for fp exceptions, so they are unlikely to be hit by this either. There is a small risk that somebody wrote their own application that manually sets the fpscr bits instead of calling fesetenv, without changing the MSR bits as well. Those programs will break with this change. It probably makes sense to change glibc in the future to be more clever about FE bits, so that when running on a CPU where this is expensive, it disables exceptions ASAP, while it keeps them enabled on CPUs where running with exceptions on is cheaper than changing the state often. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- include/asm-powerpc/processor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/asm-powerpc/processor.h b/include/asm-powerpc/processor.h index d2c2c95f913b..22e54a2a6604 100644 --- a/include/asm-powerpc/processor.h +++ b/include/asm-powerpc/processor.h @@ -190,7 +190,7 @@ struct thread_struct { .fs = KERNEL_DS, \ .fpr = {0}, \ .fpscr = { .val = 0, }, \ - .fpexc_mode = MSR_FE0|MSR_FE1, \ + .fpexc_mode = 0, \ } #endif -- cgit v1.2.3 From 1e92a550e80fef01ebcc0bcd0896109cdb986c72 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Thu, 15 Jun 2006 14:11:22 +1000 Subject: [POWERPC] Fix mdelay badness on shared processor partitions On partitioned PPC64 systems where a partition is given 1/10 of a processor, we have seen mdelay() delaying for 10 times longer than it should. The reason is that the generic mdelay(n) does n delays of 1 millisecond each. However, with 1/10 of a processor, we only get a one-millisecond timeslice every 10ms. Thus each 1 millisecond delay loop ends up taking 10ms elapsed time. The solution is just to use the PPC64 udelay function, which uses the timebase to ensure that the delay is based on elapsed time rather than how much processing time the partition has been given. (Yes, the generic mdelay uses the PPC64 udelay, but the problem is that the start time gets reset every millisecond, and each time it gets reset we lose another 9ms.) Signed-off-by: Anton Blanchard Signed-off-by: Paul Mackerras Acked-by: Andrew Morton --- include/asm-powerpc/delay.h | 13 +++++++++++++ include/linux/delay.h | 5 +---- 2 files changed, 14 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/asm-powerpc/delay.h b/include/asm-powerpc/delay.h index 057a60955474..f9200a65c632 100644 --- a/include/asm-powerpc/delay.h +++ b/include/asm-powerpc/delay.h @@ -17,5 +17,18 @@ extern void __delay(unsigned long loops); extern void udelay(unsigned long usecs); +/* + * On shared processor machines the generic implementation of mdelay can + * result in large errors. While each iteration of the loop inside mdelay + * is supposed to take 1ms, the hypervisor could sleep our partition for + * longer (eg 10ms). With the right timing these errors can add up. + * + * Since there is no 32bit overflow issue on 64bit kernels, just call + * udelay directly. + */ +#ifdef CONFIG_PPC64 +#define mdelay(n) udelay((n) * 1000) +#endif + #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_DELAY_H */ diff --git a/include/linux/delay.h b/include/linux/delay.h index acb74865b973..17ddb55430ae 100644 --- a/include/linux/delay.h +++ b/include/linux/delay.h @@ -25,10 +25,7 @@ extern unsigned long loops_per_jiffy; #define MAX_UDELAY_MS 5 #endif -#ifdef notdef -#define mdelay(n) (\ - {unsigned long __ms=(n); while (__ms--) udelay(1000);}) -#else +#ifndef mdelay #define mdelay(n) (\ (__builtin_constant_p(n) && (n)<=MAX_UDELAY_MS) ? udelay((n)*1000) : \ ({unsigned long __ms=(n); while (__ms--) udelay(1000);})) -- cgit v1.2.3 From c34b4c734482dda750deb6089521f7c891b48736 Mon Sep 17 00:00:00 2001 From: Brice Goglin Date: Tue, 9 May 2006 10:52:09 -0700 Subject: [PATCH] PCI: Add PCI_CAP_ID_VNDR Add the vendor-specific extended capability PCI_CAP_ID_VNDR. It will be used by the Myri-10G Ethernet driver (will be submitted soon). Signed-off-by: Brice Goglin Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- include/linux/pci_regs.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h index d27a78b71297..6bce4a240364 100644 --- a/include/linux/pci_regs.h +++ b/include/linux/pci_regs.h @@ -197,6 +197,7 @@ #define PCI_CAP_ID_CHSWP 0x06 /* CompactPCI HotSwap */ #define PCI_CAP_ID_PCIX 0x07 /* PCI-X */ #define PCI_CAP_ID_HT_IRQCONF 0x08 /* HyperTransport IRQ Configuration */ +#define PCI_CAP_ID_VNDR 0x09 /* Vendor specific capability */ #define PCI_CAP_ID_SHPC 0x0C /* PCI Standard Hot-Plug Controller */ #define PCI_CAP_ID_EXP 0x10 /* PCI Express */ #define PCI_CAP_ID_MSIX 0x11 /* MSI-X */ -- cgit v1.2.3 From fd58e55fcf5568e51da2ed54d7acd049c3fdb184 Mon Sep 17 00:00:00 2001 From: Mark Maule Date: Mon, 10 Apr 2006 21:17:48 -0500 Subject: [PATCH] PCI: msi abstractions and support for altix Abstract portions of the MSI core for platforms that do not use standard APIC interrupt controllers. This is implemented through a new arch-specific msi setup routine, and a set of msi ops which can be set on a per platform basis. Signed-off-by: Mark Maule Signed-off-by: Greg Kroah-Hartman --- drivers/pci/Makefile | 6 +- drivers/pci/msi-altix.c | 18 ++++ drivers/pci/msi-apic.c | 100 +++++++++++++++++++ drivers/pci/msi.c | 212 +++++++++++++++++++++++++---------------- drivers/pci/msi.h | 133 ++++++++++++++------------ include/asm-i386/msi.h | 8 ++ include/asm-ia64/machvec.h | 7 ++ include/asm-ia64/machvec_sn2.h | 7 ++ include/asm-ia64/msi.h | 12 +++ include/asm-x86_64/msi.h | 8 ++ 10 files changed, 367 insertions(+), 144 deletions(-) create mode 100644 drivers/pci/msi-altix.c create mode 100644 drivers/pci/msi-apic.c (limited to 'include') diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 6707df968934..f2d152b818f0 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -26,7 +26,11 @@ obj-$(CONFIG_PPC32) += setup-irq.o obj-$(CONFIG_PPC64) += setup-bus.o obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o obj-$(CONFIG_X86_VISWS) += setup-irq.o -obj-$(CONFIG_PCI_MSI) += msi.o + +msiobj-y := msi.o msi-apic.o +msiobj-$(CONFIG_IA64_GENERIC) += msi-altix.o +msiobj-$(CONFIG_IA64_SGI_SN2) += msi-altix.o +obj-$(CONFIG_PCI_MSI) += $(msiobj-y) # # ACPI Related PCI FW Functions diff --git a/drivers/pci/msi-altix.c b/drivers/pci/msi-altix.c new file mode 100644 index 000000000000..9bd240602c1e --- /dev/null +++ b/drivers/pci/msi-altix.c @@ -0,0 +1,18 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2006 Silicon Graphics, Inc. All Rights Reserved. + */ + +#include + +int +sn_msi_init(void) +{ + /* + * return error until MSI is supported on altix platforms + */ + return -EINVAL; +} diff --git a/drivers/pci/msi-apic.c b/drivers/pci/msi-apic.c new file mode 100644 index 000000000000..0eb5fe9003a2 --- /dev/null +++ b/drivers/pci/msi-apic.c @@ -0,0 +1,100 @@ +/* + * MSI hooks for standard x86 apic + */ + +#include +#include + +#include "msi.h" + +/* + * Shifts for APIC-based data + */ + +#define MSI_DATA_VECTOR_SHIFT 0 +#define MSI_DATA_VECTOR(v) (((u8)v) << MSI_DATA_VECTOR_SHIFT) + +#define MSI_DATA_DELIVERY_SHIFT 8 +#define MSI_DATA_DELIVERY_FIXED (0 << MSI_DATA_DELIVERY_SHIFT) +#define MSI_DATA_DELIVERY_LOWPRI (1 << MSI_DATA_DELIVERY_SHIFT) + +#define MSI_DATA_LEVEL_SHIFT 14 +#define MSI_DATA_LEVEL_DEASSERT (0 << MSI_DATA_LEVEL_SHIFT) +#define MSI_DATA_LEVEL_ASSERT (1 << MSI_DATA_LEVEL_SHIFT) + +#define MSI_DATA_TRIGGER_SHIFT 15 +#define MSI_DATA_TRIGGER_EDGE (0 << MSI_DATA_TRIGGER_SHIFT) +#define MSI_DATA_TRIGGER_LEVEL (1 << MSI_DATA_TRIGGER_SHIFT) + +/* + * Shift/mask fields for APIC-based bus address + */ + +#define MSI_ADDR_HEADER 0xfee00000 + +#define MSI_ADDR_DESTID_MASK 0xfff0000f +#define MSI_ADDR_DESTID_CPU(cpu) ((cpu) << MSI_TARGET_CPU_SHIFT) + +#define MSI_ADDR_DESTMODE_SHIFT 2 +#define MSI_ADDR_DESTMODE_PHYS (0 << MSI_ADDR_DESTMODE_SHIFT) +#define MSI_ADDR_DESTMODE_LOGIC (1 << MSI_ADDR_DESTMODE_SHIFT) + +#define MSI_ADDR_REDIRECTION_SHIFT 3 +#define MSI_ADDR_REDIRECTION_CPU (0 << MSI_ADDR_REDIRECTION_SHIFT) +#define MSI_ADDR_REDIRECTION_LOWPRI (1 << MSI_ADDR_REDIRECTION_SHIFT) + + +static void +msi_target_apic(unsigned int vector, + unsigned int dest_cpu, + u32 *address_hi, /* in/out */ + u32 *address_lo) /* in/out */ +{ + u32 addr = *address_lo; + + addr &= MSI_ADDR_DESTID_MASK; + addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(dest_cpu)); + + *address_lo = addr; +} + +static int +msi_setup_apic(struct pci_dev *pdev, /* unused in generic */ + unsigned int vector, + u32 *address_hi, + u32 *address_lo, + u32 *data) +{ + unsigned long dest_phys_id; + + dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map)); + + *address_hi = 0; + *address_lo = MSI_ADDR_HEADER | + MSI_ADDR_DESTMODE_PHYS | + MSI_ADDR_REDIRECTION_CPU | + MSI_ADDR_DESTID_CPU(dest_phys_id); + + *data = MSI_DATA_TRIGGER_EDGE | + MSI_DATA_LEVEL_ASSERT | + MSI_DATA_DELIVERY_FIXED | + MSI_DATA_VECTOR(vector); + + return 0; +} + +static void +msi_teardown_apic(unsigned int vector) +{ + return; /* no-op */ +} + +/* + * Generic ops used on most IA archs/platforms. Set with msi_register() + */ + +struct msi_ops msi_apic_ops = { + .setup = msi_setup_apic, + .teardown = msi_teardown_apic, + .target = msi_target_apic, +}; diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 9855c4c920b8..55ff52df5fe7 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -23,8 +23,6 @@ #include "pci.h" #include "msi.h" -#define MSI_TARGET_CPU first_cpu(cpu_online_map) - static DEFINE_SPINLOCK(msi_lock); static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL }; static kmem_cache_t* msi_cachep; @@ -40,6 +38,15 @@ int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1}; u8 irq_vector[NR_IRQ_VECTORS] = { FIRST_DEVICE_VECTOR , 0 }; #endif +static struct msi_ops *msi_ops; + +int +msi_register(struct msi_ops *ops) +{ + msi_ops = ops; + return 0; +} + static void msi_cache_ctor(void *p, kmem_cache_t *cache, unsigned long flags) { memset(p, 0, NR_IRQS * sizeof(struct msi_desc)); @@ -92,7 +99,7 @@ static void msi_set_mask_bit(unsigned int vector, int flag) static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask) { struct msi_desc *entry; - struct msg_address address; + u32 address_hi, address_lo; unsigned int irq = vector; unsigned int dest_cpu = first_cpu(cpu_mask); @@ -108,28 +115,36 @@ static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask) if (!pos) return; + pci_read_config_dword(entry->dev, msi_upper_address_reg(pos), + &address_hi); pci_read_config_dword(entry->dev, msi_lower_address_reg(pos), - &address.lo_address.value); - address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK; - address.lo_address.value |= (cpu_physical_id(dest_cpu) << - MSI_TARGET_CPU_SHIFT); - entry->msi_attrib.current_cpu = cpu_physical_id(dest_cpu); + &address_lo); + + msi_ops->target(vector, dest_cpu, &address_hi, &address_lo); + + pci_write_config_dword(entry->dev, msi_upper_address_reg(pos), + address_hi); pci_write_config_dword(entry->dev, msi_lower_address_reg(pos), - address.lo_address.value); + address_lo); set_native_irq_info(irq, cpu_mask); break; } case PCI_CAP_ID_MSIX: { - int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + - PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET; - - address.lo_address.value = readl(entry->mask_base + offset); - address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK; - address.lo_address.value |= (cpu_physical_id(dest_cpu) << - MSI_TARGET_CPU_SHIFT); - entry->msi_attrib.current_cpu = cpu_physical_id(dest_cpu); - writel(address.lo_address.value, entry->mask_base + offset); + int offset_hi = + entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET; + int offset_lo = + entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET; + + address_hi = readl(entry->mask_base + offset_hi); + address_lo = readl(entry->mask_base + offset_lo); + + msi_ops->target(vector, dest_cpu, &address_hi, &address_lo); + + writel(address_hi, entry->mask_base + offset_hi); + writel(address_lo, entry->mask_base + offset_lo); set_native_irq_info(irq, cpu_mask); break; } @@ -251,30 +266,6 @@ static struct hw_interrupt_type msi_irq_wo_maskbit_type = { .set_affinity = set_msi_affinity }; -static void msi_data_init(struct msg_data *msi_data, - unsigned int vector) -{ - memset(msi_data, 0, sizeof(struct msg_data)); - msi_data->vector = (u8)vector; - msi_data->delivery_mode = MSI_DELIVERY_MODE; - msi_data->level = MSI_LEVEL_MODE; - msi_data->trigger = MSI_TRIGGER_MODE; -} - -static void msi_address_init(struct msg_address *msi_address) -{ - unsigned int dest_id; - unsigned long dest_phys_id = cpu_physical_id(MSI_TARGET_CPU); - - memset(msi_address, 0, sizeof(struct msg_address)); - msi_address->hi_address = (u32)0; - dest_id = (MSI_ADDRESS_HEADER << MSI_ADDRESS_HEADER_SHIFT); - msi_address->lo_address.u.dest_mode = MSI_PHYSICAL_MODE; - msi_address->lo_address.u.redirection_hint = MSI_REDIRECTION_HINT_MODE; - msi_address->lo_address.u.dest_id = dest_id; - msi_address->lo_address.value |= (dest_phys_id << MSI_TARGET_CPU_SHIFT); -} - static int msi_free_vector(struct pci_dev* dev, int vector, int reassign); static int assign_msi_vector(void) { @@ -369,13 +360,29 @@ static int msi_init(void) return status; } + status = msi_arch_init(); + if (status < 0) { + pci_msi_enable = 0; + printk(KERN_WARNING + "PCI: MSI arch init failed. MSI disabled.\n"); + return status; + } + + if (! msi_ops) { + printk(KERN_WARNING + "PCI: MSI ops not registered. MSI disabled.\n"); + status = -EINVAL; + return status; + } + + last_alloc_vector = assign_irq_vector(AUTO_ASSIGN); status = msi_cache_init(); if (status < 0) { pci_msi_enable = 0; printk(KERN_WARNING "PCI: MSI cache init failed\n"); return status; } - last_alloc_vector = assign_irq_vector(AUTO_ASSIGN); + if (last_alloc_vector < 0) { pci_msi_enable = 0; printk(KERN_WARNING "PCI: No interrupt vectors available for MSI\n"); @@ -575,6 +582,8 @@ void pci_restore_msi_state(struct pci_dev *dev) int pci_save_msix_state(struct pci_dev *dev) { int pos; + int temp; + int vector, head, tail = 0; u16 control; struct pci_cap_saved_state *save_state; @@ -582,6 +591,7 @@ int pci_save_msix_state(struct pci_dev *dev) if (pos <= 0 || dev->no_msi) return 0; + /* save the capability */ pci_read_config_word(dev, msi_control_reg(pos), &control); if (!(control & PCI_MSIX_FLAGS_ENABLE)) return 0; @@ -593,6 +603,38 @@ int pci_save_msix_state(struct pci_dev *dev) } *((u16 *)&save_state->data[0]) = control; + /* save the table */ + temp = dev->irq; + if (msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) { + kfree(save_state); + return -EINVAL; + } + + vector = head = dev->irq; + while (head != tail) { + int j; + void __iomem *base; + struct msi_desc *entry; + + entry = msi_desc[vector]; + base = entry->mask_base; + j = entry->msi_attrib.entry_nr; + + entry->address_lo_save = + readl(base + j * PCI_MSIX_ENTRY_SIZE + + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); + entry->address_hi_save = + readl(base + j * PCI_MSIX_ENTRY_SIZE + + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); + entry->data_save = + readl(base + j * PCI_MSIX_ENTRY_SIZE + + PCI_MSIX_ENTRY_DATA_OFFSET); + + tail = msi_desc[vector]->link.tail; + vector = tail; + } + dev->irq = temp; + disable_msi_mode(dev, pos, PCI_CAP_ID_MSIX); save_state->cap_nr = PCI_CAP_ID_MSIX; pci_add_saved_cap(dev, save_state); @@ -606,8 +648,6 @@ void pci_restore_msix_state(struct pci_dev *dev) int vector, head, tail = 0; void __iomem *base; int j; - struct msg_address address; - struct msg_data data; struct msi_desc *entry; int temp; struct pci_cap_saved_state *save_state; @@ -633,20 +673,13 @@ void pci_restore_msix_state(struct pci_dev *dev) base = entry->mask_base; j = entry->msi_attrib.entry_nr; - msi_address_init(&address); - msi_data_init(&data, vector); - - address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK; - address.lo_address.value |= entry->msi_attrib.current_cpu << - MSI_TARGET_CPU_SHIFT; - - writel(address.lo_address.value, + writel(entry->address_lo_save, base + j * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); - writel(address.hi_address, + writel(entry->address_hi_save, base + j * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); - writel(*(u32*)&data, + writel(entry->data_save, base + j * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_DATA_OFFSET); @@ -660,30 +693,32 @@ void pci_restore_msix_state(struct pci_dev *dev) } #endif -static void msi_register_init(struct pci_dev *dev, struct msi_desc *entry) +static int msi_register_init(struct pci_dev *dev, struct msi_desc *entry) { - struct msg_address address; - struct msg_data data; + int status; + u32 address_hi; + u32 address_lo; + u32 data; int pos, vector = dev->irq; u16 control; pos = pci_find_capability(dev, PCI_CAP_ID_MSI); pci_read_config_word(dev, msi_control_reg(pos), &control); + /* Configure MSI capability structure */ - msi_address_init(&address); - msi_data_init(&data, vector); - entry->msi_attrib.current_cpu = ((address.lo_address.u.dest_id >> - MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK); - pci_write_config_dword(dev, msi_lower_address_reg(pos), - address.lo_address.value); + status = msi_ops->setup(dev, vector, &address_hi, &address_lo, &data); + if (status < 0) + return status; + + pci_write_config_dword(dev, msi_lower_address_reg(pos), address_lo); if (is_64bit_address(control)) { pci_write_config_dword(dev, - msi_upper_address_reg(pos), address.hi_address); + msi_upper_address_reg(pos), address_hi); pci_write_config_word(dev, - msi_data_reg(pos, 1), *((u32*)&data)); + msi_data_reg(pos, 1), data); } else pci_write_config_word(dev, - msi_data_reg(pos, 0), *((u32*)&data)); + msi_data_reg(pos, 0), data); if (entry->msi_attrib.maskbit) { unsigned int maskbits, temp; /* All MSIs are unmasked by default, Mask them all */ @@ -697,6 +732,8 @@ static void msi_register_init(struct pci_dev *dev, struct msi_desc *entry) msi_mask_bits_reg(pos, is_64bit_address(control)), maskbits); } + + return 0; } /** @@ -710,6 +747,7 @@ static void msi_register_init(struct pci_dev *dev, struct msi_desc *entry) **/ static int msi_capability_init(struct pci_dev *dev) { + int status; struct msi_desc *entry; int pos, vector; u16 control; @@ -742,7 +780,12 @@ static int msi_capability_init(struct pci_dev *dev) /* Replace with MSI handler */ irq_handler_init(PCI_CAP_ID_MSI, vector, entry->msi_attrib.maskbit); /* Configure MSI capability structure */ - msi_register_init(dev, entry); + status = msi_register_init(dev, entry); + if (status != 0) { + dev->irq = entry->msi_attrib.default_vector; + kmem_cache_free(msi_cachep, entry); + return status; + } attach_msi_entry(entry, vector); /* Set MSI enabled bits */ @@ -765,8 +808,10 @@ static int msix_capability_init(struct pci_dev *dev, struct msix_entry *entries, int nvec) { struct msi_desc *head = NULL, *tail = NULL, *entry = NULL; - struct msg_address address; - struct msg_data data; + u32 address_hi; + u32 address_lo; + u32 data; + int status; int vector, pos, i, j, nr_entries, temp = 0; unsigned long phys_addr; u32 table_offset; @@ -822,18 +867,20 @@ static int msix_capability_init(struct pci_dev *dev, /* Replace with MSI-X handler */ irq_handler_init(PCI_CAP_ID_MSIX, vector, 1); /* Configure MSI-X capability structure */ - msi_address_init(&address); - msi_data_init(&data, vector); - entry->msi_attrib.current_cpu = - ((address.lo_address.u.dest_id >> - MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK); - writel(address.lo_address.value, + status = msi_ops->setup(dev, vector, + &address_hi, + &address_lo, + &data); + if (status < 0) + break; + + writel(address_lo, base + j * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); - writel(address.hi_address, + writel(address_hi, base + j * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); - writel(*(u32*)&data, + writel(data, base + j * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_DATA_OFFSET); attach_msi_entry(entry, vector); @@ -901,9 +948,10 @@ int pci_enable_msi(struct pci_dev* dev) vector_irq[dev->irq] = -1; nr_released_vectors--; spin_unlock_irqrestore(&msi_lock, flags); - msi_register_init(dev, msi_desc[dev->irq]); - enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); - return 0; + status = msi_register_init(dev, msi_desc[dev->irq]); + if (status == 0) + enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); + return status; } spin_unlock_irqrestore(&msi_lock, flags); dev->irq = temp; @@ -980,6 +1028,8 @@ static int msi_free_vector(struct pci_dev* dev, int vector, int reassign) void __iomem *base; unsigned long flags; + msi_ops->teardown(vector); + spin_lock_irqsave(&msi_lock, flags); entry = msi_desc[vector]; if (!entry || entry->dev != dev) { diff --git a/drivers/pci/msi.h b/drivers/pci/msi.h index 4ac52d441e47..56951c39d3a3 100644 --- a/drivers/pci/msi.h +++ b/drivers/pci/msi.h @@ -6,6 +6,68 @@ #ifndef MSI_H #define MSI_H +/* + * MSI operation vector. Used by the msi core code (drivers/pci/msi.c) + * to abstract platform-specific tasks relating to MSI address generation + * and resource management. + */ +struct msi_ops { + /** + * setup - generate an MSI bus address and data for a given vector + * @pdev: PCI device context (in) + * @vector: vector allocated by the msi core (in) + * @addr_hi: upper 32 bits of PCI bus MSI address (out) + * @addr_lo: lower 32 bits of PCI bus MSI address (out) + * @data: MSI data payload (out) + * + * Description: The setup op is used to generate a PCI bus addres and + * data which the msi core will program into the card MSI capability + * registers. The setup routine is responsible for picking an initial + * cpu to target the MSI at. The setup routine is responsible for + * examining pdev to determine the MSI capabilities of the card and + * generating a suitable address/data. The setup routine is + * responsible for allocating and tracking any system resources it + * needs to route the MSI to the cpu it picks, and for associating + * those resources with the passed in vector. + * + * Returns 0 if the MSI address/data was successfully setup. + **/ + + int (*setup) (struct pci_dev *pdev, unsigned int vector, + u32 *addr_hi, u32 *addr_lo, u32 *data); + + /** + * teardown - release resources allocated by setup + * @vector: vector context for resources (in) + * + * Description: The teardown op is used to release any resources + * that were allocated in the setup routine associated with the passed + * in vector. + **/ + + void (*teardown) (unsigned int vector); + + /** + * target - retarget an MSI at a different cpu + * @vector: vector context for resources (in) + * @cpu: new cpu to direct vector at (in) + * @addr_hi: new value of PCI bus upper 32 bits (in/out) + * @addr_lo: new value of PCI bus lower 32 bits (in/out) + * + * Description: The target op is used to redirect an MSI vector + * at a different cpu. addr_hi/addr_lo coming in are the existing + * values that the MSI core has programmed into the card. The + * target code is responsible for freeing any resources (if any) + * associated with the old address, and generating a new PCI bus + * addr_hi/addr_lo that will redirect the vector at the indicated cpu. + **/ + + void (*target) (unsigned int vector, unsigned int cpu, + u32 *addr_hi, u32 *addr_lo); +}; + +extern int msi_register(struct msi_ops *ops); + #include /* @@ -63,67 +125,6 @@ extern int pci_vector_resources(int last, int nr_released); #define msix_mask(address) (address | PCI_MSIX_FLAGS_BITMASK) #define msix_is_pending(address) (address & PCI_MSIX_FLAGS_PENDMASK) -/* - * MSI Defined Data Structures - */ -#define MSI_ADDRESS_HEADER 0xfee -#define MSI_ADDRESS_HEADER_SHIFT 12 -#define MSI_ADDRESS_HEADER_MASK 0xfff000 -#define MSI_ADDRESS_DEST_ID_MASK 0xfff0000f -#define MSI_TARGET_CPU_MASK 0xff -#define MSI_DELIVERY_MODE 0 -#define MSI_LEVEL_MODE 1 /* Edge always assert */ -#define MSI_TRIGGER_MODE 0 /* MSI is edge sensitive */ -#define MSI_PHYSICAL_MODE 0 -#define MSI_LOGICAL_MODE 1 -#define MSI_REDIRECTION_HINT_MODE 0 - -struct msg_data { -#if defined(__LITTLE_ENDIAN_BITFIELD) - __u32 vector : 8; - __u32 delivery_mode : 3; /* 000b: FIXED | 001b: lowest prior */ - __u32 reserved_1 : 3; - __u32 level : 1; /* 0: deassert | 1: assert */ - __u32 trigger : 1; /* 0: edge | 1: level */ - __u32 reserved_2 : 16; -#elif defined(__BIG_ENDIAN_BITFIELD) - __u32 reserved_2 : 16; - __u32 trigger : 1; /* 0: edge | 1: level */ - __u32 level : 1; /* 0: deassert | 1: assert */ - __u32 reserved_1 : 3; - __u32 delivery_mode : 3; /* 000b: FIXED | 001b: lowest prior */ - __u32 vector : 8; -#else -#error "Bitfield endianness not defined! Check your byteorder.h" -#endif -} __attribute__ ((packed)); - -struct msg_address { - union { - struct { -#if defined(__LITTLE_ENDIAN_BITFIELD) - __u32 reserved_1 : 2; - __u32 dest_mode : 1; /*0:physic | 1:logic */ - __u32 redirection_hint: 1; /*0: dedicated CPU - 1: lowest priority */ - __u32 reserved_2 : 4; - __u32 dest_id : 24; /* Destination ID */ -#elif defined(__BIG_ENDIAN_BITFIELD) - __u32 dest_id : 24; /* Destination ID */ - __u32 reserved_2 : 4; - __u32 redirection_hint: 1; /*0: dedicated CPU - 1: lowest priority */ - __u32 dest_mode : 1; /*0:physic | 1:logic */ - __u32 reserved_1 : 2; -#else -#error "Bitfield endianness not defined! Check your byteorder.h" -#endif - }u; - __u32 value; - }lo_address; - __u32 hi_address; -} __attribute__ ((packed)); - struct msi_desc { struct { __u8 type : 5; /* {0: unused, 5h:MSI, 11h:MSI-X} */ @@ -132,7 +133,7 @@ struct msi_desc { __u8 reserved: 1; /* reserved */ __u8 entry_nr; /* specific enabled entry */ __u8 default_vector; /* default pre-assigned vector */ - __u8 current_cpu; /* current destination cpu */ + __u8 unused; /* formerly unused destination cpu*/ }msi_attrib; struct { @@ -142,6 +143,14 @@ struct msi_desc { void __iomem *mask_base; struct pci_dev *dev; + +#ifdef CONFIG_PM + /* PM save area for MSIX address/data */ + + u32 address_hi_save; + u32 address_lo_save; + u32 data_save; +#endif }; #endif /* MSI_H */ diff --git a/include/asm-i386/msi.h b/include/asm-i386/msi.h index f041d4495faf..ed1014235e9c 100644 --- a/include/asm-i386/msi.h +++ b/include/asm-i386/msi.h @@ -12,4 +12,12 @@ #define LAST_DEVICE_VECTOR 232 #define MSI_TARGET_CPU_SHIFT 12 +extern struct msi_ops msi_apic_ops; + +static inline int msi_arch_init(void) +{ + msi_register(&msi_apic_ops); + return 0; +} + #endif /* ASM_MSI_H */ diff --git a/include/asm-ia64/machvec.h b/include/asm-ia64/machvec.h index 0df72a134c8b..15b545a897a4 100644 --- a/include/asm-ia64/machvec.h +++ b/include/asm-ia64/machvec.h @@ -75,6 +75,7 @@ typedef unsigned char ia64_mv_readb_relaxed_t (const volatile void __iomem *); typedef unsigned short ia64_mv_readw_relaxed_t (const volatile void __iomem *); typedef unsigned int ia64_mv_readl_relaxed_t (const volatile void __iomem *); typedef unsigned long ia64_mv_readq_relaxed_t (const volatile void __iomem *); +typedef int ia64_mv_msi_init_t (void); static inline void machvec_noop (void) @@ -153,6 +154,7 @@ extern void machvec_tlb_migrate_finish (struct mm_struct *); # define platform_readl_relaxed ia64_mv.readl_relaxed # define platform_readq_relaxed ia64_mv.readq_relaxed # define platform_migrate ia64_mv.migrate +# define platform_msi_init ia64_mv.msi_init # endif /* __attribute__((__aligned__(16))) is required to make size of the @@ -202,6 +204,7 @@ struct ia64_machine_vector { ia64_mv_readl_relaxed_t *readl_relaxed; ia64_mv_readq_relaxed_t *readq_relaxed; ia64_mv_migrate_t *migrate; + ia64_mv_msi_init_t *msi_init; } __attribute__((__aligned__(16))); /* align attrib? see above comment */ #define MACHVEC_INIT(name) \ @@ -247,6 +250,7 @@ struct ia64_machine_vector { platform_readl_relaxed, \ platform_readq_relaxed, \ platform_migrate, \ + platform_msi_init, \ } extern struct ia64_machine_vector ia64_mv; @@ -400,5 +404,8 @@ extern int ia64_pci_legacy_write(struct pci_bus *bus, u16 port, u32 val, u8 size #ifndef platform_migrate # define platform_migrate machvec_noop_task #endif +#ifndef platform_msi_init +# define platform_msi_init ((ia64_mv_msi_init_t*)NULL) +#endif #endif /* _ASM_IA64_MACHVEC_H */ diff --git a/include/asm-ia64/machvec_sn2.h b/include/asm-ia64/machvec_sn2.h index da1d43755afe..cf724dc79d8c 100644 --- a/include/asm-ia64/machvec_sn2.h +++ b/include/asm-ia64/machvec_sn2.h @@ -67,6 +67,8 @@ extern ia64_mv_dma_sync_sg_for_device sn_dma_sync_sg_for_device; extern ia64_mv_dma_mapping_error sn_dma_mapping_error; extern ia64_mv_dma_supported sn_dma_supported; extern ia64_mv_migrate_t sn_migrate; +extern ia64_mv_msi_init_t sn_msi_init; + /* * This stuff has dual use! @@ -117,6 +119,11 @@ extern ia64_mv_migrate_t sn_migrate; #define platform_dma_mapping_error sn_dma_mapping_error #define platform_dma_supported sn_dma_supported #define platform_migrate sn_migrate +#ifdef CONFIG_PCI_MSI +#define platform_msi_init sn_msi_init +#else +#define platform_msi_init ((ia64_mv_msi_init_t*)NULL) +#endif #include diff --git a/include/asm-ia64/msi.h b/include/asm-ia64/msi.h index 97890f7762b3..bb92b0dbde2f 100644 --- a/include/asm-ia64/msi.h +++ b/include/asm-ia64/msi.h @@ -14,4 +14,16 @@ static inline void set_intr_gate (int nr, void *func) {} #define ack_APIC_irq ia64_eoi #define MSI_TARGET_CPU_SHIFT 4 +extern struct msi_ops msi_apic_ops; + +static inline int msi_arch_init(void) +{ + if (platform_msi_init) + return platform_msi_init(); + + /* default ops for most ia64 platforms */ + msi_register(&msi_apic_ops); + return 0; +} + #endif /* ASM_MSI_H */ diff --git a/include/asm-x86_64/msi.h b/include/asm-x86_64/msi.h index 356e0e82f50b..8d6d6bf8fad5 100644 --- a/include/asm-x86_64/msi.h +++ b/include/asm-x86_64/msi.h @@ -13,4 +13,12 @@ #define LAST_DEVICE_VECTOR 232 #define MSI_TARGET_CPU_SHIFT 12 +extern struct msi_ops msi_apic_ops; + +static inline int msi_arch_init(void) +{ + msi_register(&msi_apic_ops); + return 0; +} + #endif /* ASM_MSI_H */ -- cgit v1.2.3 From 10083072bfabc40bc47306e512c158c57cf55c2e Mon Sep 17 00:00:00 2001 From: Mark Maule Date: Fri, 14 Apr 2006 16:03:49 -0500 Subject: [PATCH] PCI: per-platform IA64_{FIRST,LAST}_DEVICE_VECTOR definitions Abstract IA64_FIRST_DEVICE_VECTOR/IA64_LAST_DEVICE_VECTOR since SN platforms use a subset of the IA64 range. Implement this by making the above macros global variables which the platform can override in it setup code. Also add a reserve_irq_vector() routine used by SN to mark a vector's as in-use when that weren't allocated through assign_irq_vector(). Signed-off-by: Mark Maule Signed-off-by: Greg Kroah-Hartman --- arch/ia64/kernel/irq_ia64.c | 19 ++++++++++++++++++- arch/ia64/sn/kernel/irq.c | 7 +++++++ drivers/pci/msi.c | 6 +++++- include/asm-ia64/hw_irq.h | 15 +++++++++++++-- 4 files changed, 43 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c index 6c4d59fd0364..ef9a2b49307a 100644 --- a/arch/ia64/kernel/irq_ia64.c +++ b/arch/ia64/kernel/irq_ia64.c @@ -46,6 +46,10 @@ #define IRQ_DEBUG 0 +/* These can be overridden in platform_irq_init */ +int ia64_first_device_vector = IA64_DEF_FIRST_DEVICE_VECTOR; +int ia64_last_device_vector = IA64_DEF_LAST_DEVICE_VECTOR; + /* default base addr of IPI table */ void __iomem *ipi_base_addr = ((void __iomem *) (__IA64_UNCACHED_OFFSET | IA64_IPI_DEFAULT_BASE_ADDR)); @@ -60,7 +64,7 @@ __u8 isa_irq_to_vector_map[16] = { }; EXPORT_SYMBOL(isa_irq_to_vector_map); -static unsigned long ia64_vector_mask[BITS_TO_LONGS(IA64_NUM_DEVICE_VECTORS)]; +static unsigned long ia64_vector_mask[BITS_TO_LONGS(IA64_MAX_DEVICE_VECTORS)]; int assign_irq_vector (int irq) @@ -89,6 +93,19 @@ free_irq_vector (int vector) printk(KERN_WARNING "%s: double free!\n", __FUNCTION__); } +int +reserve_irq_vector (int vector) +{ + int pos; + + if (vector < IA64_FIRST_DEVICE_VECTOR || + vector > IA64_LAST_DEVICE_VECTOR) + return -EINVAL; + + pos = vector - IA64_FIRST_DEVICE_VECTOR; + return test_and_set_bit(pos, ia64_vector_mask); +} + #ifdef CONFIG_SMP # define IS_RESCHEDULE(vec) (vec == IA64_IPI_RESCHEDULE) #else diff --git a/arch/ia64/sn/kernel/irq.c b/arch/ia64/sn/kernel/irq.c index c265e02f5036..db187f5cdae1 100644 --- a/arch/ia64/sn/kernel/irq.c +++ b/arch/ia64/sn/kernel/irq.c @@ -202,6 +202,9 @@ void sn_irq_init(void) int i; irq_desc_t *base_desc = irq_desc; + ia64_first_device_vector = IA64_SN2_FIRST_DEVICE_VECTOR; + ia64_last_device_vector = IA64_SN2_LAST_DEVICE_VECTOR; + for (i = 0; i < NR_IRQS; i++) { if (base_desc[i].handler == &no_irq_type) { base_desc[i].handler = &irq_type_sn; @@ -285,6 +288,7 @@ void sn_irq_fixup(struct pci_dev *pci_dev, struct sn_irq_info *sn_irq_info) /* link it into the sn_irq[irq] list */ spin_lock(&sn_irq_info_lock); list_add_rcu(&sn_irq_info->list, sn_irq_lh[sn_irq_info->irq_irq]); + reserve_irq_vector(sn_irq_info->irq_irq); spin_unlock(&sn_irq_info_lock); register_intr_pda(sn_irq_info); @@ -310,8 +314,11 @@ void sn_irq_unfixup(struct pci_dev *pci_dev) spin_lock(&sn_irq_info_lock); list_del_rcu(&sn_irq_info->list); spin_unlock(&sn_irq_info_lock); + if (list_empty(sn_irq_lh[sn_irq_info->irq_irq])) + free_irq_vector(sn_irq_info->irq_irq); call_rcu(&sn_irq_info->rcu, sn_irq_info_free); pci_dev_put(pci_dev); + } static inline void diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 55ff52df5fe7..f8105783da2f 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -35,7 +35,7 @@ static int nr_msix_devices; #ifndef CONFIG_X86_IO_APIC int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1}; -u8 irq_vector[NR_IRQ_VECTORS] = { FIRST_DEVICE_VECTOR , 0 }; +u8 irq_vector[NR_IRQ_VECTORS]; #endif static struct msi_ops *msi_ops; @@ -383,6 +383,10 @@ static int msi_init(void) return status; } +#ifndef CONFIG_X86_IO_APIC + irq_vector[0] = FIRST_DEVICE_VECTOR; +#endif + if (last_alloc_vector < 0) { pci_msi_enable = 0; printk(KERN_WARNING "PCI: No interrupt vectors available for MSI\n"); diff --git a/include/asm-ia64/hw_irq.h b/include/asm-ia64/hw_irq.h index 0cf119b42f7d..ea8b8c407ab4 100644 --- a/include/asm-ia64/hw_irq.h +++ b/include/asm-ia64/hw_irq.h @@ -47,9 +47,19 @@ typedef u8 ia64_vector; #define IA64_CMC_VECTOR 0x1f /* corrected machine-check interrupt vector */ /* * Vectors 0x20-0x2f are reserved for legacy ISA IRQs. + * Use vectors 0x30-0xe7 as the default device vector range for ia64. + * Platforms may choose to reduce this range in platform_irq_setup, but the + * platform range must fall within + * [IA64_DEF_FIRST_DEVICE_VECTOR..IA64_DEF_LAST_DEVICE_VECTOR] */ -#define IA64_FIRST_DEVICE_VECTOR 0x30 -#define IA64_LAST_DEVICE_VECTOR 0xe7 +extern int ia64_first_device_vector; +extern int ia64_last_device_vector; + +#define IA64_DEF_FIRST_DEVICE_VECTOR 0x30 +#define IA64_DEF_LAST_DEVICE_VECTOR 0xe7 +#define IA64_FIRST_DEVICE_VECTOR ia64_first_device_vector +#define IA64_LAST_DEVICE_VECTOR ia64_last_device_vector +#define IA64_MAX_DEVICE_VECTORS (IA64_DEF_LAST_DEVICE_VECTOR - IA64_DEF_FIRST_DEVICE_VECTOR + 1) #define IA64_NUM_DEVICE_VECTORS (IA64_LAST_DEVICE_VECTOR - IA64_FIRST_DEVICE_VECTOR + 1) #define IA64_MCA_RENDEZ_VECTOR 0xe8 /* MCA rendez interrupt */ @@ -83,6 +93,7 @@ extern struct hw_interrupt_type irq_type_ia64_lsapic; /* CPU-internal interrupt extern int assign_irq_vector (int irq); /* allocate a free vector */ extern void free_irq_vector (int vector); +extern int reserve_irq_vector (int vector); extern void ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect); extern void register_percpu_irq (ia64_vector vec, struct irqaction *action); -- cgit v1.2.3 From 83821d3f558dc651e555d62182ed0c95651f41a6 Mon Sep 17 00:00:00 2001 From: Mark Maule Date: Fri, 14 Apr 2006 16:03:54 -0500 Subject: [PATCH] PCI: altix: msi support MSI callouts for altix. Involves a fair amount of code reorg in sn irq.c code as well as adding some extensions to the altix PCI provider abstaction. Signed-off-by: Mark Maule Signed-off-by: Greg Kroah-Hartman --- arch/ia64/sn/kernel/io_init.c | 9 +- arch/ia64/sn/kernel/irq.c | 135 ++++++++++--------- arch/ia64/sn/pci/pci_dma.c | 10 +- arch/ia64/sn/pci/pcibr/pcibr_dma.c | 62 ++++++--- arch/ia64/sn/pci/tioca_provider.c | 8 +- arch/ia64/sn/pci/tioce_provider.c | 65 ++++++---- drivers/pci/msi-altix.c | 200 ++++++++++++++++++++++++++++- include/asm-ia64/sn/intr.h | 8 ++ include/asm-ia64/sn/pcibr_provider.h | 5 +- include/asm-ia64/sn/pcibus_provider_defs.h | 17 ++- include/asm-ia64/sn/tiocp.h | 3 +- 11 files changed, 401 insertions(+), 121 deletions(-) (limited to 'include') diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c index 5101ac462643..dc09a6a28a37 100644 --- a/arch/ia64/sn/kernel/io_init.c +++ b/arch/ia64/sn/kernel/io_init.c @@ -58,7 +58,7 @@ static int max_pcibus_number = 255; /* Default highest pci bus number */ */ static dma_addr_t -sn_default_pci_map(struct pci_dev *pdev, unsigned long paddr, size_t size) +sn_default_pci_map(struct pci_dev *pdev, unsigned long paddr, size_t size, int type) { return 0; } @@ -457,13 +457,6 @@ void sn_pci_fixup_slot(struct pci_dev *dev) pcidev_info->pdi_sn_irq_info = NULL; kfree(sn_irq_info); } - - /* - * MSI currently not supported on altix. Remove this when - * the MSI abstraction patches are integrated into the kernel - * (sometime after 2.6.16 releases) - */ - dev->no_msi = 1; } /* diff --git a/arch/ia64/sn/kernel/irq.c b/arch/ia64/sn/kernel/irq.c index db187f5cdae1..dc8e2b696713 100644 --- a/arch/ia64/sn/kernel/irq.c +++ b/arch/ia64/sn/kernel/irq.c @@ -26,11 +26,11 @@ static void unregister_intr_pda(struct sn_irq_info *sn_irq_info); int sn_force_interrupt_flag = 1; extern int sn_ioif_inited; -static struct list_head **sn_irq_lh; +struct list_head **sn_irq_lh; static spinlock_t sn_irq_info_lock = SPIN_LOCK_UNLOCKED; /* non-IRQ lock */ -static inline u64 sn_intr_alloc(nasid_t local_nasid, int local_widget, - u64 sn_irq_info, +u64 sn_intr_alloc(nasid_t local_nasid, int local_widget, + struct sn_irq_info *sn_irq_info, int req_irq, nasid_t req_nasid, int req_slice) { @@ -40,12 +40,13 @@ static inline u64 sn_intr_alloc(nasid_t local_nasid, int local_widget, SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_INTERRUPT, (u64) SAL_INTR_ALLOC, (u64) local_nasid, - (u64) local_widget, (u64) sn_irq_info, (u64) req_irq, + (u64) local_widget, __pa(sn_irq_info), (u64) req_irq, (u64) req_nasid, (u64) req_slice); + return ret_stuff.status; } -static inline void sn_intr_free(nasid_t local_nasid, int local_widget, +void sn_intr_free(nasid_t local_nasid, int local_widget, struct sn_irq_info *sn_irq_info) { struct ia64_sal_retval ret_stuff; @@ -112,73 +113,91 @@ static void sn_end_irq(unsigned int irq) static void sn_irq_info_free(struct rcu_head *head); -static void sn_set_affinity_irq(unsigned int irq, cpumask_t mask) +struct sn_irq_info *sn_retarget_vector(struct sn_irq_info *sn_irq_info, + nasid_t nasid, int slice) { - struct sn_irq_info *sn_irq_info, *sn_irq_info_safe; - int cpuid, cpuphys; + int vector; + int cpuphys; + int64_t bridge; + int local_widget, status; + nasid_t local_nasid; + struct sn_irq_info *new_irq_info; + struct sn_pcibus_provider *pci_provider; - cpuid = first_cpu(mask); - cpuphys = cpu_physical_id(cpuid); + new_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_ATOMIC); + if (new_irq_info == NULL) + return NULL; - list_for_each_entry_safe(sn_irq_info, sn_irq_info_safe, - sn_irq_lh[irq], list) { - u64 bridge; - int local_widget, status; - nasid_t local_nasid; - struct sn_irq_info *new_irq_info; - struct sn_pcibus_provider *pci_provider; - - new_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_ATOMIC); - if (new_irq_info == NULL) - break; - memcpy(new_irq_info, sn_irq_info, sizeof(struct sn_irq_info)); - - bridge = (u64) new_irq_info->irq_bridge; - if (!bridge) { - kfree(new_irq_info); - break; /* irq is not a device interrupt */ - } + memcpy(new_irq_info, sn_irq_info, sizeof(struct sn_irq_info)); - local_nasid = NASID_GET(bridge); + bridge = (u64) new_irq_info->irq_bridge; + if (!bridge) { + kfree(new_irq_info); + return NULL; /* irq is not a device interrupt */ + } - if (local_nasid & 1) - local_widget = TIO_SWIN_WIDGETNUM(bridge); - else - local_widget = SWIN_WIDGETNUM(bridge); + local_nasid = NASID_GET(bridge); - /* Free the old PROM new_irq_info structure */ - sn_intr_free(local_nasid, local_widget, new_irq_info); - /* Update kernels new_irq_info with new target info */ - unregister_intr_pda(new_irq_info); + if (local_nasid & 1) + local_widget = TIO_SWIN_WIDGETNUM(bridge); + else + local_widget = SWIN_WIDGETNUM(bridge); - /* allocate a new PROM new_irq_info struct */ - status = sn_intr_alloc(local_nasid, local_widget, - __pa(new_irq_info), irq, - cpuid_to_nasid(cpuid), - cpuid_to_slice(cpuid)); + vector = sn_irq_info->irq_irq; + /* Free the old PROM new_irq_info structure */ + sn_intr_free(local_nasid, local_widget, new_irq_info); + /* Update kernels new_irq_info with new target info */ + unregister_intr_pda(new_irq_info); - /* SAL call failed */ - if (status) { - kfree(new_irq_info); - break; - } + /* allocate a new PROM new_irq_info struct */ + status = sn_intr_alloc(local_nasid, local_widget, + new_irq_info, vector, + nasid, slice); + + /* SAL call failed */ + if (status) { + kfree(new_irq_info); + return NULL; + } - new_irq_info->irq_cpuid = cpuid; - register_intr_pda(new_irq_info); + cpuphys = nasid_slice_to_cpuid(nasid, slice); + new_irq_info->irq_cpuid = cpuphys; + register_intr_pda(new_irq_info); - pci_provider = sn_pci_provider[new_irq_info->irq_bridge_type]; - if (pci_provider && pci_provider->target_interrupt) - (pci_provider->target_interrupt)(new_irq_info); + pci_provider = sn_pci_provider[new_irq_info->irq_bridge_type]; + + /* + * If this represents a line interrupt, target it. If it's + * an msi (irq_int_bit < 0), it's already targeted. + */ + if (new_irq_info->irq_int_bit >= 0 && + pci_provider && pci_provider->target_interrupt) + (pci_provider->target_interrupt)(new_irq_info); - spin_lock(&sn_irq_info_lock); - list_replace_rcu(&sn_irq_info->list, &new_irq_info->list); - spin_unlock(&sn_irq_info_lock); - call_rcu(&sn_irq_info->rcu, sn_irq_info_free); + spin_lock(&sn_irq_info_lock); + list_replace_rcu(&sn_irq_info->list, &new_irq_info->list); + spin_unlock(&sn_irq_info_lock); + call_rcu(&sn_irq_info->rcu, sn_irq_info_free); #ifdef CONFIG_SMP - set_irq_affinity_info((irq & 0xff), cpuphys, 0); + set_irq_affinity_info((vector & 0xff), cpuphys, 0); #endif - } + + return new_irq_info; +} + +static void sn_set_affinity_irq(unsigned int irq, cpumask_t mask) +{ + struct sn_irq_info *sn_irq_info, *sn_irq_info_safe; + nasid_t nasid; + int slice; + + nasid = cpuid_to_nasid(first_cpu(mask)); + slice = cpuid_to_slice(first_cpu(mask)); + + list_for_each_entry_safe(sn_irq_info, sn_irq_info_safe, + sn_irq_lh[irq], list) + (void)sn_retarget_vector(sn_irq_info, nasid, slice); } struct hw_interrupt_type irq_type_sn = { diff --git a/arch/ia64/sn/pci/pci_dma.c b/arch/ia64/sn/pci/pci_dma.c index b4b84c269210..7a291a271511 100644 --- a/arch/ia64/sn/pci/pci_dma.c +++ b/arch/ia64/sn/pci/pci_dma.c @@ -11,7 +11,7 @@ #include #include -#include +#include #include #include #include @@ -113,7 +113,8 @@ void *sn_dma_alloc_coherent(struct device *dev, size_t size, * resources. */ - *dma_handle = provider->dma_map_consistent(pdev, phys_addr, size); + *dma_handle = provider->dma_map_consistent(pdev, phys_addr, size, + SN_DMA_ADDR_PHYS); if (!*dma_handle) { printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__); free_pages((unsigned long)cpuaddr, get_order(size)); @@ -176,7 +177,7 @@ dma_addr_t sn_dma_map_single(struct device *dev, void *cpu_addr, size_t size, BUG_ON(dev->bus != &pci_bus_type); phys_addr = __pa(cpu_addr); - dma_addr = provider->dma_map(pdev, phys_addr, size); + dma_addr = provider->dma_map(pdev, phys_addr, size, SN_DMA_ADDR_PHYS); if (!dma_addr) { printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__); return 0; @@ -260,7 +261,8 @@ int sn_dma_map_sg(struct device *dev, struct scatterlist *sg, int nhwentries, for (i = 0; i < nhwentries; i++, sg++) { phys_addr = SG_ENT_PHYS_ADDRESS(sg); sg->dma_address = provider->dma_map(pdev, - phys_addr, sg->length); + phys_addr, sg->length, + SN_DMA_ADDR_PHYS); if (!sg->dma_address) { printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__); diff --git a/arch/ia64/sn/pci/pcibr/pcibr_dma.c b/arch/ia64/sn/pci/pcibr/pcibr_dma.c index 9f86bb6519aa..a86c7b945962 100644 --- a/arch/ia64/sn/pci/pcibr/pcibr_dma.c +++ b/arch/ia64/sn/pci/pcibr/pcibr_dma.c @@ -41,7 +41,7 @@ extern int sn_ioif_inited; static dma_addr_t pcibr_dmamap_ate32(struct pcidev_info *info, - u64 paddr, size_t req_size, u64 flags) + u64 paddr, size_t req_size, u64 flags, int dma_flags) { struct pcidev_info *pcidev_info = info->pdi_host_pcidev_info; @@ -81,9 +81,12 @@ pcibr_dmamap_ate32(struct pcidev_info *info, if (IS_PCIX(pcibus_info)) ate_flags &= ~(PCI32_ATE_PREF); - xio_addr = - IS_PIC_SOFT(pcibus_info) ? PHYS_TO_DMA(paddr) : - PHYS_TO_TIODMA(paddr); + if (SN_DMA_ADDRTYPE(dma_flags == SN_DMA_ADDR_PHYS)) + xio_addr = IS_PIC_SOFT(pcibus_info) ? PHYS_TO_DMA(paddr) : + PHYS_TO_TIODMA(paddr); + else + xio_addr = paddr; + offset = IOPGOFF(xio_addr); ate = ate_flags | (xio_addr - offset); @@ -91,6 +94,13 @@ pcibr_dmamap_ate32(struct pcidev_info *info, if (IS_PIC_SOFT(pcibus_info)) { ate |= (pcibus_info->pbi_hub_xid << PIC_ATE_TARGETID_SHFT); } + + /* + * If we're mapping for MSI, set the MSI bit in the ATE + */ + if (dma_flags & SN_DMA_MSI) + ate |= PCI32_ATE_MSI; + ate_write(pcibus_info, ate_index, ate_count, ate); /* @@ -105,20 +115,27 @@ pcibr_dmamap_ate32(struct pcidev_info *info, if (pcibus_info->pbi_devreg[internal_device] & PCIBR_DEV_SWAP_DIR) ATE_SWAP_ON(pci_addr); + return pci_addr; } static dma_addr_t pcibr_dmatrans_direct64(struct pcidev_info * info, u64 paddr, - u64 dma_attributes) + u64 dma_attributes, int dma_flags) { struct pcibus_info *pcibus_info = (struct pcibus_info *) ((info->pdi_host_pcidev_info)->pdi_pcibus_info); u64 pci_addr; /* Translate to Crosstalk View of Physical Address */ - pci_addr = (IS_PIC_SOFT(pcibus_info) ? PHYS_TO_DMA(paddr) : - PHYS_TO_TIODMA(paddr)) | dma_attributes; + if (SN_DMA_ADDRTYPE(dma_flags) == SN_DMA_ADDR_PHYS) + pci_addr = IS_PIC_SOFT(pcibus_info) ? + PHYS_TO_DMA(paddr) : + PHYS_TO_TIODMA(paddr) | dma_attributes; + else + pci_addr = IS_PIC_SOFT(pcibus_info) ? + paddr : + paddr | dma_attributes; /* Handle Bus mode */ if (IS_PCIX(pcibus_info)) @@ -130,7 +147,9 @@ pcibr_dmatrans_direct64(struct pcidev_info * info, u64 paddr, ((u64) pcibus_info-> pbi_hub_xid << PIC_PCI64_ATTR_TARG_SHFT); } else - pci_addr |= TIOCP_PCI64_CMDTYPE_MEM; + pci_addr |= (dma_flags & SN_DMA_MSI) ? + TIOCP_PCI64_CMDTYPE_MSI : + TIOCP_PCI64_CMDTYPE_MEM; /* If PCI mode, func zero uses VCHAN0, every other func uses VCHAN1 */ if (!IS_PCIX(pcibus_info) && PCI_FUNC(info->pdi_linux_pcidev->devfn)) @@ -141,7 +160,7 @@ pcibr_dmatrans_direct64(struct pcidev_info * info, u64 paddr, static dma_addr_t pcibr_dmatrans_direct32(struct pcidev_info * info, - u64 paddr, size_t req_size, u64 flags) + u64 paddr, size_t req_size, u64 flags, int dma_flags) { struct pcidev_info *pcidev_info = info->pdi_host_pcidev_info; struct pcibus_info *pcibus_info = (struct pcibus_info *)pcidev_info-> @@ -156,8 +175,14 @@ pcibr_dmatrans_direct32(struct pcidev_info * info, return 0; } - xio_addr = IS_PIC_SOFT(pcibus_info) ? PHYS_TO_DMA(paddr) : - PHYS_TO_TIODMA(paddr); + if (dma_flags & SN_DMA_MSI) + return 0; + + if (SN_DMA_ADDRTYPE(dma_flags) == SN_DMA_ADDR_PHYS) + xio_addr = IS_PIC_SOFT(pcibus_info) ? PHYS_TO_DMA(paddr) : + PHYS_TO_TIODMA(paddr); + else + xio_addr = paddr; xio_base = pcibus_info->pbi_dir_xbase; offset = xio_addr - xio_base; @@ -327,7 +352,7 @@ void sn_dma_flush(u64 addr) */ dma_addr_t -pcibr_dma_map(struct pci_dev * hwdev, unsigned long phys_addr, size_t size) +pcibr_dma_map(struct pci_dev * hwdev, unsigned long phys_addr, size_t size, int dma_flags) { dma_addr_t dma_handle; struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(hwdev); @@ -344,11 +369,11 @@ pcibr_dma_map(struct pci_dev * hwdev, unsigned long phys_addr, size_t size) */ dma_handle = pcibr_dmatrans_direct64(pcidev_info, phys_addr, - PCI64_ATTR_PREF); + PCI64_ATTR_PREF, dma_flags); } else { /* Handle 32-63 bit cards via direct mapping */ dma_handle = pcibr_dmatrans_direct32(pcidev_info, phys_addr, - size, 0); + size, 0, dma_flags); if (!dma_handle) { /* * It is a 32 bit card and we cannot do direct mapping, @@ -356,7 +381,8 @@ pcibr_dma_map(struct pci_dev * hwdev, unsigned long phys_addr, size_t size) */ dma_handle = pcibr_dmamap_ate32(pcidev_info, phys_addr, - size, PCI32_ATE_PREF); + size, PCI32_ATE_PREF, + dma_flags); } } @@ -365,18 +391,18 @@ pcibr_dma_map(struct pci_dev * hwdev, unsigned long phys_addr, size_t size) dma_addr_t pcibr_dma_map_consistent(struct pci_dev * hwdev, unsigned long phys_addr, - size_t size) + size_t size, int dma_flags) { dma_addr_t dma_handle; struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(hwdev); if (hwdev->dev.coherent_dma_mask == ~0UL) { dma_handle = pcibr_dmatrans_direct64(pcidev_info, phys_addr, - PCI64_ATTR_BAR); + PCI64_ATTR_BAR, dma_flags); } else { dma_handle = (dma_addr_t) pcibr_dmamap_ate32(pcidev_info, phys_addr, size, - PCI32_ATE_BAR); + PCI32_ATE_BAR, dma_flags); } return dma_handle; diff --git a/arch/ia64/sn/pci/tioca_provider.c b/arch/ia64/sn/pci/tioca_provider.c index be0176912968..20de72791b97 100644 --- a/arch/ia64/sn/pci/tioca_provider.c +++ b/arch/ia64/sn/pci/tioca_provider.c @@ -515,10 +515,16 @@ tioca_dma_unmap(struct pci_dev *pdev, dma_addr_t bus_addr, int dir) * use the GART mapped mode. */ static u64 -tioca_dma_map(struct pci_dev *pdev, u64 paddr, size_t byte_count) +tioca_dma_map(struct pci_dev *pdev, u64 paddr, size_t byte_count, int dma_flags) { u64 mapaddr; + /* + * Not supported for now ... + */ + if (dma_flags & SN_DMA_MSI) + return 0; + /* * If card is 64 or 48 bit addresable, use a direct mapping. 32 * bit direct is so restrictive w.r.t. where the memory resides that diff --git a/arch/ia64/sn/pci/tioce_provider.c b/arch/ia64/sn/pci/tioce_provider.c index 833295624e5d..4cac7bdc7c7f 100644 --- a/arch/ia64/sn/pci/tioce_provider.c +++ b/arch/ia64/sn/pci/tioce_provider.c @@ -170,7 +170,8 @@ tioce_mmr_war_post(struct tioce_kernel *kern, void *mmr_addr) (ATE_PAGE((start)+(len)-1, pagesize) - ATE_PAGE(start, pagesize) + 1) #define ATE_VALID(ate) ((ate) & (1UL << 63)) -#define ATE_MAKE(addr, ps) (((addr) & ~ATE_PAGEMASK(ps)) | (1UL << 63)) +#define ATE_MAKE(addr, ps, msi) \ + (((addr) & ~ATE_PAGEMASK(ps)) | (1UL << 63) | ((msi)?(1UL << 62):0)) /* * Flavors of ate-based mapping supported by tioce_alloc_map() @@ -196,15 +197,17 @@ tioce_mmr_war_post(struct tioce_kernel *kern, void *mmr_addr) * * 63 - must be 1 to indicate d64 mode to CE hardware * 62 - barrier bit ... controlled with tioce_dma_barrier() - * 61 - 0 since this is not an MSI transaction + * 61 - msi bit ... specified through dma_flags * 60:54 - reserved, MBZ */ static u64 -tioce_dma_d64(unsigned long ct_addr) +tioce_dma_d64(unsigned long ct_addr, int dma_flags) { u64 bus_addr; bus_addr = ct_addr | (1UL << 63); + if (dma_flags & SN_DMA_MSI) + bus_addr |= (1UL << 61); return bus_addr; } @@ -261,7 +264,7 @@ pcidev_to_tioce(struct pci_dev *pdev, struct tioce **base, */ static u64 tioce_alloc_map(struct tioce_kernel *ce_kern, int type, int port, - u64 ct_addr, int len) + u64 ct_addr, int len, int dma_flags) { int i; int j; @@ -270,6 +273,7 @@ tioce_alloc_map(struct tioce_kernel *ce_kern, int type, int port, int entries; int nates; u64 pagesize; + int msi_capable, msi_wanted; u64 *ate_shadow; u64 *ate_reg; u64 addr; @@ -291,6 +295,7 @@ tioce_alloc_map(struct tioce_kernel *ce_kern, int type, int port, ate_reg = ce_mmr->ce_ure_ate3240; pagesize = ce_kern->ce_ate3240_pagesize; bus_base = TIOCE_M32_MIN; + msi_capable = 1; break; case TIOCE_ATE_M40: first = 0; @@ -299,6 +304,7 @@ tioce_alloc_map(struct tioce_kernel *ce_kern, int type, int port, ate_reg = ce_mmr->ce_ure_ate40; pagesize = MB(64); bus_base = TIOCE_M40_MIN; + msi_capable = 0; break; case TIOCE_ATE_M40S: /* @@ -311,11 +317,16 @@ tioce_alloc_map(struct tioce_kernel *ce_kern, int type, int port, ate_reg = ce_mmr->ce_ure_ate3240; pagesize = GB(16); bus_base = TIOCE_M40S_MIN; + msi_capable = 0; break; default: return 0; } + msi_wanted = dma_flags & SN_DMA_MSI; + if (msi_wanted && !msi_capable) + return 0; + nates = ATE_NPAGES(ct_addr, len, pagesize); if (nates > entries) return 0; @@ -344,7 +355,7 @@ tioce_alloc_map(struct tioce_kernel *ce_kern, int type, int port, for (j = 0; j < nates; j++) { u64 ate; - ate = ATE_MAKE(addr, pagesize); + ate = ATE_MAKE(addr, pagesize, msi_wanted); ate_shadow[i + j] = ate; tioce_mmr_storei(ce_kern, &ate_reg[i + j], ate); addr += pagesize; @@ -371,7 +382,7 @@ tioce_alloc_map(struct tioce_kernel *ce_kern, int type, int port, * Map @paddr into 32-bit bus space of the CE associated with @pcidev_info. */ static u64 -tioce_dma_d32(struct pci_dev *pdev, u64 ct_addr) +tioce_dma_d32(struct pci_dev *pdev, u64 ct_addr, int dma_flags) { int dma_ok; int port; @@ -381,6 +392,9 @@ tioce_dma_d32(struct pci_dev *pdev, u64 ct_addr) u64 ct_lower; dma_addr_t bus_addr; + if (dma_flags & SN_DMA_MSI) + return 0; + ct_upper = ct_addr & ~0x3fffffffUL; ct_lower = ct_addr & 0x3fffffffUL; @@ -507,7 +521,7 @@ tioce_dma_unmap(struct pci_dev *pdev, dma_addr_t bus_addr, int dir) */ static u64 tioce_do_dma_map(struct pci_dev *pdev, u64 paddr, size_t byte_count, - int barrier) + int barrier, int dma_flags) { unsigned long flags; u64 ct_addr; @@ -523,15 +537,18 @@ tioce_do_dma_map(struct pci_dev *pdev, u64 paddr, size_t byte_count, if (dma_mask < 0x7fffffffUL) return 0; - ct_addr = PHYS_TO_TIODMA(paddr); + if (SN_DMA_ADDRTYPE(dma_flags) == SN_DMA_ADDR_PHYS) + ct_addr = PHYS_TO_TIODMA(paddr); + else + ct_addr = paddr; /* * If the device can generate 64 bit addresses, create a D64 map. - * Since this should never fail, bypass the rest of the checks. */ if (dma_mask == ~0UL) { - mapaddr = tioce_dma_d64(ct_addr); - goto dma_map_done; + mapaddr = tioce_dma_d64(ct_addr, dma_flags); + if (mapaddr) + goto dma_map_done; } pcidev_to_tioce(pdev, NULL, &ce_kern, &port); @@ -574,18 +591,22 @@ tioce_do_dma_map(struct pci_dev *pdev, u64 paddr, size_t byte_count, if (byte_count > MB(64)) { mapaddr = tioce_alloc_map(ce_kern, TIOCE_ATE_M40S, - port, ct_addr, byte_count); + port, ct_addr, byte_count, + dma_flags); if (!mapaddr) mapaddr = tioce_alloc_map(ce_kern, TIOCE_ATE_M40, -1, - ct_addr, byte_count); + ct_addr, byte_count, + dma_flags); } else { mapaddr = tioce_alloc_map(ce_kern, TIOCE_ATE_M40, -1, - ct_addr, byte_count); + ct_addr, byte_count, + dma_flags); if (!mapaddr) mapaddr = tioce_alloc_map(ce_kern, TIOCE_ATE_M40S, - port, ct_addr, byte_count); + port, ct_addr, byte_count, + dma_flags); } } @@ -593,7 +614,7 @@ tioce_do_dma_map(struct pci_dev *pdev, u64 paddr, size_t byte_count, * 32-bit direct is the next mode to try */ if (!mapaddr && dma_mask >= 0xffffffffUL) - mapaddr = tioce_dma_d32(pdev, ct_addr); + mapaddr = tioce_dma_d32(pdev, ct_addr, dma_flags); /* * Last resort, try 32-bit ATE-based map. @@ -601,7 +622,7 @@ tioce_do_dma_map(struct pci_dev *pdev, u64 paddr, size_t byte_count, if (!mapaddr) mapaddr = tioce_alloc_map(ce_kern, TIOCE_ATE_M32, -1, ct_addr, - byte_count); + byte_count, dma_flags); spin_unlock_irqrestore(&ce_kern->ce_lock, flags); @@ -622,9 +643,9 @@ dma_map_done: * in the address. */ static u64 -tioce_dma(struct pci_dev *pdev, u64 paddr, size_t byte_count) +tioce_dma(struct pci_dev *pdev, u64 paddr, size_t byte_count, int dma_flags) { - return tioce_do_dma_map(pdev, paddr, byte_count, 0); + return tioce_do_dma_map(pdev, paddr, byte_count, 0, dma_flags); } /** @@ -636,9 +657,9 @@ tioce_dma(struct pci_dev *pdev, u64 paddr, size_t byte_count) * Simply call tioce_do_dma_map() to create a map with the barrier bit set * in the address. */ static u64 -tioce_dma_consistent(struct pci_dev *pdev, u64 paddr, size_t byte_count) +tioce_dma_consistent(struct pci_dev *pdev, u64 paddr, size_t byte_count, int dma_flags) { - return tioce_do_dma_map(pdev, paddr, byte_count, 1); + return tioce_do_dma_map(pdev, paddr, byte_count, 1, dma_flags); } /** @@ -696,7 +717,7 @@ tioce_reserve_m32(struct tioce_kernel *ce_kern, u64 base, u64 limit) while (ate_index <= last_ate) { u64 ate; - ate = ATE_MAKE(0xdeadbeef, ps); + ate = ATE_MAKE(0xdeadbeef, ps, 0); ce_kern->ce_ate3240_shadow[ate_index] = ate; tioce_mmr_storei(ce_kern, &ce_mmr->ce_ure_ate3240[ate_index], ate); diff --git a/drivers/pci/msi-altix.c b/drivers/pci/msi-altix.c index 9bd240602c1e..bed4183a5e39 100644 --- a/drivers/pci/msi-altix.c +++ b/drivers/pci/msi-altix.c @@ -6,13 +6,205 @@ * Copyright (C) 2006 Silicon Graphics, Inc. All Rights Reserved. */ -#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "msi.h" + +struct sn_msi_info { + u64 pci_addr; + struct sn_irq_info *sn_irq_info; +}; + +static struct sn_msi_info *sn_msi_info; + +static void +sn_msi_teardown(unsigned int vector) +{ + nasid_t nasid; + int widget; + struct pci_dev *pdev; + struct pcidev_info *sn_pdev; + struct sn_irq_info *sn_irq_info; + struct pcibus_bussoft *bussoft; + struct sn_pcibus_provider *provider; + + sn_irq_info = sn_msi_info[vector].sn_irq_info; + if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0) + return; + + sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo; + pdev = sn_pdev->pdi_linux_pcidev; + provider = SN_PCIDEV_BUSPROVIDER(pdev); + + (*provider->dma_unmap)(pdev, + sn_msi_info[vector].pci_addr, + PCI_DMA_FROMDEVICE); + sn_msi_info[vector].pci_addr = 0; + + bussoft = SN_PCIDEV_BUSSOFT(pdev); + nasid = NASID_GET(bussoft->bs_base); + widget = (nasid & 1) ? + TIO_SWIN_WIDGETNUM(bussoft->bs_base) : + SWIN_WIDGETNUM(bussoft->bs_base); + + sn_intr_free(nasid, widget, sn_irq_info); + sn_msi_info[vector].sn_irq_info = NULL; + + return; +} int -sn_msi_init(void) +sn_msi_setup(struct pci_dev *pdev, unsigned int vector, + u32 *addr_hi, u32 *addr_lo, u32 *data) { + int widget; + int status; + nasid_t nasid; + u64 bus_addr; + struct sn_irq_info *sn_irq_info; + struct pcibus_bussoft *bussoft = SN_PCIDEV_BUSSOFT(pdev); + struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); + + if (bussoft == NULL) + return -EINVAL; + + if (provider == NULL || provider->dma_map_consistent == NULL) + return -EINVAL; + + /* + * Set up the vector plumbing. Let the prom (via sn_intr_alloc) + * decide which cpu to direct this msi at by default. + */ + + nasid = NASID_GET(bussoft->bs_base); + widget = (nasid & 1) ? + TIO_SWIN_WIDGETNUM(bussoft->bs_base) : + SWIN_WIDGETNUM(bussoft->bs_base); + + sn_irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL); + if (! sn_irq_info) + return -ENOMEM; + + status = sn_intr_alloc(nasid, widget, sn_irq_info, vector, -1, -1); + if (status) { + kfree(sn_irq_info); + return -ENOMEM; + } + + sn_irq_info->irq_int_bit = -1; /* mark this as an MSI irq */ + sn_irq_fixup(pdev, sn_irq_info); + + /* Prom probably should fill these in, but doesn't ... */ + sn_irq_info->irq_bridge_type = bussoft->bs_asic_type; + sn_irq_info->irq_bridge = (void *)bussoft->bs_base; + /* - * return error until MSI is supported on altix platforms + * Map the xio address into bus space */ - return -EINVAL; + bus_addr = (*provider->dma_map_consistent)(pdev, + sn_irq_info->irq_xtalkaddr, + sizeof(sn_irq_info->irq_xtalkaddr), + SN_DMA_MSI|SN_DMA_ADDR_XIO); + if (! bus_addr) { + sn_intr_free(nasid, widget, sn_irq_info); + kfree(sn_irq_info); + return -ENOMEM; + } + + sn_msi_info[vector].sn_irq_info = sn_irq_info; + sn_msi_info[vector].pci_addr = bus_addr; + + *addr_hi = (u32)(bus_addr >> 32); + *addr_lo = (u32)(bus_addr & 0x00000000ffffffff); + + /* + * In the SN platform, bit 16 is a "send vector" bit which + * must be present in order to move the vector through the system. + */ + *data = 0x100 + (unsigned int)vector; + +#ifdef CONFIG_SMP + set_irq_affinity_info((vector & 0xff), sn_irq_info->irq_cpuid, 0); +#endif + + return 0; +} + +static void +sn_msi_target(unsigned int vector, unsigned int cpu, + u32 *addr_hi, u32 *addr_lo) +{ + int slice; + nasid_t nasid; + u64 bus_addr; + struct pci_dev *pdev; + struct pcidev_info *sn_pdev; + struct sn_irq_info *sn_irq_info; + struct sn_irq_info *new_irq_info; + struct sn_pcibus_provider *provider; + + sn_irq_info = sn_msi_info[vector].sn_irq_info; + if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0) + return; + + /* + * Release XIO resources for the old MSI PCI address + */ + + sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo; + pdev = sn_pdev->pdi_linux_pcidev; + provider = SN_PCIDEV_BUSPROVIDER(pdev); + + bus_addr = (u64)(*addr_hi) << 32 | (u64)(*addr_lo); + (*provider->dma_unmap)(pdev, bus_addr, PCI_DMA_FROMDEVICE); + sn_msi_info[vector].pci_addr = 0; + + nasid = cpuid_to_nasid(cpu); + slice = cpuid_to_slice(cpu); + + new_irq_info = sn_retarget_vector(sn_irq_info, nasid, slice); + sn_msi_info[vector].sn_irq_info = new_irq_info; + if (new_irq_info == NULL) + return; + + /* + * Map the xio address into bus space + */ + + bus_addr = (*provider->dma_map_consistent)(pdev, + new_irq_info->irq_xtalkaddr, + sizeof(new_irq_info->irq_xtalkaddr), + SN_DMA_MSI|SN_DMA_ADDR_XIO); + + sn_msi_info[vector].pci_addr = bus_addr; + *addr_hi = (u32)(bus_addr >> 32); + *addr_lo = (u32)(bus_addr & 0x00000000ffffffff); +} + +struct msi_ops sn_msi_ops = { + .setup = sn_msi_setup, + .teardown = sn_msi_teardown, +#ifdef CONFIG_SMP + .target = sn_msi_target, +#endif +}; + +int +sn_msi_init(void) +{ + sn_msi_info = + kzalloc(sizeof(struct sn_msi_info) * NR_VECTORS, GFP_KERNEL); + if (! sn_msi_info) + return -ENOMEM; + + msi_register(&sn_msi_ops); + return 0; } diff --git a/include/asm-ia64/sn/intr.h b/include/asm-ia64/sn/intr.h index 60a51a406eec..12b54ddb06be 100644 --- a/include/asm-ia64/sn/intr.h +++ b/include/asm-ia64/sn/intr.h @@ -10,6 +10,7 @@ #define _ASM_IA64_SN_INTR_H #include +#include #define SGI_UART_VECTOR 0xe9 @@ -40,6 +41,7 @@ struct sn_irq_info { int irq_cpuid; /* kernel logical cpuid */ int irq_irq; /* the IRQ number */ int irq_int_bit; /* Bridge interrupt pin */ + /* <0 means MSI */ u64 irq_xtalkaddr; /* xtalkaddr IRQ is sent to */ int irq_bridge_type;/* pciio asic type (pciio.h) */ void *irq_bridge; /* bridge generating irq */ @@ -53,6 +55,12 @@ struct sn_irq_info { }; extern void sn_send_IPI_phys(int, long, int, int); +extern u64 sn_intr_alloc(nasid_t, int, + struct sn_irq_info *, + int, nasid_t, int); +extern void sn_intr_free(nasid_t, int, struct sn_irq_info *); +extern struct sn_irq_info *sn_retarget_vector(struct sn_irq_info *, nasid_t, int); +extern struct list_head **sn_irq_lh; #define CPU_VECTOR_TO_IRQ(cpuid,vector) (vector) diff --git a/include/asm-ia64/sn/pcibr_provider.h b/include/asm-ia64/sn/pcibr_provider.h index 51260ab70d91..e3b0c3fe5eed 100644 --- a/include/asm-ia64/sn/pcibr_provider.h +++ b/include/asm-ia64/sn/pcibr_provider.h @@ -55,6 +55,7 @@ #define PCI32_ATE_V (0x1 << 0) #define PCI32_ATE_CO (0x1 << 1) #define PCI32_ATE_PREC (0x1 << 2) +#define PCI32_ATE_MSI (0x1 << 2) #define PCI32_ATE_PREF (0x1 << 3) #define PCI32_ATE_BAR (0x1 << 4) #define PCI32_ATE_ADDR_SHFT 12 @@ -117,8 +118,8 @@ struct pcibus_info { extern int pcibr_init_provider(void); extern void *pcibr_bus_fixup(struct pcibus_bussoft *, struct pci_controller *); -extern dma_addr_t pcibr_dma_map(struct pci_dev *, unsigned long, size_t); -extern dma_addr_t pcibr_dma_map_consistent(struct pci_dev *, unsigned long, size_t); +extern dma_addr_t pcibr_dma_map(struct pci_dev *, unsigned long, size_t, int type); +extern dma_addr_t pcibr_dma_map_consistent(struct pci_dev *, unsigned long, size_t, int type); extern void pcibr_dma_unmap(struct pci_dev *, dma_addr_t, int); /* diff --git a/include/asm-ia64/sn/pcibus_provider_defs.h b/include/asm-ia64/sn/pcibus_provider_defs.h index ce3f6c328241..8f7c83d0f6d3 100644 --- a/include/asm-ia64/sn/pcibus_provider_defs.h +++ b/include/asm-ia64/sn/pcibus_provider_defs.h @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2004 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2005 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_PCI_PCIBUS_PROVIDER_H #define _ASM_IA64_SN_PCI_PCIBUS_PROVIDER_H @@ -45,13 +45,24 @@ struct pci_controller; */ struct sn_pcibus_provider { - dma_addr_t (*dma_map)(struct pci_dev *, unsigned long, size_t); - dma_addr_t (*dma_map_consistent)(struct pci_dev *, unsigned long, size_t); + dma_addr_t (*dma_map)(struct pci_dev *, unsigned long, size_t, int flags); + dma_addr_t (*dma_map_consistent)(struct pci_dev *, unsigned long, size_t, int flags); void (*dma_unmap)(struct pci_dev *, dma_addr_t, int); void * (*bus_fixup)(struct pcibus_bussoft *, struct pci_controller *); void (*force_interrupt)(struct sn_irq_info *); void (*target_interrupt)(struct sn_irq_info *); }; +/* + * Flags used by the map interfaces + * bits 3:0 specifies format of passed in address + * bit 4 specifies that address is to be used for MSI + */ + +#define SN_DMA_ADDRTYPE(x) ((x) & 0xf) +#define SN_DMA_ADDR_PHYS 1 /* address is an xio address. */ +#define SN_DMA_ADDR_XIO 2 /* address is phys memory */ +#define SN_DMA_MSI 0x10 /* Bus address is to be used for MSI */ + extern struct sn_pcibus_provider *sn_pci_provider[]; #endif /* _ASM_IA64_SN_PCI_PCIBUS_PROVIDER_H */ diff --git a/include/asm-ia64/sn/tiocp.h b/include/asm-ia64/sn/tiocp.h index f47c08ab483c..e8ad0bb5b6c5 100644 --- a/include/asm-ia64/sn/tiocp.h +++ b/include/asm-ia64/sn/tiocp.h @@ -3,13 +3,14 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2003-2004 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2003-2005 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_PCI_TIOCP_H #define _ASM_IA64_SN_PCI_TIOCP_H #define TIOCP_HOST_INTR_ADDR 0x003FFFFFFFFFFFFFUL #define TIOCP_PCI64_CMDTYPE_MEM (0x1ull << 60) +#define TIOCP_PCI64_CMDTYPE_MSI (0x3ull << 60) /***************************************************************************** -- cgit v1.2.3 From 75acfecaa031c0e1bc412cee4fe58ba49ff3406c Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Mon, 1 May 2006 10:43:46 -0500 Subject: [PATCH] PCI: Add pci_assign_resource_fixed -- allow fixed address assignments PCI: Add pci_assign_resource_fixed -- allow fixed address assignments On some embedded systems the PCI address for hotplug devices are not only known a priori but are required to be at a given PCI address for other master in the system to be able to access. An example of such a system would be an FPGA which is setup from user space after the system has booted. The FPGA may be access by DSPs in the system and those DSPs expect the FPGA at a fixed PCI address. Added pci_assign_resource_fixed() as a way to allow assignment of the PCI devices's BARs at fixed PCI addresses. Signed-off-by: Kumar Gala Signed-off-by: Greg Kroah-Hartman --- drivers/pci/setup-res.c | 40 ++++++++++++++++++++++++++++++++++++++++ include/linux/pci.h | 1 + 2 files changed, 41 insertions(+) (limited to 'include') diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index ea9277b7f899..577f4b55c46d 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c @@ -155,6 +155,46 @@ int pci_assign_resource(struct pci_dev *dev, int resno) return ret; } +#ifdef CONFIG_EMBEDDED +int pci_assign_resource_fixed(struct pci_dev *dev, int resno) +{ + struct pci_bus *bus = dev->bus; + struct resource *res = dev->resource + resno; + unsigned int type_mask; + int i, ret = -EBUSY; + + type_mask = IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH; + + for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) { + struct resource *r = bus->resource[i]; + if (!r) + continue; + + /* type_mask must match */ + if ((res->flags ^ r->flags) & type_mask) + continue; + + ret = request_resource(r, res); + + if (ret == 0) + break; + } + + if (ret) { + printk(KERN_ERR "PCI: Failed to allocate %s resource " + "#%d:%llx@%llx for %s\n", + res->flags & IORESOURCE_IO ? "I/O" : "mem", + resno, (unsigned long long)(res->end - res->start + 1), + (unsigned long long)res->start, pci_name(dev)); + } else if (resno < PCI_BRIDGE_RESOURCES) { + pci_update_resource(dev, res, resno); + } + + return ret; +} +EXPORT_SYMBOL_GPL(pci_assign_resource_fixed); +#endif + /* Sort resources by alignment */ void __devinit pdev_sort_resources(struct pci_dev *dev, struct resource_list *head) diff --git a/include/linux/pci.h b/include/linux/pci.h index 6c4bc773f7b7..b9eb9b021d6a 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -496,6 +496,7 @@ int pci_set_dma_mask(struct pci_dev *dev, u64 mask); int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask); void pci_update_resource(struct pci_dev *dev, struct resource *res, int resno); int pci_assign_resource(struct pci_dev *dev, int i); +int pci_assign_resource_fixed(struct pci_dev *dev, int i); void pci_restore_bars(struct pci_dev *dev); /* ROM control related routines */ -- cgit v1.2.3 From bd8481e1646d7649fa101ee57a5139b9da3c2436 Mon Sep 17 00:00:00 2001 From: Doug Thompson Date: Mon, 8 May 2006 17:06:09 -0700 Subject: [PATCH] PCI Bus Parity Status-broken hardware attribute, EDAC foundation Currently, the EDAC (error detection and correction) modules that are in the kernel contain some features that need to be moved. After some good feedback on the PCI Parity detection code and interface (http://www.ussg.iu.edu/hypermail/linux/kernel/0603.1/0897.html) this patch ADDs an new attribute to the pci_dev structure: Namely the 'broken_parity_status' bit. When set this indicates that the respective hardware generates false positives of Parity errors. The EDAC "blacklist" solution was inferior and will be removed in a future patch. Also in this patch is a PCI quirk.c entry for an Infiniband PCI-X card which generates false positive parity errors. I am requesting comments on this AND on the possibility of a exposing this 'broken_parity_status' bit to userland via the PCI device sysfs directory for devices. This access would allow for enabling of this feature on new devices and for old devices that have their drivers updated. (SLES 9 SP3 did this on an ATI motherboard video device). There is a need to update such a PCI attribute between kernel releases. This patch just adds a storage place for the attribute and a quirk entry for a known bad PCI device. PCI Parity reaper/harvestor operations are in EDAC itself and will be refactored to use this PCI attribute instead of its own mechanisms (which are currently disabled) in the future. Signed-off-by: Doug Thompson Signed-off-by: Greg Kroah-Hartman --- drivers/pci/quirks.c | 11 +++++++++++ include/linux/pci.h | 1 + include/linux/pci_ids.h | 1 + 3 files changed, 13 insertions(+) (limited to 'include') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index d378478612fb..ea48e969a12e 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -24,6 +24,17 @@ #include #include "pci.h" +/* The Mellanox Tavor device gives false positive parity errors + * Mark this device with a broken_parity_status, to allow + * PCI scanning code to "skip" this now blacklisted device. + */ +static void __devinit quirk_mellanox_tavor(struct pci_dev *dev) +{ + dev->broken_parity_status = 1; /* This device gives false positives */ +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MELLANOX,PCI_DEVICE_ID_MELLANOX_TAVOR,quirk_mellanox_tavor); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MELLANOX,PCI_DEVICE_ID_MELLANOX_TAVOR_BRIDGE,quirk_mellanox_tavor); + /* Deal with broken BIOS'es that neglect to enable passive release, which can cause problems in combination with the 82441FX/PPro MTRRs */ static void __devinit quirk_passive_release(struct pci_dev *dev) diff --git a/include/linux/pci.h b/include/linux/pci.h index b9eb9b021d6a..91c37750cd34 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -162,6 +162,7 @@ struct pci_dev { unsigned int is_busmaster:1; /* device is busmaster */ unsigned int no_msi:1; /* device may not use msi */ unsigned int block_ucfg_access:1; /* userspace config space access is blocked */ + unsigned int broken_parity_status:1; /* Device generates false positive parity */ u32 saved_config_space[16]; /* config space saved at suspend time */ struct hlist_head saved_cap_space; diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index bcfe9d4f56ae..3d197cdcfa3a 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1946,6 +1946,7 @@ #define PCI_VENDOR_ID_MELLANOX 0x15b3 #define PCI_DEVICE_ID_MELLANOX_TAVOR 0x5a44 +#define PCI_DEVICE_ID_MELLANOX_TAVOR_BRIDGE 0x5a46 #define PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT 0x6278 #define PCI_DEVICE_ID_MELLANOX_ARBEL 0x6282 #define PCI_DEVICE_ID_MELLANOX_SINAI_OLD 0x5e8c -- cgit v1.2.3 From 74d0a988d3aa359b6b8a8536c8cb92cce02ca5d5 Mon Sep 17 00:00:00 2001 From: Brent Casavant Date: Wed, 10 May 2006 01:49:14 -0700 Subject: [PATCH] PCI: Move various PCI IDs to header file Move various QLogic, Vitesse, and Intel storage controller PCI IDs to the main header file. Signed-off-by: Brent Casavant Acked-by: Jes Sorensen Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/qla1280.c | 24 ------------------------ drivers/scsi/sata_vsc.c | 11 ++++++----- include/linux/pci_ids.h | 9 +++++++++ 3 files changed, 15 insertions(+), 29 deletions(-) (limited to 'include') diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 77bb2351500c..680f6063954b 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -397,30 +397,6 @@ #include "ql1280_fw.h" #include "ql1040_fw.h" - -/* - * Missing PCI ID's - */ -#ifndef PCI_DEVICE_ID_QLOGIC_ISP1080 -#define PCI_DEVICE_ID_QLOGIC_ISP1080 0x1080 -#endif -#ifndef PCI_DEVICE_ID_QLOGIC_ISP1240 -#define PCI_DEVICE_ID_QLOGIC_ISP1240 0x1240 -#endif -#ifndef PCI_DEVICE_ID_QLOGIC_ISP1280 -#define PCI_DEVICE_ID_QLOGIC_ISP1280 0x1280 -#endif -#ifndef PCI_DEVICE_ID_QLOGIC_ISP10160 -#define PCI_DEVICE_ID_QLOGIC_ISP10160 0x1016 -#endif -#ifndef PCI_DEVICE_ID_QLOGIC_ISP12160 -#define PCI_DEVICE_ID_QLOGIC_ISP12160 0x1216 -#endif - -#ifndef PCI_VENDOR_ID_AMI -#define PCI_VENDOR_ID_AMI 0x101e -#endif - #ifndef BITS_PER_LONG #error "BITS_PER_LONG not defined!" #endif diff --git a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c index 8a29ce340b47..27d658704cf9 100644 --- a/drivers/scsi/sata_vsc.c +++ b/drivers/scsi/sata_vsc.c @@ -433,13 +433,14 @@ err_out: /* - * 0x1725/0x7174 is the Vitesse VSC-7174 - * 0x8086/0x3200 is the Intel 31244, which is supposed to be identical - * compatibility is untested as of yet + * Intel 31244 is supposed to be identical. + * Compatibility is untested as of yet. */ static const struct pci_device_id vsc_sata_pci_tbl[] = { - { 0x1725, 0x7174, PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 }, - { 0x8086, 0x3200, PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 }, + { PCI_VENDOR_ID_VITESSE, PCI_DEVICE_ID_VITESSE_VSC7174, + PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_GD31244, + PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 }, { } }; diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 3d197cdcfa3a..e526e7b5ea47 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -848,7 +848,12 @@ #define PCI_VENDOR_ID_QLOGIC 0x1077 +#define PCI_DEVICE_ID_QLOGIC_ISP10160 0x1016 #define PCI_DEVICE_ID_QLOGIC_ISP1020 0x1020 +#define PCI_DEVICE_ID_QLOGIC_ISP1080 0x1080 +#define PCI_DEVICE_ID_QLOGIC_ISP12160 0x1216 +#define PCI_DEVICE_ID_QLOGIC_ISP1240 0x1240 +#define PCI_DEVICE_ID_QLOGIC_ISP1280 0x1280 #define PCI_DEVICE_ID_QLOGIC_ISP2100 0x2100 #define PCI_DEVICE_ID_QLOGIC_ISP2200 0x2200 #define PCI_DEVICE_ID_QLOGIC_ISP2300 0x2300 @@ -1970,6 +1975,9 @@ #define PCI_VENDOR_ID_NETCELL 0x169c #define PCI_DEVICE_ID_REVOLUTION 0x0044 +#define PCI_VENDOR_ID_VITESSE 0x1725 +#define PCI_DEVICE_ID_VITESSE_VSC7174 0x7174 + #define PCI_VENDOR_ID_LINKSYS 0x1737 #define PCI_DEVICE_ID_LINKSYS_EG1064 0x1064 @@ -2149,6 +2157,7 @@ #define PCI_DEVICE_ID_INTEL_ICH8_4 0x2815 #define PCI_DEVICE_ID_INTEL_ICH8_5 0x283e #define PCI_DEVICE_ID_INTEL_ICH8_6 0x2850 +#define PCI_DEVICE_ID_INTEL_GD31244 0x3200 #define PCI_DEVICE_ID_INTEL_82855PM_HB 0x3340 #define PCI_DEVICE_ID_INTEL_82830_HB 0x3575 #define PCI_DEVICE_ID_INTEL_82830_CGC 0x3577 -- cgit v1.2.3 From 99dc804d9bcc2c53f4c20c291bf4e185312a1a0c Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Fri, 26 May 2006 10:58:27 +0800 Subject: [PATCH] PCI: disable msi mode in pci_disable_device Brice said the pci_save_msi_state breaks his driver in his special usage (not in suspend/resume), as pci_save_msi_state will disable msi mode. In his usage, pci_save_state will be called at runtime, and later (after the device operates for some time and has an error) pci_restore_state will be called. In another hand, suspend/resume needs disable msi mode, as device should stop working completely. This patch try to workaround this issue. Drivers are expected call pci_disable_device in suspend time after pci_save_state. Signed-off-by: Shaohua Li Signed-off-by: Greg Kroah-Hartman --- drivers/pci/msi.c | 6 ++++-- drivers/pci/pci.c | 9 ++++++++- include/linux/pci.h | 2 ++ 3 files changed, 14 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 9c69b6966e79..3ec558dc6523 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -453,9 +453,11 @@ static void enable_msi_mode(struct pci_dev *dev, int pos, int type) /* Set enabled bits to single MSI & enable MSI_enable bit */ msi_enable(control, 1); pci_write_config_word(dev, msi_control_reg(pos), control); + dev->msi_enabled = 1; } else { msix_enable(control); pci_write_config_word(dev, msi_control_reg(pos), control); + dev->msix_enabled = 1; } if (pci_find_capability(dev, PCI_CAP_ID_EXP)) { /* PCI Express Endpoint device detected */ @@ -472,9 +474,11 @@ void disable_msi_mode(struct pci_dev *dev, int pos, int type) /* Set enabled bits to single MSI & enable MSI_enable bit */ msi_disable(control); pci_write_config_word(dev, msi_control_reg(pos), control); + dev->msi_enabled = 0; } else { msix_disable(control); pci_write_config_word(dev, msi_control_reg(pos), control); + dev->msix_enabled = 0; } if (pci_find_capability(dev, PCI_CAP_ID_EXP)) { /* PCI Express Endpoint device detected */ @@ -549,7 +553,6 @@ int pci_save_msi_state(struct pci_dev *dev) pci_read_config_dword(dev, pos + PCI_MSI_DATA_32, &cap[i++]); if (control & PCI_MSI_FLAGS_MASKBIT) pci_read_config_dword(dev, pos + PCI_MSI_MASK_BIT, &cap[i++]); - disable_msi_mode(dev, pos, PCI_CAP_ID_MSI); save_state->cap_nr = PCI_CAP_ID_MSI; pci_add_saved_cap(dev, save_state); return 0; @@ -639,7 +642,6 @@ int pci_save_msix_state(struct pci_dev *dev) } dev->irq = temp; - disable_msi_mode(dev, pos, PCI_CAP_ID_MSIX); save_state->cap_nr = PCI_CAP_ID_MSIX; pci_add_saved_cap(dev, save_state); return 0; diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index aa480370ef10..d408a3c30426 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -551,7 +551,14 @@ void pci_disable_device(struct pci_dev *dev) { u16 pci_command; - + + if (dev->msi_enabled) + disable_msi_mode(dev, pci_find_capability(dev, PCI_CAP_ID_MSI), + PCI_CAP_ID_MSI); + if (dev->msix_enabled) + disable_msi_mode(dev, pci_find_capability(dev, PCI_CAP_ID_MSI), + PCI_CAP_ID_MSIX); + pci_read_config_word(dev, PCI_COMMAND, &pci_command); if (pci_command & PCI_COMMAND_MASTER) { pci_command &= ~PCI_COMMAND_MASTER; diff --git a/include/linux/pci.h b/include/linux/pci.h index 91c37750cd34..62a8c22f5f60 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -163,6 +163,8 @@ struct pci_dev { unsigned int no_msi:1; /* device may not use msi */ unsigned int block_ucfg_access:1; /* userspace config space access is blocked */ unsigned int broken_parity_status:1; /* Device generates false positive parity */ + unsigned int msi_enabled:1; + unsigned int msix_enabled:1; u32 saved_config_space[16]; /* config space saved at suspend time */ struct hlist_head saved_cap_space; -- cgit v1.2.3 From b209a6ee49099b7500abf024f7b6b9648b5a3eac Mon Sep 17 00:00:00 2001 From: "bibo,mao" Date: Wed, 31 May 2006 18:17:33 +0800 Subject: [PATCH] PCI: cleanup unused variable about msi driver In IA64 platform, msi driver does not use irq_vector variable, and in x86 platform LAST_DEVICE_VECTOR should one before FIRST_SYSTEM_VECTOR, this patch modify this. Signed-off-by: bibo, mao Signed-off-by: Greg Kroah-Hartman --- drivers/pci/msi.c | 5 ----- include/asm-i386/msi.h | 2 +- include/asm-x86_64/msi.h | 2 +- 3 files changed, 2 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 3ec558dc6523..a81c5b99daf3 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -35,7 +35,6 @@ static int nr_msix_devices; #ifndef CONFIG_X86_IO_APIC int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1}; -u8 irq_vector[NR_IRQ_VECTORS]; #endif static struct msi_ops *msi_ops; @@ -383,10 +382,6 @@ static int msi_init(void) return status; } -#ifndef CONFIG_X86_IO_APIC - irq_vector[0] = FIRST_DEVICE_VECTOR; -#endif - if (last_alloc_vector < 0) { pci_msi_enable = 0; printk(KERN_WARNING "PCI: No interrupt vectors available for MSI\n"); diff --git a/include/asm-i386/msi.h b/include/asm-i386/msi.h index ed1014235e9c..b11c4b7dfaef 100644 --- a/include/asm-i386/msi.h +++ b/include/asm-i386/msi.h @@ -9,7 +9,7 @@ #include #include -#define LAST_DEVICE_VECTOR 232 +#define LAST_DEVICE_VECTOR (FIRST_SYSTEM_VECTOR - 1) #define MSI_TARGET_CPU_SHIFT 12 extern struct msi_ops msi_apic_ops; diff --git a/include/asm-x86_64/msi.h b/include/asm-x86_64/msi.h index 8d6d6bf8fad5..3ad2346624b2 100644 --- a/include/asm-x86_64/msi.h +++ b/include/asm-x86_64/msi.h @@ -10,7 +10,7 @@ #include #include -#define LAST_DEVICE_VECTOR 232 +#define LAST_DEVICE_VECTOR (FIRST_SYSTEM_VECTOR - 1) #define MSI_TARGET_CPU_SHIFT 12 extern struct msi_ops msi_apic_ops; -- cgit v1.2.3 From cf34a8e07f02c76f3f1232eecb681301a3d7b10b Mon Sep 17 00:00:00 2001 From: Brice Goglin Date: Tue, 13 Jun 2006 14:35:42 -0400 Subject: [PATCH] PCI: nVidia quirk to make AER PCI-E extended capability visible The nVidia CK804 PCI-E chipset supports the AER extended capability but sometimes fails to link it (with some BIOS or after a warm reboot). It makes the AER cap invisible to pci_find_ext_capability(). The patch adds a quirk to set the missing bit that controls the linking of the capability. By the way, it removes the corresponding code in the myri10ge driver. Signed-off-by: Brice Goglin Signed-off-by: Loic Prylli Signed-off-by: Greg Kroah-Hartman --- drivers/pci/quirks.c | 19 +++++++++++++++++++ include/linux/pci_ids.h | 1 + 2 files changed, 20 insertions(+) (limited to 'include') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index aea4d49bcce3..4364d793f73b 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -1499,6 +1499,25 @@ static void __devinit quirk_p64h2_1k_io(struct pci_dev *dev) } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1460, quirk_p64h2_1k_io); +/* Under some circumstances, AER is not linked with extended capabilities. + * Force it to be linked by setting the corresponding control bit in the + * config space. + */ +static void __devinit quirk_nvidia_ck804_pcie_aer_ext_cap(struct pci_dev *dev) +{ + uint8_t b; + if (pci_read_config_byte(dev, 0xf41, &b) == 0) { + if (!(b & 0x20)) { + pci_write_config_byte(dev, 0xf41, b | 0x20); + printk(KERN_INFO + "PCI: Linking AER extended capability on %s\n", + pci_name(dev)); + } + } +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE, + quirk_nvidia_ck804_pcie_aer_ext_cap); + EXPORT_SYMBOL(pcie_mch_quirk); #ifdef CONFIG_HOTPLUG EXPORT_SYMBOL(pci_fixup_device); diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index e526e7b5ea47..fd54a9d4c3d4 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1023,6 +1023,7 @@ #define PCI_DEVICE_ID_NVIDIA_NVENET_8 0x0056 #define PCI_DEVICE_ID_NVIDIA_NVENET_9 0x0057 #define PCI_DEVICE_ID_NVIDIA_CK804_AUDIO 0x0059 +#define PCI_DEVICE_ID_NVIDIA_CK804_PCIE 0x005d #define PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS 0x0064 #define PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE 0x0065 #define PCI_DEVICE_ID_NVIDIA_NVENET_2 0x0066 -- cgit v1.2.3 From 1cdcb6b43fda7424b7435dac8f80b2b5d8a48899 Mon Sep 17 00:00:00 2001 From: Hansjoerg Lipp Date: Sat, 22 Apr 2006 18:36:53 +0200 Subject: [PATCH] TTY: return class device pointer from tty_register_device() Let tty_register_device() return a pointer to the class device it creates. This allows registrants to add their own sysfs files under the class device node. Signed-off-by: Hansjoerg Lipp Signed-off-by: Tilman Schmidt Signed-off-by: Greg Kroah-Hartman --- drivers/char/tty_io.c | 11 +++++++---- include/linux/tty.h | 4 +++- 2 files changed, 10 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index a88b94a82b14..8b2a59969868 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -2961,12 +2961,14 @@ static struct class *tty_class; * This field is optional, if there is no known struct device for this * tty device it can be set to NULL safely. * + * Returns a pointer to the class device (or ERR_PTR(-EFOO) on error). + * * This call is required to be made to register an individual tty device if * the tty driver's flags have the TTY_DRIVER_NO_DEVFS bit set. If that * bit is not set, this function should not be called. */ -void tty_register_device(struct tty_driver *driver, unsigned index, - struct device *device) +struct class_device *tty_register_device(struct tty_driver *driver, + unsigned index, struct device *device) { char name[64]; dev_t dev = MKDEV(driver->major, driver->minor_start) + index; @@ -2974,7 +2976,7 @@ void tty_register_device(struct tty_driver *driver, unsigned index, if (index >= driver->num) { printk(KERN_ERR "Attempt to register invalid tty line number " " (%d).\n", index); - return; + return ERR_PTR(-EINVAL); } devfs_mk_cdev(dev, S_IFCHR | S_IRUSR | S_IWUSR, @@ -2984,7 +2986,8 @@ void tty_register_device(struct tty_driver *driver, unsigned index, pty_line_name(driver, index, name); else tty_line_name(driver, index, name); - class_device_create(tty_class, NULL, dev, device, "%s", name); + + return class_device_create(tty_class, NULL, dev, device, "%s", name); } /** diff --git a/include/linux/tty.h b/include/linux/tty.h index e898eeb94166..cb35ca50a0a6 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -290,7 +290,9 @@ extern int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc); extern int tty_unregister_ldisc(int disc); extern int tty_register_driver(struct tty_driver *driver); extern int tty_unregister_driver(struct tty_driver *driver); -extern void tty_register_device(struct tty_driver *driver, unsigned index, struct device *dev); +extern struct class_device *tty_register_device(struct tty_driver *driver, + unsigned index, + struct device *dev); extern void tty_unregister_device(struct tty_driver *driver, unsigned index); extern int tty_read_raw_data(struct tty_struct *tty, unsigned char *bufp, int buflen); -- cgit v1.2.3 From 1740757e8f94c6899705eb6f5434de9404992778 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 2 May 2006 16:59:59 +0200 Subject: [PATCH] Driver Core: remove unused exports Cc: Arjan van de Ven Signed-off-by: Greg Kroah-Hartman --- drivers/base/attribute_container.c | 8 -------- drivers/base/base.h | 2 ++ drivers/base/bus.c | 6 ------ drivers/base/class.c | 6 ++---- include/linux/device.h | 8 -------- 5 files changed, 4 insertions(+), 26 deletions(-) (limited to 'include') diff --git a/drivers/base/attribute_container.c b/drivers/base/attribute_container.c index 2a7d7ae83e1e..22220733f76f 100644 --- a/drivers/base/attribute_container.c +++ b/drivers/base/attribute_container.c @@ -236,7 +236,6 @@ attribute_container_remove_device(struct device *dev, } up(&attribute_container_mutex); } -EXPORT_SYMBOL_GPL(attribute_container_remove_device); /** * attribute_container_device_trigger - execute a trigger for each matching classdev @@ -276,7 +275,6 @@ attribute_container_device_trigger(struct device *dev, } up(&attribute_container_mutex); } -EXPORT_SYMBOL_GPL(attribute_container_device_trigger); /** * attribute_container_trigger - trigger a function for each matching container @@ -304,7 +302,6 @@ attribute_container_trigger(struct device *dev, } up(&attribute_container_mutex); } -EXPORT_SYMBOL_GPL(attribute_container_trigger); /** * attribute_container_add_attrs - add attributes @@ -333,7 +330,6 @@ attribute_container_add_attrs(struct class_device *classdev) return 0; } -EXPORT_SYMBOL_GPL(attribute_container_add_attrs); /** * attribute_container_add_class_device - same function as class_device_add @@ -352,7 +348,6 @@ attribute_container_add_class_device(struct class_device *classdev) return error; return attribute_container_add_attrs(classdev); } -EXPORT_SYMBOL_GPL(attribute_container_add_class_device); /** * attribute_container_add_class_device_adapter - simple adapter for triggers @@ -367,7 +362,6 @@ attribute_container_add_class_device_adapter(struct attribute_container *cont, { return attribute_container_add_class_device(classdev); } -EXPORT_SYMBOL_GPL(attribute_container_add_class_device_adapter); /** * attribute_container_remove_attrs - remove any attribute files @@ -389,7 +383,6 @@ attribute_container_remove_attrs(struct class_device *classdev) for (i = 0; attrs[i]; i++) class_device_remove_file(classdev, attrs[i]); } -EXPORT_SYMBOL_GPL(attribute_container_remove_attrs); /** * attribute_container_class_device_del - equivalent of class_device_del @@ -405,7 +398,6 @@ attribute_container_class_device_del(struct class_device *classdev) attribute_container_remove_attrs(classdev); class_device_del(classdev); } -EXPORT_SYMBOL_GPL(attribute_container_class_device_del); /** * attribute_container_find_class_device - find the corresponding class_device diff --git a/drivers/base/base.h b/drivers/base/base.h index bbbc2acd921c..122498aef50b 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -13,6 +13,8 @@ extern int attribute_container_init(void); extern int bus_add_device(struct device * dev); extern void bus_attach_device(struct device * dev); extern void bus_remove_device(struct device * dev); +extern struct bus_type *get_bus(struct bus_type * bus); +extern void put_bus(struct bus_type * bus); extern int bus_add_driver(struct device_driver *); extern void bus_remove_driver(struct device_driver *); diff --git a/drivers/base/bus.c b/drivers/base/bus.c index b27a6067e5a4..64ba9011d1a8 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -745,15 +745,9 @@ EXPORT_SYMBOL_GPL(bus_for_each_dev); EXPORT_SYMBOL_GPL(bus_find_device); EXPORT_SYMBOL_GPL(bus_for_each_drv); -EXPORT_SYMBOL_GPL(bus_add_device); -EXPORT_SYMBOL_GPL(bus_attach_device); -EXPORT_SYMBOL_GPL(bus_remove_device); EXPORT_SYMBOL_GPL(bus_register); EXPORT_SYMBOL_GPL(bus_unregister); EXPORT_SYMBOL_GPL(bus_rescan_devices); -EXPORT_SYMBOL_GPL(get_bus); -EXPORT_SYMBOL_GPL(put_bus); -EXPORT_SYMBOL_GPL(find_bus); EXPORT_SYMBOL_GPL(bus_create_file); EXPORT_SYMBOL_GPL(bus_remove_file); diff --git a/drivers/base/class.c b/drivers/base/class.c index 48ad5df72812..4b598be0e4b6 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -91,14 +91,14 @@ void class_remove_file(struct class * cls, const struct class_attribute * attr) sysfs_remove_file(&cls->subsys.kset.kobj, &attr->attr); } -struct class * class_get(struct class * cls) +static struct class *class_get(struct class *cls) { if (cls) return container_of(subsys_get(&cls->subsys), struct class, subsys); return NULL; } -void class_put(struct class * cls) +static void class_put(struct class * cls) { if (cls) subsys_put(&cls->subsys); @@ -894,8 +894,6 @@ EXPORT_SYMBOL_GPL(class_create_file); EXPORT_SYMBOL_GPL(class_remove_file); EXPORT_SYMBOL_GPL(class_register); EXPORT_SYMBOL_GPL(class_unregister); -EXPORT_SYMBOL_GPL(class_get); -EXPORT_SYMBOL_GPL(class_put); EXPORT_SYMBOL_GPL(class_create); EXPORT_SYMBOL_GPL(class_destroy); diff --git a/include/linux/device.h b/include/linux/device.h index b2e5da2b637b..ade10dd6b779 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -60,11 +60,6 @@ extern void bus_unregister(struct bus_type * bus); extern void bus_rescan_devices(struct bus_type * bus); -extern struct bus_type * get_bus(struct bus_type * bus); -extern void put_bus(struct bus_type * bus); - -extern struct bus_type * find_bus(char * name); - /* iterator helpers for buses */ int bus_for_each_dev(struct bus_type * bus, struct device * start, void * data, @@ -163,9 +158,6 @@ struct class { extern int class_register(struct class *); extern void class_unregister(struct class *); -extern struct class * class_get(struct class *); -extern void class_put(struct class *); - struct class_attribute { struct attribute attr; -- cgit v1.2.3 From 670dd90d81f60ef429cbba54ad235e9207f4d444 Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Mon, 8 May 2006 13:45:57 +0800 Subject: [PATCH] Driver Core: Allow sysdev_class have attributes allow sysdev_class adding attribute. Next patch will use the new API to add an attribute under /sys/device/system/cpu/. Signed-off-by: Shaohua Li Signed-off-by: Greg Kroah-Hartman --- drivers/base/sys.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++- include/linux/sysdev.h | 18 +++++++++++++++++- 2 files changed, 67 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/base/sys.c b/drivers/base/sys.c index 6fc23ab127bd..6858178b3aff 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c @@ -80,10 +80,59 @@ void sysdev_remove_file(struct sys_device * s, struct sysdev_attribute * a) EXPORT_SYMBOL_GPL(sysdev_create_file); EXPORT_SYMBOL_GPL(sysdev_remove_file); +#define to_sysdev_class(k) container_of(k, struct sysdev_class, kset.kobj) +#define to_sysdev_class_attr(a) container_of(a, \ + struct sysdev_class_attribute, attr) + +static ssize_t sysdev_class_show(struct kobject *kobj, struct attribute *attr, + char *buffer) +{ + struct sysdev_class * class = to_sysdev_class(kobj); + struct sysdev_class_attribute *class_attr = to_sysdev_class_attr(attr); + + if (class_attr->show) + return class_attr->show(class, buffer); + return -EIO; +} + +static ssize_t sysdev_class_store(struct kobject *kobj, struct attribute *attr, + const char *buffer, size_t count) +{ + struct sysdev_class * class = to_sysdev_class(kobj); + struct sysdev_class_attribute * class_attr = to_sysdev_class_attr(attr); + + if (class_attr->store) + return class_attr->store(class, buffer, count); + return -EIO; +} + +static struct sysfs_ops sysfs_class_ops = { + .show = sysdev_class_show, + .store = sysdev_class_store, +}; + +static struct kobj_type ktype_sysdev_class = { + .sysfs_ops = &sysfs_class_ops, +}; + +int sysdev_class_create_file(struct sysdev_class *c, + struct sysdev_class_attribute *a) +{ + return sysfs_create_file(&c->kset.kobj, &a->attr); +} +EXPORT_SYMBOL_GPL(sysdev_class_create_file); + +void sysdev_class_remove_file(struct sysdev_class *c, + struct sysdev_class_attribute *a) +{ + sysfs_remove_file(&c->kset.kobj, &a->attr); +} +EXPORT_SYMBOL_GPL(sysdev_class_remove_file); + /* * declare system_subsys */ -static decl_subsys(system, &ktype_sysdev, NULL); +static decl_subsys(system, &ktype_sysdev_class, NULL); int sysdev_class_register(struct sysdev_class * cls) { diff --git a/include/linux/sysdev.h b/include/linux/sysdev.h index 2a4b432e1176..166a2e58c287 100644 --- a/include/linux/sysdev.h +++ b/include/linux/sysdev.h @@ -37,11 +37,27 @@ struct sysdev_class { struct kset kset; }; +struct sysdev_class_attribute { + struct attribute attr; + ssize_t (*show)(struct sysdev_class *, char *); + ssize_t (*store)(struct sysdev_class *, const char *, size_t); +}; + +#define SYSDEV_CLASS_ATTR(_name,_mode,_show,_store) \ +struct sysdev_class_attribute attr_##_name = { \ + .attr = {.name = __stringify(_name), .mode = _mode }, \ + .show = _show, \ + .store = _store, \ +}; + extern int sysdev_class_register(struct sysdev_class *); extern void sysdev_class_unregister(struct sysdev_class *); - +extern int sysdev_class_create_file(struct sysdev_class *, + struct sysdev_class_attribute *); +extern void sysdev_class_remove_file(struct sysdev_class *, + struct sysdev_class_attribute *); /** * Auxillary system device drivers. */ -- cgit v1.2.3 From 4039483fd3065920f035eed39ec59085421c0a4f Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Tue, 9 May 2006 12:53:49 +0200 Subject: [PATCH] Driver Core: Add /sys/hypervisor when needed To have a home for all hypervisors, this patch creates /sys/hypervisor. A new config option SYS_HYPERVISOR is introduced, which should to be set by architecture dependent hypervisors (e.g. s390 or Xen). Acked-by: Martin Schwidefsky Signed-off-by: Michael Holzheu Signed-off-by: Greg Kroah-Hartman --- drivers/base/Kconfig | 4 ++++ drivers/base/Makefile | 1 + drivers/base/base.h | 5 +++++ drivers/base/hypervisor.c | 19 +++++++++++++++++++ drivers/base/init.c | 1 + include/linux/kobject.h | 2 ++ 6 files changed, 32 insertions(+) create mode 100644 drivers/base/hypervisor.c (limited to 'include') diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index f0eff3dac58d..80502dc6ed66 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -38,3 +38,7 @@ config DEBUG_DRIVER If you are unsure about this, say N here. endmenu + +config SYS_HYPERVISOR + bool + default n diff --git a/drivers/base/Makefile b/drivers/base/Makefile index e99471d3232b..659cde6c2fb9 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_FW_LOADER) += firmware_class.o obj-$(CONFIG_NUMA) += node.o obj-$(CONFIG_MEMORY_HOTPLUG) += memory.o obj-$(CONFIG_SMP) += topology.o +obj-$(CONFIG_SYS_HYPERVISOR) += hypervisor.o ifeq ($(CONFIG_DEBUG_DRIVER),y) EXTRA_CFLAGS += -DDEBUG diff --git a/drivers/base/base.h b/drivers/base/base.h index 122498aef50b..79115eff6e94 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -5,6 +5,11 @@ extern int devices_init(void); extern int buses_init(void); extern int classes_init(void); extern int firmware_init(void); +#ifdef CONFIG_SYS_HYPERVISOR +extern int hypervisor_init(void); +#else +static inline int hypervisor_init(void) { return 0; } +#endif extern int platform_bus_init(void); extern int system_bus_init(void); extern int cpu_dev_init(void); diff --git a/drivers/base/hypervisor.c b/drivers/base/hypervisor.c new file mode 100644 index 000000000000..0c85e9d6a448 --- /dev/null +++ b/drivers/base/hypervisor.c @@ -0,0 +1,19 @@ +/* + * hypervisor.c - /sys/hypervisor subsystem. + * + * This file is released under the GPLv2 + * + */ + +#include +#include + +#include "base.h" + +decl_subsys(hypervisor, NULL, NULL); +EXPORT_SYMBOL_GPL(hypervisor_subsys); + +int __init hypervisor_init(void) +{ + return subsystem_register(&hypervisor_subsys); +} diff --git a/drivers/base/init.c b/drivers/base/init.c index c648914b9cde..37138154f9e8 100644 --- a/drivers/base/init.c +++ b/drivers/base/init.c @@ -27,6 +27,7 @@ void __init driver_init(void) buses_init(); classes_init(); firmware_init(); + hypervisor_init(); /* These are also core pieces, but must come after the * core core pieces. diff --git a/include/linux/kobject.h b/include/linux/kobject.h index c187c53cecd0..2d229327959e 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -190,6 +190,8 @@ struct subsystem _varname##_subsys = { \ /* The global /sys/kernel/ subsystem for people to chain off of */ extern struct subsystem kernel_subsys; +/* The global /sys/hypervisor/ subsystem */ +extern struct subsystem hypervisor_subsys; /** * Helpers for setting the kset of registered objects. -- cgit v1.2.3 From 23681e479129854305da1da32f7f1eaf635ef22c Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 14 Jun 2006 12:14:34 -0700 Subject: [PATCH] Driver core: allow struct device to have a dev_t This is the first step in moving class_device to being replaced by struct device. It allows struct device to export a dev_t and makes it easy to dynamically create and destroy struct device as long as they are associated with a specific class. Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/base/class.c | 1 + drivers/base/core.c | 162 ++++++++++++++++++++++++++++++++++++++++++++++++- include/linux/device.h | 14 +++++ 3 files changed, 176 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/base/class.c b/drivers/base/class.c index 41a8e0934e3a..50e841a33af0 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -142,6 +142,7 @@ int class_register(struct class * cls) pr_debug("device class '%s': registering\n", cls->name); INIT_LIST_HEAD(&cls->children); + INIT_LIST_HEAD(&cls->devices); INIT_LIST_HEAD(&cls->interfaces); init_MUTEX(&cls->sem); error = kobject_set_name(&cls->subsys.kset.kobj, "%s", cls->name); diff --git a/drivers/base/core.c b/drivers/base/core.c index d5e15a03584e..252cf403f891 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -15,6 +15,7 @@ #include #include #include +#include #include @@ -98,6 +99,8 @@ static int dev_uevent_filter(struct kset *kset, struct kobject *kobj) struct device *dev = to_dev(kobj); if (dev->bus) return 1; + if (dev->class) + return 1; } return 0; } @@ -106,7 +109,11 @@ static const char *dev_uevent_name(struct kset *kset, struct kobject *kobj) { struct device *dev = to_dev(kobj); - return dev->bus->name; + if (dev->bus) + return dev->bus->name; + if (dev->class) + return dev->class->name; + return NULL; } static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp, @@ -117,6 +124,16 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp, int length = 0; int retval = 0; + /* add the major/minor if present */ + if (MAJOR(dev->devt)) { + add_uevent_var(envp, num_envp, &i, + buffer, buffer_size, &length, + "MAJOR=%u", MAJOR(dev->devt)); + add_uevent_var(envp, num_envp, &i, + buffer, buffer_size, &length, + "MINOR=%u", MINOR(dev->devt)); + } + /* add bus name of physical device */ if (dev->bus) add_uevent_var(envp, num_envp, &i, @@ -161,6 +178,12 @@ static ssize_t store_uevent(struct device *dev, struct device_attribute *attr, return count; } +static ssize_t show_dev(struct device *dev, struct device_attribute *attr, + char *buf) +{ + return print_dev_t(buf, dev->devt); +} + /* * devices_subsys - structure to be registered with kobject core. */ @@ -231,6 +254,7 @@ void device_initialize(struct device *dev) klist_init(&dev->klist_children, klist_children_get, klist_children_put); INIT_LIST_HEAD(&dev->dma_pools); + INIT_LIST_HEAD(&dev->node); init_MUTEX(&dev->sem); device_init_wakeup(dev, 0); } @@ -274,6 +298,31 @@ int device_add(struct device *dev) dev->uevent_attr.store = store_uevent; device_create_file(dev, &dev->uevent_attr); + if (MAJOR(dev->devt)) { + struct device_attribute *attr; + attr = kzalloc(sizeof(*attr), GFP_KERNEL); + if (!attr) { + error = -ENOMEM; + goto PMError; + } + attr->attr.name = "dev"; + attr->attr.mode = S_IRUGO; + if (dev->driver) + attr->attr.owner = dev->driver->owner; + attr->show = show_dev; + error = device_create_file(dev, attr); + if (error) { + kfree(attr); + goto attrError; + } + + dev->devt_attr = attr; + } + + if (dev->class) + sysfs_create_link(&dev->class->subsys.kset.kobj, &dev->kobj, + dev->bus_id); + if ((error = device_pm_add(dev))) goto PMError; if ((error = bus_add_device(dev))) @@ -292,6 +341,11 @@ int device_add(struct device *dev) BusError: device_pm_remove(dev); PMError: + if (dev->devt_attr) { + device_remove_file(dev, dev->devt_attr); + kfree(dev->devt_attr); + } + attrError: kobject_uevent(&dev->kobj, KOBJ_REMOVE); kobject_del(&dev->kobj); Error: @@ -366,6 +420,10 @@ void device_del(struct device * dev) if (parent) klist_del(&dev->knode_parent); + if (dev->devt_attr) + device_remove_file(dev, dev->devt_attr); + if (dev->class) + sysfs_remove_link(&dev->class->subsys.kset.kobj, dev->bus_id); device_remove_file(dev, &dev->uevent_attr); /* Notify the platform of the removal, in case they @@ -450,3 +508,105 @@ EXPORT_SYMBOL_GPL(put_device); EXPORT_SYMBOL_GPL(device_create_file); EXPORT_SYMBOL_GPL(device_remove_file); + + +static void device_create_release(struct device *dev) +{ + pr_debug("%s called for %s\n", __FUNCTION__, dev->bus_id); + kfree(dev); +} + +/** + * device_create - creates a device and registers it with sysfs + * @cs: pointer to the struct class that this device should be registered to. + * @parent: pointer to the parent struct device of this new device, if any. + * @dev: the dev_t for the char device to be added. + * @fmt: string for the class device's name + * + * This function can be used by char device classes. A struct + * device will be created in sysfs, registered to the specified + * class. + * A "dev" file will be created, showing the dev_t for the device, if + * the dev_t is not 0,0. + * If a pointer to a parent struct device is passed in, the newly + * created struct device will be a child of that device in sysfs. The + * pointer to the struct device will be returned from the call. Any + * further sysfs files that might be required can be created using this + * pointer. + * + * Note: the struct class passed to this function must have previously + * been created with a call to class_create(). + */ +struct device *device_create(struct class *class, struct device *parent, + dev_t devt, char *fmt, ...) +{ + va_list args; + struct device *dev = NULL; + int retval = -ENODEV; + + if (class == NULL || IS_ERR(class)) + goto error; + if (parent == NULL) { + printk(KERN_WARNING "%s does not work yet for NULL parents\n", __FUNCTION__); + goto error; + } + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { + retval = -ENOMEM; + goto error; + } + + dev->devt = devt; + dev->class = class; + dev->parent = parent; + dev->release = device_create_release; + + va_start(args, fmt); + vsnprintf(dev->bus_id, BUS_ID_SIZE, fmt, args); + va_end(args); + retval = device_register(dev); + if (retval) + goto error; + + /* tie the class to the device */ + down(&class->sem); + list_add_tail(&dev->node, &class->devices); + up(&class->sem); + + return dev; + +error: + kfree(dev); + return ERR_PTR(retval); +} +EXPORT_SYMBOL_GPL(device_create); + +/** + * device_destroy - removes a device that was created with device_create() + * @class: the pointer to the struct class that this device was registered * with. + * @dev: the dev_t of the device that was previously registered. + * + * This call unregisters and cleans up a class device that was created with a + * call to class_device_create() + */ +void device_destroy(struct class *class, dev_t devt) +{ + struct device *dev = NULL; + struct device *dev_tmp; + + down(&class->sem); + list_for_each_entry(dev_tmp, &class->devices, node) { + if (dev_tmp->devt == devt) { + dev = dev_tmp; + break; + } + } + up(&class->sem); + + if (dev) { + list_del_init(&dev->node); + device_unregister(dev); + } +} +EXPORT_SYMBOL_GPL(device_destroy); diff --git a/include/linux/device.h b/include/linux/device.h index ade10dd6b779..b473f4278910 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -142,6 +142,7 @@ struct class { struct subsystem subsys; struct list_head children; + struct list_head devices; struct list_head interfaces; struct semaphore sem; /* locks both the children and interfaces lists */ @@ -305,6 +306,7 @@ struct device { struct kobject kobj; char bus_id[BUS_ID_SIZE]; /* position on parent bus */ struct device_attribute uevent_attr; + struct device_attribute *devt_attr; struct semaphore sem; /* semaphore to synchronize calls to * its driver. @@ -332,6 +334,11 @@ struct device { struct dma_coherent_mem *dma_mem; /* internal for coherent mem override */ + /* class_device migration path */ + struct list_head node; + struct class *class; /* optional*/ + dev_t devt; /* dev_t, creates the sysfs "dev" */ + void (*release)(struct device * dev); }; @@ -373,6 +380,13 @@ extern int device_attach(struct device * dev); extern void driver_attach(struct device_driver * drv); extern void device_reprobe(struct device *dev); +/* + * Easy functions for dynamically creating devices on the fly + */ +extern struct device *device_create(struct class *cls, struct device *parent, + dev_t devt, char *fmt, ...) + __attribute__((format(printf,4,5))); +extern void device_destroy(struct class *cls, dev_t devt); /* * Platform "fixup" functions - allow the platform to have their say -- cgit v1.2.3 From 3e95637a48820ff8bedb33e6439def96ccff1de5 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 16 Jun 2006 17:10:48 -0400 Subject: [PATCH] Driver Core: Make dev_info and friends print the bus name if there is no driver This patch (as721) makes dev_info and related macros print the device's bus name if the device doesn't have a driver, instead of printing just a blank. If the device isn't on a bus either... well, then it does leave a blank space. But it will be easier for someone else to change if they want. Cc: Matthew Wilcox Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 16 ++++++++++++++++ include/linux/device.h | 3 ++- 2 files changed, 18 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/base/core.c b/drivers/base/core.c index a979bc3f49a9..d0f84ff78776 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -29,6 +29,22 @@ int (*platform_notify_remove)(struct device * dev) = NULL; * sysfs bindings for devices. */ +/** + * dev_driver_string - Return a device's driver name, if at all possible + * @dev: struct device to get the name of + * + * Will return the device's driver's name if it is bound to a device. If + * the device is not bound to a device, it will return the name of the bus + * it is attached to. If it is not attached to a bus either, an empty + * string will be returned. + */ +const char *dev_driver_string(struct device *dev) +{ + return dev->driver ? dev->driver->name : + (dev->bus ? dev->bus->name : ""); +} +EXPORT_SYMBOL_GPL(dev_driver_string); + #define to_dev(obj) container_of(obj, struct device, kobj) #define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr) diff --git a/include/linux/device.h b/include/linux/device.h index b473f4278910..1e5f30da98bc 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -416,8 +416,9 @@ extern int firmware_register(struct subsystem *); extern void firmware_unregister(struct subsystem *); /* debugging and troubleshooting/diagnostic helpers. */ +extern const char *dev_driver_string(struct device *dev); #define dev_printk(level, dev, format, arg...) \ - printk(level "%s %s: " format , (dev)->driver ? (dev)->driver->name : "" , (dev)->bus_id , ## arg) + printk(level "%s %s: " format , dev_driver_string(dev) , (dev)->bus_id , ## arg) #ifdef DEBUG #define dev_dbg(dev, format, arg...) \ -- cgit v1.2.3 From a5117ba7da37deb09df5eb802dace229b3fb1e9f Mon Sep 17 00:00:00 2001 From: Rene Herman Date: Tue, 6 Jun 2006 23:54:02 +0200 Subject: [PATCH] Driver model: add ISA bus During the recent "isa drivers using platform devices" discussion it was pointed out that (ALSA) ISA drivers ran into the problem of not having the option to fail driver load (device registration rather) upon not finding their hardware due to a probe() error not being passed up through the driver model. In the course of that, I suggested a seperate ISA bus might be best; Russell King agreed and suggested this bus could use the .match() method for the actual device discovery. The attached does this. For this old non (generically) discoverable ISA hardware only the driver itself can do discovery so as a difference with the platform_bus, this isa_bus also distributes match() up to the driver. As another difference: these devices only exist in the driver model due to the driver creating them because it might want to drive them, meaning that all device creation has been made internal as well. The usage model this provides is nice, and has been acked from the ALSA side by Takashi Iwai and Jaroslav Kysela. The ALSA driver module_init's now (for oldisa-only drivers) become: static int __init alsa_card_foo_init(void) { return isa_register_driver(&snd_foo_isa_driver, SNDRV_CARDS); } static void __exit alsa_card_foo_exit(void) { isa_unregister_driver(&snd_foo_isa_driver); } Quite like the other bus models therefore. This removes a lot of duplicated init code from the ALSA ISA drivers. The passed in isa_driver struct is the regular driver struct embedding a struct device_driver, the normal probe/remove/shutdown/suspend/resume callbacks, and as indicated that .match callback. The "SNDRV_CARDS" you see being passed in is a "unsigned int ndev" parameter, indicating how many devices to create and call our methods with. The platform_driver callbacks are called with a platform_device param; the isa_driver callbacks are being called with a "struct device *dev, unsigned int id" pair directly -- with the device creation completely internal to the bus it's much cleaner to not leak isa_dev's by passing them in at all. The id is the only thing we ever want other then the struct device * anyways, and it makes for nicer code in the callbacks as well. With this additional .match() callback ISA drivers have all options. If ALSA would want to keep the old non-load behaviour, it could stick all of the old .probe in .match, which would only keep them registered after everything was found to be present and accounted for. If it wanted the behaviour of always loading as it inadvertently did for a bit after the changeover to platform devices, it could just not provide a .match() and do everything in .probe() as before. If it, as Takashi Iwai already suggested earlier as a way of following the model from saner buses more closely, wants to load when a later bind could conceivably succeed, it could use .match() for the prerequisites (such as checking the user wants the card enabled and that port/irq/dma values have been passed in) and .probe() for everything else. This is the nicest model. To the code... This exports only two functions; isa_{,un}register_driver(). isa_register_driver() register's the struct device_driver, and then loops over the passed in ndev creating devices and registering them. This causes the bus match method to be called for them, which is: int isa_bus_match(struct device *dev, struct device_driver *driver) { struct isa_driver *isa_driver = to_isa_driver(driver); if (dev->platform_data == isa_driver) { if (!isa_driver->match || isa_driver->match(dev, to_isa_dev(dev)->id)) return 1; dev->platform_data = NULL; } return 0; } The first thing this does is check if this device is in fact one of this driver's devices by seeing if the device's platform_data pointer is set to this driver. Platform devices compare strings, but we don't need to do that with everything being internal, so isa_register_driver() abuses dev->platform_data as a isa_driver pointer which we can then check here. I believe platform_data is available for this, but if rather not, moving the isa_driver pointer to the private struct isa_dev is ofcourse fine as well. Then, if the the driver did not provide a .match, it matches. If it did, the driver match() method is called to determine a match. If it did _not_ match, dev->platform_data is reset to indicate this to isa_register_driver which can then unregister the device again. If during all this, there's any error, or no devices matched at all everything is backed out again and the error, or -ENODEV, is returned. isa_unregister_driver() just unregisters the matched devices and the driver itself. More global points/questions... - I'm introducing include/linux/isa.h. It was available but is ofcourse a somewhat generic name. Moving more isa stuff over to it in time is ofcourse fine, so can I have it please? :) - I'm using device_initcall() and added the isa.o (dependent on CONFIG_ISA) after the base driver model things in the Makefile. Will this do, or I really need to stick it in drivers/base/init.c, inside #ifdef CONFIG_ISA? It's working fine. Lastly -- I also looked, a bit, into integrating with PnP. "Old ISA" could be another pnp_protocol, but this does not seem to be a good match, largely due to the same reason platform_devices weren't -- the devices do not have a life of their own outside the driver, meaning the pnp_protocol {get,set}_resources callbacks would need to callback into driver -- which again means you first need to _have_ that driver. Even if there's clean way around that, you only end up inventing fake but valid-form PnP IDs and generally catering to the PnP layer without any practical advantages over this very simple isa_bus. The thing I also suggested earlier about the user echoing values into /sys to set up the hardware from userspace first is... well, cute, but a horrible idea from a user standpoint. Comments ofcourse appreciated. Hope it's okay. As said, the usage model is nice at least. Signed-off-by: Rene Herman --- drivers/base/Makefile | 1 + drivers/base/isa.c | 180 ++++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/isa.h | 28 ++++++++ 3 files changed, 209 insertions(+) create mode 100644 drivers/base/isa.c create mode 100644 include/linux/isa.h (limited to 'include') diff --git a/drivers/base/Makefile b/drivers/base/Makefile index 659cde6c2fb9..b539e5e75b56 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile @@ -5,6 +5,7 @@ obj-y := core.o sys.o bus.o dd.o \ cpu.o firmware.o init.o map.o dmapool.o \ attribute_container.o transport_class.o obj-y += power/ +obj-$(CONFIG_ISA) += isa.o obj-$(CONFIG_FW_LOADER) += firmware_class.o obj-$(CONFIG_NUMA) += node.o obj-$(CONFIG_MEMORY_HOTPLUG) += memory.o diff --git a/drivers/base/isa.c b/drivers/base/isa.c new file mode 100644 index 000000000000..d2222397a401 --- /dev/null +++ b/drivers/base/isa.c @@ -0,0 +1,180 @@ +/* + * ISA bus. + */ + +#include +#include +#include +#include +#include +#include + +static struct device isa_bus = { + .bus_id = "isa" +}; + +struct isa_dev { + struct device dev; + struct device *next; + unsigned int id; +}; + +#define to_isa_dev(x) container_of((x), struct isa_dev, dev) + +static int isa_bus_match(struct device *dev, struct device_driver *driver) +{ + struct isa_driver *isa_driver = to_isa_driver(driver); + + if (dev->platform_data == isa_driver) { + if (!isa_driver->match || + isa_driver->match(dev, to_isa_dev(dev)->id)) + return 1; + dev->platform_data = NULL; + } + return 0; +} + +static int isa_bus_probe(struct device *dev) +{ + struct isa_driver *isa_driver = dev->platform_data; + + if (isa_driver->probe) + return isa_driver->probe(dev, to_isa_dev(dev)->id); + + return 0; +} + +static int isa_bus_remove(struct device *dev) +{ + struct isa_driver *isa_driver = dev->platform_data; + + if (isa_driver->remove) + return isa_driver->remove(dev, to_isa_dev(dev)->id); + + return 0; +} + +static void isa_bus_shutdown(struct device *dev) +{ + struct isa_driver *isa_driver = dev->platform_data; + + if (isa_driver->shutdown) + isa_driver->shutdown(dev, to_isa_dev(dev)->id); +} + +static int isa_bus_suspend(struct device *dev, pm_message_t state) +{ + struct isa_driver *isa_driver = dev->platform_data; + + if (isa_driver->suspend) + return isa_driver->suspend(dev, to_isa_dev(dev)->id, state); + + return 0; +} + +static int isa_bus_resume(struct device *dev) +{ + struct isa_driver *isa_driver = dev->platform_data; + + if (isa_driver->resume) + return isa_driver->resume(dev, to_isa_dev(dev)->id); + + return 0; +} + +static struct bus_type isa_bus_type = { + .name = "isa", + .match = isa_bus_match, + .probe = isa_bus_probe, + .remove = isa_bus_remove, + .shutdown = isa_bus_shutdown, + .suspend = isa_bus_suspend, + .resume = isa_bus_resume +}; + +static void isa_dev_release(struct device *dev) +{ + kfree(to_isa_dev(dev)); +} + +void isa_unregister_driver(struct isa_driver *isa_driver) +{ + struct device *dev = isa_driver->devices; + + while (dev) { + struct device *tmp = to_isa_dev(dev)->next; + device_unregister(dev); + dev = tmp; + } + driver_unregister(&isa_driver->driver); +} +EXPORT_SYMBOL_GPL(isa_unregister_driver); + +int isa_register_driver(struct isa_driver *isa_driver, unsigned int ndev) +{ + int error; + unsigned int id; + + isa_driver->driver.bus = &isa_bus_type; + isa_driver->devices = NULL; + + error = driver_register(&isa_driver->driver); + if (error) + return error; + + for (id = 0; id < ndev; id++) { + struct isa_dev *isa_dev; + + isa_dev = kzalloc(sizeof *isa_dev, GFP_KERNEL); + if (!isa_dev) { + error = -ENOMEM; + break; + } + + isa_dev->dev.parent = &isa_bus; + isa_dev->dev.bus = &isa_bus_type; + + snprintf(isa_dev->dev.bus_id, BUS_ID_SIZE, "%s.%u", + isa_driver->driver.name, id); + + isa_dev->dev.platform_data = isa_driver; + isa_dev->dev.release = isa_dev_release; + isa_dev->id = id; + + error = device_register(&isa_dev->dev); + if (error) { + put_device(&isa_dev->dev); + break; + } + + if (isa_dev->dev.platform_data) { + isa_dev->next = isa_driver->devices; + isa_driver->devices = &isa_dev->dev; + } else + device_unregister(&isa_dev->dev); + } + + if (!error && !isa_driver->devices) + error = -ENODEV; + + if (error) + isa_unregister_driver(isa_driver); + + return error; +} +EXPORT_SYMBOL_GPL(isa_register_driver); + +static int __init isa_bus_init(void) +{ + int error; + + error = bus_register(&isa_bus_type); + if (!error) { + error = device_register(&isa_bus); + if (error) + bus_unregister(&isa_bus_type); + } + return error; +} + +device_initcall(isa_bus_init); diff --git a/include/linux/isa.h b/include/linux/isa.h new file mode 100644 index 000000000000..1b855335cb11 --- /dev/null +++ b/include/linux/isa.h @@ -0,0 +1,28 @@ +/* + * ISA bus. + */ + +#ifndef __LINUX_ISA_H +#define __LINUX_ISA_H + +#include +#include + +struct isa_driver { + int (*match)(struct device *, unsigned int); + int (*probe)(struct device *, unsigned int); + int (*remove)(struct device *, unsigned int); + void (*shutdown)(struct device *, unsigned int); + int (*suspend)(struct device *, unsigned int, pm_message_t); + int (*resume)(struct device *, unsigned int); + + struct device_driver driver; + struct device *devices; +}; + +#define to_isa_driver(x) container_of((x), struct isa_driver, driver) + +int isa_register_driver(struct isa_driver *, unsigned int); +void isa_unregister_driver(struct isa_driver *); + +#endif /* __LINUX_ISA_H */ -- cgit v1.2.3 From ea95972f18481089e73368f9e62f6d70087bf4de Mon Sep 17 00:00:00 2001 From: Russ Anderson Date: Wed, 10 May 2006 11:09:01 -0500 Subject: [IA64-SGI] Remove SN SAL error handling feature bit that is no longer needed Due to improvements in linux & SAL MCA handling, the SAL_ERR_FEAT_MCA_SLV_TO_OS_INIT_SLV error handling features bit is no longer needed. Signed-off-by: Russ Anderson (rja@sgi.com) Signed-off-by: Tony Luck --- include/asm-ia64/sn/sn_sal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/asm-ia64/sn/sn_sal.h b/include/asm-ia64/sn/sn_sal.h index 8c865e43f609..cd490b20d592 100644 --- a/include/asm-ia64/sn/sn_sal.h +++ b/include/asm-ia64/sn/sn_sal.h @@ -345,7 +345,7 @@ ia64_sn_plat_set_error_handling_features(void) ret_stuff.v1 = 0; ret_stuff.v2 = 0; SAL_CALL_REENTRANT(ret_stuff, SN_SAL_SET_ERROR_HANDLING_FEATURES, - (SAL_ERR_FEAT_MCA_SLV_TO_OS_INIT_SLV | SAL_ERR_FEAT_LOG_SBES), + SAL_ERR_FEAT_LOG_SBES, 0, 0, 0, 0, 0, 0); return ret_stuff.status; -- cgit v1.2.3 From d270acbc24f0ce451c773c214ac0e92e95396b2f Mon Sep 17 00:00:00 2001 From: Keith Owens Date: Fri, 7 Apr 2006 18:08:11 +1000 Subject: [IA64] Sanitize assembler code for ia64_sal_os_state struct ia64_sal_os_state has three semi-independent sections. The code in mca_asm.S assumes that these three sections are contiguous, which makes it very awkward to add new data to this structure. Remove the assumption that the sections are contiguous. Define a macro to shorten references to offsets in ia64_sal_os_state. This patch does not change the way that the code behaves. It just makes it easier to update the code in future and to add fields to ia64_sal_os_state when debugging the MCA/INIT handlers. Signed-off-by: Keith Owens Signed-off-by: Tony Luck --- arch/ia64/kernel/asm-offsets.c | 16 ++++++++++++---- arch/ia64/kernel/entry.h | 1 + arch/ia64/kernel/mca_asm.S | 28 +++++++++++++++++----------- include/asm-ia64/mca.h | 9 ++++++--- 4 files changed, 36 insertions(+), 18 deletions(-) (limited to 'include') diff --git a/arch/ia64/kernel/asm-offsets.c b/arch/ia64/kernel/asm-offsets.c index 77225659e968..16e7b6600ae6 100644 --- a/arch/ia64/kernel/asm-offsets.c +++ b/arch/ia64/kernel/asm-offsets.c @@ -217,16 +217,24 @@ void foo(void) DEFINE(IA64_MCA_CPU_INIT_STACK_OFFSET, offsetof (struct ia64_mca_cpu, init_stack)); BLANK(); - DEFINE(IA64_SAL_OS_STATE_COMMON_OFFSET, - offsetof (struct ia64_sal_os_state, sal_ra)); DEFINE(IA64_SAL_OS_STATE_OS_GP_OFFSET, offsetof (struct ia64_sal_os_state, os_gp)); - DEFINE(IA64_SAL_OS_STATE_PAL_MIN_STATE_OFFSET, - offsetof (struct ia64_sal_os_state, pal_min_state)); DEFINE(IA64_SAL_OS_STATE_PROC_STATE_PARAM_OFFSET, offsetof (struct ia64_sal_os_state, proc_state_param)); + DEFINE(IA64_SAL_OS_STATE_SAL_RA_OFFSET, + offsetof (struct ia64_sal_os_state, sal_ra)); + DEFINE(IA64_SAL_OS_STATE_SAL_GP_OFFSET, + offsetof (struct ia64_sal_os_state, sal_gp)); + DEFINE(IA64_SAL_OS_STATE_PAL_MIN_STATE_OFFSET, + offsetof (struct ia64_sal_os_state, pal_min_state)); + DEFINE(IA64_SAL_OS_STATE_OS_STATUS_OFFSET, + offsetof (struct ia64_sal_os_state, os_status)); + DEFINE(IA64_SAL_OS_STATE_CONTEXT_OFFSET, + offsetof (struct ia64_sal_os_state, context)); DEFINE(IA64_SAL_OS_STATE_SIZE, sizeof (struct ia64_sal_os_state)); + BLANK(); + DEFINE(IA64_PMSA_GR_OFFSET, offsetof (struct pal_min_state_area_s, pmsa_gr)); DEFINE(IA64_PMSA_BANK1_GR_OFFSET, diff --git a/arch/ia64/kernel/entry.h b/arch/ia64/kernel/entry.h index 78eeb0793419..ebc3dfb88826 100644 --- a/arch/ia64/kernel/entry.h +++ b/arch/ia64/kernel/entry.h @@ -23,6 +23,7 @@ #define PT(f) (IA64_PT_REGS_##f##_OFFSET) #define SW(f) (IA64_SWITCH_STACK_##f##_OFFSET) +#define SOS(f) (IA64_SAL_OS_STATE_##f##_OFFSET) #define PT_REGS_SAVES(off) \ .unwabi 3, 'i'; \ diff --git a/arch/ia64/kernel/mca_asm.S b/arch/ia64/kernel/mca_asm.S index 6dff024cd62b..c1bd1feffab0 100644 --- a/arch/ia64/kernel/mca_asm.S +++ b/arch/ia64/kernel/mca_asm.S @@ -159,7 +159,7 @@ ia64_os_mca_spin: GET_IA64_MCA_DATA(r2) // Using MCA stack, struct ia64_sal_os_state, variable proc_state_param ;; - add r3=IA64_MCA_CPU_MCA_STACK_OFFSET+MCA_SOS_OFFSET+IA64_SAL_OS_STATE_PROC_STATE_PARAM_OFFSET, r2 + add r3=IA64_MCA_CPU_MCA_STACK_OFFSET+MCA_SOS_OFFSET+SOS(PROC_STATE_PARAM), r2 ;; ld8 r18=[r3] // Get processor state parameter on existing PALE_CHECK. ;; @@ -479,9 +479,11 @@ ia64_state_save: st8 [temp2]=r11,16 // rv_rc mov r11=cr.iipa ;; - st8 [temp1]=r18,16 // proc_state_param - st8 [temp2]=r19,16 // monarch + st8 [temp1]=r18 // proc_state_param + st8 [temp2]=r19 // monarch mov r6=IA64_KR(CURRENT) + add temp1=SOS(SAL_RA), regs + add temp2=SOS(SAL_GP), regs ;; st8 [temp1]=r12,16 // sal_ra st8 [temp2]=r10,16 // sal_gp @@ -503,12 +505,14 @@ ia64_state_save: st8 [temp2]=r11,16 // cr.iipa mov r12=cr.iim ;; - st8 [temp1]=r12,16 // cr.iim + st8 [temp1]=r12 // cr.iim (p1) mov r12=IA64_MCA_COLD_BOOT (p2) mov r12=IA64_INIT_WARM_BOOT mov r6=cr.iha + add temp1=SOS(OS_STATUS), regs ;; - st8 [temp2]=r6,16 // cr.iha + st8 [temp2]=r6 // cr.iha + add temp2=SOS(CONTEXT), regs st8 [temp1]=r12 // os_status, default is cold boot mov r6=IA64_MCA_SAME_CONTEXT ;; @@ -820,8 +824,8 @@ ia64_state_restore: // Restore the SAL to OS state. The previous code left regs at pt_regs. add regs=MCA_SOS_OFFSET-MCA_PT_REGS_OFFSET, regs ;; - add temp1=IA64_SAL_OS_STATE_COMMON_OFFSET, regs - add temp2=IA64_SAL_OS_STATE_COMMON_OFFSET+8, regs + add temp1=SOS(SAL_RA), regs + add temp2=SOS(SAL_GP), regs ;; ld8 r12=[temp1],16 // sal_ra ld8 r9=[temp2],16 // sal_gp @@ -842,8 +846,10 @@ ia64_state_restore: ;; mov cr.itir=temp3 mov cr.iipa=temp4 - ld8 temp3=[temp1],16 // cr.iim - ld8 temp4=[temp2],16 // cr.iha + ld8 temp3=[temp1] // cr.iim + ld8 temp4=[temp2] // cr.iha + add temp1=SOS(OS_STATUS), regs + add temp2=SOS(CONTEXT), regs ;; mov cr.iim=temp3 mov cr.iha=temp4 @@ -916,7 +922,7 @@ ia64_state_restore: ia64_new_stack: add regs=MCA_PT_REGS_OFFSET, r3 - add temp2=MCA_SOS_OFFSET+IA64_SAL_OS_STATE_PAL_MIN_STATE_OFFSET, r3 + add temp2=MCA_SOS_OFFSET+SOS(PAL_MIN_STATE), r3 mov b0=r2 // save return address GET_IA64_MCA_DATA(temp1) invala @@ -1020,7 +1026,7 @@ ia64_old_stack: ia64_set_kernel_registers: add temp3=MCA_SP_OFFSET, r3 - add temp4=MCA_SOS_OFFSET+IA64_SAL_OS_STATE_OS_GP_OFFSET, r3 + add temp4=MCA_SOS_OFFSET+SOS(OS_GP), r3 mov b0=r2 // save return address GET_IA64_MCA_DATA(temp1) ;; diff --git a/include/asm-ia64/mca.h b/include/asm-ia64/mca.h index 9c5389b7e623..ee97f7c2d462 100644 --- a/include/asm-ia64/mca.h +++ b/include/asm-ia64/mca.h @@ -69,14 +69,16 @@ typedef struct ia64_mc_info_s { */ struct ia64_sal_os_state { - /* SAL to OS, must be at offset 0 */ + + /* SAL to OS */ u64 os_gp; /* GP of the os registered with the SAL, physical */ u64 pal_proc; /* PAL_PROC entry point, physical */ u64 sal_proc; /* SAL_PROC entry point, physical */ u64 rv_rc; /* MCA - Rendezvous state, INIT - reason code */ u64 proc_state_param; /* from R18 */ u64 monarch; /* 1 for a monarch event, 0 for a slave */ - /* common, must follow SAL to OS */ + + /* common */ u64 sal_ra; /* Return address in SAL, physical */ u64 sal_gp; /* GP of the SAL - physical */ pal_min_state_area_t *pal_min_state; /* from R17. physical in asm, virtual in C */ @@ -98,7 +100,8 @@ struct ia64_sal_os_state { u64 iipa; u64 iim; u64 iha; - /* OS to SAL, must follow common */ + + /* OS to SAL */ u64 os_status; /* OS status to SAL, enum below */ u64 context; /* 0 if return to same context 1 if return to new context */ -- cgit v1.2.3 From 782a7a632e4b0581ade665e3d89ee97c8db0f441 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 19 May 2006 13:20:20 -0700 Subject: [PATCH] USB: add usb_interrupt_msg() function for api completeness. Really just a wrapper around usb_bulk_msg() but now it's documented much better. Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/message.c | 31 +++++++++++++++++++++++++++++++ include/linux/usb.h | 2 ++ 2 files changed, 33 insertions(+) (limited to 'include') diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 08fb20f06f3e..b2f608b0538d 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -157,6 +157,37 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u } +/** + * usb_interrupt_msg - Builds an interrupt urb, sends it off and waits for completion + * @usb_dev: pointer to the usb device to send the message to + * @pipe: endpoint "pipe" to send the message to + * @data: pointer to the data to send + * @len: length in bytes of the data to send + * @actual_length: pointer to a location to put the actual length transferred in bytes + * @timeout: time in msecs to wait for the message to complete before + * timing out (if 0 the wait is forever) + * Context: !in_interrupt () + * + * This function sends a simple interrupt message to a specified endpoint and + * waits for the message to complete, or timeout. + * + * If successful, it returns 0, otherwise a negative error number. The number + * of actual bytes transferred will be stored in the actual_length paramater. + * + * Don't use this function from within an interrupt context, like a bottom half + * handler. If you need an asynchronous message, or need to send a message + * from within interrupt context, use usb_submit_urb() If a thread in your + * driver uses this call, make sure your disconnect() method can wait for it to + * complete. Since you don't have a handle on the URB used, you can't cancel + * the request. + */ +int usb_interrupt_msg(struct usb_device *usb_dev, unsigned int pipe, + void *data, int len, int *actual_length, int timeout) +{ + return usb_bulk_msg(usb_dev, pipe, data, len, actual_length, timeout); +} +EXPORT_SYMBOL_GPL(usb_interrupt_msg); + /** * usb_bulk_msg - Builds a bulk urb, sends it off and waits for completion * @usb_dev: pointer to the usb device to send the message to diff --git a/include/linux/usb.h b/include/linux/usb.h index 1f492c0c7047..317ec9f28bce 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -1008,6 +1008,8 @@ void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe, extern int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, __u16 size, int timeout); +extern int usb_interrupt_msg(struct usb_device *usb_dev, unsigned int pipe, + void *data, int len, int *actual_length, int timeout); extern int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int *actual_length, int timeout); -- cgit v1.2.3 From 79efa097e75018a2918155f343f0e08e61ee8a8c Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 1 Jun 2006 13:33:42 -0400 Subject: [PATCH] usbcore: port reset for composite devices This patch (as699) adds usb_reset_composite_device(), a routine for sending a USB port reset to a device with multiple interfaces owned by different drivers. Drivers are notified about impending and completed resets through two new methods in the usb_driver structure. The patch modifieds the usbfs ioctl code to make it use the new routine instead of usb_reset_device(). Follow-up patches will modify the hub, usb-storage, and usbhid drivers so they can utilize this new API. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 3 +- drivers/usb/core/hub.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++-- drivers/usb/core/usb.c | 1 + include/linux/usb.h | 9 ++++++ 4 files changed, 92 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index b04ede772f2c..df3fb57d71e6 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -823,8 +823,7 @@ static int proc_connectinfo(struct dev_state *ps, void __user *arg) static int proc_resetdevice(struct dev_state *ps) { - return usb_reset_device(ps->dev); - + return usb_reset_composite_device(ps->dev, NULL); } static int proc_setintf(struct dev_state *ps, void __user *arg) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index f41c08946a52..37c67d7e8b84 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -3007,9 +3007,9 @@ static int config_descriptors_changed(struct usb_device *udev) * usb_reset_device - perform a USB port reset to reinitialize a device * @udev: device to reset (not in SUSPENDED or NOTATTACHED state) * - * WARNING - don't reset any device unless drivers for all of its - * interfaces are expecting that reset! Maybe some driver->reset() - * method should eventually help ensure sufficient cooperation. + * WARNING - don't use this routine to reset a composite device + * (one with multiple interfaces owned by separate drivers)! + * Use usb_reset_composite_device() instead. * * Do a port reset, reassign the device's address, and establish its * former operating configuration. If the reset fails, or the device's @@ -3125,3 +3125,81 @@ re_enumerate: hub_port_logical_disconnect(parent_hub, port1); return -ENODEV; } + +/** + * usb_reset_composite_device - warn interface drivers and perform a USB port reset + * @udev: device to reset (not in SUSPENDED or NOTATTACHED state) + * @iface: interface bound to the driver making the request (optional) + * + * Warns all drivers bound to registered interfaces (using their pre_reset + * method), performs the port reset, and then lets the drivers know that + * the reset is over (using their post_reset method). + * + * Return value is the same as for usb_reset_device(). + * + * The caller must own the device lock. For example, it's safe to use + * this from a driver probe() routine after downloading new firmware. + * For calls that might not occur during probe(), drivers should lock + * the device using usb_lock_device_for_reset(). + * + * The interface locks are acquired during the pre_reset stage and released + * during the post_reset stage. However if iface is not NULL and is + * currently being probed, we assume that the caller already owns its + * lock. + */ +int usb_reset_composite_device(struct usb_device *udev, + struct usb_interface *iface) +{ + int ret; + struct usb_host_config *config = udev->actconfig; + + if (udev->state == USB_STATE_NOTATTACHED || + udev->state == USB_STATE_SUSPENDED) { + dev_dbg(&udev->dev, "device reset not allowed in state %d\n", + udev->state); + return -EINVAL; + } + + if (iface && iface->condition != USB_INTERFACE_BINDING) + iface = NULL; + + if (config) { + int i; + struct usb_interface *cintf; + struct usb_driver *drv; + + for (i = 0; i < config->desc.bNumInterfaces; ++i) { + cintf = config->interface[i]; + if (cintf != iface) + down(&cintf->dev.sem); + if (device_is_registered(&cintf->dev) && + cintf->dev.driver) { + drv = to_usb_driver(cintf->dev.driver); + if (drv->pre_reset) + (drv->pre_reset)(cintf); + } + } + } + + ret = usb_reset_device(udev); + + if (config) { + int i; + struct usb_interface *cintf; + struct usb_driver *drv; + + for (i = config->desc.bNumInterfaces - 1; i >= 0; --i) { + cintf = config->interface[i]; + if (device_is_registered(&cintf->dev) && + cintf->dev.driver) { + drv = to_usb_driver(cintf->dev.driver); + if (drv->post_reset) + (drv->post_reset)(cintf); + } + if (cintf != iface) + up(&cintf->dev.sem); + } + } + + return ret; +} diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index b7fdc1cd134a..515310751303 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -1207,6 +1207,7 @@ EXPORT_SYMBOL(usb_ifnum_to_if); EXPORT_SYMBOL(usb_altnum_to_altsetting); EXPORT_SYMBOL(usb_reset_device); +EXPORT_SYMBOL(usb_reset_composite_device); EXPORT_SYMBOL(__usb_get_extra_descriptor); diff --git a/include/linux/usb.h b/include/linux/usb.h index 317ec9f28bce..5ad30cefe7b2 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -386,6 +386,8 @@ extern int usb_lock_device_for_reset(struct usb_device *udev, /* USB port reset for device reinitialization */ extern int usb_reset_device(struct usb_device *dev); +extern int usb_reset_composite_device(struct usb_device *dev, + struct usb_interface *iface); extern struct usb_device *usb_find_device(u16 vendor_id, u16 product_id); @@ -554,6 +556,10 @@ struct usb_dynids { * do (or don't) show up otherwise in the filesystem. * @suspend: Called when the device is going to be suspended by the system. * @resume: Called when the device is being resumed by the system. + * @pre_reset: Called by usb_reset_composite_device() when the device + * is about to be reset. + * @post_reset: Called by usb_reset_composite_device() after the device + * has been reset. * @id_table: USB drivers use ID table to support hotplugging. * Export this with MODULE_DEVICE_TABLE(usb,...). This must be set * or your driver's probe function will never get called. @@ -592,6 +598,9 @@ struct usb_driver { int (*suspend) (struct usb_interface *intf, pm_message_t message); int (*resume) (struct usb_interface *intf); + void (*pre_reset) (struct usb_interface *intf); + void (*post_reset) (struct usb_interface *intf); + const struct usb_device_id *id_table; struct usb_dynids dynids; -- cgit v1.2.3 From a8c28f2389942bab376e39351d27525499630248 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 13 Jun 2006 09:57:47 -0700 Subject: [PATCH] USB: move to This moves to to reduce some of the clutter of usb header files. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 2 +- drivers/usb/gadget/ether.c | 2 +- drivers/usb/gadget/serial.c | 2 +- drivers/usb/net/cdc_ether.c | 2 +- drivers/usb/net/rndis_host.c | 2 +- drivers/usb/net/zaurus.c | 2 +- include/linux/usb/cdc.h | 205 +++++++++++++++++++++++++++++++++++++++++++ include/linux/usb_cdc.h | 205 ------------------------------------------- 8 files changed, 211 insertions(+), 211 deletions(-) create mode 100644 include/linux/usb/cdc.h delete mode 100644 include/linux/usb_cdc.h (limited to 'include') diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 506aff60dac5..d41dc67ba4cc 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -63,7 +63,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index fc4684096fcc..078daa026718 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -49,7 +49,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index e477edd681d3..9d6e1d295528 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -45,7 +45,7 @@ #include #include -#include +#include #include #include "gadget_chips.h" diff --git a/drivers/usb/net/cdc_ether.c b/drivers/usb/net/cdc_ether.c index 9c6c5b0b01ad..efd195b5912c 100644 --- a/drivers/usb/net/cdc_ether.c +++ b/drivers/usb/net/cdc_ether.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include "usbnet.h" diff --git a/drivers/usb/net/rndis_host.c b/drivers/usb/net/rndis_host.c index 94ddfe16fdda..f551546d7521 100644 --- a/drivers/usb/net/rndis_host.c +++ b/drivers/usb/net/rndis_host.c @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include "usbnet.h" diff --git a/drivers/usb/net/zaurus.c b/drivers/usb/net/zaurus.c index bf2035d329f4..813e470d0600 100644 --- a/drivers/usb/net/zaurus.c +++ b/drivers/usb/net/zaurus.c @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include "usbnet.h" diff --git a/include/linux/usb/cdc.h b/include/linux/usb/cdc.h new file mode 100644 index 000000000000..ba617c372455 --- /dev/null +++ b/include/linux/usb/cdc.h @@ -0,0 +1,205 @@ +/* + * USB Communications Device Class (CDC) definitions + * + * CDC says how to talk to lots of different types of network adapters, + * notably ethernet adapters and various modems. It's used mostly with + * firmware based USB peripherals. + */ + +#define USB_CDC_SUBCLASS_ACM 0x02 +#define USB_CDC_SUBCLASS_ETHERNET 0x06 +#define USB_CDC_SUBCLASS_WHCM 0x08 +#define USB_CDC_SUBCLASS_DMM 0x09 +#define USB_CDC_SUBCLASS_MDLM 0x0a +#define USB_CDC_SUBCLASS_OBEX 0x0b + +#define USB_CDC_PROTO_NONE 0 + +#define USB_CDC_ACM_PROTO_AT_V25TER 1 +#define USB_CDC_ACM_PROTO_AT_PCCA101 2 +#define USB_CDC_ACM_PROTO_AT_PCCA101_WAKE 3 +#define USB_CDC_ACM_PROTO_AT_GSM 4 +#define USB_CDC_ACM_PROTO_AT_3G 5 +#define USB_CDC_ACM_PROTO_AT_CDMA 6 +#define USB_CDC_ACM_PROTO_VENDOR 0xff + +/*-------------------------------------------------------------------------*/ + +/* + * Class-Specific descriptors ... there are a couple dozen of them + */ + +#define USB_CDC_HEADER_TYPE 0x00 /* header_desc */ +#define USB_CDC_CALL_MANAGEMENT_TYPE 0x01 /* call_mgmt_descriptor */ +#define USB_CDC_ACM_TYPE 0x02 /* acm_descriptor */ +#define USB_CDC_UNION_TYPE 0x06 /* union_desc */ +#define USB_CDC_COUNTRY_TYPE 0x07 +#define USB_CDC_NETWORK_TERMINAL_TYPE 0x0a /* network_terminal_desc */ +#define USB_CDC_ETHERNET_TYPE 0x0f /* ether_desc */ +#define USB_CDC_WHCM_TYPE 0x11 +#define USB_CDC_MDLM_TYPE 0x12 /* mdlm_desc */ +#define USB_CDC_MDLM_DETAIL_TYPE 0x13 /* mdlm_detail_desc */ +#define USB_CDC_DMM_TYPE 0x14 +#define USB_CDC_OBEX_TYPE 0x15 + +/* "Header Functional Descriptor" from CDC spec 5.2.3.1 */ +struct usb_cdc_header_desc { + __u8 bLength; + __u8 bDescriptorType; + __u8 bDescriptorSubType; + + __le16 bcdCDC; +} __attribute__ ((packed)); + +/* "Call Management Descriptor" from CDC spec 5.2.3.2 */ +struct usb_cdc_call_mgmt_descriptor { + __u8 bLength; + __u8 bDescriptorType; + __u8 bDescriptorSubType; + + __u8 bmCapabilities; +#define USB_CDC_CALL_MGMT_CAP_CALL_MGMT 0x01 +#define USB_CDC_CALL_MGMT_CAP_DATA_INTF 0x02 + + __u8 bDataInterface; +} __attribute__ ((packed)); + +/* "Abstract Control Management Descriptor" from CDC spec 5.2.3.3 */ +struct usb_cdc_acm_descriptor { + __u8 bLength; + __u8 bDescriptorType; + __u8 bDescriptorSubType; + + __u8 bmCapabilities; +} __attribute__ ((packed)); + +/* "Union Functional Descriptor" from CDC spec 5.2.3.8 */ +struct usb_cdc_union_desc { + __u8 bLength; + __u8 bDescriptorType; + __u8 bDescriptorSubType; + + __u8 bMasterInterface0; + __u8 bSlaveInterface0; + /* ... and there could be other slave interfaces */ +} __attribute__ ((packed)); + +/* "Network Channel Terminal Functional Descriptor" from CDC spec 5.2.3.11 */ +struct usb_cdc_network_terminal_desc { + __u8 bLength; + __u8 bDescriptorType; + __u8 bDescriptorSubType; + + __u8 bEntityId; + __u8 iName; + __u8 bChannelIndex; + __u8 bPhysicalInterface; +} __attribute__ ((packed)); + +/* "Ethernet Networking Functional Descriptor" from CDC spec 5.2.3.16 */ +struct usb_cdc_ether_desc { + __u8 bLength; + __u8 bDescriptorType; + __u8 bDescriptorSubType; + + __u8 iMACAddress; + __le32 bmEthernetStatistics; + __le16 wMaxSegmentSize; + __le16 wNumberMCFilters; + __u8 bNumberPowerFilters; +} __attribute__ ((packed)); + +/* "MDLM Functional Descriptor" from CDC WMC spec 6.7.2.3 */ +struct usb_cdc_mdlm_desc { + __u8 bLength; + __u8 bDescriptorType; + __u8 bDescriptorSubType; + + __le16 bcdVersion; + __u8 bGUID[16]; +} __attribute__ ((packed)); + +/* "MDLM Detail Functional Descriptor" from CDC WMC spec 6.7.2.4 */ +struct usb_cdc_mdlm_detail_desc { + __u8 bLength; + __u8 bDescriptorType; + __u8 bDescriptorSubType; + + /* type is associated with mdlm_desc.bGUID */ + __u8 bGuidDescriptorType; + __u8 bDetailData[0]; +} __attribute__ ((packed)); + +/*-------------------------------------------------------------------------*/ + +/* + * Class-Specific Control Requests (6.2) + * + * section 3.6.2.1 table 4 has the ACM profile, for modems. + * section 3.8.2 table 10 has the ethernet profile. + * + * Microsoft's RNDIS stack for Ethernet is a vendor-specific CDC ACM variant, + * heavily dependent on the encapsulated (proprietary) command mechanism. + */ + +#define USB_CDC_SEND_ENCAPSULATED_COMMAND 0x00 +#define USB_CDC_GET_ENCAPSULATED_RESPONSE 0x01 +#define USB_CDC_REQ_SET_LINE_CODING 0x20 +#define USB_CDC_REQ_GET_LINE_CODING 0x21 +#define USB_CDC_REQ_SET_CONTROL_LINE_STATE 0x22 +#define USB_CDC_REQ_SEND_BREAK 0x23 +#define USB_CDC_SET_ETHERNET_MULTICAST_FILTERS 0x40 +#define USB_CDC_SET_ETHERNET_PM_PATTERN_FILTER 0x41 +#define USB_CDC_GET_ETHERNET_PM_PATTERN_FILTER 0x42 +#define USB_CDC_SET_ETHERNET_PACKET_FILTER 0x43 +#define USB_CDC_GET_ETHERNET_STATISTIC 0x44 + +/* Line Coding Structure from CDC spec 6.2.13 */ +struct usb_cdc_line_coding { + __le32 dwDTERate; + __u8 bCharFormat; +#define USB_CDC_1_STOP_BITS 0 +#define USB_CDC_1_5_STOP_BITS 1 +#define USB_CDC_2_STOP_BITS 2 + + __u8 bParityType; +#define USB_CDC_NO_PARITY 0 +#define USB_CDC_ODD_PARITY 1 +#define USB_CDC_EVEN_PARITY 2 +#define USB_CDC_MARK_PARITY 3 +#define USB_CDC_SPACE_PARITY 4 + + __u8 bDataBits; +} __attribute__ ((packed)); + +/* table 62; bits in multicast filter */ +#define USB_CDC_PACKET_TYPE_PROMISCUOUS (1 << 0) +#define USB_CDC_PACKET_TYPE_ALL_MULTICAST (1 << 1) /* no filter */ +#define USB_CDC_PACKET_TYPE_DIRECTED (1 << 2) +#define USB_CDC_PACKET_TYPE_BROADCAST (1 << 3) +#define USB_CDC_PACKET_TYPE_MULTICAST (1 << 4) /* filtered */ + + +/*-------------------------------------------------------------------------*/ + +/* + * Class-Specific Notifications (6.3) sent by interrupt transfers + * + * section 3.8.2 table 11 of the CDC spec lists Ethernet notifications + * section 3.6.2.1 table 5 specifies ACM notifications, accepted by RNDIS + * RNDIS also defines its own bit-incompatible notifications + */ + +#define USB_CDC_NOTIFY_NETWORK_CONNECTION 0x00 +#define USB_CDC_NOTIFY_RESPONSE_AVAILABLE 0x01 +#define USB_CDC_NOTIFY_SERIAL_STATE 0x20 +#define USB_CDC_NOTIFY_SPEED_CHANGE 0x2a + +struct usb_cdc_notification { + __u8 bmRequestType; + __u8 bNotificationType; + __le16 wValue; + __le16 wIndex; + __le16 wLength; +} __attribute__ ((packed)); + diff --git a/include/linux/usb_cdc.h b/include/linux/usb_cdc.h deleted file mode 100644 index ba617c372455..000000000000 --- a/include/linux/usb_cdc.h +++ /dev/null @@ -1,205 +0,0 @@ -/* - * USB Communications Device Class (CDC) definitions - * - * CDC says how to talk to lots of different types of network adapters, - * notably ethernet adapters and various modems. It's used mostly with - * firmware based USB peripherals. - */ - -#define USB_CDC_SUBCLASS_ACM 0x02 -#define USB_CDC_SUBCLASS_ETHERNET 0x06 -#define USB_CDC_SUBCLASS_WHCM 0x08 -#define USB_CDC_SUBCLASS_DMM 0x09 -#define USB_CDC_SUBCLASS_MDLM 0x0a -#define USB_CDC_SUBCLASS_OBEX 0x0b - -#define USB_CDC_PROTO_NONE 0 - -#define USB_CDC_ACM_PROTO_AT_V25TER 1 -#define USB_CDC_ACM_PROTO_AT_PCCA101 2 -#define USB_CDC_ACM_PROTO_AT_PCCA101_WAKE 3 -#define USB_CDC_ACM_PROTO_AT_GSM 4 -#define USB_CDC_ACM_PROTO_AT_3G 5 -#define USB_CDC_ACM_PROTO_AT_CDMA 6 -#define USB_CDC_ACM_PROTO_VENDOR 0xff - -/*-------------------------------------------------------------------------*/ - -/* - * Class-Specific descriptors ... there are a couple dozen of them - */ - -#define USB_CDC_HEADER_TYPE 0x00 /* header_desc */ -#define USB_CDC_CALL_MANAGEMENT_TYPE 0x01 /* call_mgmt_descriptor */ -#define USB_CDC_ACM_TYPE 0x02 /* acm_descriptor */ -#define USB_CDC_UNION_TYPE 0x06 /* union_desc */ -#define USB_CDC_COUNTRY_TYPE 0x07 -#define USB_CDC_NETWORK_TERMINAL_TYPE 0x0a /* network_terminal_desc */ -#define USB_CDC_ETHERNET_TYPE 0x0f /* ether_desc */ -#define USB_CDC_WHCM_TYPE 0x11 -#define USB_CDC_MDLM_TYPE 0x12 /* mdlm_desc */ -#define USB_CDC_MDLM_DETAIL_TYPE 0x13 /* mdlm_detail_desc */ -#define USB_CDC_DMM_TYPE 0x14 -#define USB_CDC_OBEX_TYPE 0x15 - -/* "Header Functional Descriptor" from CDC spec 5.2.3.1 */ -struct usb_cdc_header_desc { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - - __le16 bcdCDC; -} __attribute__ ((packed)); - -/* "Call Management Descriptor" from CDC spec 5.2.3.2 */ -struct usb_cdc_call_mgmt_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - - __u8 bmCapabilities; -#define USB_CDC_CALL_MGMT_CAP_CALL_MGMT 0x01 -#define USB_CDC_CALL_MGMT_CAP_DATA_INTF 0x02 - - __u8 bDataInterface; -} __attribute__ ((packed)); - -/* "Abstract Control Management Descriptor" from CDC spec 5.2.3.3 */ -struct usb_cdc_acm_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - - __u8 bmCapabilities; -} __attribute__ ((packed)); - -/* "Union Functional Descriptor" from CDC spec 5.2.3.8 */ -struct usb_cdc_union_desc { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - - __u8 bMasterInterface0; - __u8 bSlaveInterface0; - /* ... and there could be other slave interfaces */ -} __attribute__ ((packed)); - -/* "Network Channel Terminal Functional Descriptor" from CDC spec 5.2.3.11 */ -struct usb_cdc_network_terminal_desc { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - - __u8 bEntityId; - __u8 iName; - __u8 bChannelIndex; - __u8 bPhysicalInterface; -} __attribute__ ((packed)); - -/* "Ethernet Networking Functional Descriptor" from CDC spec 5.2.3.16 */ -struct usb_cdc_ether_desc { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - - __u8 iMACAddress; - __le32 bmEthernetStatistics; - __le16 wMaxSegmentSize; - __le16 wNumberMCFilters; - __u8 bNumberPowerFilters; -} __attribute__ ((packed)); - -/* "MDLM Functional Descriptor" from CDC WMC spec 6.7.2.3 */ -struct usb_cdc_mdlm_desc { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - - __le16 bcdVersion; - __u8 bGUID[16]; -} __attribute__ ((packed)); - -/* "MDLM Detail Functional Descriptor" from CDC WMC spec 6.7.2.4 */ -struct usb_cdc_mdlm_detail_desc { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - - /* type is associated with mdlm_desc.bGUID */ - __u8 bGuidDescriptorType; - __u8 bDetailData[0]; -} __attribute__ ((packed)); - -/*-------------------------------------------------------------------------*/ - -/* - * Class-Specific Control Requests (6.2) - * - * section 3.6.2.1 table 4 has the ACM profile, for modems. - * section 3.8.2 table 10 has the ethernet profile. - * - * Microsoft's RNDIS stack for Ethernet is a vendor-specific CDC ACM variant, - * heavily dependent on the encapsulated (proprietary) command mechanism. - */ - -#define USB_CDC_SEND_ENCAPSULATED_COMMAND 0x00 -#define USB_CDC_GET_ENCAPSULATED_RESPONSE 0x01 -#define USB_CDC_REQ_SET_LINE_CODING 0x20 -#define USB_CDC_REQ_GET_LINE_CODING 0x21 -#define USB_CDC_REQ_SET_CONTROL_LINE_STATE 0x22 -#define USB_CDC_REQ_SEND_BREAK 0x23 -#define USB_CDC_SET_ETHERNET_MULTICAST_FILTERS 0x40 -#define USB_CDC_SET_ETHERNET_PM_PATTERN_FILTER 0x41 -#define USB_CDC_GET_ETHERNET_PM_PATTERN_FILTER 0x42 -#define USB_CDC_SET_ETHERNET_PACKET_FILTER 0x43 -#define USB_CDC_GET_ETHERNET_STATISTIC 0x44 - -/* Line Coding Structure from CDC spec 6.2.13 */ -struct usb_cdc_line_coding { - __le32 dwDTERate; - __u8 bCharFormat; -#define USB_CDC_1_STOP_BITS 0 -#define USB_CDC_1_5_STOP_BITS 1 -#define USB_CDC_2_STOP_BITS 2 - - __u8 bParityType; -#define USB_CDC_NO_PARITY 0 -#define USB_CDC_ODD_PARITY 1 -#define USB_CDC_EVEN_PARITY 2 -#define USB_CDC_MARK_PARITY 3 -#define USB_CDC_SPACE_PARITY 4 - - __u8 bDataBits; -} __attribute__ ((packed)); - -/* table 62; bits in multicast filter */ -#define USB_CDC_PACKET_TYPE_PROMISCUOUS (1 << 0) -#define USB_CDC_PACKET_TYPE_ALL_MULTICAST (1 << 1) /* no filter */ -#define USB_CDC_PACKET_TYPE_DIRECTED (1 << 2) -#define USB_CDC_PACKET_TYPE_BROADCAST (1 << 3) -#define USB_CDC_PACKET_TYPE_MULTICAST (1 << 4) /* filtered */ - - -/*-------------------------------------------------------------------------*/ - -/* - * Class-Specific Notifications (6.3) sent by interrupt transfers - * - * section 3.8.2 table 11 of the CDC spec lists Ethernet notifications - * section 3.6.2.1 table 5 specifies ACM notifications, accepted by RNDIS - * RNDIS also defines its own bit-incompatible notifications - */ - -#define USB_CDC_NOTIFY_NETWORK_CONNECTION 0x00 -#define USB_CDC_NOTIFY_RESPONSE_AVAILABLE 0x01 -#define USB_CDC_NOTIFY_SERIAL_STATE 0x20 -#define USB_CDC_NOTIFY_SPEED_CHANGE 0x2a - -struct usb_cdc_notification { - __u8 bmRequestType; - __u8 bNotificationType; - __le16 wValue; - __le16 wIndex; - __le16 wLength; -} __attribute__ ((packed)); - -- cgit v1.2.3 From 325a4af60dc945bf2da9cbcdbabb276e312b297c Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 13 Jun 2006 09:59:32 -0700 Subject: [PATCH] USB: move hardware-specific to This moves header files for controller-specific platform data from to to start reducing some clutter. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/isp116x-hcd.c | 2 +- drivers/usb/host/sl811-hcd.c | 2 +- drivers/usb/host/sl811_cs.c | 2 +- include/linux/usb/isp116x.h | 29 +++++++++++++++++++++++++++++ include/linux/usb/sl811.h | 26 ++++++++++++++++++++++++++ include/linux/usb_isp116x.h | 29 ----------------------------- include/linux/usb_sl811.h | 26 -------------------------- 7 files changed, 58 insertions(+), 58 deletions(-) create mode 100644 include/linux/usb/isp116x.h create mode 100644 include/linux/usb/sl811.h delete mode 100644 include/linux/usb_isp116x.h delete mode 100644 include/linux/usb_sl811.h (limited to 'include') diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index c5e224048efa..14386254c870 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -63,7 +63,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index a92343052751..6b4bc3f2bd86 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -46,7 +46,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/usb/host/sl811_cs.c b/drivers/usb/host/sl811_cs.c index 302aa1ec312f..54f554e0f0ad 100644 --- a/drivers/usb/host/sl811_cs.c +++ b/drivers/usb/host/sl811_cs.c @@ -27,7 +27,7 @@ #include #include -#include +#include MODULE_AUTHOR("Botond Botyanszki"); MODULE_DESCRIPTION("REX-CFU1U PCMCIA driver for 2.6"); diff --git a/include/linux/usb/isp116x.h b/include/linux/usb/isp116x.h new file mode 100644 index 000000000000..436dd8a2b64a --- /dev/null +++ b/include/linux/usb/isp116x.h @@ -0,0 +1,29 @@ + +/* + * Board initialization code should put one of these into dev->platform_data + * and place the isp116x onto platform_bus. + */ + +struct isp116x_platform_data { + /* Enable internal resistors on downstream ports */ + unsigned sel15Kres:1; + /* On-chip overcurrent detection */ + unsigned oc_enable:1; + /* INT output polarity */ + unsigned int_act_high:1; + /* INT edge or level triggered */ + unsigned int_edge_triggered:1; + /* Enable wakeup by devices on usb bus (e.g. wakeup + by attachment/detachment or by device activity + such as moving a mouse). When chosen, this option + prevents stopping internal clock, increasing + thereby power consumption in suspended state. */ + unsigned remote_wakeup_enable:1; + /* Inter-io delay (ns). The chip is picky about access timings; it + expects at least: + 150ns delay between consecutive accesses to DATA_REG, + 300ns delay between access to ADDR_REG and DATA_REG + OE, WE MUST NOT be changed during these intervals + */ + void (*delay) (struct device * dev, int delay); +}; diff --git a/include/linux/usb/sl811.h b/include/linux/usb/sl811.h new file mode 100644 index 000000000000..397ee3b3d7f3 --- /dev/null +++ b/include/linux/usb/sl811.h @@ -0,0 +1,26 @@ + +/* + * board initialization should put one of these into dev->platform_data + * and place the sl811hs onto platform_bus named "sl811-hcd". + */ + +struct sl811_platform_data { + unsigned can_wakeup:1; + + /* given port_power, msec/2 after power on till power good */ + u8 potpg; + + /* mA/2 power supplied on this port (max = default = 250) */ + u8 power; + + /* sl811 relies on an external source of VBUS current */ + void (*port_power)(struct device *dev, int is_on); + + /* pulse sl811 nRST (probably with a GPIO) */ + void (*reset)(struct device *dev); + + // some boards need something like these: + // int (*check_overcurrent)(struct device *dev); + // void (*clock_enable)(struct device *dev, int is_on); +}; + diff --git a/include/linux/usb_isp116x.h b/include/linux/usb_isp116x.h deleted file mode 100644 index 436dd8a2b64a..000000000000 --- a/include/linux/usb_isp116x.h +++ /dev/null @@ -1,29 +0,0 @@ - -/* - * Board initialization code should put one of these into dev->platform_data - * and place the isp116x onto platform_bus. - */ - -struct isp116x_platform_data { - /* Enable internal resistors on downstream ports */ - unsigned sel15Kres:1; - /* On-chip overcurrent detection */ - unsigned oc_enable:1; - /* INT output polarity */ - unsigned int_act_high:1; - /* INT edge or level triggered */ - unsigned int_edge_triggered:1; - /* Enable wakeup by devices on usb bus (e.g. wakeup - by attachment/detachment or by device activity - such as moving a mouse). When chosen, this option - prevents stopping internal clock, increasing - thereby power consumption in suspended state. */ - unsigned remote_wakeup_enable:1; - /* Inter-io delay (ns). The chip is picky about access timings; it - expects at least: - 150ns delay between consecutive accesses to DATA_REG, - 300ns delay between access to ADDR_REG and DATA_REG - OE, WE MUST NOT be changed during these intervals - */ - void (*delay) (struct device * dev, int delay); -}; diff --git a/include/linux/usb_sl811.h b/include/linux/usb_sl811.h deleted file mode 100644 index 4f2d012d7309..000000000000 --- a/include/linux/usb_sl811.h +++ /dev/null @@ -1,26 +0,0 @@ - -/* - * board initialization should put one of these into dev->platform_data - * and place the sl811hs onto platform_bus named "sl811-hcd". - */ - -struct sl811_platform_data { - unsigned can_wakeup:1; - - /* given port_power, msec/2 after power on till power good */ - u8 potpg; - - /* mA/2 power supplied on this port (max = default = 250) */ - u8 power; - - /* sl811 relies on an external source of VBUS current */ - void (*port_power)(struct device *dev, int is_on); - - /* pulse sl811 nRST (probably with a GPIO) */ - void (*reset)(struct device *dev); - - // some boards need something like these: - // int (*check_overcurrent)(struct device *dev); - // void (*clock_enable)(struct device *dev, int is_on); -}; - -- cgit v1.2.3 From ae0dadcf0f912cbab2ac84caa437454620bf71b2 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 13 Jun 2006 10:04:34 -0700 Subject: [PATCH] USB: move to Move to and remove some redundant includes. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/media/video/usbvideo/konicawc.c | 3 +-- drivers/usb/input/acecad.c | 4 +--- drivers/usb/input/aiptek.c | 4 +--- drivers/usb/input/appletouch.c | 4 +--- drivers/usb/input/ati_remote.c | 4 +--- drivers/usb/input/ati_remote2.c | 2 +- drivers/usb/input/hid-input.c | 4 +--- drivers/usb/input/itmtouch.c | 4 +--- drivers/usb/input/kbtab.c | 5 +---- drivers/usb/input/keyspan_remote.c | 4 +--- drivers/usb/input/mtouchusb.c | 4 +--- drivers/usb/input/powermate.c | 4 +--- drivers/usb/input/touchkitusb.c | 4 +--- drivers/usb/input/usbkbd.c | 4 +--- drivers/usb/input/usbmouse.c | 4 +--- drivers/usb/input/usbtouchscreen.c | 2 +- drivers/usb/input/wacom.c | 5 +---- drivers/usb/input/xpad.c | 4 +--- drivers/usb/input/yealink.c | 4 +--- drivers/usb/storage/onetouch.c | 3 +-- include/linux/usb/input.h | 25 +++++++++++++++++++++++++ include/linux/usb_input.h | 25 ------------------------- 22 files changed, 45 insertions(+), 81 deletions(-) create mode 100644 include/linux/usb/input.h delete mode 100644 include/linux/usb_input.h (limited to 'include') diff --git a/drivers/media/video/usbvideo/konicawc.c b/drivers/media/video/usbvideo/konicawc.c index c11f5d46b114..6f31ecc88843 100644 --- a/drivers/media/video/usbvideo/konicawc.c +++ b/drivers/media/video/usbvideo/konicawc.c @@ -15,8 +15,7 @@ #include #include #include -#include -#include +#include #include "usbvideo.h" diff --git a/drivers/usb/input/acecad.c b/drivers/usb/input/acecad.c index df29b8078b54..18c10e150ef3 100644 --- a/drivers/usb/input/acecad.c +++ b/drivers/usb/input/acecad.c @@ -27,11 +27,9 @@ #include #include -#include #include #include -#include -#include +#include /* * Version Information diff --git a/drivers/usb/input/aiptek.c b/drivers/usb/input/aiptek.c index a6693b0d1c4c..b138dae2b055 100644 --- a/drivers/usb/input/aiptek.c +++ b/drivers/usb/input/aiptek.c @@ -73,11 +73,9 @@ #include #include #include -#include #include #include -#include -#include +#include #include #include #include diff --git a/drivers/usb/input/appletouch.c b/drivers/usb/input/appletouch.c index 4eff8d7a79d4..36855062eacc 100644 --- a/drivers/usb/input/appletouch.c +++ b/drivers/usb/input/appletouch.c @@ -33,9 +33,7 @@ #include #include #include -#include -#include -#include +#include /* Apple has powerbooks which have the keyboard with different Product IDs */ #define APPLE_VENDOR_ID 0x05AC diff --git a/drivers/usb/input/ati_remote.c b/drivers/usb/input/ati_remote.c index 99f986cb6e95..07c8c0e665dd 100644 --- a/drivers/usb/input/ati_remote.c +++ b/drivers/usb/input/ati_remote.c @@ -92,9 +92,7 @@ #include #include #include -#include -#include -#include +#include #include #include diff --git a/drivers/usb/input/ati_remote2.c b/drivers/usb/input/ati_remote2.c index ab1a1ae24be9..ea71de81ca6b 100644 --- a/drivers/usb/input/ati_remote2.c +++ b/drivers/usb/input/ati_remote2.c @@ -8,7 +8,7 @@ * as published by the Free Software Foundation. */ -#include +#include #define DRIVER_DESC "ATI/Philips USB RF remote driver" #define DRIVER_VERSION "0.1" diff --git a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c index 2f665195f4ac..028e1ad89f5d 100644 --- a/drivers/usb/input/hid-input.c +++ b/drivers/usb/input/hid-input.c @@ -29,9 +29,7 @@ #include #include #include -#include -#include -#include +#include #undef DEBUG diff --git a/drivers/usb/input/itmtouch.c b/drivers/usb/input/itmtouch.c index 7618ae5c104f..5c570cc703f3 100644 --- a/drivers/usb/input/itmtouch.c +++ b/drivers/usb/input/itmtouch.c @@ -42,11 +42,9 @@ #include #include #include -#include #include #include -#include -#include +#include /* only an 8 byte buffer necessary for a single packet */ #define ITM_BUFSIZE 8 diff --git a/drivers/usb/input/kbtab.c b/drivers/usb/input/kbtab.c index f6d5cead542b..604ade356ead 100644 --- a/drivers/usb/input/kbtab.c +++ b/drivers/usb/input/kbtab.c @@ -1,12 +1,9 @@ #include #include -#include #include #include -#include -#include +#include #include -#include /* * Version Information diff --git a/drivers/usb/input/keyspan_remote.c b/drivers/usb/input/keyspan_remote.c index 3d911976f378..70af985b5db9 100644 --- a/drivers/usb/input/keyspan_remote.c +++ b/drivers/usb/input/keyspan_remote.c @@ -18,9 +18,7 @@ #include #include #include -#include -#include -#include +#include #define DRIVER_VERSION "v0.1" #define DRIVER_AUTHOR "Michael Downey " diff --git a/drivers/usb/input/mtouchusb.c b/drivers/usb/input/mtouchusb.c index f018953a5485..4fdee4db0729 100644 --- a/drivers/usb/input/mtouchusb.c +++ b/drivers/usb/input/mtouchusb.c @@ -42,11 +42,9 @@ #include #include #include -#include #include #include -#include -#include +#include #define MTOUCHUSB_MIN_XC 0x0 #define MTOUCHUSB_MAX_RAW_XC 0x4000 diff --git a/drivers/usb/input/powermate.c b/drivers/usb/input/powermate.c index fdf0f788062c..b3c0d0c3eae9 100644 --- a/drivers/usb/input/powermate.c +++ b/drivers/usb/input/powermate.c @@ -30,12 +30,10 @@ #include #include -#include #include #include #include -#include -#include +#include #define POWERMATE_VENDOR 0x077d /* Griffin Technology, Inc. */ #define POWERMATE_PRODUCT_NEW 0x0410 /* Griffin PowerMate */ diff --git a/drivers/usb/input/touchkitusb.c b/drivers/usb/input/touchkitusb.c index 697c5e573a11..da7b0bf51aff 100644 --- a/drivers/usb/input/touchkitusb.c +++ b/drivers/usb/input/touchkitusb.c @@ -27,11 +27,9 @@ #include #include #include -#include #include #include -#include -#include +#include #define TOUCHKIT_MIN_XC 0x0 #define TOUCHKIT_MAX_XC 0x07ff diff --git a/drivers/usb/input/usbkbd.c b/drivers/usb/input/usbkbd.c index 2f3edc26cb50..5067a6ae650f 100644 --- a/drivers/usb/input/usbkbd.c +++ b/drivers/usb/input/usbkbd.c @@ -29,10 +29,8 @@ #include #include #include -#include #include -#include -#include +#include /* * Version Information diff --git a/drivers/usb/input/usbmouse.c b/drivers/usb/input/usbmouse.c index af526135d210..446935b671d9 100644 --- a/drivers/usb/input/usbmouse.c +++ b/drivers/usb/input/usbmouse.c @@ -28,11 +28,9 @@ #include #include -#include #include #include -#include -#include +#include /* * Version Information diff --git a/drivers/usb/input/usbtouchscreen.c b/drivers/usb/input/usbtouchscreen.c index e9a07c1e905b..3b175aa482cd 100644 --- a/drivers/usb/input/usbtouchscreen.c +++ b/drivers/usb/input/usbtouchscreen.c @@ -39,7 +39,7 @@ #include #include #include -#include +#include #define DRIVER_VERSION "v0.3" diff --git a/drivers/usb/input/wacom.c b/drivers/usb/input/wacom.c index cf84c6096f29..369461a70b72 100644 --- a/drivers/usb/input/wacom.c +++ b/drivers/usb/input/wacom.c @@ -69,13 +69,10 @@ #include #include -#include #include #include -#include -#include +#include #include -#include /* * Version Information diff --git a/drivers/usb/input/xpad.c b/drivers/usb/input/xpad.c index e278489a80c6..cfd4a4e04334 100644 --- a/drivers/usb/input/xpad.c +++ b/drivers/usb/input/xpad.c @@ -56,13 +56,11 @@ #include #include -#include #include #include #include #include -#include -#include +#include #define DRIVER_VERSION "v0.0.5" #define DRIVER_AUTHOR "Marko Friedemann " diff --git a/drivers/usb/input/yealink.c b/drivers/usb/input/yealink.c index 37d2f0ba0319..24aedbb20f03 100644 --- a/drivers/usb/input/yealink.c +++ b/drivers/usb/input/yealink.c @@ -48,13 +48,11 @@ #include #include -#include #include #include #include #include -#include -#include +#include #include "map_to_7segment.h" #include "yealink.h" diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c index 55ee2d36d585..026a587eb8dd 100644 --- a/drivers/usb/storage/onetouch.c +++ b/drivers/usb/storage/onetouch.c @@ -34,9 +34,8 @@ #include #include #include -#include #include -#include +#include #include "usb.h" #include "onetouch.h" #include "debug.h" diff --git a/include/linux/usb/input.h b/include/linux/usb/input.h new file mode 100644 index 000000000000..716e0cc16043 --- /dev/null +++ b/include/linux/usb/input.h @@ -0,0 +1,25 @@ +#ifndef __USB_INPUT_H +#define __USB_INPUT_H + +/* + * Copyright (C) 2005 Dmitry Torokhov + * + * 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 published by + * the Free Software Foundation. + */ + +#include +#include +#include + +static inline void +usb_to_input_id(const struct usb_device *dev, struct input_id *id) +{ + id->bustype = BUS_USB; + id->vendor = le16_to_cpu(dev->descriptor.idVendor); + id->product = le16_to_cpu(dev->descriptor.idProduct); + id->version = le16_to_cpu(dev->descriptor.bcdDevice); +} + +#endif diff --git a/include/linux/usb_input.h b/include/linux/usb_input.h deleted file mode 100644 index 716e0cc16043..000000000000 --- a/include/linux/usb_input.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef __USB_INPUT_H -#define __USB_INPUT_H - -/* - * Copyright (C) 2005 Dmitry Torokhov - * - * 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 published by - * the Free Software Foundation. - */ - -#include -#include -#include - -static inline void -usb_to_input_id(const struct usb_device *dev, struct input_id *id) -{ - id->bustype = BUS_USB; - id->vendor = le16_to_cpu(dev->descriptor.idVendor); - id->product = le16_to_cpu(dev->descriptor.idProduct); - id->version = le16_to_cpu(dev->descriptor.bcdDevice); -} - -#endif -- cgit v1.2.3 From 9bde7497e0b54178c317fac47a18be7f948dd471 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 14 Jun 2006 12:14:34 -0700 Subject: [PATCH] USB: make endpoints real struct devices This will allow for us to give endpoints a major/minor to create a "usbfs2-like" way to access endpoints directly from userspace in an easier manner than the current usbfs provides us. Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/endpoint.c | 238 ++++++++++++++++++++++++++++---------------- include/linux/usb.h | 4 +- 2 files changed, 153 insertions(+), 89 deletions(-) (limited to 'include') diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c index 4c2fe8f723e5..247b5a4913a8 100644 --- a/drivers/usb/core/endpoint.c +++ b/drivers/usb/core/endpoint.c @@ -14,13 +14,14 @@ #include "usb.h" /* endpoint stuff */ -struct ep_object { + +struct ep_device { struct usb_endpoint_descriptor *desc; struct usb_device *udev; - struct kobject kobj; + struct device dev; }; -#define to_ep_object(_kobj) \ - container_of(_kobj, struct ep_object, kobj) +#define to_ep_device(_dev) \ + container_of(_dev, struct ep_device, dev) struct ep_attribute { struct attribute attr; @@ -30,40 +31,37 @@ struct ep_attribute { #define to_ep_attribute(_attr) \ container_of(_attr, struct ep_attribute, attr) -#define EP_ATTR(_name) \ -struct ep_attribute ep_##_name = { \ - .attr = {.name = #_name, .owner = THIS_MODULE, \ - .mode = S_IRUGO}, \ - .show = show_ep_##_name} - #define usb_ep_attr(field, format_string) \ -static ssize_t show_ep_##field(struct usb_device *udev, \ - struct usb_endpoint_descriptor *desc, \ - char *buf) \ +static ssize_t show_ep_##field(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ { \ - return sprintf(buf, format_string, desc->field); \ + struct ep_device *ep = to_ep_device(dev); \ + return sprintf(buf, format_string, ep->desc->field); \ } \ -static EP_ATTR(field); +static DEVICE_ATTR(field, S_IRUGO, show_ep_##field, NULL); usb_ep_attr(bLength, "%02x\n") usb_ep_attr(bEndpointAddress, "%02x\n") usb_ep_attr(bmAttributes, "%02x\n") usb_ep_attr(bInterval, "%02x\n") -static ssize_t show_ep_wMaxPacketSize(struct usb_device *udev, - struct usb_endpoint_descriptor *desc, char *buf) +static ssize_t show_ep_wMaxPacketSize(struct device *dev, + struct device_attribute *attr, char *buf) { + struct ep_device *ep = to_ep_device(dev); return sprintf(buf, "%04x\n", - le16_to_cpu(desc->wMaxPacketSize) & 0x07ff); + le16_to_cpu(ep->desc->wMaxPacketSize) & 0x07ff); } -static EP_ATTR(wMaxPacketSize); +static DEVICE_ATTR(wMaxPacketSize, S_IRUGO, show_ep_wMaxPacketSize, NULL); -static ssize_t show_ep_type(struct usb_device *udev, - struct usb_endpoint_descriptor *desc, char *buf) +static ssize_t show_ep_type(struct device *dev, struct device_attribute *attr, + char *buf) { + struct ep_device *ep = to_ep_device(dev); char *type = "unknown"; - switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + switch (ep->desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { case USB_ENDPOINT_XFER_CONTROL: type = "Control"; break; @@ -79,37 +77,38 @@ static ssize_t show_ep_type(struct usb_device *udev, } return sprintf(buf, "%s\n", type); } -static EP_ATTR(type); +static DEVICE_ATTR(type, S_IRUGO, show_ep_type, NULL); -static ssize_t show_ep_interval(struct usb_device *udev, - struct usb_endpoint_descriptor *desc, char *buf) +static ssize_t show_ep_interval(struct device *dev, + struct device_attribute *attr, char *buf) { + struct ep_device *ep = to_ep_device(dev); char unit; unsigned interval = 0; unsigned in; - in = (desc->bEndpointAddress & USB_DIR_IN); + in = (ep->desc->bEndpointAddress & USB_DIR_IN); - switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + switch (ep->desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { case USB_ENDPOINT_XFER_CONTROL: - if (udev->speed == USB_SPEED_HIGH) /* uframes per NAK */ - interval = desc->bInterval; + if (ep->udev->speed == USB_SPEED_HIGH) /* uframes per NAK */ + interval = ep->desc->bInterval; break; case USB_ENDPOINT_XFER_ISOC: - interval = 1 << (desc->bInterval - 1); + interval = 1 << (ep->desc->bInterval - 1); break; case USB_ENDPOINT_XFER_BULK: - if (udev->speed == USB_SPEED_HIGH && !in) /* uframes per NAK */ - interval = desc->bInterval; + if (ep->udev->speed == USB_SPEED_HIGH && !in) /* uframes per NAK */ + interval = ep->desc->bInterval; break; case USB_ENDPOINT_XFER_INT: - if (udev->speed == USB_SPEED_HIGH) - interval = 1 << (desc->bInterval - 1); + if (ep->udev->speed == USB_SPEED_HIGH) + interval = 1 << (ep->desc->bInterval - 1); else - interval = desc->bInterval; + interval = ep->desc->bInterval; break; } - interval *= (udev->speed == USB_SPEED_HIGH) ? 125 : 1000; + interval *= (ep->udev->speed == USB_SPEED_HIGH) ? 125 : 1000; if (interval % 1000) unit = 'u'; else { @@ -119,95 +118,158 @@ static ssize_t show_ep_interval(struct usb_device *udev, return sprintf(buf, "%d%cs\n", interval, unit); } -static EP_ATTR(interval); +static DEVICE_ATTR(interval, S_IRUGO, show_ep_interval, NULL); -static ssize_t show_ep_direction(struct usb_device *udev, - struct usb_endpoint_descriptor *desc, char *buf) +static ssize_t show_ep_direction(struct device *dev, + struct device_attribute *attr, char *buf) { + struct ep_device *ep = to_ep_device(dev); char *direction; - if ((desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == + if ((ep->desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_CONTROL) direction = "both"; - else if (desc->bEndpointAddress & USB_DIR_IN) + else if (ep->desc->bEndpointAddress & USB_DIR_IN) direction = "in"; else direction = "out"; return sprintf(buf, "%s\n", direction); } -static EP_ATTR(direction); - -static struct attribute *ep_attrs[] = { - &ep_bLength.attr, - &ep_bEndpointAddress.attr, - &ep_bmAttributes.attr, - &ep_bInterval.attr, - &ep_wMaxPacketSize.attr, - &ep_type.attr, - &ep_interval.attr, - &ep_direction.attr, +static DEVICE_ATTR(direction, S_IRUGO, show_ep_direction, NULL); + +static struct attribute *ep_dev_attrs[] = { + &dev_attr_bLength.attr, + &dev_attr_bEndpointAddress.attr, + &dev_attr_bmAttributes.attr, + &dev_attr_bInterval.attr, + &dev_attr_wMaxPacketSize.attr, + &dev_attr_interval.attr, + &dev_attr_type.attr, + &dev_attr_direction.attr, NULL, }; +static struct attribute_group ep_dev_attr_grp = { + .attrs = ep_dev_attrs, +}; -static void ep_object_release(struct kobject *kobj) +static struct endpoint_class { + struct kref kref; + struct class *class; +} *ep_class; + +static int init_endpoint_class(void) { - kfree(to_ep_object(kobj)); + int result = 0; + + if (ep_class != NULL) { + kref_get(&ep_class->kref); + goto exit; + } + + ep_class = kmalloc(sizeof(*ep_class), GFP_KERNEL); + if (!ep_class) { + result = -ENOMEM; + goto exit; + } + + kref_init(&ep_class->kref); + ep_class->class = class_create(THIS_MODULE, "usb_endpoint"); + if (IS_ERR(ep_class->class)) { + result = IS_ERR(ep_class->class); + kfree(ep_class); + ep_class = NULL; + goto exit; + } + +exit: + return result; } -static ssize_t ep_object_show(struct kobject *kobj, struct attribute *attr, - char *buf) +static void release_endpoint_class(struct kref *kref) { - struct ep_object *ep_obj = to_ep_object(kobj); - struct ep_attribute *ep_attr = to_ep_attribute(attr); + /* Ok, we cheat as we know we only have one ep_class */ + class_destroy(ep_class->class); + kfree(ep_class); + ep_class = NULL; +} - return (ep_attr->show)(ep_obj->udev, ep_obj->desc, buf); +static void destroy_endpoint_class(void) +{ + if (ep_class) + kref_put(&ep_class->kref, release_endpoint_class); } -static struct sysfs_ops ep_object_sysfs_ops = { - .show = ep_object_show, -}; +static void ep_device_release(struct device *dev) +{ + struct ep_device *ep_dev = to_ep_device(dev); -static struct kobj_type ep_object_ktype = { - .release = ep_object_release, - .sysfs_ops = &ep_object_sysfs_ops, - .default_attrs = ep_attrs, -}; + dev_dbg(dev, "%s called for %s\n", __FUNCTION__, dev->bus_id); + kfree(ep_dev); +} void usb_create_ep_files(struct device *parent, struct usb_host_endpoint *endpoint, struct usb_device *udev) { - struct ep_object *ep_obj; - struct kobject *kobj; + char name[8]; + struct ep_device *ep_dev; + int minor; + int retval; + + retval = init_endpoint_class(); + if (retval) + goto exit; - ep_obj = kzalloc(sizeof(struct ep_object), GFP_KERNEL); - if (!ep_obj) - return; + ep_dev = kzalloc(sizeof(*ep_dev), GFP_KERNEL); + if (!ep_dev) { + retval = -ENOMEM; + goto exit; + } - ep_obj->desc = &endpoint->desc; - ep_obj->udev = udev; + /* fun calculation to determine the minor of this endpoint */ + minor = (((udev->bus->busnum - 1) * 128) * 16) + (udev->devnum - 1); - kobj = &ep_obj->kobj; - kobject_set_name(kobj, "ep_%02x", endpoint->desc.bEndpointAddress); - kobj->parent = &parent->kobj; - kobj->ktype = &ep_object_ktype; + ep_dev->desc = &endpoint->desc; + ep_dev->udev = udev; + ep_dev->dev.devt = MKDEV(442, minor); // FIXME fake number... + ep_dev->dev.class = ep_class->class; + ep_dev->dev.parent = parent; + ep_dev->dev.release = ep_device_release; + snprintf(ep_dev->dev.bus_id, BUS_ID_SIZE, "usbdev%d.%d_ep%02x", + udev->bus->busnum, udev->devnum, + endpoint->desc.bEndpointAddress); - /* Don't use kobject_register, because it generates a hotplug event */ - kobject_init(kobj); - if (kobject_add(kobj) == 0) - endpoint->kobj = kobj; - else - kobject_put(kobj); + retval = device_register(&ep_dev->dev); + if (retval) + goto error; + sysfs_create_group(&ep_dev->dev.kobj, &ep_dev_attr_grp); + + endpoint->ep_dev = ep_dev; + + /* create the symlink to the old-style "ep_XX" directory */ + sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress); + sysfs_create_link(&parent->kobj, &endpoint->ep_dev->dev.kobj, name); + +exit: + return; +error: + kfree(ep_dev); + return; } void usb_remove_ep_files(struct usb_host_endpoint *endpoint) { - if (endpoint->kobj) { - kobject_del(endpoint->kobj); - kobject_put(endpoint->kobj); - endpoint->kobj = NULL; + if (endpoint->ep_dev) { + char name[8]; + + sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress); + sysfs_remove_link(&endpoint->ep_dev->dev.parent->kobj, name); + sysfs_remove_group(&endpoint->ep_dev->dev.kobj, &ep_dev_attr_grp); + device_unregister(&endpoint->ep_dev->dev); + endpoint->ep_dev = NULL; } + destroy_endpoint_class(); } diff --git a/include/linux/usb.h b/include/linux/usb.h index 5ad30cefe7b2..46956a72de5d 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -40,6 +40,8 @@ struct usb_driver; * Devices may also have class-specific or vendor-specific descriptors. */ +struct ep_device; + /** * struct usb_host_endpoint - host-side endpoint descriptor and queue * @desc: descriptor for this endpoint, wMaxPacketSize in native byteorder @@ -57,7 +59,7 @@ struct usb_host_endpoint { struct usb_endpoint_descriptor desc; struct list_head urb_list; void *hcpriv; - struct kobject *kobj; /* For sysfs info */ + struct ep_device *ep_dev; /* For sysfs info */ unsigned char *extra; /* Extra descriptors */ int extralen; -- cgit v1.2.3 From c182274ffe1277f4e7c564719a696a37cacf74ea Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 19 Jun 2006 23:59:31 -0700 Subject: [PATCH] USB: move usb_device_class class devices to be real devices This moves the usb class devices that control the usbfs nodes to show up in the proper place in the larger device tree. No userspace changes is needed, this is compatible due to the symlinks generated by the driver core. Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 20 ++++++++++---------- include/linux/usb.h | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 2eda52fc1ebc..3f8e06279c92 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -515,19 +515,19 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsig static struct usb_device *usbdev_lookup_minor(int minor) { - struct class_device *class_dev; - struct usb_device *dev = NULL; + struct device *device; + struct usb_device *udev = NULL; down(&usb_device_class->sem); - list_for_each_entry(class_dev, &usb_device_class->children, node) { - if (class_dev->devt == MKDEV(USB_DEVICE_MAJOR, minor)) { - dev = class_dev->class_data; + list_for_each_entry(device, &usb_device_class->devices, node) { + if (device->devt == MKDEV(USB_DEVICE_MAJOR, minor)) { + udev = device->platform_data; break; } } up(&usb_device_class->sem); - return dev; + return udev; }; /* @@ -1580,16 +1580,16 @@ static void usbdev_add(struct usb_device *dev) { int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1); - dev->class_dev = class_device_create(usb_device_class, NULL, - MKDEV(USB_DEVICE_MAJOR, minor), &dev->dev, + dev->usbfs_dev = device_create(usb_device_class, &dev->dev, + MKDEV(USB_DEVICE_MAJOR, minor), "usbdev%d.%d", dev->bus->busnum, dev->devnum); - dev->class_dev->class_data = dev; + dev->usbfs_dev->platform_data = dev; } static void usbdev_remove(struct usb_device *dev) { - class_device_unregister(dev->class_dev); + device_unregister(dev->usbfs_dev); } static int usbdev_notify(struct notifier_block *self, unsigned long action, diff --git a/include/linux/usb.h b/include/linux/usb.h index 46956a72de5d..b69b6cfb0bd7 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -360,7 +360,7 @@ struct usb_device { char *serial; /* iSerialNumber string, if present */ struct list_head filelist; - struct class_device *class_dev; + struct device *usbfs_dev; struct dentry *usbfs_dentry; /* usbfs dentry entry for the device */ /* -- cgit v1.2.3 From bd00949647ddcea47ce4ea8bb2cfcfc98ebf9f2a Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 20 Jun 2006 13:09:50 -0700 Subject: [PATCH] USB: convert usb class devices to real devices Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/file.c | 13 ++++++------- include/linux/usb.h | 5 +++-- 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c index b263a54a13c0..70898716dd9a 100644 --- a/drivers/usb/core/file.c +++ b/drivers/usb/core/file.c @@ -158,14 +158,13 @@ int usb_register_dev(struct usb_interface *intf, ++temp; else temp = name; - intf->class_dev = class_device_create(usb_class, NULL, - MKDEV(USB_MAJOR, minor), - &intf->dev, "%s", temp); - if (IS_ERR(intf->class_dev)) { + intf->usb_dev = device_create(usb_class, &intf->dev, + MKDEV(USB_MAJOR, minor), "%s", temp); + if (IS_ERR(intf->usb_dev)) { spin_lock (&minor_lock); usb_minors[intf->minor] = NULL; spin_unlock (&minor_lock); - retval = PTR_ERR(intf->class_dev); + retval = PTR_ERR(intf->usb_dev); } exit: return retval; @@ -206,8 +205,8 @@ void usb_deregister_dev(struct usb_interface *intf, spin_unlock (&minor_lock); snprintf(name, BUS_ID_SIZE, class_driver->name, intf->minor - minor_base); - class_device_destroy(usb_class, MKDEV(USB_MAJOR, intf->minor)); - intf->class_dev = NULL; + device_destroy(usb_class, MKDEV(USB_MAJOR, intf->minor)); + intf->usb_dev = NULL; intf->minor = -1; } EXPORT_SYMBOL(usb_deregister_dev); diff --git a/include/linux/usb.h b/include/linux/usb.h index b69b6cfb0bd7..8dead32e7ebf 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -103,7 +103,8 @@ enum usb_interface_condition { * @condition: binding state of the interface: not bound, binding * (in probe()), bound to a driver, or unbinding (in disconnect()) * @dev: driver model's view of this device - * @class_dev: driver model's class view of this device. + * @usb_dev: if an interface is bound to the USB major, this will point + * to the sysfs representation for that device. * * USB device drivers attach to interfaces on a physical device. Each * interface encapsulates a single high level function, such as feeding @@ -143,7 +144,7 @@ struct usb_interface { * bound to */ enum usb_interface_condition condition; /* state of binding */ struct device dev; /* interface specific device info */ - struct class_device *class_dev; + struct device *usb_dev; /* pointer to the usb class's device, if any */ }; #define to_usb_interface(d) container_of(d, struct usb_interface, dev) #define interface_to_usbdev(intf) \ -- cgit v1.2.3 From d6551e884cf66de072b81f8b6d23259462c40baf Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 21 Jun 2006 13:31:52 +0100 Subject: [ARM] Add thread_notify infrastructure Some machine classes need to allow VFP support to be built into the kernel, but still allow the kernel to run even though VFP isn't present. Unfortunately, the kernel hard-codes VFP instructions into the thread switch, which prevents this being run-time selectable. Solve this by introducing a notifier which things such as VFP can hook into to be informed of events which affect the VFP subsystem (eg, creation and destruction of threads, switches between threads.) Signed-off-by: Russell King --- arch/arm/kernel/entry-armv.S | 24 +++++++------- arch/arm/kernel/iwmmxt.S | 2 +- arch/arm/kernel/process.c | 24 ++++++-------- arch/arm/nwfpe/fpmodule.c | 25 +++++++++++---- arch/arm/vfp/vfpmodule.c | 71 ++++++++++++++++++++++++++--------------- include/asm-arm/thread_notify.h | 48 ++++++++++++++++++++++++++++ 6 files changed, 135 insertions(+), 59 deletions(-) create mode 100644 include/asm-arm/thread_notify.h (limited to 'include') diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index ab8e600c18c8..86c92523a346 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -20,6 +20,7 @@ #include #include #include +#include #include "entry-header.S" @@ -560,10 +561,8 @@ ENTRY(__switch_to) add ip, r1, #TI_CPU_SAVE ldr r3, [r2, #TI_TP_VALUE] stmia ip!, {r4 - sl, fp, sp, lr} @ Store most regs on stack -#ifndef CONFIG_MMU - add r2, r2, #TI_CPU_DOMAIN -#else - ldr r6, [r2, #TI_CPU_DOMAIN]! +#ifdef CONFIG_MMU + ldr r6, [r2, #TI_CPU_DOMAIN] #endif #if __LINUX_ARM_ARCH__ >= 6 #ifdef CONFIG_CPU_32v6K @@ -585,21 +584,20 @@ ENTRY(__switch_to) #ifdef CONFIG_MMU mcr p15, 0, r6, c3, c0, 0 @ Set domain register #endif -#ifdef CONFIG_VFP - @ Always disable VFP so we can lazily save/restore the old - @ state. This occurs in the context of the previous thread. - VFPFMRX r4, FPEXC - bic r4, r4, #FPEXC_ENABLE - VFPFMXR FPEXC, r4 -#endif #if defined(CONFIG_IWMMXT) bl iwmmxt_task_switch #elif defined(CONFIG_CPU_XSCALE) - add r4, r2, #40 @ cpu_context_save->extra + add r4, r2, #TI_CPU_DOMAIN + 40 @ cpu_context_save->extra ldmib r4, {r4, r5} mar acc0, r4, r5 #endif - ldmib r2, {r4 - sl, fp, sp, pc} @ Load all regs saved previously + mov r5, r0 + add r4, r2, #TI_CPU_SAVE + ldr r0, =thread_notify_head + mov r1, #THREAD_NOTIFY_SWITCH + bl atomic_notifier_call_chain + mov r0, r5 + ldmia r4, {r4 - sl, fp, sp, pc} @ Load all regs saved previously __INIT diff --git a/arch/arm/kernel/iwmmxt.S b/arch/arm/kernel/iwmmxt.S index 24c7b0477a09..af9e0ae952d5 100644 --- a/arch/arm/kernel/iwmmxt.S +++ b/arch/arm/kernel/iwmmxt.S @@ -285,7 +285,7 @@ ENTRY(iwmmxt_task_switch) bne 1f @ yes: block them for next task ldr r5, =concan_owner - add r6, r2, #(TI_IWMMXT_STATE - TI_CPU_DOMAIN) @ get next task Concan save area + add r6, r2, #TI_IWMMXT_STATE @ get next task Concan save area ldr r5, [r5] @ get current Concan owner teq r5, r6 @ next task owns it? movne pc, lr @ no: leave Concan disabled diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 17c38dbf2f3c..e1c77ee885a7 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -338,13 +339,9 @@ void exit_thread(void) { } -static void default_fp_init(union fp_state *fp) -{ - memset(fp, 0, sizeof(union fp_state)); -} +ATOMIC_NOTIFIER_HEAD(thread_notify_head); -void (*fp_init)(union fp_state *) = default_fp_init; -EXPORT_SYMBOL(fp_init); +EXPORT_SYMBOL_GPL(thread_notify_head); void flush_thread(void) { @@ -353,22 +350,21 @@ void flush_thread(void) memset(thread->used_cp, 0, sizeof(thread->used_cp)); memset(&tsk->thread.debug, 0, sizeof(struct debug_info)); + memset(&thread->fpstate, 0, sizeof(union fp_state)); + + thread_notify(THREAD_NOTIFY_FLUSH, thread); #if defined(CONFIG_IWMMXT) iwmmxt_task_release(thread); -#endif - fp_init(&thread->fpstate); -#if defined(CONFIG_VFP) - vfp_flush_thread(&thread->vfpstate); #endif } void release_thread(struct task_struct *dead_task) { -#if defined(CONFIG_VFP) - vfp_release_thread(&task_thread_info(dead_task)->vfpstate); -#endif + struct thread_info *thread = task_thread_info(dead_task); + + thread_notify(THREAD_NOTIFY_RELEASE, thread); #if defined(CONFIG_IWMMXT) - iwmmxt_task_release(task_thread_info(dead_task)); + iwmmxt_task_release(thread); #endif } diff --git a/arch/arm/nwfpe/fpmodule.c b/arch/arm/nwfpe/fpmodule.c index 2dfe1ac42ee8..7d977d23f026 100644 --- a/arch/arm/nwfpe/fpmodule.c +++ b/arch/arm/nwfpe/fpmodule.c @@ -33,7 +33,8 @@ #include #include #include -/* XXX */ + +#include #include "softfloat.h" #include "fpopcode.h" @@ -56,16 +57,28 @@ void fp_send_sig(unsigned long sig, struct task_struct *p, int priv); extern char fpe_type[]; #endif +static int nwfpe_notify(struct notifier_block *self, unsigned long cmd, void *v) +{ + struct thread_info *thread = v; + + if (cmd == THREAD_NOTIFY_FLUSH) + nwfpe_init_fpa(&thread->fpstate); + + return NOTIFY_DONE; +} + +static struct notifier_block nwfpe_notifier_block = { + .notifier_call = nwfpe_notify, +}; + /* kernel function prototypes required */ void fp_setup(void); /* external declarations for saved kernel symbols */ extern void (*kern_fp_enter)(void); -extern void (*fp_init)(union fp_state *); /* Original value of fp_enter from kernel before patched by fpe_init. */ static void (*orig_fp_enter)(void); -static void (*orig_fp_init)(union fp_state *); /* forward declarations */ extern void nwfpe_enter(void); @@ -88,20 +101,20 @@ static int __init fpe_init(void) printk(KERN_WARNING "NetWinder Floating Point Emulator V0.97 (" NWFPE_BITS " precision)\n"); + thread_register_notifier(&nwfpe_notifier_block); + /* Save pointer to the old FP handler and then patch ourselves in */ orig_fp_enter = kern_fp_enter; - orig_fp_init = fp_init; kern_fp_enter = nwfpe_enter; - fp_init = nwfpe_init_fpa; return 0; } static void __exit fpe_exit(void) { + thread_unregister_notifier(&nwfpe_notifier_block); /* Restore the values we saved earlier. */ kern_fp_enter = orig_fp_enter; - fp_init = orig_fp_init; } /* diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index 03486be04193..2476f4c2e760 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c @@ -15,6 +15,8 @@ #include #include #include + +#include #include #include "vfpinstr.h" @@ -36,38 +38,55 @@ union vfp_state *last_VFP_context; */ unsigned int VFP_arch; -/* - * Per-thread VFP initialisation. - */ -void vfp_flush_thread(union vfp_state *vfp) +static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v) { - memset(vfp, 0, sizeof(union vfp_state)); + struct thread_info *thread = v; + union vfp_state *vfp = &thread->vfpstate; - vfp->hard.fpexc = FPEXC_ENABLE; - vfp->hard.fpscr = FPSCR_ROUND_NEAREST; + switch (cmd) { + case THREAD_NOTIFY_FLUSH: + /* + * Per-thread VFP initialisation. + */ + memset(vfp, 0, sizeof(union vfp_state)); - /* - * Disable VFP to ensure we initialise it first. - */ - fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_ENABLE); + vfp->hard.fpexc = FPEXC_ENABLE; + vfp->hard.fpscr = FPSCR_ROUND_NEAREST; - /* - * Ensure we don't try to overwrite our newly initialised - * state information on the first fault. - */ - if (last_VFP_context == vfp) - last_VFP_context = NULL; -} + /* + * Disable VFP to ensure we initialise it first. + */ + fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_ENABLE); -/* - * Per-thread VFP cleanup. - */ -void vfp_release_thread(union vfp_state *vfp) -{ - if (last_VFP_context == vfp) - last_VFP_context = NULL; + /* + * FALLTHROUGH: Ensure we don't try to overwrite our newly + * initialised state information on the first fault. + */ + + case THREAD_NOTIFY_RELEASE: + /* + * Per-thread VFP cleanup. + */ + if (last_VFP_context == vfp) + last_VFP_context = NULL; + break; + + case THREAD_NOTIFY_SWITCH: + /* + * Always disable VFP so we can lazily save/restore the + * old state. + */ + fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_ENABLE); + break; + } + + return NOTIFY_DONE; } +static struct notifier_block vfp_notifier_block = { + .notifier_call = vfp_notifier, +}; + /* * Raise a SIGFPE for the current process. * sicode describes the signal being raised. @@ -281,6 +300,8 @@ static int __init vfp_init(void) (vfpsid & FPSID_VARIANT_MASK) >> FPSID_VARIANT_BIT, (vfpsid & FPSID_REV_MASK) >> FPSID_REV_BIT); vfp_vector = vfp_support_entry; + + thread_register_notifier(&vfp_notifier_block); } return 0; } diff --git a/include/asm-arm/thread_notify.h b/include/asm-arm/thread_notify.h new file mode 100644 index 000000000000..8866e5216840 --- /dev/null +++ b/include/asm-arm/thread_notify.h @@ -0,0 +1,48 @@ +/* + * linux/include/asm-arm/thread_notify.h + * + * Copyright (C) 2006 Russell King. + * + * 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 + * published by the Free Software Foundation. + */ +#ifndef ASMARM_THREAD_NOTIFY_H +#define ASMARM_THREAD_NOTIFY_H + +#ifdef __KERNEL__ + +#ifndef __ASSEMBLY__ + +#include +#include + +static inline int thread_register_notifier(struct notifier_block *n) +{ + extern struct atomic_notifier_head thread_notify_head; + return atomic_notifier_chain_register(&thread_notify_head, n); +} + +static inline void thread_unregister_notifier(struct notifier_block *n) +{ + extern struct atomic_notifier_head thread_notify_head; + atomic_notifier_chain_unregister(&thread_notify_head, n); +} + +static inline void thread_notify(unsigned long rc, struct thread_info *thread) +{ + extern struct atomic_notifier_head thread_notify_head; + atomic_notifier_call_chain(&thread_notify_head, rc, thread); +} + +#endif + +/* + * These are the reason codes for the thread notifier. + */ +#define THREAD_NOTIFY_FLUSH 0 +#define THREAD_NOTIFY_RELEASE 1 +#define THREAD_NOTIFY_SWITCH 2 + +#endif +#endif -- cgit v1.2.3 From b741483d7d8d86d215daf2a1f77bc3d3770746a6 Mon Sep 17 00:00:00 2001 From: Vitaly Wool Date: Thu, 22 Jun 2006 10:26:21 +0100 Subject: [ARM] 3623/1: pnx4008: move GPIO-related defines to gpio.h Patch from Vitaly Wool This patch moves GPIO-related defines and static inline funcs from include/asm-arm/arch-pnx4008/pm.h to include/asm-arm/arch-pnx4008/gpio.h. Also, some more GPIO-related defines are added to include/asm-arm/arch-pnx4008/gpio.h as they are needed for the USB host driver (coming soon...) Signed-off-by: Vitaly Wool Signed-off-by: Russell King --- arch/arm/mach-pnx4008/serial.c | 2 +- include/asm-arm/arch-pnx4008/gpio.h | 102 ++++++++++++++++++++++++++++++++++++ include/asm-arm/arch-pnx4008/pm.h | 29 ---------- 3 files changed, 103 insertions(+), 30 deletions(-) (limited to 'include') diff --git a/arch/arm/mach-pnx4008/serial.c b/arch/arm/mach-pnx4008/serial.c index 10322384e45d..95a1b3f964a2 100644 --- a/arch/arm/mach-pnx4008/serial.c +++ b/arch/arm/mach-pnx4008/serial.c @@ -20,7 +20,7 @@ #include #include -#include +#include #include diff --git a/include/asm-arm/arch-pnx4008/gpio.h b/include/asm-arm/arch-pnx4008/gpio.h index 1fa5a77c3010..d01bf83d55c2 100644 --- a/include/asm-arm/arch-pnx4008/gpio.h +++ b/include/asm-arm/arch-pnx4008/gpio.h @@ -127,6 +127,79 @@ #define GPIO_ISOUT(K) ((GPIO_TYPE_MASK(K) == GPIO_OUT) && (GPIO_BIT(K) & GPIO_OUT_MASK)) #define GPIO_ISIN(K) ((GPIO_TYPE_MASK(K) == GPIO_IN) && (GPIO_BIT(K) & GPIO_IN_MASK)) +/* Start Enable Pin Interrupts - table 58 page 66 */ + +#define SE_PIN_BASE_INT 32 + +#define SE_U7_RX_INT 63 +#define SE_U7_HCTS_INT 62 +#define SE_BT_CLKREQ_INT 61 +#define SE_U6_IRRX_INT 60 +/*59 unused*/ +#define SE_U5_RX_INT 58 +#define SE_GPI_11_INT 57 +#define SE_U3_RX_INT 56 +#define SE_U2_HCTS_INT 55 +#define SE_U2_RX_INT 54 +#define SE_U1_RX_INT 53 +#define SE_DISP_SYNC_INT 52 +/*51 unused*/ +#define SE_SDIO_INT_N 50 +#define SE_MSDIO_START_INT 49 +#define SE_GPI_06_INT 48 +#define SE_GPI_05_INT 47 +#define SE_GPI_04_INT 46 +#define SE_GPI_03_INT 45 +#define SE_GPI_02_INT 44 +#define SE_GPI_01_INT 43 +#define SE_GPI_00_INT 42 +#define SE_SYSCLKEN_PIN_INT 41 +#define SE_SPI1_DATAIN_INT 40 +#define SE_GPI_07_INT 39 +#define SE_SPI2_DATAIN_INT 38 +#define SE_GPI_10_INT 37 +#define SE_GPI_09_INT 36 +#define SE_GPI_08_INT 35 +/*34-32 unused*/ + +/* Start Enable Internal Interrupts - table 57 page 65 */ + +#define SE_INT_BASE_INT 0 + +#define SE_TS_IRQ 31 +#define SE_TS_P_INT 30 +#define SE_TS_AUX_INT 29 +/*27-28 unused*/ +#define SE_USB_AHB_NEED_CLK_INT 26 +#define SE_MSTIMER_INT 25 +#define SE_RTC_INT 24 +#define SE_USB_NEED_CLK_INT 23 +#define SE_USB_INT 22 +#define SE_USB_I2C_INT 21 +#define SE_USB_OTG_TIMER_INT 20 +#define SE_USB_OTG_ATX_INT_N 19 +/*18 unused*/ +#define SE_DSP_GPIO4_INT 17 +#define SE_KEY_IRQ 16 +#define SE_DSP_SLAVEPORT_INT 15 +#define SE_DSP_GPIO1_INT 14 +#define SE_DSP_GPIO0_INT 13 +#define SE_DSP_AHB_INT 12 +/*11-6 unused*/ +#define SE_GPIO_05_INT 5 +#define SE_GPIO_04_INT 4 +#define SE_GPIO_03_INT 3 +#define SE_GPIO_02_INT 2 +#define SE_GPIO_01_INT 1 +#define SE_GPIO_00_INT 0 + +#define START_INT_REG_BIT(irq) (1<<((irq)&0x1F)) + +#define START_INT_ER_REG(irq) IO_ADDRESS((PNX4008_PWRMAN_BASE + 0x20 + (((irq)&(0x1<<5))>>1))) +#define START_INT_RSR_REG(irq) IO_ADDRESS((PNX4008_PWRMAN_BASE + 0x24 + (((irq)&(0x1<<5))>>1))) +#define START_INT_SR_REG(irq) IO_ADDRESS((PNX4008_PWRMAN_BASE + 0x28 + (((irq)&(0x1<<5))>>1))) +#define START_INT_APR_REG(irq) IO_ADDRESS((PNX4008_PWRMAN_BASE + 0x2C + (((irq)&(0x1<<5))>>1))) + extern int pnx4008_gpio_register_pin(unsigned short pin); extern int pnx4008_gpio_unregister_pin(unsigned short pin); extern unsigned long pnx4008_gpio_read_pin(unsigned short pin); @@ -136,4 +209,33 @@ extern int pnx4008_gpio_read_pin_direction(unsigned short pin); extern int pnx4008_gpio_set_pin_mux(unsigned short pin, int output); extern int pnx4008_gpio_read_pin_mux(unsigned short pin); +static inline void start_int_umask(u8 irq) +{ + __raw_writel(__raw_readl(START_INT_ER_REG(irq)) | + START_INT_REG_BIT(irq), START_INT_ER_REG(irq)); +} + +static inline void start_int_mask(u8 irq) +{ + __raw_writel(__raw_readl(START_INT_ER_REG(irq)) & + ~START_INT_REG_BIT(irq), START_INT_ER_REG(irq)); +} + +static inline void start_int_ack(u8 irq) +{ + __raw_writel(START_INT_REG_BIT(irq), START_INT_RSR_REG(irq)); +} + +static inline void start_int_set_falling_edge(u8 irq) +{ + __raw_writel(__raw_readl(START_INT_APR_REG(irq)) & + ~START_INT_REG_BIT(irq), START_INT_APR_REG(irq)); +} + +static inline void start_int_set_rising_edge(u8 irq) +{ + __raw_writel(__raw_readl(START_INT_APR_REG(irq)) | + START_INT_REG_BIT(irq), START_INT_APR_REG(irq)); +} + #endif /* _PNX4008_GPIO_H_ */ diff --git a/include/asm-arm/arch-pnx4008/pm.h b/include/asm-arm/arch-pnx4008/pm.h index c660486670fb..bac1634cb3e0 100644 --- a/include/asm-arm/arch-pnx4008/pm.h +++ b/include/asm-arm/arch-pnx4008/pm.h @@ -29,34 +29,5 @@ extern void pnx4008_cpu_standby(void); extern int pnx4008_startup_pll(struct clk *); extern int pnx4008_shutdown_pll(struct clk *); -static inline void start_int_umask(u8 irq) -{ - __raw_writel(__raw_readl(START_INT_ER_REG(irq)) | - START_INT_REG_BIT(irq), START_INT_ER_REG(irq)); -} - -static inline void start_int_mask(u8 irq) -{ - __raw_writel(__raw_readl(START_INT_ER_REG(irq)) & - ~START_INT_REG_BIT(irq), START_INT_ER_REG(irq)); -} - -static inline void start_int_ack(u8 irq) -{ - __raw_writel(START_INT_REG_BIT(irq), START_INT_RSR_REG(irq)); -} - -static inline void start_int_set_falling_edge(u8 irq) -{ - __raw_writel(__raw_readl(START_INT_APR_REG(irq)) & - ~START_INT_REG_BIT(irq), START_INT_APR_REG(irq)); -} - -static inline void start_int_set_rising_edge(u8 irq) -{ - __raw_writel(__raw_readl(START_INT_APR_REG(irq)) | - START_INT_REG_BIT(irq), START_INT_APR_REG(irq)); -} - #endif /* ASSEMBLER */ #endif /* __ASM_ARCH_PNX4008_PM_H */ -- cgit v1.2.3 From ae2a120ce50e9dc8092f9bd4d76d8c8150a12c48 Mon Sep 17 00:00:00 2001 From: Vitaly Wool Date: Thu, 22 Jun 2006 10:27:15 +0100 Subject: [ARM] 3621/1: fix compilation breakage for pnx4008 Patch from Vitaly Wool pnx4008_defconfig fails to build: include/asm/hardware/debug-8250.S: Assembler messages: include/asm/hardware/debug-8250.S:12: Error: Macro with this name was already defined. This is due to senduart macro erroneously defined in include/asm-arm/arch-pnx4008/debug-macro.S. This patch removes it from that file. Signed-off-by: Vitaly Wool Signed-off-by: Russell King --- include/asm-arm/arch-pnx4008/debug-macro.S | 4 ---- 1 file changed, 4 deletions(-) (limited to 'include') diff --git a/include/asm-arm/arch-pnx4008/debug-macro.S b/include/asm-arm/arch-pnx4008/debug-macro.S index eb3839de389a..67d18a203d23 100644 --- a/include/asm-arm/arch-pnx4008/debug-macro.S +++ b/include/asm-arm/arch-pnx4008/debug-macro.S @@ -19,9 +19,5 @@ addne \rx, \rx, #0xf4000000 .endm - .macro senduart,rd,rx - strb \rd, [\rx, #0x0] - .endm - #define UART_SHIFT 2 #include -- cgit v1.2.3 From 8b76a68c6caafef5a91cdc80958aecaca76a8896 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 22 Jun 2006 10:30:56 +0100 Subject: [ARM] 3620/2: ixp23xx: add uengine loader support Patch from Lennert Buytenhek This patch allows the ixp2000 uengine loader that is already in the tree to also be used on the ixp23xx. Signed-off-by: Lennert Buytenhek Signed-off-by: Russell King --- arch/arm/common/Makefile | 1 + arch/arm/common/uengine.c | 58 +++++++++++++++++++++++++++------ arch/arm/mach-ixp23xx/core.c | 1 + include/asm-arm/arch-ixp23xx/ixp23xx.h | 3 ++ include/asm-arm/arch-ixp23xx/platform.h | 15 +++++++++ 5 files changed, 68 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile index 847e3e6356c6..e1289a256ce5 100644 --- a/arch/arm/common/Makefile +++ b/arch/arm/common/Makefile @@ -16,3 +16,4 @@ obj-$(CONFIG_SHARP_PARAM) += sharpsl_param.o obj-$(CONFIG_SHARPSL_PM) += sharpsl_pm.o obj-$(CONFIG_SHARP_SCOOP) += scoop.o obj-$(CONFIG_ARCH_IXP2000) += uengine.o +obj-$(CONFIG_ARCH_IXP23XX) += uengine.o diff --git a/arch/arm/common/uengine.c b/arch/arm/common/uengine.c index a1310b71004e..dfca596a9a27 100644 --- a/arch/arm/common/uengine.c +++ b/arch/arm/common/uengine.c @@ -18,10 +18,26 @@ #include #include #include -#include +#include #include #include +#if defined(CONFIG_ARCH_IXP2000) +#define IXP_UENGINE_CSR_VIRT_BASE IXP2000_UENGINE_CSR_VIRT_BASE +#define IXP_PRODUCT_ID IXP2000_PRODUCT_ID +#define IXP_MISC_CONTROL IXP2000_MISC_CONTROL +#define IXP_RESET1 IXP2000_RESET1 +#else +#if defined(CONFIG_ARCH_IXP23XX) +#define IXP_UENGINE_CSR_VIRT_BASE IXP23XX_UENGINE_CSR_VIRT_BASE +#define IXP_PRODUCT_ID IXP23XX_PRODUCT_ID +#define IXP_MISC_CONTROL IXP23XX_MISC_CONTROL +#define IXP_RESET1 IXP23XX_RESET1 +#else +#error unknown platform +#endif +#endif + #define USTORE_ADDRESS 0x000 #define USTORE_DATA_LOWER 0x004 #define USTORE_DATA_UPPER 0x008 @@ -43,7 +59,7 @@ u32 ixp2000_uengine_mask; static void *ixp2000_uengine_csr_area(int uengine) { - return ((void *)IXP2000_UENGINE_CSR_VIRT_BASE) + (uengine << 10); + return ((void *)IXP_UENGINE_CSR_VIRT_BASE) + (uengine << 10); } /* @@ -91,8 +107,13 @@ EXPORT_SYMBOL(ixp2000_uengine_csr_write); void ixp2000_uengine_reset(u32 uengine_mask) { - ixp2000_reg_wrb(IXP2000_RESET1, uengine_mask & ixp2000_uengine_mask); - ixp2000_reg_wrb(IXP2000_RESET1, 0); + u32 value; + + value = ixp2000_reg_read(IXP_RESET1) & ~ixp2000_uengine_mask; + + uengine_mask &= ixp2000_uengine_mask; + ixp2000_reg_wrb(IXP_RESET1, value | uengine_mask); + ixp2000_reg_wrb(IXP_RESET1, value); } EXPORT_SYMBOL(ixp2000_uengine_reset); @@ -235,11 +256,12 @@ static int check_ixp_type(struct ixp2000_uengine_code *c) u32 product_id; u32 rev; - product_id = ixp2000_reg_read(IXP2000_PRODUCT_ID); + product_id = ixp2000_reg_read(IXP_PRODUCT_ID); if (((product_id >> 16) & 0x1f) != 0) return 0; switch ((product_id >> 8) & 0xff) { +#ifdef CONFIG_ARCH_IXP2000 case 0: /* IXP2800 */ if (!(c->cpu_model_bitmask & 4)) return 0; @@ -254,6 +276,14 @@ static int check_ixp_type(struct ixp2000_uengine_code *c) if (!(c->cpu_model_bitmask & 2)) return 0; break; +#endif + +#ifdef CONFIG_ARCH_IXP23XX + case 4: /* IXP23xx */ + if (!(c->cpu_model_bitmask & 0x3f0)) + return 0; + break; +#endif default: return 0; @@ -432,7 +462,8 @@ static int __init ixp2000_uengine_init(void) /* * Determine number of microengines present. */ - switch ((ixp2000_reg_read(IXP2000_PRODUCT_ID) >> 8) & 0x1fff) { + switch ((ixp2000_reg_read(IXP_PRODUCT_ID) >> 8) & 0x1fff) { +#ifdef CONFIG_ARCH_IXP2000 case 0: /* IXP2800 */ case 1: /* IXP2850 */ ixp2000_uengine_mask = 0x00ff00ff; @@ -441,10 +472,17 @@ static int __init ixp2000_uengine_init(void) case 2: /* IXP2400 */ ixp2000_uengine_mask = 0x000f000f; break; +#endif + +#ifdef CONFIG_ARCH_IXP23XX + case 4: /* IXP23xx */ + ixp2000_uengine_mask = (*IXP23XX_EXP_CFG_FUSE >> 8) & 0xf; + break; +#endif default: printk(KERN_INFO "Detected unknown IXP2000 model (%.8x)\n", - (unsigned int)ixp2000_reg_read(IXP2000_PRODUCT_ID)); + (unsigned int)ixp2000_reg_read(IXP_PRODUCT_ID)); ixp2000_uengine_mask = 0x00000000; break; } @@ -457,15 +495,15 @@ static int __init ixp2000_uengine_init(void) /* * Synchronise timestamp counters across all microengines. */ - value = ixp2000_reg_read(IXP2000_MISC_CONTROL); - ixp2000_reg_wrb(IXP2000_MISC_CONTROL, value & ~0x80); + value = ixp2000_reg_read(IXP_MISC_CONTROL); + ixp2000_reg_wrb(IXP_MISC_CONTROL, value & ~0x80); for (uengine = 0; uengine < 32; uengine++) { if (ixp2000_uengine_mask & (1 << uengine)) { ixp2000_uengine_csr_write(uengine, TIMESTAMP_LOW, 0); ixp2000_uengine_csr_write(uengine, TIMESTAMP_HIGH, 0); } } - ixp2000_reg_wrb(IXP2000_MISC_CONTROL, value | 0x80); + ixp2000_reg_wrb(IXP_MISC_CONTROL, value | 0x80); return 0; } diff --git a/arch/arm/mach-ixp23xx/core.c b/arch/arm/mach-ixp23xx/core.c index e2aad734080e..051e3d70026e 100644 --- a/arch/arm/mach-ixp23xx/core.c +++ b/arch/arm/mach-ixp23xx/core.c @@ -439,5 +439,6 @@ static struct platform_device *ixp23xx_devices[] __initdata = { void __init ixp23xx_sys_init(void) { + *IXP23XX_EXP_UNIT_FUSE |= 0xf; platform_add_devices(ixp23xx_devices, ARRAY_SIZE(ixp23xx_devices)); } diff --git a/include/asm-arm/arch-ixp23xx/ixp23xx.h b/include/asm-arm/arch-ixp23xx/ixp23xx.h index 01efdbd1180f..d0a72201ee96 100644 --- a/include/asm-arm/arch-ixp23xx/ixp23xx.h +++ b/include/asm-arm/arch-ixp23xx/ixp23xx.h @@ -124,6 +124,7 @@ #define IXP23XX_EXP_UNIT_FUSE IXP23XX_EXP_CFG_REG(0x28) #define IXP23XX_EXP_MSF_MUX IXP23XX_EXP_CFG_REG(0x30) +#define IXP23XX_EXP_CFG_FUSE IXP23XX_EXP_CFG_REG(0x34) #define IXP23XX_EXP_BUS_PHYS 0x90000000 #define IXP23XX_EXP_BUS_WINDOW_SIZE 0x01000000 @@ -265,6 +266,8 @@ #define IXP23XX_PCI_UNIT_RESET (1 << 1) #define IXP23XX_XSCALE_RESET (1 << 0) +#define IXP23XX_UENGINE_CSR_VIRT_BASE (IXP23XX_CAP_CSR_VIRT + 0x18000) + /**************************************************************************** * PCI CSRs. diff --git a/include/asm-arm/arch-ixp23xx/platform.h b/include/asm-arm/arch-ixp23xx/platform.h index e4d99060a049..19a73b39c864 100644 --- a/include/asm-arm/arch-ixp23xx/platform.h +++ b/include/asm-arm/arch-ixp23xx/platform.h @@ -14,6 +14,21 @@ #ifndef __ASSEMBLY__ +extern inline unsigned long ixp2000_reg_read(volatile void *reg) +{ + return *((volatile unsigned long *)reg); +} + +extern inline void ixp2000_reg_write(volatile void *reg, unsigned long val) +{ + *((volatile unsigned long *)reg) = val; +} + +extern inline void ixp2000_reg_wrb(volatile void *reg, unsigned long val) +{ + *((volatile unsigned long *)reg) = val; +} + struct pci_sys_data; void ixp23xx_map_io(void); -- cgit v1.2.3 From 02e0c5d5c2e00374b6808a42f8eea4ea9baaa216 Mon Sep 17 00:00:00 2001 From: Rudolf Marek Date: Thu, 23 Mar 2006 16:48:09 +0100 Subject: [PATCH] i2c-piix4: Add ATI IXP200/300/400 support This patch adds the ATI IXP southbridges support to i2c-piix4, as it turned out those chips are compatible with it. Signed-off-by: Rudolf Marek Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- Documentation/i2c/busses/i2c-piix4 | 2 ++ drivers/i2c/busses/Kconfig | 5 ++++- drivers/i2c/busses/i2c-piix4.c | 6 ++++++ include/linux/pci_ids.h | 3 +++ 4 files changed, 15 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/Documentation/i2c/busses/i2c-piix4 b/Documentation/i2c/busses/i2c-piix4 index a1c8f581afed..6e6c905143a1 100644 --- a/Documentation/i2c/busses/i2c-piix4 +++ b/Documentation/i2c/busses/i2c-piix4 @@ -6,6 +6,8 @@ Supported adapters: Datasheet: Publicly available at the Intel website * ServerWorks OSB4, CSB5, CSB6 and HT-1000 southbridges Datasheet: Only available via NDA from ServerWorks + * ATI IXP southbridges IXP200, IXP300, IXP400 + Datasheet: Not publicly available * Standard Microsystems (SMSC) SLC90E66 (Victory66) southbridge Datasheet: Publicly available at the SMSC website http://www.smsc.com diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index d6d44946a283..e3450d16d8a4 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -163,7 +163,7 @@ config I2C_PXA_SLAVE I2C bus. config I2C_PIIX4 - tristate "Intel PIIX4" + tristate "Intel PIIX4 and compatible (ATI/Serverworks/Broadcom/SMSC)" depends on I2C && PCI help If you say yes to this option, support will be included for the Intel @@ -172,6 +172,9 @@ config I2C_PIIX4 of Broadcom): Intel PIIX4 Intel 440MX + ATI IXP200 + ATI IXP300 + ATI IXP400 Serverworks OSB4 Serverworks CSB5 Serverworks CSB6 diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index d9c7c00e71f9..5f06e81a2087 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -413,6 +413,12 @@ static struct i2c_adapter piix4_adapter = { static struct pci_device_id piix4_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3), .driver_data = 3 }, + { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP200_SMBUS), + .driver_data = 0 }, + { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP300_SMBUS), + .driver_data = 0 }, + { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS), + .driver_data = 0 }, { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4), .driver_data = 0 }, { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5), diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index bcfe9d4f56ae..489af9d3ce1f 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -352,8 +352,11 @@ #define PCI_DEVICE_ID_ATI_RS480 0x5950 /* ATI IXP Chipset */ #define PCI_DEVICE_ID_ATI_IXP200_IDE 0x4349 +#define PCI_DEVICE_ID_ATI_IXP200_SMBUS 0x4353 +#define PCI_DEVICE_ID_ATI_IXP300_SMBUS 0x4363 #define PCI_DEVICE_ID_ATI_IXP300_IDE 0x4369 #define PCI_DEVICE_ID_ATI_IXP300_SATA 0x436e +#define PCI_DEVICE_ID_ATI_IXP400_SMBUS 0x4372 #define PCI_DEVICE_ID_ATI_IXP400_IDE 0x4376 #define PCI_DEVICE_ID_ATI_IXP400_SATA 0x4379 #define PCI_DEVICE_ID_ATI_IXP400_SATA2 0x437a -- cgit v1.2.3 From 5e9f4f2e5a02bb6908278a819952aa31fffefaa2 Mon Sep 17 00:00:00 2001 From: "Mark A. Greer" Date: Tue, 25 Apr 2006 13:04:54 +0200 Subject: [PATCH] I2C: m41t00: Add support for the ST M41T81 and M41T85 This patch adds support for the ST m41t81 and m41t85 i2c rtc chips to the existing m41t00 driver. Since there is no way to reliably determine what type of rtc chip is in use, the chip type is passed in via platform_data. The i2c address and square wave frequency are passed in via platform_data as well. To accommodate the use of platform_data, a new header file include/linux/m41t00.h has been added. The m41t81 and m41t85 chips halt the updating of their time registers while they are being accessed. They resume when a stop condition exists on the i2c bus or when non-time related regs are accessed. To make the best use of that facility and to make more efficient use of the i2c bus, this patch replaces multiple i2c_smbus_xxx calls with a single i2c_transfer call. Signed-off-by: Mark A. Greer Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/chips/m41t00.c | 313 ++++++++++++++++++++++++++++++++++----------- include/linux/m41t00.h | 50 ++++++++ 2 files changed, 291 insertions(+), 72 deletions(-) create mode 100644 include/linux/m41t00.h (limited to 'include') diff --git a/drivers/i2c/chips/m41t00.c b/drivers/i2c/chips/m41t00.c index eb2be3e4416c..2dd0a34d9472 100644 --- a/drivers/i2c/chips/m41t00.c +++ b/drivers/i2c/chips/m41t00.c @@ -1,9 +1,9 @@ /* - * I2C client/driver for the ST M41T00 Real-Time Clock chip. + * I2C client/driver for the ST M41T00 family of i2c rtc chips. * * Author: Mark A. Greer * - * 2005 (c) MontaVista Software, Inc. This file is licensed under + * 2005, 2006 (c) MontaVista Software, Inc. 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. @@ -19,21 +19,17 @@ #include #include #include -#include #include - +#include +#include #include #include -#define M41T00_DRV_NAME "m41t00" - -static DEFINE_MUTEX(m41t00_mutex); - static struct i2c_driver m41t00_driver; static struct i2c_client *save_client; static unsigned short ignore[] = { I2C_CLIENT_END }; -static unsigned short normal_addr[] = { 0x68, I2C_CLIENT_END }; +static unsigned short normal_addr[] = { I2C_CLIENT_END, I2C_CLIENT_END }; static struct i2c_client_address_data addr_data = { .normal_i2c = normal_addr, @@ -41,34 +37,92 @@ static struct i2c_client_address_data addr_data = { .ignore = ignore, }; +struct m41t00_chip_info { + u8 type; + char *name; + u8 read_limit; + u8 sec; /* Offsets for chip regs */ + u8 min; + u8 hour; + u8 day; + u8 mon; + u8 year; + u8 alarm_mon; + u8 alarm_hour; + u8 sqw; + u8 sqw_freq; +}; + +static struct m41t00_chip_info m41t00_chip_info_tbl[] = { + { + .type = M41T00_TYPE_M41T00, + .name = "m41t00", + .read_limit = 5, + .sec = 0, + .min = 1, + .hour = 2, + .day = 4, + .mon = 5, + .year = 6, + }, + { + .type = M41T00_TYPE_M41T81, + .name = "m41t81", + .read_limit = 1, + .sec = 1, + .min = 2, + .hour = 3, + .day = 5, + .mon = 6, + .year = 7, + .alarm_mon = 0xa, + .alarm_hour = 0xc, + .sqw = 0x13, + }, + { + .type = M41T00_TYPE_M41T85, + .name = "m41t85", + .read_limit = 1, + .sec = 1, + .min = 2, + .hour = 3, + .day = 5, + .mon = 6, + .year = 7, + .alarm_mon = 0xa, + .alarm_hour = 0xc, + .sqw = 0x13, + }, +}; +static struct m41t00_chip_info *m41t00_chip; + ulong m41t00_get_rtc_time(void) { s32 sec, min, hour, day, mon, year; s32 sec1, min1, hour1, day1, mon1, year1; - ulong limit = 10; + u8 reads = 0; + u8 buf[8], msgbuf[1] = { 0 }; /* offset into rtc's regs */ + struct i2c_msg msgs[] = { + { + .addr = save_client->addr, + .flags = 0, + .len = 1, + .buf = msgbuf, + }, + { + .addr = save_client->addr, + .flags = I2C_M_RD, + .len = 8, + .buf = buf, + }, + }; sec = min = hour = day = mon = year = 0; - sec1 = min1 = hour1 = day1 = mon1 = year1 = 0; - mutex_lock(&m41t00_mutex); do { - if (((sec = i2c_smbus_read_byte_data(save_client, 0)) >= 0) - && ((min = i2c_smbus_read_byte_data(save_client, 1)) - >= 0) - && ((hour = i2c_smbus_read_byte_data(save_client, 2)) - >= 0) - && ((day = i2c_smbus_read_byte_data(save_client, 4)) - >= 0) - && ((mon = i2c_smbus_read_byte_data(save_client, 5)) - >= 0) - && ((year = i2c_smbus_read_byte_data(save_client, 6)) - >= 0) - && ((sec == sec1) && (min == min1) && (hour == hour1) - && (day == day1) && (mon == mon1) - && (year == year1))) - - break; + if (i2c_transfer(save_client->adapter, msgs, 2) < 0) + goto read_err; sec1 = sec; min1 = min; @@ -76,21 +130,21 @@ m41t00_get_rtc_time(void) day1 = day; mon1 = mon; year1 = year; - } while (--limit > 0); - mutex_unlock(&m41t00_mutex); - - if (limit == 0) { - dev_warn(&save_client->dev, - "m41t00: can't read rtc chip\n"); - sec = min = hour = day = mon = year = 0; - } - sec &= 0x7f; - min &= 0x7f; - hour &= 0x3f; - day &= 0x3f; - mon &= 0x1f; - year &= 0xff; + sec = buf[m41t00_chip->sec] & 0x7f; + min = buf[m41t00_chip->min] & 0x7f; + hour = buf[m41t00_chip->hour] & 0x3f; + day = buf[m41t00_chip->day] & 0x3f; + mon = buf[m41t00_chip->mon] & 0x1f; + year = buf[m41t00_chip->year]; + } while ((++reads < m41t00_chip->read_limit) && ((sec != sec1) + || (min != min1) || (hour != hour1) || (day != day1) + || (mon != mon1) || (year != year1))); + + if ((m41t00_chip->read_limit > 1) && ((sec != sec1) || (min != min1) + || (hour != hour1) || (day != day1) || (mon != mon1) + || (year != year1))) + goto read_err; sec = BCD2BIN(sec); min = BCD2BIN(min); @@ -104,40 +158,60 @@ m41t00_get_rtc_time(void) year += 100; return mktime(year, mon, day, hour, min, sec); + +read_err: + dev_err(&save_client->dev, "m41t00_get_rtc_time: Read error\n"); + return 0; } +EXPORT_SYMBOL_GPL(m41t00_get_rtc_time); static void m41t00_set(void *arg) { struct rtc_time tm; - ulong nowtime = *(ulong *)arg; + int nowtime = *(int *)arg; + s32 sec, min, hour, day, mon, year; + u8 wbuf[9], *buf = &wbuf[1], msgbuf[1] = { 0 }; + struct i2c_msg msgs[] = { + { + .addr = save_client->addr, + .flags = 0, + .len = 1, + .buf = msgbuf, + }, + { + .addr = save_client->addr, + .flags = I2C_M_RD, + .len = 8, + .buf = buf, + }, + }; to_tm(nowtime, &tm); tm.tm_year = (tm.tm_year - 1900) % 100; - tm.tm_sec = BIN2BCD(tm.tm_sec); - tm.tm_min = BIN2BCD(tm.tm_min); - tm.tm_hour = BIN2BCD(tm.tm_hour); - tm.tm_mon = BIN2BCD(tm.tm_mon); - tm.tm_mday = BIN2BCD(tm.tm_mday); - tm.tm_year = BIN2BCD(tm.tm_year); - - mutex_lock(&m41t00_mutex); - if ((i2c_smbus_write_byte_data(save_client, 0, tm.tm_sec & 0x7f) < 0) - || (i2c_smbus_write_byte_data(save_client, 1, tm.tm_min & 0x7f) - < 0) - || (i2c_smbus_write_byte_data(save_client, 2, tm.tm_hour & 0x3f) - < 0) - || (i2c_smbus_write_byte_data(save_client, 4, tm.tm_mday & 0x3f) - < 0) - || (i2c_smbus_write_byte_data(save_client, 5, tm.tm_mon & 0x1f) - < 0) - || (i2c_smbus_write_byte_data(save_client, 6, tm.tm_year & 0xff) - < 0)) - - dev_warn(&save_client->dev,"m41t00: can't write to rtc chip\n"); - - mutex_unlock(&m41t00_mutex); + sec = BIN2BCD(tm.tm_sec); + min = BIN2BCD(tm.tm_min); + hour = BIN2BCD(tm.tm_hour); + day = BIN2BCD(tm.tm_mday); + mon = BIN2BCD(tm.tm_mon); + year = BIN2BCD(tm.tm_year); + + /* Read reg values into buf[0..7]/wbuf[1..8] */ + if (i2c_transfer(save_client->adapter, msgs, 2) < 0) { + dev_err(&save_client->dev, "m41t00_set: Read error\n"); + return; + } + + wbuf[0] = 0; /* offset into rtc's regs */ + buf[m41t00_chip->sec] = (buf[m41t00_chip->sec] & ~0x7f) | (sec & 0x7f); + buf[m41t00_chip->min] = (buf[m41t00_chip->min] & ~0x7f) | (min & 0x7f); + buf[m41t00_chip->hour] = (buf[m41t00_chip->hour] & ~0x3f) | (hour& 0x3f); + buf[m41t00_chip->day] = (buf[m41t00_chip->day] & ~0x3f) | (day & 0x3f); + buf[m41t00_chip->mon] = (buf[m41t00_chip->mon] & ~0x1f) | (mon & 0x1f); + + if (i2c_master_send(save_client, wbuf, 9) < 0) + dev_err(&save_client->dev, "m41t00_set: Write error\n"); } static ulong new_time; @@ -156,6 +230,48 @@ m41t00_set_rtc_time(ulong nowtime) return 0; } +EXPORT_SYMBOL_GPL(m41t00_set_rtc_time); + +/* + ***************************************************************************** + * + * platform_data Driver Interface + * + ***************************************************************************** + */ +static int __init +m41t00_platform_probe(struct platform_device *pdev) +{ + struct m41t00_platform_data *pdata; + int i; + + if (pdev && (pdata = pdev->dev.platform_data)) { + normal_addr[0] = pdata->i2c_addr; + + for (i=0; itype) { + m41t00_chip = &m41t00_chip_info_tbl[i]; + m41t00_chip->sqw_freq = pdata->sqw_freq; + return 0; + } + } + return -ENODEV; +} + +static int __exit +m41t00_platform_remove(struct platform_device *pdev) +{ + return 0; +} + +static struct platform_driver m41t00_platform_driver = { + .probe = m41t00_platform_probe, + .remove = m41t00_platform_remove, + .driver = { + .owner = THIS_MODULE, + .name = M41T00_DRV_NAME, + }, +}; /* ***************************************************************************** @@ -170,23 +286,71 @@ m41t00_probe(struct i2c_adapter *adap, int addr, int kind) struct i2c_client *client; int rc; + if (!i2c_check_functionality(adap, I2C_FUNC_I2C + | I2C_FUNC_SMBUS_BYTE_DATA)) + return 0; + client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); if (!client) return -ENOMEM; - strlcpy(client->name, M41T00_DRV_NAME, I2C_NAME_SIZE); + strlcpy(client->name, m41t00_chip->name, I2C_NAME_SIZE); client->addr = addr; client->adapter = adap; client->driver = &m41t00_driver; - if ((rc = i2c_attach_client(client)) != 0) { - kfree(client); - return rc; + if ((rc = i2c_attach_client(client))) + goto attach_err; + + if (m41t00_chip->type != M41T00_TYPE_M41T00) { + /* If asked, disable SQW, set SQW frequency & re-enable */ + if (m41t00_chip->sqw_freq) + if (((rc = i2c_smbus_read_byte_data(client, + m41t00_chip->alarm_mon)) < 0) + || ((rc = i2c_smbus_write_byte_data(client, + m41t00_chip->alarm_mon, rc & ~0x40)) <0) + || ((rc = i2c_smbus_write_byte_data(client, + m41t00_chip->sqw, + m41t00_chip->sqw_freq)) < 0) + || ((rc = i2c_smbus_write_byte_data(client, + m41t00_chip->alarm_mon, rc | 0x40)) <0)) + goto sqw_err; + + /* Make sure HT (Halt Update) bit is cleared */ + if ((rc = i2c_smbus_read_byte_data(client, + m41t00_chip->alarm_hour)) < 0) + goto ht_err; + + if (rc & 0x40) + if ((rc = i2c_smbus_write_byte_data(client, + m41t00_chip->alarm_hour, rc & ~0x40))<0) + goto ht_err; } - m41t00_wq = create_singlethread_workqueue("m41t00"); + /* Make sure ST (stop) bit is cleared */ + if ((rc = i2c_smbus_read_byte_data(client, m41t00_chip->sec)) < 0) + goto st_err; + + if (rc & 0x80) + if ((rc = i2c_smbus_write_byte_data(client, m41t00_chip->sec, + rc & ~0x80)) < 0) + goto st_err; + + m41t00_wq = create_singlethread_workqueue(m41t00_chip->name); save_client = client; return 0; + +st_err: + dev_err(&client->dev, "m41t00_probe: Can't clear ST bit\n"); + goto attach_err; +ht_err: + dev_err(&client->dev, "m41t00_probe: Can't clear HT bit\n"); + goto attach_err; +sqw_err: + dev_err(&client->dev, "m41t00_probe: Can't set SQW Frequency\n"); +attach_err: + kfree(client); + return rc; } static int @@ -219,13 +383,18 @@ static struct i2c_driver m41t00_driver = { static int __init m41t00_init(void) { - return i2c_add_driver(&m41t00_driver); + int rc; + + if (!(rc = platform_driver_register(&m41t00_platform_driver))) + rc = i2c_add_driver(&m41t00_driver); + return rc; } static void __exit m41t00_exit(void) { i2c_del_driver(&m41t00_driver); + platform_driver_unregister(&m41t00_platform_driver); } module_init(m41t00_init); diff --git a/include/linux/m41t00.h b/include/linux/m41t00.h new file mode 100644 index 000000000000..b423360ca38e --- /dev/null +++ b/include/linux/m41t00.h @@ -0,0 +1,50 @@ +/* + * Definitions for the ST M41T00 family of i2c rtc chips. + * + * Author: Mark A. Greer + * + * 2005, 2006 (c) MontaVista Software, Inc. 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 _M41T00_H +#define _M41T00_H + +#define M41T00_DRV_NAME "m41t00" +#define M41T00_I2C_ADDR 0x68 + +#define M41T00_TYPE_M41T00 0 +#define M41T00_TYPE_M41T81 81 +#define M41T00_TYPE_M41T85 85 + +struct m41t00_platform_data { + u8 type; + u8 i2c_addr; + u8 sqw_freq; +}; + +/* SQW output disabled, this is default value by power on */ +#define M41T00_SQW_DISABLE (0) + +#define M41T00_SQW_32KHZ (1<<4) /* 32.768 KHz */ +#define M41T00_SQW_8KHZ (2<<4) /* 8.192 KHz */ +#define M41T00_SQW_4KHZ (3<<4) /* 4.096 KHz */ +#define M41T00_SQW_2KHZ (4<<4) /* 2.048 KHz */ +#define M41T00_SQW_1KHZ (5<<4) /* 1.024 KHz */ +#define M41T00_SQW_512HZ (6<<4) /* 512 Hz */ +#define M41T00_SQW_256HZ (7<<4) /* 256 Hz */ +#define M41T00_SQW_128HZ (8<<4) /* 128 Hz */ +#define M41T00_SQW_64HZ (9<<4) /* 64 Hz */ +#define M41T00_SQW_32HZ (10<<4) /* 32 Hz */ +#define M41T00_SQW_16HZ (11<<4) /* 16 Hz */ +#define M41T00_SQW_8HZ (12<<4) /* 8 Hz */ +#define M41T00_SQW_4HZ (13<<4) /* 4 Hz */ +#define M41T00_SQW_2HZ (14<<4) /* 2 Hz */ +#define M41T00_SQW_1HZ (15<<4) /* 1 Hz */ + +extern ulong m41t00_get_rtc_time(void); +extern int m41t00_set_rtc_time(ulong nowtime); + +#endif /* _M41T00_H */ -- cgit v1.2.3 From 5c7ae65899a4c5b05b6277f856018d1eeeb98907 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 25 Apr 2006 14:18:16 +0200 Subject: [PATCH] I2C: i2c-nforce2: Add support for the nForce4 MCP51 and MCP55 Add support for the new nForce4 MCP51 (also known as nForce 410 or 430) and nForce4 MCP55 to the i2c-nforce2 driver. Some code changes were required because the base I/O address registers have changed in these versions. Standard BARs are now being used, while the original nForce2 chips used non-standard ones. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- Documentation/i2c/busses/i2c-nforce2 | 2 ++ drivers/i2c/busses/i2c-nforce2.c | 38 +++++++++++++++++++++++++----------- include/linux/pci_ids.h | 2 ++ 3 files changed, 31 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/Documentation/i2c/busses/i2c-nforce2 b/Documentation/i2c/busses/i2c-nforce2 index d751282d9b2a..cd49c428a3ab 100644 --- a/Documentation/i2c/busses/i2c-nforce2 +++ b/Documentation/i2c/busses/i2c-nforce2 @@ -7,6 +7,8 @@ Supported adapters: * nForce3 250Gb MCP 10de:00E4 * nForce4 MCP 10de:0052 * nForce4 MCP-04 10de:0034 + * nForce4 MCP51 10de:0264 + * nForce4 MCP55 10de:0368 Datasheet: not publically available, but seems to be similar to the AMD-8111 SMBus 2.0 adapter. diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index 2d80eb26f688..604b49e22df1 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -31,6 +31,8 @@ nForce3 250Gb MCP 00E4 nForce4 MCP 0052 nForce4 MCP-04 0034 + nForce4 MCP51 0264 + nForce4 MCP55 0368 This driver supports the 2 SMBuses that are included in the MCP of the nForce2/3/4 chipsets. @@ -64,6 +66,7 @@ struct nforce2_smbus { /* * nVidia nForce2 SMBus control register definitions + * (Newer incarnations use standard BARs 4 and 5 instead) */ #define NFORCE_PCI_SMB1 0x50 #define NFORCE_PCI_SMB2 0x54 @@ -259,6 +262,8 @@ static struct pci_device_id nforce2_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE4_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS) }, { 0 } }; @@ -266,19 +271,29 @@ static struct pci_device_id nforce2_ids[] = { MODULE_DEVICE_TABLE (pci, nforce2_ids); -static int __devinit nforce2_probe_smb (struct pci_dev *dev, int reg, - struct nforce2_smbus *smbus, char *name) +static int __devinit nforce2_probe_smb (struct pci_dev *dev, int bar, + int alt_reg, struct nforce2_smbus *smbus, const char *name) { - u16 iobase; int error; - if (pci_read_config_word(dev, reg, &iobase) != PCIBIOS_SUCCESSFUL) { - dev_err(&smbus->adapter.dev, "Error reading PCI config for %s\n", name); - return -1; + smbus->base = pci_resource_start(dev, bar); + if (smbus->base) { + smbus->size = pci_resource_len(dev, bar); + } else { + /* Older incarnations of the device used non-standard BARs */ + u16 iobase; + + if (pci_read_config_word(dev, alt_reg, &iobase) + != PCIBIOS_SUCCESSFUL) { + dev_err(&dev->dev, "Error reading PCI config for %s\n", + name); + return -1; + } + + smbus->base = iobase & PCI_BASE_ADDRESS_IO_MASK; + smbus->size = 8; } - smbus->dev = dev; - smbus->base = iobase & 0xfffc; - smbus->size = 8; + smbus->dev = dev; if (!request_region(smbus->base, smbus->size, nforce2_driver.name)) { dev_err(&smbus->adapter.dev, "Error requesting region %02x .. %02X for %s\n", @@ -313,12 +328,13 @@ static int __devinit nforce2_probe(struct pci_dev *dev, const struct pci_device_ pci_set_drvdata(dev, smbuses); /* SMBus adapter 1 */ - res1 = nforce2_probe_smb (dev, NFORCE_PCI_SMB1, &smbuses[0], "SMB1"); + res1 = nforce2_probe_smb(dev, 4, NFORCE_PCI_SMB1, &smbuses[0], "SMB1"); if (res1 < 0) { dev_err(&dev->dev, "Error probing SMB1.\n"); smbuses[0].base = 0; /* to have a check value */ } - res2 = nforce2_probe_smb (dev, NFORCE_PCI_SMB2, &smbuses[1], "SMB2"); + /* SMBus adapter 2 */ + res2 = nforce2_probe_smb(dev, 5, NFORCE_PCI_SMB2, &smbuses[1], "SMB2"); if (res2 < 0) { dev_err(&dev->dev, "Error probing SMB2.\n"); smbuses[1].base = 0; /* to have a check value */ diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 489af9d3ce1f..d33436097e1d 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1130,9 +1130,11 @@ #define PCI_DEVICE_ID_NVIDIA_QUADRO4_900XGL 0x0258 #define PCI_DEVICE_ID_NVIDIA_QUADRO4_750XGL 0x0259 #define PCI_DEVICE_ID_NVIDIA_QUADRO4_700XGL 0x025B +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS 0x0264 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE 0x0265 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA 0x0266 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2 0x0267 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS 0x0368 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE 0x036E #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA 0x037E #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2 0x037F -- cgit v1.2.3 From 18f98b1e3147afdb51e545cc6ff2b016c7d088a7 Mon Sep 17 00:00:00 2001 From: Peter Korsgaard Date: Sun, 4 Jun 2006 20:01:08 +0200 Subject: [PATCH] i2c: New bus driver for the OpenCores I2C controller The following patch adds support for the OpenCores I2C controller IP core (See http://www.opencores.org/projects.cgi/web/i2c/overview). Signed-off-by: Peter Korsgaard Signed-off-by: Andrew Morton Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- Documentation/i2c/busses/i2c-ocores | 51 ++++++ drivers/i2c/busses/Kconfig | 11 ++ drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-ocores.c | 343 ++++++++++++++++++++++++++++++++++++ include/linux/i2c-ocores.h | 19 ++ 5 files changed, 425 insertions(+) create mode 100644 Documentation/i2c/busses/i2c-ocores create mode 100644 drivers/i2c/busses/i2c-ocores.c create mode 100644 include/linux/i2c-ocores.h (limited to 'include') diff --git a/Documentation/i2c/busses/i2c-ocores b/Documentation/i2c/busses/i2c-ocores new file mode 100644 index 000000000000..cfcebb10d14e --- /dev/null +++ b/Documentation/i2c/busses/i2c-ocores @@ -0,0 +1,51 @@ +Kernel driver i2c-ocores + +Supported adapters: + * OpenCores.org I2C controller by Richard Herveille (see datasheet link) + Datasheet: http://www.opencores.org/projects.cgi/web/i2c/overview + +Author: Peter Korsgaard + +Description +----------- + +i2c-ocores is an i2c bus driver for the OpenCores.org I2C controller +IP core by Richard Herveille. + +Usage +----- + +i2c-ocores uses the platform bus, so you need to provide a struct +platform_device with the base address and interrupt number. The +dev.platform_data of the device should also point to a struct +ocores_i2c_platform_data (see linux/i2c-ocores.h) describing the +distance between registers and the input clock speed. + +E.G. something like: + +static struct resource ocores_resources[] = { + [0] = { + .start = MYI2C_BASEADDR, + .end = MYI2C_BASEADDR + 8, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = MYI2C_IRQ, + .end = MYI2C_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct ocores_i2c_platform_data myi2c_data = { + .regstep = 2, /* two bytes between registers */ + .clock_khz = 50000, /* input clock of 50MHz */ +}; + +static struct platform_device myi2c = { + .name = "ocores-i2c", + .dev = { + .platform_data = &myi2c_data, + }, + .num_resources = ARRAY_SIZE(ocores_resources), + .resource = ocores_resources, +}; diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index d25a8cbbec0a..f7af7e9bb7d9 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -276,6 +276,17 @@ config I2C_NFORCE2 This driver can also be built as a module. If so, the module will be called i2c-nforce2. +config I2C_OCORES + tristate "OpenCores I2C Controller" + depends on I2C && EXPERIMENTAL + help + If you say yes to this option, support will be included for the + OpenCores I2C controller. For details see + http://www.opencores.org/projects.cgi/web/i2c/overview + + This driver can also be built as a module. If so, the module + will be called i2c-ocores. + config I2C_PARPORT tristate "Parallel port adapter" depends on I2C && PARPORT diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index b44831dff683..ac56df53155b 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o obj-$(CONFIG_I2C_MPC) += i2c-mpc.o obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o +obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c new file mode 100644 index 000000000000..d5c0610bfe6d --- /dev/null +++ b/drivers/i2c/busses/i2c-ocores.c @@ -0,0 +1,343 @@ +/* + * i2c-ocores.c: I2C bus driver for OpenCores I2C controller + * (http://www.opencores.org/projects.cgi/web/i2c/overview). + * + * Peter Korsgaard + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct ocores_i2c { + void __iomem *base; + int regstep; + wait_queue_head_t wait; + struct i2c_adapter adap; + struct i2c_msg *msg; + int pos; + int nmsgs; + int state; /* see STATE_ */ +}; + +/* registers */ +#define OCI2C_PRELOW 0 +#define OCI2C_PREHIGH 1 +#define OCI2C_CONTROL 2 +#define OCI2C_DATA 3 +#define OCI2C_CMD 4 +#define OCI2C_STATUS 4 + +#define OCI2C_CTRL_IEN 0x40 +#define OCI2C_CTRL_EN 0x80 + +#define OCI2C_CMD_START 0x91 +#define OCI2C_CMD_STOP 0x41 +#define OCI2C_CMD_READ 0x21 +#define OCI2C_CMD_WRITE 0x11 +#define OCI2C_CMD_READ_ACK 0x21 +#define OCI2C_CMD_READ_NACK 0x29 +#define OCI2C_CMD_IACK 0x01 + +#define OCI2C_STAT_IF 0x01 +#define OCI2C_STAT_TIP 0x02 +#define OCI2C_STAT_ARBLOST 0x20 +#define OCI2C_STAT_BUSY 0x40 +#define OCI2C_STAT_NACK 0x80 + +#define STATE_DONE 0 +#define STATE_START 1 +#define STATE_WRITE 2 +#define STATE_READ 3 +#define STATE_ERROR 4 + +static inline void oc_setreg(struct ocores_i2c *i2c, int reg, u8 value) +{ + iowrite8(value, i2c->base + reg * i2c->regstep); +} + +static inline u8 oc_getreg(struct ocores_i2c *i2c, int reg) +{ + return ioread8(i2c->base + reg * i2c->regstep); +} + +static void ocores_process(struct ocores_i2c *i2c) +{ + struct i2c_msg *msg = i2c->msg; + u8 stat = oc_getreg(i2c, OCI2C_STATUS); + + if ((i2c->state == STATE_DONE) || (i2c->state == STATE_ERROR)) { + /* stop has been sent */ + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK); + wake_up(&i2c->wait); + return; + } + + /* error? */ + if (stat & OCI2C_STAT_ARBLOST) { + i2c->state = STATE_ERROR; + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); + return; + } + + if ((i2c->state == STATE_START) || (i2c->state == STATE_WRITE)) { + i2c->state = + (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE; + + if (stat & OCI2C_STAT_NACK) { + i2c->state = STATE_ERROR; + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); + return; + } + } else + msg->buf[i2c->pos++] = oc_getreg(i2c, OCI2C_DATA); + + /* end of msg? */ + if (i2c->pos == msg->len) { + i2c->nmsgs--; + i2c->msg++; + i2c->pos = 0; + msg = i2c->msg; + + if (i2c->nmsgs) { /* end? */ + /* send start? */ + if (!(msg->flags & I2C_M_NOSTART)) { + u8 addr = (msg->addr << 1); + + if (msg->flags & I2C_M_RD) + addr |= 1; + + i2c->state = STATE_START; + + oc_setreg(i2c, OCI2C_DATA, addr); + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START); + return; + } else + i2c->state = (msg->flags & I2C_M_RD) + ? STATE_READ : STATE_WRITE; + } else { + i2c->state = STATE_DONE; + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); + return; + } + } + + if (i2c->state == STATE_READ) { + oc_setreg(i2c, OCI2C_CMD, i2c->pos == (msg->len-1) ? + OCI2C_CMD_READ_NACK : OCI2C_CMD_READ_ACK); + } else { + oc_setreg(i2c, OCI2C_DATA, msg->buf[i2c->pos++]); + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_WRITE); + } +} + +static irqreturn_t ocores_isr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct ocores_i2c *i2c = dev_id; + + ocores_process(i2c); + + return IRQ_HANDLED; +} + +static int ocores_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +{ + struct ocores_i2c *i2c = i2c_get_adapdata(adap); + + i2c->msg = msgs; + i2c->pos = 0; + i2c->nmsgs = num; + i2c->state = STATE_START; + + oc_setreg(i2c, OCI2C_DATA, + (i2c->msg->addr << 1) | + ((i2c->msg->flags & I2C_M_RD) ? 1:0)); + + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START); + + if (wait_event_timeout(i2c->wait, (i2c->state == STATE_ERROR) || + (i2c->state == STATE_DONE), HZ)) + return (i2c->state == STATE_DONE) ? num : -EIO; + else + return -ETIMEDOUT; +} + +static void ocores_init(struct ocores_i2c *i2c, + struct ocores_i2c_platform_data *pdata) +{ + int prescale; + u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL); + + /* make sure the device is disabled */ + oc_setreg(i2c, OCI2C_CONTROL, ctrl & ~(OCI2C_CTRL_EN|OCI2C_CTRL_IEN)); + + prescale = (pdata->clock_khz / (5*100)) - 1; + oc_setreg(i2c, OCI2C_PRELOW, prescale & 0xff); + oc_setreg(i2c, OCI2C_PREHIGH, prescale >> 8); + + /* Init the device */ + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK); + oc_setreg(i2c, OCI2C_CONTROL, ctrl | OCI2C_CTRL_IEN | OCI2C_CTRL_EN); +} + + +static u32 ocores_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static struct i2c_algorithm ocores_algorithm = { + .master_xfer = ocores_xfer, + .functionality = ocores_func, +}; + +static struct i2c_adapter ocores_adapter = { + .owner = THIS_MODULE, + .name = "i2c-ocores", + .class = I2C_CLASS_HWMON, + .algo = &ocores_algorithm, + .timeout = 2, + .retries = 1, +}; + + +static int __devinit ocores_i2c_probe(struct platform_device *pdev) +{ + struct ocores_i2c *i2c; + struct ocores_i2c_platform_data *pdata; + struct resource *res, *res2; + int ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res2) + return -ENODEV; + + pdata = (struct ocores_i2c_platform_data*) pdev->dev.platform_data; + if (!pdata) + return -ENODEV; + + i2c = kzalloc(sizeof(*i2c), GFP_KERNEL); + if (!i2c) + return -ENOMEM; + + if (!request_mem_region(res->start, res->end - res->start + 1, + pdev->name)) { + dev_err(&pdev->dev, "Memory region busy\n"); + ret = -EBUSY; + goto request_mem_failed; + } + + i2c->base = ioremap(res->start, res->end - res->start + 1); + if (!i2c->base) { + dev_err(&pdev->dev, "Unable to map registers\n"); + ret = -EIO; + goto map_failed; + } + + i2c->regstep = pdata->regstep; + ocores_init(i2c, pdata); + + init_waitqueue_head(&i2c->wait); + ret = request_irq(res2->start, ocores_isr, 0, pdev->name, i2c); + if (ret) { + dev_err(&pdev->dev, "Cannot claim IRQ\n"); + goto request_irq_failed; + } + + /* hook up driver to tree */ + platform_set_drvdata(pdev, i2c); + i2c->adap = ocores_adapter; + i2c_set_adapdata(&i2c->adap, i2c); + i2c->adap.dev.parent = &pdev->dev; + + /* add i2c adapter to i2c tree */ + ret = i2c_add_adapter(&i2c->adap); + if (ret) { + dev_err(&pdev->dev, "Failed to add adapter\n"); + goto add_adapter_failed; + } + + return 0; + +add_adapter_failed: + free_irq(res2->start, i2c); +request_irq_failed: + iounmap(i2c->base); +map_failed: + release_mem_region(res->start, res->end - res->start + 1); +request_mem_failed: + kfree(i2c); + + return ret; +} + +static int __devexit ocores_i2c_remove(struct platform_device* pdev) +{ + struct ocores_i2c *i2c = platform_get_drvdata(pdev); + struct resource *res; + + /* disable i2c logic */ + oc_setreg(i2c, OCI2C_CONTROL, oc_getreg(i2c, OCI2C_CONTROL) + & ~(OCI2C_CTRL_EN|OCI2C_CTRL_IEN)); + + /* remove adapter & data */ + i2c_del_adapter(&i2c->adap); + platform_set_drvdata(pdev, NULL); + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (res) + free_irq(res->start, i2c); + + iounmap(i2c->base); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res) + release_mem_region(res->start, res->end - res->start + 1); + + kfree(i2c); + + return 0; +} + +static struct platform_driver ocores_i2c_driver = { + .probe = ocores_i2c_probe, + .remove = __devexit_p(ocores_i2c_remove), + .driver = { + .owner = THIS_MODULE, + .name = "ocores-i2c", + }, +}; + +static int __init ocores_i2c_init(void) +{ + return platform_driver_register(&ocores_i2c_driver); +} + +static void __exit ocores_i2c_exit(void) +{ + platform_driver_unregister(&ocores_i2c_driver); +} + +module_init(ocores_i2c_init); +module_exit(ocores_i2c_exit); + +MODULE_AUTHOR("Peter Korsgaard "); +MODULE_DESCRIPTION("OpenCores I2C bus driver"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/i2c-ocores.h b/include/linux/i2c-ocores.h new file mode 100644 index 000000000000..8ed591b0887e --- /dev/null +++ b/include/linux/i2c-ocores.h @@ -0,0 +1,19 @@ +/* + * i2c-ocores.h - definitions for the i2c-ocores interface + * + * Peter Korsgaard + * + * 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 _LINUX_I2C_OCORES_H +#define _LINUX_I2C_OCORES_H + +struct ocores_i2c_platform_data { + u32 regstep; /* distance between registers */ + u32 clock_khz; /* input clock in kHz */ +}; + +#endif /* _LINUX_I2C_OCORES_H */ -- cgit v1.2.3 From 46f5ed753fac512f73069bd07455555b41a8a06e Mon Sep 17 00:00:00 2001 From: Krzysztof Halasa Date: Mon, 12 Jun 2006 21:42:20 +0200 Subject: [PATCH] i2c: Mark block write buffers as const The attached patch marks i2c_smbus_write_block_data() and i2c_smbus_write_i2c_block_data() buffers as const. Signed-off-by: Krzysztof Halasa Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/i2c-core.c | 4 ++-- include/linux/i2c.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 45e2cdf54736..a45155f799d4 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -916,7 +916,7 @@ s32 i2c_smbus_write_word_data(struct i2c_client *client, u8 command, u16 value) } s32 i2c_smbus_write_block_data(struct i2c_client *client, u8 command, - u8 length, u8 *values) + u8 length, const u8 *values) { union i2c_smbus_data data; @@ -944,7 +944,7 @@ s32 i2c_smbus_read_i2c_block_data(struct i2c_client *client, u8 command, u8 *val } s32 i2c_smbus_write_i2c_block_data(struct i2c_client *client, u8 command, - u8 length, u8 *values) + u8 length, const u8 *values) { union i2c_smbus_data data; diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 0510430e00db..526ddc8eecfb 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -97,13 +97,13 @@ extern s32 i2c_smbus_write_word_data(struct i2c_client * client, u8 command, u16 value); extern s32 i2c_smbus_write_block_data(struct i2c_client * client, u8 command, u8 length, - u8 *values); + const u8 *values); /* Returns the number of read bytes */ extern s32 i2c_smbus_read_i2c_block_data(struct i2c_client * client, u8 command, u8 *values); extern s32 i2c_smbus_write_i2c_block_data(struct i2c_client * client, u8 command, u8 length, - u8 *values); + const u8 *values); /* * A driver is capable of handling one or more physical devices present on -- cgit v1.2.3 From b6043fcab4b2b06b9fcde4c783ab253cdc2c1129 Mon Sep 17 00:00:00 2001 From: Evgeniy Polyakov Date: Thu, 23 Mar 2006 19:11:58 +0300 Subject: [PATCH] w1: Move w1-connector definitions into linux/include/connector.h Signed-off-by: Evgeniy Polyakov Signed-off-by: Greg Kroah-Hartman --- drivers/w1/w1_netlink.h | 3 --- include/linux/connector.h | 5 ++++- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/w1/w1_netlink.h b/drivers/w1/w1_netlink.h index 5644221f9a44..56122b9e9294 100644 --- a/drivers/w1/w1_netlink.h +++ b/drivers/w1/w1_netlink.h @@ -27,9 +27,6 @@ #include "w1.h" -#define CN_W1_IDX 3 -#define CN_W1_VAL 1 - enum w1_netlink_message_types { W1_SLAVE_ADD = 0, W1_SLAVE_REMOVE, diff --git a/include/linux/connector.h b/include/linux/connector.h index ad1a22c1c42e..4c02119c6ab9 100644 --- a/include/linux/connector.h +++ b/include/linux/connector.h @@ -34,8 +34,11 @@ #define CN_VAL_PROC 0x1 #define CN_IDX_CIFS 0x2 #define CN_VAL_CIFS 0x1 +#define CN_W1_IDX 0x3 /* w1 communication */ +#define CN_W1_VAL 0x1 -#define CN_NETLINK_USERS 1 + +#define CN_NETLINK_USERS 4 /* * Maximum connector's message size. -- cgit v1.2.3 From bb5427b5466782ba0bbf56a4ed752e08b65a5d08 Mon Sep 17 00:00:00 2001 From: Evgeniy Polyakov Date: Thu, 23 Mar 2006 19:11:58 +0300 Subject: [PATCH] w1: netlink: Mark netlink group 1 as unused. netlink_w1 was moved to connector. Signed-off-by: Evgeniy Polyakov Signed-off-by: Greg Kroah-Hartman --- include/linux/netlink.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/netlink.h b/include/linux/netlink.h index 87b8a5703ebc..855b44668caa 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -5,7 +5,7 @@ #include #define NETLINK_ROUTE 0 /* Routing/device hook */ -#define NETLINK_W1 1 /* 1-wire subsystem */ +#define NETLINK_UNUSED 1 /* Unused number */ #define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols */ #define NETLINK_FIREWALL 3 /* Firewalling hook */ #define NETLINK_INET_DIAG 4 /* INET socket monitoring */ -- cgit v1.2.3 From 21fdddea8e4cc54341d389916d0c17db8c1ca452 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Sun, 9 Apr 2006 17:36:39 +0100 Subject: [ALSA] emu10k1: Add support for Audigy4 (not Pro) Signed-off-by: James Courtier-Dutton --- include/sound/emu10k1.h | 2 ++ sound/pci/ac97/ac97_codec.c | 4 +-- sound/pci/ac97/ac97_patch.c | 4 +-- sound/pci/emu10k1/emu10k1_main.c | 56 +++++++++++++++++++++++++++++++++------- sound/pci/emu10k1/emumixer.c | 54 ++++++++++++++++++++++++++++++++++++-- sound/pci/emu10k1/tina2.h | 8 ++---- 6 files changed, 107 insertions(+), 21 deletions(-) (limited to 'include') diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 186e00ad9e79..884bbf54cd36 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -245,6 +245,7 @@ #define A_IOCFG_GPOUT0 0x0044 /* analog/digital */ #define A_IOCFG_DISABLE_ANALOG 0x0040 /* = 'enable' for Audigy2 (chiprev=4) */ #define A_IOCFG_ENABLE_DIGITAL 0x0004 +#define A_IOCFG_ENABLE_DIGITAL_AUDIGY4 0x0080 #define A_IOCFG_UNKNOWN_20 0x0020 #define A_IOCFG_DISABLE_AC97_FRONT 0x0080 /* turn off ac97 front -> front (10k2.1) */ #define A_IOCFG_GPOUT1 0x0002 /* IR? drive's internal bypass (?) */ @@ -1065,6 +1066,7 @@ struct snd_emu_chip_details { unsigned char emu1212m; /* EMU 1212m card */ unsigned char spi_dac; /* SPI interface for DAC */ unsigned char i2c_adc; /* I2C interface for ADC */ + unsigned char adc_1361t; /* Use Philips 1361T ADC */ const char *driver; const char *name; const char *id; /* for backward compatibility - can be NULL if not needed */ diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index d05200741ac3..4544f6aa089d 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -563,7 +563,7 @@ AC97_SINGLE("PC Speaker Playback Volume", AC97_PC_BEEP, 1, 15, 1) }; static const struct snd_kcontrol_new snd_ac97_controls_mic_boost = - AC97_SINGLE("Mic Boost (+20dB)", AC97_MIC, 6, 1, 0); + AC97_SINGLE("Mic Boost (+20dB) Capture Switch", AC97_MIC, 6, 1, 0); static const char* std_rec_sel[] = {"Mic", "CD", "Video", "Aux", "Line", "Mix", "Mix Mono", "Phone"}; @@ -605,7 +605,7 @@ AC97_SINGLE("Simulated Stereo Enhancement", AC97_GENERAL_PURPOSE, 14, 1, 0), AC97_SINGLE("3D Control - Switch", AC97_GENERAL_PURPOSE, 13, 1, 0), AC97_SINGLE("Loudness (bass boost)", AC97_GENERAL_PURPOSE, 12, 1, 0), AC97_ENUM("Mono Output Select", std_enum[2]), -AC97_ENUM("Mic Select", std_enum[3]), +AC97_ENUM("Mic Select Capture Switch", std_enum[3]), AC97_SINGLE("ADC/DAC Loopback", AC97_GENERAL_PURPOSE, 7, 1, 0) }; diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 4d9cf37300f7..7ae7bc6524e6 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -563,7 +563,7 @@ AC97_SINGLE("Mic 1 to Phone Switch", AC97_MIC, 14, 1, 1), AC97_SINGLE("Mic 2 to Phone Switch", AC97_MIC, 13, 1, 1), AC97_ENUM("Mic Select Source", wm9711_enum[7]), AC97_SINGLE("Mic 1 Volume", AC97_MIC, 8, 32, 1), -AC97_SINGLE("Mic 20dB Boost Switch", AC97_MIC, 7, 1, 0), +AC97_SINGLE("Mic 20dB Boost Capture Switch", AC97_MIC, 7, 1, 0), AC97_SINGLE("Master ZC Switch", AC97_MASTER, 7, 1, 0), AC97_SINGLE("Headphone ZC Switch", AC97_HEADPHONE, 7, 1, 0), @@ -653,7 +653,7 @@ AC97_SINGLE("Mic 1 Volume", AC97_MIC, 8, 31, 1), AC97_SINGLE("Mic 2 Volume", AC97_MIC, 0, 31, 1), AC97_SINGLE("Mic 1 to Mono Switch", AC97_LINE, 7, 1, 1), AC97_SINGLE("Mic 2 to Mono Switch", AC97_LINE, 6, 1, 1), -AC97_SINGLE("Mic Boost (+20dB) Switch", AC97_LINE, 5, 1, 0), +AC97_SINGLE("Mic Boost (+20dB) Capture Switch", AC97_LINE, 5, 1, 0), AC97_ENUM("Mic to Headphone Mux", wm9713_enum[0]), AC97_SINGLE("Mic Headphone Mixer Volume", AC97_LINE, 0, 7, 1), diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 6bfa08436efa..e71485c23cc7 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -777,14 +777,6 @@ static int snd_emu10k1_dev_free(struct snd_device *device) static struct snd_emu_chip_details emu_chip_details[] = { /* Audigy 2 Value AC3 out does not work yet. Need to find out how to turn off interpolators.*/ - /* Audigy4 SB0400 */ - {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x10211102, - .driver = "Audigy2", .name = "Audigy 4 [SB0400]", - .id = "Audigy2", - .emu10k2_chip = 1, - .ca0108_chip = 1, - .spk71 = 1, - .ac97_chip = 1} , /* Tested by James@superbug.co.uk 3rd July 2005 */ /* DSP: CA0108-IAT * DAC: CS4382-KQ @@ -799,13 +791,59 @@ static struct snd_emu_chip_details emu_chip_details[] = { .ca0108_chip = 1, .spk71 = 1, .ac97_chip = 1} , + /* Audigy4 (Not PRO) SB0610 */ + /* Tested by James@superbug.co.uk 4th April 2006 */ + /* A_IOCFG bits + * Output + * 0: ? + * 1: ? + * 2: ? + * 3: 0 - Digital Out, 1 - Line in + * 4: ? + * 5: ? + * 6: ? + * 7: ? + * Input + * 8: ? + * 9: ? + * A: Green jack sense (Front) + * B: ? + * C: Black jack sense (Rear/Side Right) + * D: Yellow jack sense (Center/LFE/Side Left) + * E: ? + * F: ? + * + * Digital Out/Line in switch using A_IOCFG bit 3 (0x08) + * 0 - Digital Out + * 1 - Line in + */ + /* Mic input not tested. + * Analog CD input not tested + * Digital Out not tested. + * Line in working. + * Audio output 5.1 working. Side outputs not working. + */ + /* DSP: CA10300-IAT LF + * DAC: Cirrus Logic CS4382-KQZ + * ADC: Philips 1361T + * AC97: Sigmatel STAC9750 + * CA0151: None + */ + {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x10211102, + .driver = "Audigy2", .name = "Audigy 4 [SB0610]", + .id = "Audigy2", + .emu10k2_chip = 1, + .ca0108_chip = 1, + .spk71 = 1, + .adc_1361t = 1, /* 24 bit capture instead of 16bit */ + .ac97_chip = 1} , /* Audigy 2 ZS Notebook Cardbus card.*/ /* Tested by James@superbug.co.uk 22th December 2005 */ /* Audio output 7.1/Headphones working. * Digital output working. (AC3 not checked, only PCM) * Audio inputs not tested. */ - /* DSP: Tiny2 + /* DSP: Tina2 * DAC: Wolfson WM8768/WM8568 * ADC: Wolfson WM8775 * AC97: None diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index 2a9d12d10680..c31f3d0877fa 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -777,6 +777,8 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, }; static char *audigy_remove_ctls[] = { /* Master/PCM controls on ac97 of Audigy has no effect */ + /* On the Audigy2 the AC97 playback is piped into + * the Philips ADC for 24bit capture */ "PCM Playback Switch", "PCM Playback Volume", "Master Mono Playback Switch", @@ -804,6 +806,47 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, "AMic Playback Volume", "Mic Playback Volume", NULL }; + static char *audigy_remove_ctls_1361t_adc[] = { + /* On the Audigy2 the AC97 playback is piped into + * the Philips ADC for 24bit capture */ + "PCM Playback Switch", + "PCM Playback Volume", + "Master Mono Playback Switch", + "Master Mono Playback Volume", + "Capture Source", + "Capture Switch", + "Capture Volume", + "Mic Capture Volume", + "Headphone Playback Switch", + "Headphone Playback Volume", + "3D Control - Center", + "3D Control - Depth", + "3D Control - Switch", + "Line2 Playback Volume", + "Line2 Capture Volume", + NULL + }; + static char *audigy_rename_ctls_1361t_adc[] = { + "Master Playback Switch", "Master Capture Switch", + "Master Playback Volume", "Master Capture Volume", + "Wave Master Playback Volume", "Master Playback Volume", + "PC Speaker Playback Switch", "PC Speaker Capture Switch", + "PC Speaker Playback Volume", "PC Speaker Capture Volume", + "Phone Playback Switch", "Phone Capture Switch", + "Phone Playback Volume", "Phone Capture Volume", + "Mic Playback Switch", "Mic Capture Switch", + "Mic Playback Volume", "Mic Capture Volume", + "Line Playback Switch", "Line Capture Switch", + "Line Playback Volume", "Line Capture Volume", + "CD Playback Switch", "CD Capture Switch", + "CD Playback Volume", "CD Capture Volume", + "Aux Playback Switch", "Aux Capture Switch", + "Aux Playback Volume", "Aux Capture Volume", + "Video Playback Switch", "Video Capture Switch", + "Video Playback Volume", "Video Capture Volume", + + NULL + }; if (emu->card_capabilities->ac97_chip) { struct snd_ac97_bus *pbus; @@ -834,7 +877,10 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, snd_ac97_write_cache(emu->ac97, AC97_MASTER, 0x0000); /* set capture source to mic */ snd_ac97_write_cache(emu->ac97, AC97_REC_SEL, 0x0000); - c = audigy_remove_ctls; + if (emu->card_capabilities->adc_1361t) + c = audigy_remove_ctls_1361t_adc; + else + c = audigy_remove_ctls; } else { /* * Credits for cards based on STAC9758: @@ -863,11 +909,15 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, } if (emu->audigy) - c = audigy_rename_ctls; + if (emu->card_capabilities->adc_1361t) + c = audigy_rename_ctls_1361t_adc; + else + c = audigy_rename_ctls; else c = emu10k1_rename_ctls; for (; *c; c += 2) rename_ctl(card, c[0], c[1]); + if (emu->card_capabilities->subsystem == 0x20071102) { /* Audigy 4 Pro */ rename_ctl(card, "Line2 Capture Volume", "Line1/Mic Capture Volume"); rename_ctl(card, "Analog Mix Capture Volume", "Line2 Capture Volume"); diff --git a/sound/pci/emu10k1/tina2.h b/sound/pci/emu10k1/tina2.h index 5c43abf03e89..f2d8eb6c89e1 100644 --- a/sound/pci/emu10k1/tina2.h +++ b/sound/pci/emu10k1/tina2.h @@ -1,11 +1,7 @@ /* * Copyright (c) by James Courtier-Dutton - * Driver p16v chips - * Version: 0.21 - * - * - * This code was initally based on code from ALSA's emu10k1x.c which is: - * Copyright (c) by Francisco Moraes + * Driver tina2 chips + * Version: 0.1 * * 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 -- cgit v1.2.3 From 9bb22e215c28204faee73dd7ac0ad98c075d6f7b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 28 Apr 2006 15:13:39 +0200 Subject: [ALSA] Clean up ugly hacks in pcm_params.h Clean up ugly hacks for sync with alsa-lib in pcm_params.h. Signed-off-by: Takashi Iwai --- include/sound/pcm_params.h | 105 ++++++++++++++++++--------------------------- 1 file changed, 42 insertions(+), 63 deletions(-) (limited to 'include') diff --git a/include/sound/pcm_params.h b/include/sound/pcm_params.h index fb18aef77341..e3bebd98e1ce 100644 --- a/include/sound/pcm_params.h +++ b/include/sound/pcm_params.h @@ -35,16 +35,12 @@ extern int _snd_pcm_hw_param_setinteger(struct snd_pcm_hw_params *params, extern int _snd_pcm_hw_param_set(struct snd_pcm_hw_params *params, snd_pcm_hw_param_t var, unsigned int val, int dir); -/* To share the same code we have alsa-lib */ -#define INLINE static inline -#define assert(a) (void)(a) - #define SNDRV_MASK_BITS 64 /* we use so far 64bits only */ #define SNDRV_MASK_SIZE (SNDRV_MASK_BITS / 32) #define MASK_OFS(i) ((i) >> 5) #define MASK_BIT(i) (1U << ((i) & 31)) -INLINE unsigned int ld2(u_int32_t v) +static inline unsigned int ld2(u_int32_t v) { unsigned r = 0; @@ -69,22 +65,22 @@ INLINE unsigned int ld2(u_int32_t v) return r; } -INLINE size_t snd_mask_sizeof(void) +static inline size_t snd_mask_sizeof(void) { return sizeof(struct snd_mask); } -INLINE void snd_mask_none(struct snd_mask *mask) +static inline void snd_mask_none(struct snd_mask *mask) { memset(mask, 0, sizeof(*mask)); } -INLINE void snd_mask_any(struct snd_mask *mask) +static inline void snd_mask_any(struct snd_mask *mask) { memset(mask, 0xff, SNDRV_MASK_SIZE * sizeof(u_int32_t)); } -INLINE int snd_mask_empty(const struct snd_mask *mask) +static inline int snd_mask_empty(const struct snd_mask *mask) { int i; for (i = 0; i < SNDRV_MASK_SIZE; i++) @@ -93,10 +89,9 @@ INLINE int snd_mask_empty(const struct snd_mask *mask) return 1; } -INLINE unsigned int snd_mask_min(const struct snd_mask *mask) +static inline unsigned int snd_mask_min(const struct snd_mask *mask) { int i; - assert(!snd_mask_empty(mask)); for (i = 0; i < SNDRV_MASK_SIZE; i++) { if (mask->bits[i]) return ffs(mask->bits[i]) - 1 + (i << 5); @@ -104,10 +99,9 @@ INLINE unsigned int snd_mask_min(const struct snd_mask *mask) return 0; } -INLINE unsigned int snd_mask_max(const struct snd_mask *mask) +static inline unsigned int snd_mask_max(const struct snd_mask *mask) { int i; - assert(!snd_mask_empty(mask)); for (i = SNDRV_MASK_SIZE - 1; i >= 0; i--) { if (mask->bits[i]) return ld2(mask->bits[i]) + (i << 5); @@ -115,70 +109,68 @@ INLINE unsigned int snd_mask_max(const struct snd_mask *mask) return 0; } -INLINE void snd_mask_set(struct snd_mask *mask, unsigned int val) +static inline void snd_mask_set(struct snd_mask *mask, unsigned int val) { - assert(val <= SNDRV_MASK_BITS); mask->bits[MASK_OFS(val)] |= MASK_BIT(val); } -INLINE void snd_mask_reset(struct snd_mask *mask, unsigned int val) +static inline void snd_mask_reset(struct snd_mask *mask, unsigned int val) { - assert(val <= SNDRV_MASK_BITS); mask->bits[MASK_OFS(val)] &= ~MASK_BIT(val); } -INLINE void snd_mask_set_range(struct snd_mask *mask, unsigned int from, unsigned int to) +static inline void snd_mask_set_range(struct snd_mask *mask, + unsigned int from, unsigned int to) { unsigned int i; - assert(to <= SNDRV_MASK_BITS && from <= to); for (i = from; i <= to; i++) mask->bits[MASK_OFS(i)] |= MASK_BIT(i); } -INLINE void snd_mask_reset_range(struct snd_mask *mask, unsigned int from, unsigned int to) +static inline void snd_mask_reset_range(struct snd_mask *mask, + unsigned int from, unsigned int to) { unsigned int i; - assert(to <= SNDRV_MASK_BITS && from <= to); for (i = from; i <= to; i++) mask->bits[MASK_OFS(i)] &= ~MASK_BIT(i); } -INLINE void snd_mask_leave(struct snd_mask *mask, unsigned int val) +static inline void snd_mask_leave(struct snd_mask *mask, unsigned int val) { unsigned int v; - assert(val <= SNDRV_MASK_BITS); v = mask->bits[MASK_OFS(val)] & MASK_BIT(val); snd_mask_none(mask); mask->bits[MASK_OFS(val)] = v; } -INLINE void snd_mask_intersect(struct snd_mask *mask, const struct snd_mask *v) +static inline void snd_mask_intersect(struct snd_mask *mask, + const struct snd_mask *v) { int i; for (i = 0; i < SNDRV_MASK_SIZE; i++) mask->bits[i] &= v->bits[i]; } -INLINE int snd_mask_eq(const struct snd_mask *mask, const struct snd_mask *v) +static inline int snd_mask_eq(const struct snd_mask *mask, + const struct snd_mask *v) { return ! memcmp(mask, v, SNDRV_MASK_SIZE * sizeof(u_int32_t)); } -INLINE void snd_mask_copy(struct snd_mask *mask, const struct snd_mask *v) +static inline void snd_mask_copy(struct snd_mask *mask, + const struct snd_mask *v) { *mask = *v; } -INLINE int snd_mask_test(const struct snd_mask *mask, unsigned int val) +static inline int snd_mask_test(const struct snd_mask *mask, unsigned int val) { - assert(val <= SNDRV_MASK_BITS); return mask->bits[MASK_OFS(val)] & MASK_BIT(val); } -INLINE int snd_mask_single(const struct snd_mask *mask) +static inline int snd_mask_single(const struct snd_mask *mask) { int i, c = 0; - assert(!snd_mask_empty(mask)); for (i = 0; i < SNDRV_MASK_SIZE; i++) { if (! mask->bits[i]) continue; @@ -191,10 +183,10 @@ INLINE int snd_mask_single(const struct snd_mask *mask) return 1; } -INLINE int snd_mask_refine(struct snd_mask *mask, const struct snd_mask *v) +static inline int snd_mask_refine(struct snd_mask *mask, + const struct snd_mask *v) { struct snd_mask old; - assert(!snd_mask_empty(mask)); snd_mask_copy(&old, mask); snd_mask_intersect(mask, v); if (snd_mask_empty(mask)) @@ -202,27 +194,24 @@ INLINE int snd_mask_refine(struct snd_mask *mask, const struct snd_mask *v) return !snd_mask_eq(mask, &old); } -INLINE int snd_mask_refine_first(struct snd_mask *mask) +static inline int snd_mask_refine_first(struct snd_mask *mask) { - assert(!snd_mask_empty(mask)); if (snd_mask_single(mask)) return 0; snd_mask_leave(mask, snd_mask_min(mask)); return 1; } -INLINE int snd_mask_refine_last(struct snd_mask *mask) +static inline int snd_mask_refine_last(struct snd_mask *mask) { - assert(!snd_mask_empty(mask)); if (snd_mask_single(mask)) return 0; snd_mask_leave(mask, snd_mask_max(mask)); return 1; } -INLINE int snd_mask_refine_min(struct snd_mask *mask, unsigned int val) +static inline int snd_mask_refine_min(struct snd_mask *mask, unsigned int val) { - assert(!snd_mask_empty(mask)); if (snd_mask_min(mask) >= val) return 0; snd_mask_reset_range(mask, 0, val - 1); @@ -231,9 +220,8 @@ INLINE int snd_mask_refine_min(struct snd_mask *mask, unsigned int val) return 1; } -INLINE int snd_mask_refine_max(struct snd_mask *mask, unsigned int val) +static inline int snd_mask_refine_max(struct snd_mask *mask, unsigned int val) { - assert(!snd_mask_empty(mask)); if (snd_mask_max(mask) <= val) return 0; snd_mask_reset_range(mask, val + 1, SNDRV_MASK_BITS); @@ -242,10 +230,9 @@ INLINE int snd_mask_refine_max(struct snd_mask *mask, unsigned int val) return 1; } -INLINE int snd_mask_refine_set(struct snd_mask *mask, unsigned int val) +static inline int snd_mask_refine_set(struct snd_mask *mask, unsigned int val) { int changed; - assert(!snd_mask_empty(mask)); changed = !snd_mask_single(mask); snd_mask_leave(mask, val); if (snd_mask_empty(mask)) @@ -253,13 +240,12 @@ INLINE int snd_mask_refine_set(struct snd_mask *mask, unsigned int val) return changed; } -INLINE int snd_mask_value(const struct snd_mask *mask) +static inline int snd_mask_value(const struct snd_mask *mask) { - assert(!snd_mask_empty(mask)); return snd_mask_min(mask); } -INLINE void snd_interval_any(struct snd_interval *i) +static inline void snd_interval_any(struct snd_interval *i) { i->min = 0; i->openmin = 0; @@ -269,63 +255,59 @@ INLINE void snd_interval_any(struct snd_interval *i) i->empty = 0; } -INLINE void snd_interval_none(struct snd_interval *i) +static inline void snd_interval_none(struct snd_interval *i) { i->empty = 1; } -INLINE int snd_interval_checkempty(const struct snd_interval *i) +static inline int snd_interval_checkempty(const struct snd_interval *i) { return (i->min > i->max || (i->min == i->max && (i->openmin || i->openmax))); } -INLINE int snd_interval_empty(const struct snd_interval *i) +static inline int snd_interval_empty(const struct snd_interval *i) { return i->empty; } -INLINE int snd_interval_single(const struct snd_interval *i) +static inline int snd_interval_single(const struct snd_interval *i) { - assert(!snd_interval_empty(i)); return (i->min == i->max || (i->min + 1 == i->max && i->openmax)); } -INLINE int snd_interval_value(const struct snd_interval *i) +static inline int snd_interval_value(const struct snd_interval *i) { - assert(snd_interval_single(i)); return i->min; } -INLINE int snd_interval_min(const struct snd_interval *i) +static inline int snd_interval_min(const struct snd_interval *i) { - assert(!snd_interval_empty(i)); return i->min; } -INLINE int snd_interval_max(const struct snd_interval *i) +static inline int snd_interval_max(const struct snd_interval *i) { unsigned int v; - assert(!snd_interval_empty(i)); v = i->max; if (i->openmax) v--; return v; } -INLINE int snd_interval_test(const struct snd_interval *i, unsigned int val) +static inline int snd_interval_test(const struct snd_interval *i, unsigned int val) { return !((i->min > val || (i->min == val && i->openmin) || i->max < val || (i->max == val && i->openmax))); } -INLINE void snd_interval_copy(struct snd_interval *d, const struct snd_interval *s) +static inline void snd_interval_copy(struct snd_interval *d, const struct snd_interval *s) { *d = *s; } -INLINE int snd_interval_setinteger(struct snd_interval *i) +static inline int snd_interval_setinteger(struct snd_interval *i) { if (i->integer) return 0; @@ -335,7 +317,7 @@ INLINE int snd_interval_setinteger(struct snd_interval *i) return 1; } -INLINE int snd_interval_eq(const struct snd_interval *i1, const struct snd_interval *i2) +static inline int snd_interval_eq(const struct snd_interval *i1, const struct snd_interval *i2) { if (i1->empty) return i2->empty; @@ -359,8 +341,5 @@ static inline unsigned int sub(unsigned int a, unsigned int b) return 0; } -#undef INLINE -#undef assert - #endif /* __SOUND_PCM_PARAMS_H */ -- cgit v1.2.3 From e88e8ae639a4908b903d9406c54e99a729b01a28 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 28 Apr 2006 15:13:40 +0200 Subject: [ALSA] Move OSS-specific hw_params helper to snd-pcm-oss module Move EXPORT_SYMBOL()s to places adjacent to functions/variables. Also move OSS-specific hw_params helper functions to pcm_oss.c. Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 8 - include/sound/pcm_params.h | 20 +- sound/core/oss/pcm_oss.c | 481 +++++++++++++++++++++++++++++++++ sound/core/pcm.c | 36 +-- sound/core/pcm_lib.c | 649 ++++----------------------------------------- sound/core/pcm_memory.c | 12 + sound/core/pcm_misc.c | 24 ++ sound/core/pcm_native.c | 21 +- 8 files changed, 605 insertions(+), 646 deletions(-) (limited to 'include') diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 373425895faa..998bacefc8f8 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -825,14 +825,6 @@ int snd_interval_ratnum(struct snd_interval *i, void _snd_pcm_hw_params_any(struct snd_pcm_hw_params *params); void _snd_pcm_hw_param_setempty(struct snd_pcm_hw_params *params, snd_pcm_hw_param_t var); -int snd_pcm_hw_param_near(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - snd_pcm_hw_param_t var, - unsigned int val, int *dir); -int snd_pcm_hw_param_set(struct snd_pcm_substream *pcm, - struct snd_pcm_hw_params *params, - snd_pcm_hw_param_t var, - unsigned int val, int dir); int snd_pcm_hw_params_choose(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params); int snd_pcm_hw_refine(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params); diff --git a/include/sound/pcm_params.h b/include/sound/pcm_params.h index e3bebd98e1ce..85cf1cf4f31a 100644 --- a/include/sound/pcm_params.h +++ b/include/sound/pcm_params.h @@ -22,18 +22,14 @@ * */ -extern int snd_pcm_hw_param_mask(struct snd_pcm_substream *pcm, struct snd_pcm_hw_params *params, - snd_pcm_hw_param_t var, const struct snd_mask *val); -extern unsigned int snd_pcm_hw_param_value_min(const struct snd_pcm_hw_params *params, - snd_pcm_hw_param_t var, int *dir); -extern unsigned int snd_pcm_hw_param_value_max(const struct snd_pcm_hw_params *params, - snd_pcm_hw_param_t var, int *dir); -extern int _snd_pcm_hw_param_min(struct snd_pcm_hw_params *params, - snd_pcm_hw_param_t var, unsigned int val, int dir); -extern int _snd_pcm_hw_param_setinteger(struct snd_pcm_hw_params *params, - snd_pcm_hw_param_t var); -extern int _snd_pcm_hw_param_set(struct snd_pcm_hw_params *params, - snd_pcm_hw_param_t var, unsigned int val, int dir); +int snd_pcm_hw_param_first(struct snd_pcm_substream *pcm, + struct snd_pcm_hw_params *params, + snd_pcm_hw_param_t var, int *dir); +int snd_pcm_hw_param_last(struct snd_pcm_substream *pcm, + struct snd_pcm_hw_params *params, + snd_pcm_hw_param_t var, int *dir); +int snd_pcm_hw_param_value(const struct snd_pcm_hw_params *params, + snd_pcm_hw_param_t var, int *dir); #define SNDRV_MASK_BITS 64 /* we use so far 64bits only */ #define SNDRV_MASK_SIZE (SNDRV_MASK_BITS / 32) diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index ac990bf0b48f..0d2e232afe6c 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -78,6 +78,487 @@ static inline void snd_leave_user(mm_segment_t fs) set_fs(fs); } +/* + * helper functions to process hw_params + */ +static int snd_interval_refine_min(struct snd_interval *i, unsigned int min, int openmin) +{ + int changed = 0; + if (i->min < min) { + i->min = min; + i->openmin = openmin; + changed = 1; + } else if (i->min == min && !i->openmin && openmin) { + i->openmin = 1; + changed = 1; + } + if (i->integer) { + if (i->openmin) { + i->min++; + i->openmin = 0; + } + } + if (snd_interval_checkempty(i)) { + snd_interval_none(i); + return -EINVAL; + } + return changed; +} + +static int snd_interval_refine_max(struct snd_interval *i, unsigned int max, int openmax) +{ + int changed = 0; + if (i->max > max) { + i->max = max; + i->openmax = openmax; + changed = 1; + } else if (i->max == max && !i->openmax && openmax) { + i->openmax = 1; + changed = 1; + } + if (i->integer) { + if (i->openmax) { + i->max--; + i->openmax = 0; + } + } + if (snd_interval_checkempty(i)) { + snd_interval_none(i); + return -EINVAL; + } + return changed; +} + +static int snd_interval_refine_set(struct snd_interval *i, unsigned int val) +{ + struct snd_interval t; + t.empty = 0; + t.min = t.max = val; + t.openmin = t.openmax = 0; + t.integer = 1; + return snd_interval_refine(i, &t); +} + +/** + * snd_pcm_hw_param_value_min + * @params: the hw_params instance + * @var: parameter to retrieve + * @dir: pointer to the direction (-1,0,1) or NULL + * + * Return the minimum value for field PAR. + */ +static unsigned int +snd_pcm_hw_param_value_min(const struct snd_pcm_hw_params *params, + snd_pcm_hw_param_t var, int *dir) +{ + if (hw_is_mask(var)) { + if (dir) + *dir = 0; + return snd_mask_min(hw_param_mask_c(params, var)); + } + if (hw_is_interval(var)) { + const struct snd_interval *i = hw_param_interval_c(params, var); + if (dir) + *dir = i->openmin; + return snd_interval_min(i); + } + return -EINVAL; +} + +/** + * snd_pcm_hw_param_value_max + * @params: the hw_params instance + * @var: parameter to retrieve + * @dir: pointer to the direction (-1,0,1) or NULL + * + * Return the maximum value for field PAR. + */ +static unsigned int +snd_pcm_hw_param_value_max(const struct snd_pcm_hw_params *params, + snd_pcm_hw_param_t var, int *dir) +{ + if (hw_is_mask(var)) { + if (dir) + *dir = 0; + return snd_mask_max(hw_param_mask_c(params, var)); + } + if (hw_is_interval(var)) { + const struct snd_interval *i = hw_param_interval_c(params, var); + if (dir) + *dir = - (int) i->openmax; + return snd_interval_max(i); + } + return -EINVAL; +} + +static int _snd_pcm_hw_param_mask(struct snd_pcm_hw_params *params, + snd_pcm_hw_param_t var, + const struct snd_mask *val) +{ + int changed; + changed = snd_mask_refine(hw_param_mask(params, var), val); + if (changed) { + params->cmask |= 1 << var; + params->rmask |= 1 << var; + } + return changed; +} + +static int snd_pcm_hw_param_mask(struct snd_pcm_substream *pcm, + struct snd_pcm_hw_params *params, + snd_pcm_hw_param_t var, + const struct snd_mask *val) +{ + int changed = _snd_pcm_hw_param_mask(params, var, val); + if (changed < 0) + return changed; + if (params->rmask) { + int err = snd_pcm_hw_refine(pcm, params); + if (err < 0) + return err; + } + return 0; +} + +static int _snd_pcm_hw_param_min(struct snd_pcm_hw_params *params, + snd_pcm_hw_param_t var, unsigned int val, + int dir) +{ + int changed; + int open = 0; + if (dir) { + if (dir > 0) { + open = 1; + } else if (dir < 0) { + if (val > 0) { + open = 1; + val--; + } + } + } + if (hw_is_mask(var)) + changed = snd_mask_refine_min(hw_param_mask(params, var), + val + !!open); + else if (hw_is_interval(var)) + changed = snd_interval_refine_min(hw_param_interval(params, var), + val, open); + else + return -EINVAL; + if (changed) { + params->cmask |= 1 << var; + params->rmask |= 1 << var; + } + return changed; +} + +/** + * snd_pcm_hw_param_min + * @pcm: PCM instance + * @params: the hw_params instance + * @var: parameter to retrieve + * @val: minimal value + * @dir: pointer to the direction (-1,0,1) or NULL + * + * Inside configuration space defined by PARAMS remove from PAR all + * values < VAL. Reduce configuration space accordingly. + * Return new minimum or -EINVAL if the configuration space is empty + */ +static int snd_pcm_hw_param_min(struct snd_pcm_substream *pcm, + struct snd_pcm_hw_params *params, + snd_pcm_hw_param_t var, unsigned int val, + int *dir) +{ + int changed = _snd_pcm_hw_param_min(params, var, val, dir ? *dir : 0); + if (changed < 0) + return changed; + if (params->rmask) { + int err = snd_pcm_hw_refine(pcm, params); + if (err < 0) + return err; + } + return snd_pcm_hw_param_value_min(params, var, dir); +} + +static int _snd_pcm_hw_param_max(struct snd_pcm_hw_params *params, + snd_pcm_hw_param_t var, unsigned int val, + int dir) +{ + int changed; + int open = 0; + if (dir) { + if (dir < 0) { + open = 1; + } else if (dir > 0) { + open = 1; + val++; + } + } + if (hw_is_mask(var)) { + if (val == 0 && open) { + snd_mask_none(hw_param_mask(params, var)); + changed = -EINVAL; + } else + changed = snd_mask_refine_max(hw_param_mask(params, var), + val - !!open); + } else if (hw_is_interval(var)) + changed = snd_interval_refine_max(hw_param_interval(params, var), + val, open); + else + return -EINVAL; + if (changed) { + params->cmask |= 1 << var; + params->rmask |= 1 << var; + } + return changed; +} + +/** + * snd_pcm_hw_param_max + * @pcm: PCM instance + * @params: the hw_params instance + * @var: parameter to retrieve + * @val: maximal value + * @dir: pointer to the direction (-1,0,1) or NULL + * + * Inside configuration space defined by PARAMS remove from PAR all + * values >= VAL + 1. Reduce configuration space accordingly. + * Return new maximum or -EINVAL if the configuration space is empty + */ +static int snd_pcm_hw_param_max(struct snd_pcm_substream *pcm, + struct snd_pcm_hw_params *params, + snd_pcm_hw_param_t var, unsigned int val, + int *dir) +{ + int changed = _snd_pcm_hw_param_max(params, var, val, dir ? *dir : 0); + if (changed < 0) + return changed; + if (params->rmask) { + int err = snd_pcm_hw_refine(pcm, params); + if (err < 0) + return err; + } + return snd_pcm_hw_param_value_max(params, var, dir); +} + +static int boundary_sub(int a, int adir, + int b, int bdir, + int *c, int *cdir) +{ + adir = adir < 0 ? -1 : (adir > 0 ? 1 : 0); + bdir = bdir < 0 ? -1 : (bdir > 0 ? 1 : 0); + *c = a - b; + *cdir = adir - bdir; + if (*cdir == -2) { + (*c)--; + } else if (*cdir == 2) { + (*c)++; + } + return 0; +} + +static int boundary_lt(unsigned int a, int adir, + unsigned int b, int bdir) +{ + if (adir < 0) { + a--; + adir = 1; + } else if (adir > 0) + adir = 1; + if (bdir < 0) { + b--; + bdir = 1; + } else if (bdir > 0) + bdir = 1; + return a < b || (a == b && adir < bdir); +} + +/* Return 1 if min is nearer to best than max */ +static int boundary_nearer(int min, int mindir, + int best, int bestdir, + int max, int maxdir) +{ + int dmin, dmindir; + int dmax, dmaxdir; + boundary_sub(best, bestdir, min, mindir, &dmin, &dmindir); + boundary_sub(max, maxdir, best, bestdir, &dmax, &dmaxdir); + return boundary_lt(dmin, dmindir, dmax, dmaxdir); +} + +/** + * snd_pcm_hw_param_near + * @pcm: PCM instance + * @params: the hw_params instance + * @var: parameter to retrieve + * @best: value to set + * @dir: pointer to the direction (-1,0,1) or NULL + * + * Inside configuration space defined by PARAMS set PAR to the available value + * nearest to VAL. Reduce configuration space accordingly. + * This function cannot be called for SNDRV_PCM_HW_PARAM_ACCESS, + * SNDRV_PCM_HW_PARAM_FORMAT, SNDRV_PCM_HW_PARAM_SUBFORMAT. + * Return the value found. + */ +static int snd_pcm_hw_param_near(struct snd_pcm_substream *pcm, + struct snd_pcm_hw_params *params, + snd_pcm_hw_param_t var, unsigned int best, + int *dir) +{ + struct snd_pcm_hw_params *save = NULL; + int v; + unsigned int saved_min; + int last = 0; + int min, max; + int mindir, maxdir; + int valdir = dir ? *dir : 0; + /* FIXME */ + if (best > INT_MAX) + best = INT_MAX; + min = max = best; + mindir = maxdir = valdir; + if (maxdir > 0) + maxdir = 0; + else if (maxdir == 0) + maxdir = -1; + else { + maxdir = 1; + max--; + } + save = kmalloc(sizeof(*save), GFP_KERNEL); + if (save == NULL) + return -ENOMEM; + *save = *params; + saved_min = min; + min = snd_pcm_hw_param_min(pcm, params, var, min, &mindir); + if (min >= 0) { + struct snd_pcm_hw_params *params1; + if (max < 0) + goto _end; + if ((unsigned int)min == saved_min && mindir == valdir) + goto _end; + params1 = kmalloc(sizeof(*params1), GFP_KERNEL); + if (params1 == NULL) { + kfree(save); + return -ENOMEM; + } + *params1 = *save; + max = snd_pcm_hw_param_max(pcm, params1, var, max, &maxdir); + if (max < 0) { + kfree(params1); + goto _end; + } + if (boundary_nearer(max, maxdir, best, valdir, min, mindir)) { + *params = *params1; + last = 1; + } + kfree(params1); + } else { + *params = *save; + max = snd_pcm_hw_param_max(pcm, params, var, max, &maxdir); + snd_assert(max >= 0, return -EINVAL); + last = 1; + } + _end: + kfree(save); + if (last) + v = snd_pcm_hw_param_last(pcm, params, var, dir); + else + v = snd_pcm_hw_param_first(pcm, params, var, dir); + snd_assert(v >= 0, return -EINVAL); + return v; +} + +static int _snd_pcm_hw_param_set(struct snd_pcm_hw_params *params, + snd_pcm_hw_param_t var, unsigned int val, + int dir) +{ + int changed; + if (hw_is_mask(var)) { + struct snd_mask *m = hw_param_mask(params, var); + if (val == 0 && dir < 0) { + changed = -EINVAL; + snd_mask_none(m); + } else { + if (dir > 0) + val++; + else if (dir < 0) + val--; + changed = snd_mask_refine_set(hw_param_mask(params, var), val); + } + } else if (hw_is_interval(var)) { + struct snd_interval *i = hw_param_interval(params, var); + if (val == 0 && dir < 0) { + changed = -EINVAL; + snd_interval_none(i); + } else if (dir == 0) + changed = snd_interval_refine_set(i, val); + else { + struct snd_interval t; + t.openmin = 1; + t.openmax = 1; + t.empty = 0; + t.integer = 0; + if (dir < 0) { + t.min = val - 1; + t.max = val; + } else { + t.min = val; + t.max = val+1; + } + changed = snd_interval_refine(i, &t); + } + } else + return -EINVAL; + if (changed) { + params->cmask |= 1 << var; + params->rmask |= 1 << var; + } + return changed; +} + +/** + * snd_pcm_hw_param_set + * @pcm: PCM instance + * @params: the hw_params instance + * @var: parameter to retrieve + * @val: value to set + * @dir: pointer to the direction (-1,0,1) or NULL + * + * Inside configuration space defined by PARAMS remove from PAR all + * values != VAL. Reduce configuration space accordingly. + * Return VAL or -EINVAL if the configuration space is empty + */ +static int snd_pcm_hw_param_set(struct snd_pcm_substream *pcm, + struct snd_pcm_hw_params *params, + snd_pcm_hw_param_t var, unsigned int val, + int dir) +{ + int changed = _snd_pcm_hw_param_set(params, var, val, dir); + if (changed < 0) + return changed; + if (params->rmask) { + int err = snd_pcm_hw_refine(pcm, params); + if (err < 0) + return err; + } + return snd_pcm_hw_param_value(params, var, NULL); +} + +static int _snd_pcm_hw_param_setinteger(struct snd_pcm_hw_params *params, + snd_pcm_hw_param_t var) +{ + int changed; + changed = snd_interval_setinteger(hw_param_interval(params, var)); + if (changed) { + params->cmask |= 1 << var; + params->rmask |= 1 << var; + } + return changed; +} + +/* + * plugin + */ + #ifdef CONFIG_SND_PCM_OSS_PLUGINS static int snd_pcm_oss_plugin_clear(struct snd_pcm_substream *substream) { diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 84b00038236d..8c15c01907f4 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -671,6 +671,8 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count) return 0; } +EXPORT_SYMBOL(snd_pcm_new_stream); + /** * snd_pcm_new - create a new PCM instance * @card: the card instance @@ -730,6 +732,8 @@ int snd_pcm_new(struct snd_card *card, char *id, int device, return 0; } +EXPORT_SYMBOL(snd_pcm_new); + static void snd_pcm_free_stream(struct snd_pcm_str * pstr) { struct snd_pcm_substream *substream, *substream_next; @@ -1022,6 +1026,8 @@ int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree) return 0; } +EXPORT_SYMBOL(snd_pcm_notify); + #ifdef CONFIG_PROC_FS /* * Info interface @@ -1099,33 +1105,3 @@ static void __exit alsa_pcm_exit(void) module_init(alsa_pcm_init) module_exit(alsa_pcm_exit) - -EXPORT_SYMBOL(snd_pcm_new); -EXPORT_SYMBOL(snd_pcm_new_stream); -EXPORT_SYMBOL(snd_pcm_notify); -EXPORT_SYMBOL(snd_pcm_open_substream); -EXPORT_SYMBOL(snd_pcm_release_substream); - /* pcm_native.c */ -EXPORT_SYMBOL(snd_pcm_link_rwlock); -#ifdef CONFIG_PM -EXPORT_SYMBOL(snd_pcm_suspend); -EXPORT_SYMBOL(snd_pcm_suspend_all); -#endif -EXPORT_SYMBOL(snd_pcm_kernel_ioctl); -EXPORT_SYMBOL(snd_pcm_mmap_data); -#if SNDRV_PCM_INFO_MMAP_IOMEM -EXPORT_SYMBOL(snd_pcm_lib_mmap_iomem); -#endif - /* pcm_misc.c */ -EXPORT_SYMBOL(snd_pcm_format_signed); -EXPORT_SYMBOL(snd_pcm_format_unsigned); -EXPORT_SYMBOL(snd_pcm_format_linear); -EXPORT_SYMBOL(snd_pcm_format_little_endian); -EXPORT_SYMBOL(snd_pcm_format_big_endian); -EXPORT_SYMBOL(snd_pcm_format_width); -EXPORT_SYMBOL(snd_pcm_format_physical_width); -EXPORT_SYMBOL(snd_pcm_format_size); -EXPORT_SYMBOL(snd_pcm_format_silence_64); -EXPORT_SYMBOL(snd_pcm_format_set_silence); -EXPORT_SYMBOL(snd_pcm_build_linear_format); -EXPORT_SYMBOL(snd_pcm_limit_hw_rates); diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index eedc6cb038bb..786f88145ee8 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -289,6 +289,7 @@ void snd_pcm_set_ops(struct snd_pcm *pcm, int direction, struct snd_pcm_ops *ops substream->ops = ops; } +EXPORT_SYMBOL(snd_pcm_set_ops); /** * snd_pcm_sync - set the PCM sync id @@ -306,13 +307,12 @@ void snd_pcm_set_sync(struct snd_pcm_substream *substream) runtime->sync.id32[3] = -1; } +EXPORT_SYMBOL(snd_pcm_set_sync); + /* * Standard ioctl routine */ -/* Code taken from alsa-lib */ -#define assert(a) snd_assert((a), return -EINVAL) - static inline unsigned int div32(unsigned int a, unsigned int b, unsigned int *r) { @@ -369,56 +369,6 @@ static inline unsigned int muldiv32(unsigned int a, unsigned int b, return n; } -static int snd_interval_refine_min(struct snd_interval *i, unsigned int min, int openmin) -{ - int changed = 0; - assert(!snd_interval_empty(i)); - if (i->min < min) { - i->min = min; - i->openmin = openmin; - changed = 1; - } else if (i->min == min && !i->openmin && openmin) { - i->openmin = 1; - changed = 1; - } - if (i->integer) { - if (i->openmin) { - i->min++; - i->openmin = 0; - } - } - if (snd_interval_checkempty(i)) { - snd_interval_none(i); - return -EINVAL; - } - return changed; -} - -static int snd_interval_refine_max(struct snd_interval *i, unsigned int max, int openmax) -{ - int changed = 0; - assert(!snd_interval_empty(i)); - if (i->max > max) { - i->max = max; - i->openmax = openmax; - changed = 1; - } else if (i->max == max && !i->openmax && openmax) { - i->openmax = 1; - changed = 1; - } - if (i->integer) { - if (i->openmax) { - i->max--; - i->openmax = 0; - } - } - if (snd_interval_checkempty(i)) { - snd_interval_none(i); - return -EINVAL; - } - return changed; -} - /** * snd_interval_refine - refine the interval value of configurator * @i: the interval value to refine @@ -433,7 +383,7 @@ static int snd_interval_refine_max(struct snd_interval *i, unsigned int max, int int snd_interval_refine(struct snd_interval *i, const struct snd_interval *v) { int changed = 0; - assert(!snd_interval_empty(i)); + snd_assert(!snd_interval_empty(i), return -EINVAL); if (i->min < v->min) { i->min = v->min; i->openmin = v->openmin; @@ -472,9 +422,11 @@ int snd_interval_refine(struct snd_interval *i, const struct snd_interval *v) return changed; } +EXPORT_SYMBOL(snd_interval_refine); + static int snd_interval_refine_first(struct snd_interval *i) { - assert(!snd_interval_empty(i)); + snd_assert(!snd_interval_empty(i), return -EINVAL); if (snd_interval_single(i)) return 0; i->max = i->min; @@ -486,7 +438,7 @@ static int snd_interval_refine_first(struct snd_interval *i) static int snd_interval_refine_last(struct snd_interval *i) { - assert(!snd_interval_empty(i)); + snd_assert(!snd_interval_empty(i), return -EINVAL); if (snd_interval_single(i)) return 0; i->min = i->max; @@ -496,16 +448,6 @@ static int snd_interval_refine_last(struct snd_interval *i) return 1; } -static int snd_interval_refine_set(struct snd_interval *i, unsigned int val) -{ - struct snd_interval t; - t.empty = 0; - t.min = t.max = val; - t.openmin = t.openmax = 0; - t.integer = 1; - return snd_interval_refine(i, &t); -} - void snd_interval_mul(const struct snd_interval *a, const struct snd_interval *b, struct snd_interval *c) { if (a->empty || b->empty) { @@ -621,7 +563,6 @@ void snd_interval_mulkdiv(const struct snd_interval *a, unsigned int k, c->integer = 0; } -#undef assert /* ---- */ @@ -727,6 +668,8 @@ int snd_interval_ratnum(struct snd_interval *i, return err; } +EXPORT_SYMBOL(snd_interval_ratnum); + /** * snd_interval_ratden - refine the interval value * @i: interval to refine @@ -877,6 +820,8 @@ int snd_interval_list(struct snd_interval *i, unsigned int count, unsigned int * return changed; } +EXPORT_SYMBOL(snd_interval_list); + static int snd_interval_step(struct snd_interval *i, unsigned int min, unsigned int step) { unsigned int n; @@ -953,6 +898,8 @@ int snd_pcm_hw_rule_add(struct snd_pcm_runtime *runtime, unsigned int cond, return 0; } +EXPORT_SYMBOL(snd_pcm_hw_rule_add); + /** * snd_pcm_hw_constraint_mask * @runtime: PCM runtime instance @@ -1007,6 +954,8 @@ int snd_pcm_hw_constraint_integer(struct snd_pcm_runtime *runtime, snd_pcm_hw_pa return snd_interval_setinteger(constrs_interval(constrs, var)); } +EXPORT_SYMBOL(snd_pcm_hw_constraint_integer); + /** * snd_pcm_hw_constraint_minmax * @runtime: PCM runtime instance @@ -1028,6 +977,8 @@ int snd_pcm_hw_constraint_minmax(struct snd_pcm_runtime *runtime, snd_pcm_hw_par return snd_interval_refine(constrs_interval(constrs, var), &t); } +EXPORT_SYMBOL(snd_pcm_hw_constraint_minmax); + static int snd_pcm_hw_rule_list(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { @@ -1055,6 +1006,8 @@ int snd_pcm_hw_constraint_list(struct snd_pcm_runtime *runtime, var, -1); } +EXPORT_SYMBOL(snd_pcm_hw_constraint_list); + static int snd_pcm_hw_rule_ratnums(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { @@ -1087,6 +1040,8 @@ int snd_pcm_hw_constraint_ratnums(struct snd_pcm_runtime *runtime, var, -1); } +EXPORT_SYMBOL(snd_pcm_hw_constraint_ratnums); + static int snd_pcm_hw_rule_ratdens(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { @@ -1118,6 +1073,8 @@ int snd_pcm_hw_constraint_ratdens(struct snd_pcm_runtime *runtime, var, -1); } +EXPORT_SYMBOL(snd_pcm_hw_constraint_ratdens); + static int snd_pcm_hw_rule_msbits(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { @@ -1149,6 +1106,8 @@ int snd_pcm_hw_constraint_msbits(struct snd_pcm_runtime *runtime, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1); } +EXPORT_SYMBOL(snd_pcm_hw_constraint_msbits); + static int snd_pcm_hw_rule_step(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { @@ -1173,6 +1132,8 @@ int snd_pcm_hw_constraint_step(struct snd_pcm_runtime *runtime, var, -1); } +EXPORT_SYMBOL(snd_pcm_hw_constraint_step); + static int snd_pcm_hw_rule_pow2(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { static int pow2_sizes[] = { @@ -1200,6 +1161,8 @@ int snd_pcm_hw_constraint_pow2(struct snd_pcm_runtime *runtime, var, -1); } +EXPORT_SYMBOL(snd_pcm_hw_constraint_pow2); + /* To use the same code we have in alsa-lib */ #define assert(i) snd_assert((i), return -EINVAL) #ifndef INT_MIN @@ -1224,18 +1187,6 @@ static void _snd_pcm_hw_param_any(struct snd_pcm_hw_params *params, snd_BUG(); } -#if 0 -/* - * snd_pcm_hw_param_any - */ -int snd_pcm_hw_param_any(struct snd_pcm_substream *pcm, struct snd_pcm_hw_params *params, - snd_pcm_hw_param_t var) -{ - _snd_pcm_hw_param_any(params, var); - return snd_pcm_hw_refine(pcm, params); -} -#endif /* 0 */ - void _snd_pcm_hw_params_any(struct snd_pcm_hw_params *params) { unsigned int k; @@ -1247,18 +1198,7 @@ void _snd_pcm_hw_params_any(struct snd_pcm_hw_params *params) params->info = ~0U; } -#if 0 -/* - * snd_pcm_hw_params_any - * - * Fill PARAMS with full configuration space boundaries - */ -int snd_pcm_hw_params_any(struct snd_pcm_substream *pcm, struct snd_pcm_hw_params *params) -{ - _snd_pcm_hw_params_any(params); - return snd_pcm_hw_refine(pcm, params); -} -#endif /* 0 */ +EXPORT_SYMBOL(_snd_pcm_hw_params_any); /** * snd_pcm_hw_param_value @@ -1269,8 +1209,8 @@ int snd_pcm_hw_params_any(struct snd_pcm_substream *pcm, struct snd_pcm_hw_param * Return the value for field PAR if it's fixed in configuration space * defined by PARAMS. Return -EINVAL otherwise */ -static int snd_pcm_hw_param_value(const struct snd_pcm_hw_params *params, - snd_pcm_hw_param_t var, int *dir) +int snd_pcm_hw_param_value(const struct snd_pcm_hw_params *params, + snd_pcm_hw_param_t var, int *dir) { if (hw_is_mask(var)) { const struct snd_mask *mask = hw_param_mask_c(params, var); @@ -1292,57 +1232,7 @@ static int snd_pcm_hw_param_value(const struct snd_pcm_hw_params *params, return -EINVAL; } -/** - * snd_pcm_hw_param_value_min - * @params: the hw_params instance - * @var: parameter to retrieve - * @dir: pointer to the direction (-1,0,1) or NULL - * - * Return the minimum value for field PAR. - */ -unsigned int snd_pcm_hw_param_value_min(const struct snd_pcm_hw_params *params, - snd_pcm_hw_param_t var, int *dir) -{ - if (hw_is_mask(var)) { - if (dir) - *dir = 0; - return snd_mask_min(hw_param_mask_c(params, var)); - } - if (hw_is_interval(var)) { - const struct snd_interval *i = hw_param_interval_c(params, var); - if (dir) - *dir = i->openmin; - return snd_interval_min(i); - } - assert(0); - return -EINVAL; -} - -/** - * snd_pcm_hw_param_value_max - * @params: the hw_params instance - * @var: parameter to retrieve - * @dir: pointer to the direction (-1,0,1) or NULL - * - * Return the maximum value for field PAR. - */ -unsigned int snd_pcm_hw_param_value_max(const struct snd_pcm_hw_params *params, - snd_pcm_hw_param_t var, int *dir) -{ - if (hw_is_mask(var)) { - if (dir) - *dir = 0; - return snd_mask_max(hw_param_mask_c(params, var)); - } - if (hw_is_interval(var)) { - const struct snd_interval *i = hw_param_interval_c(params, var); - if (dir) - *dir = - (int) i->openmax; - return snd_interval_max(i); - } - assert(0); - return -EINVAL; -} +EXPORT_SYMBOL(snd_pcm_hw_param_value); void _snd_pcm_hw_param_setempty(struct snd_pcm_hw_params *params, snd_pcm_hw_param_t var) @@ -1360,42 +1250,7 @@ void _snd_pcm_hw_param_setempty(struct snd_pcm_hw_params *params, } } -int _snd_pcm_hw_param_setinteger(struct snd_pcm_hw_params *params, - snd_pcm_hw_param_t var) -{ - int changed; - assert(hw_is_interval(var)); - changed = snd_interval_setinteger(hw_param_interval(params, var)); - if (changed) { - params->cmask |= 1 << var; - params->rmask |= 1 << var; - } - return changed; -} - -#if 0 -/* - * snd_pcm_hw_param_setinteger - * - * Inside configuration space defined by PARAMS remove from PAR all - * non integer values. Reduce configuration space accordingly. - * Return -EINVAL if the configuration space is empty - */ -int snd_pcm_hw_param_setinteger(struct snd_pcm_substream *pcm, - struct snd_pcm_hw_params *params, - snd_pcm_hw_param_t var) -{ - int changed = _snd_pcm_hw_param_setinteger(params, var); - if (changed < 0) - return changed; - if (params->rmask) { - int err = snd_pcm_hw_refine(pcm, params); - if (err < 0) - return err; - } - return 0; -} -#endif /* 0 */ +EXPORT_SYMBOL(_snd_pcm_hw_param_setempty); static int _snd_pcm_hw_param_first(struct snd_pcm_hw_params *params, snd_pcm_hw_param_t var) @@ -1428,9 +1283,9 @@ static int _snd_pcm_hw_param_first(struct snd_pcm_hw_params *params, * values > minimum. Reduce configuration space accordingly. * Return the minimum. */ -static int snd_pcm_hw_param_first(struct snd_pcm_substream *pcm, - struct snd_pcm_hw_params *params, - snd_pcm_hw_param_t var, int *dir) +int snd_pcm_hw_param_first(struct snd_pcm_substream *pcm, + struct snd_pcm_hw_params *params, + snd_pcm_hw_param_t var, int *dir) { int changed = _snd_pcm_hw_param_first(params, var); if (changed < 0) @@ -1442,6 +1297,8 @@ static int snd_pcm_hw_param_first(struct snd_pcm_substream *pcm, return snd_pcm_hw_param_value(params, var, dir); } +EXPORT_SYMBOL(snd_pcm_hw_param_first); + static int _snd_pcm_hw_param_last(struct snd_pcm_hw_params *params, snd_pcm_hw_param_t var) { @@ -1473,9 +1330,9 @@ static int _snd_pcm_hw_param_last(struct snd_pcm_hw_params *params, * values < maximum. Reduce configuration space accordingly. * Return the maximum. */ -static int snd_pcm_hw_param_last(struct snd_pcm_substream *pcm, - struct snd_pcm_hw_params *params, - snd_pcm_hw_param_t var, int *dir) +int snd_pcm_hw_param_last(struct snd_pcm_substream *pcm, + struct snd_pcm_hw_params *params, + snd_pcm_hw_param_t var, int *dir) { int changed = _snd_pcm_hw_param_last(params, var); if (changed < 0) @@ -1487,367 +1344,7 @@ static int snd_pcm_hw_param_last(struct snd_pcm_substream *pcm, return snd_pcm_hw_param_value(params, var, dir); } -int _snd_pcm_hw_param_min(struct snd_pcm_hw_params *params, - snd_pcm_hw_param_t var, unsigned int val, int dir) -{ - int changed; - int open = 0; - if (dir) { - if (dir > 0) { - open = 1; - } else if (dir < 0) { - if (val > 0) { - open = 1; - val--; - } - } - } - if (hw_is_mask(var)) - changed = snd_mask_refine_min(hw_param_mask(params, var), val + !!open); - else if (hw_is_interval(var)) - changed = snd_interval_refine_min(hw_param_interval(params, var), val, open); - else { - assert(0); - return -EINVAL; - } - if (changed) { - params->cmask |= 1 << var; - params->rmask |= 1 << var; - } - return changed; -} - -/** - * snd_pcm_hw_param_min - * @pcm: PCM instance - * @params: the hw_params instance - * @var: parameter to retrieve - * @val: minimal value - * @dir: pointer to the direction (-1,0,1) or NULL - * - * Inside configuration space defined by PARAMS remove from PAR all - * values < VAL. Reduce configuration space accordingly. - * Return new minimum or -EINVAL if the configuration space is empty - */ -static int snd_pcm_hw_param_min(struct snd_pcm_substream *pcm, struct snd_pcm_hw_params *params, - snd_pcm_hw_param_t var, unsigned int val, - int *dir) -{ - int changed = _snd_pcm_hw_param_min(params, var, val, dir ? *dir : 0); - if (changed < 0) - return changed; - if (params->rmask) { - int err = snd_pcm_hw_refine(pcm, params); - if (err < 0) - return err; - } - return snd_pcm_hw_param_value_min(params, var, dir); -} - -static int _snd_pcm_hw_param_max(struct snd_pcm_hw_params *params, - snd_pcm_hw_param_t var, unsigned int val, - int dir) -{ - int changed; - int open = 0; - if (dir) { - if (dir < 0) { - open = 1; - } else if (dir > 0) { - open = 1; - val++; - } - } - if (hw_is_mask(var)) { - if (val == 0 && open) { - snd_mask_none(hw_param_mask(params, var)); - changed = -EINVAL; - } else - changed = snd_mask_refine_max(hw_param_mask(params, var), val - !!open); - } else if (hw_is_interval(var)) - changed = snd_interval_refine_max(hw_param_interval(params, var), val, open); - else { - assert(0); - return -EINVAL; - } - if (changed) { - params->cmask |= 1 << var; - params->rmask |= 1 << var; - } - return changed; -} - -/** - * snd_pcm_hw_param_max - * @pcm: PCM instance - * @params: the hw_params instance - * @var: parameter to retrieve - * @val: maximal value - * @dir: pointer to the direction (-1,0,1) or NULL - * - * Inside configuration space defined by PARAMS remove from PAR all - * values >= VAL + 1. Reduce configuration space accordingly. - * Return new maximum or -EINVAL if the configuration space is empty - */ -static int snd_pcm_hw_param_max(struct snd_pcm_substream *pcm, struct snd_pcm_hw_params *params, - snd_pcm_hw_param_t var, unsigned int val, - int *dir) -{ - int changed = _snd_pcm_hw_param_max(params, var, val, dir ? *dir : 0); - if (changed < 0) - return changed; - if (params->rmask) { - int err = snd_pcm_hw_refine(pcm, params); - if (err < 0) - return err; - } - return snd_pcm_hw_param_value_max(params, var, dir); -} - -int _snd_pcm_hw_param_set(struct snd_pcm_hw_params *params, - snd_pcm_hw_param_t var, unsigned int val, int dir) -{ - int changed; - if (hw_is_mask(var)) { - struct snd_mask *m = hw_param_mask(params, var); - if (val == 0 && dir < 0) { - changed = -EINVAL; - snd_mask_none(m); - } else { - if (dir > 0) - val++; - else if (dir < 0) - val--; - changed = snd_mask_refine_set(hw_param_mask(params, var), val); - } - } else if (hw_is_interval(var)) { - struct snd_interval *i = hw_param_interval(params, var); - if (val == 0 && dir < 0) { - changed = -EINVAL; - snd_interval_none(i); - } else if (dir == 0) - changed = snd_interval_refine_set(i, val); - else { - struct snd_interval t; - t.openmin = 1; - t.openmax = 1; - t.empty = 0; - t.integer = 0; - if (dir < 0) { - t.min = val - 1; - t.max = val; - } else { - t.min = val; - t.max = val+1; - } - changed = snd_interval_refine(i, &t); - } - } else { - assert(0); - return -EINVAL; - } - if (changed) { - params->cmask |= 1 << var; - params->rmask |= 1 << var; - } - return changed; -} - -/** - * snd_pcm_hw_param_set - * @pcm: PCM instance - * @params: the hw_params instance - * @var: parameter to retrieve - * @val: value to set - * @dir: pointer to the direction (-1,0,1) or NULL - * - * Inside configuration space defined by PARAMS remove from PAR all - * values != VAL. Reduce configuration space accordingly. - * Return VAL or -EINVAL if the configuration space is empty - */ -int snd_pcm_hw_param_set(struct snd_pcm_substream *pcm, struct snd_pcm_hw_params *params, - snd_pcm_hw_param_t var, unsigned int val, int dir) -{ - int changed = _snd_pcm_hw_param_set(params, var, val, dir); - if (changed < 0) - return changed; - if (params->rmask) { - int err = snd_pcm_hw_refine(pcm, params); - if (err < 0) - return err; - } - return snd_pcm_hw_param_value(params, var, NULL); -} - -static int _snd_pcm_hw_param_mask(struct snd_pcm_hw_params *params, - snd_pcm_hw_param_t var, const struct snd_mask *val) -{ - int changed; - assert(hw_is_mask(var)); - changed = snd_mask_refine(hw_param_mask(params, var), val); - if (changed) { - params->cmask |= 1 << var; - params->rmask |= 1 << var; - } - return changed; -} - -/** - * snd_pcm_hw_param_mask - * @pcm: PCM instance - * @params: the hw_params instance - * @var: parameter to retrieve - * @val: mask to apply - * - * Inside configuration space defined by PARAMS remove from PAR all values - * not contained in MASK. Reduce configuration space accordingly. - * This function can be called only for SNDRV_PCM_HW_PARAM_ACCESS, - * SNDRV_PCM_HW_PARAM_FORMAT, SNDRV_PCM_HW_PARAM_SUBFORMAT. - * Return 0 on success or -EINVAL - * if the configuration space is empty - */ -int snd_pcm_hw_param_mask(struct snd_pcm_substream *pcm, struct snd_pcm_hw_params *params, - snd_pcm_hw_param_t var, const struct snd_mask *val) -{ - int changed = _snd_pcm_hw_param_mask(params, var, val); - if (changed < 0) - return changed; - if (params->rmask) { - int err = snd_pcm_hw_refine(pcm, params); - if (err < 0) - return err; - } - return 0; -} - -static int boundary_sub(int a, int adir, - int b, int bdir, - int *c, int *cdir) -{ - adir = adir < 0 ? -1 : (adir > 0 ? 1 : 0); - bdir = bdir < 0 ? -1 : (bdir > 0 ? 1 : 0); - *c = a - b; - *cdir = adir - bdir; - if (*cdir == -2) { - assert(*c > INT_MIN); - (*c)--; - } else if (*cdir == 2) { - assert(*c < INT_MAX); - (*c)++; - } - return 0; -} - -static int boundary_lt(unsigned int a, int adir, - unsigned int b, int bdir) -{ - assert(a > 0 || adir >= 0); - assert(b > 0 || bdir >= 0); - if (adir < 0) { - a--; - adir = 1; - } else if (adir > 0) - adir = 1; - if (bdir < 0) { - b--; - bdir = 1; - } else if (bdir > 0) - bdir = 1; - return a < b || (a == b && adir < bdir); -} - -/* Return 1 if min is nearer to best than max */ -static int boundary_nearer(int min, int mindir, - int best, int bestdir, - int max, int maxdir) -{ - int dmin, dmindir; - int dmax, dmaxdir; - boundary_sub(best, bestdir, min, mindir, &dmin, &dmindir); - boundary_sub(max, maxdir, best, bestdir, &dmax, &dmaxdir); - return boundary_lt(dmin, dmindir, dmax, dmaxdir); -} - -/** - * snd_pcm_hw_param_near - * @pcm: PCM instance - * @params: the hw_params instance - * @var: parameter to retrieve - * @best: value to set - * @dir: pointer to the direction (-1,0,1) or NULL - * - * Inside configuration space defined by PARAMS set PAR to the available value - * nearest to VAL. Reduce configuration space accordingly. - * This function cannot be called for SNDRV_PCM_HW_PARAM_ACCESS, - * SNDRV_PCM_HW_PARAM_FORMAT, SNDRV_PCM_HW_PARAM_SUBFORMAT. - * Return the value found. - */ -int snd_pcm_hw_param_near(struct snd_pcm_substream *pcm, struct snd_pcm_hw_params *params, - snd_pcm_hw_param_t var, unsigned int best, int *dir) -{ - struct snd_pcm_hw_params *save = NULL; - int v; - unsigned int saved_min; - int last = 0; - int min, max; - int mindir, maxdir; - int valdir = dir ? *dir : 0; - /* FIXME */ - if (best > INT_MAX) - best = INT_MAX; - min = max = best; - mindir = maxdir = valdir; - if (maxdir > 0) - maxdir = 0; - else if (maxdir == 0) - maxdir = -1; - else { - maxdir = 1; - max--; - } - save = kmalloc(sizeof(*save), GFP_KERNEL); - if (save == NULL) - return -ENOMEM; - *save = *params; - saved_min = min; - min = snd_pcm_hw_param_min(pcm, params, var, min, &mindir); - if (min >= 0) { - struct snd_pcm_hw_params *params1; - if (max < 0) - goto _end; - if ((unsigned int)min == saved_min && mindir == valdir) - goto _end; - params1 = kmalloc(sizeof(*params1), GFP_KERNEL); - if (params1 == NULL) { - kfree(save); - return -ENOMEM; - } - *params1 = *save; - max = snd_pcm_hw_param_max(pcm, params1, var, max, &maxdir); - if (max < 0) { - kfree(params1); - goto _end; - } - if (boundary_nearer(max, maxdir, best, valdir, min, mindir)) { - *params = *params1; - last = 1; - } - kfree(params1); - } else { - *params = *save; - max = snd_pcm_hw_param_max(pcm, params, var, max, &maxdir); - assert(max >= 0); - last = 1; - } - _end: - kfree(save); - if (last) - v = snd_pcm_hw_param_last(pcm, params, var, dir); - else - v = snd_pcm_hw_param_first(pcm, params, var, dir); - assert(v >= 0); - return v; -} +EXPORT_SYMBOL(snd_pcm_hw_param_last); /** * snd_pcm_hw_param_choose @@ -1967,6 +1464,8 @@ int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream, return -ENXIO; } +EXPORT_SYMBOL(snd_pcm_lib_ioctl); + /* * Conditions */ @@ -2101,6 +1600,8 @@ void snd_pcm_period_elapsed(struct snd_pcm_substream *substream) kill_fasync(&runtime->fasync, SIGIO, POLL_IN); } +EXPORT_SYMBOL(snd_pcm_period_elapsed); + static int snd_pcm_lib_write_transfer(struct snd_pcm_substream *substream, unsigned int hwoff, unsigned long data, unsigned int off, @@ -2308,6 +1809,8 @@ snd_pcm_sframes_t snd_pcm_lib_write(struct snd_pcm_substream *substream, const v snd_pcm_lib_write_transfer); } +EXPORT_SYMBOL(snd_pcm_lib_write); + static int snd_pcm_lib_writev_transfer(struct snd_pcm_substream *substream, unsigned int hwoff, unsigned long data, unsigned int off, @@ -2370,6 +1873,8 @@ snd_pcm_sframes_t snd_pcm_lib_writev(struct snd_pcm_substream *substream, nonblock, snd_pcm_lib_writev_transfer); } +EXPORT_SYMBOL(snd_pcm_lib_writev); + static int snd_pcm_lib_read_transfer(struct snd_pcm_substream *substream, unsigned int hwoff, unsigned long data, unsigned int off, @@ -2578,6 +2083,8 @@ snd_pcm_sframes_t snd_pcm_lib_read(struct snd_pcm_substream *substream, void __u return snd_pcm_lib_read1(substream, (unsigned long)buf, size, nonblock, snd_pcm_lib_read_transfer); } +EXPORT_SYMBOL(snd_pcm_lib_read); + static int snd_pcm_lib_readv_transfer(struct snd_pcm_substream *substream, unsigned int hwoff, unsigned long data, unsigned int off, @@ -2635,52 +2142,4 @@ snd_pcm_sframes_t snd_pcm_lib_readv(struct snd_pcm_substream *substream, return snd_pcm_lib_read1(substream, (unsigned long)bufs, frames, nonblock, snd_pcm_lib_readv_transfer); } -/* - * Exported symbols - */ - -EXPORT_SYMBOL(snd_interval_refine); -EXPORT_SYMBOL(snd_interval_list); -EXPORT_SYMBOL(snd_interval_ratnum); -EXPORT_SYMBOL(_snd_pcm_hw_params_any); -EXPORT_SYMBOL(_snd_pcm_hw_param_min); -EXPORT_SYMBOL(_snd_pcm_hw_param_set); -EXPORT_SYMBOL(_snd_pcm_hw_param_setempty); -EXPORT_SYMBOL(_snd_pcm_hw_param_setinteger); -EXPORT_SYMBOL(snd_pcm_hw_param_value_min); -EXPORT_SYMBOL(snd_pcm_hw_param_value_max); -EXPORT_SYMBOL(snd_pcm_hw_param_mask); -EXPORT_SYMBOL(snd_pcm_hw_param_first); -EXPORT_SYMBOL(snd_pcm_hw_param_last); -EXPORT_SYMBOL(snd_pcm_hw_param_near); -EXPORT_SYMBOL(snd_pcm_hw_param_set); -EXPORT_SYMBOL(snd_pcm_hw_refine); -EXPORT_SYMBOL(snd_pcm_hw_constraints_init); -EXPORT_SYMBOL(snd_pcm_hw_constraints_complete); -EXPORT_SYMBOL(snd_pcm_hw_constraint_list); -EXPORT_SYMBOL(snd_pcm_hw_constraint_step); -EXPORT_SYMBOL(snd_pcm_hw_constraint_ratnums); -EXPORT_SYMBOL(snd_pcm_hw_constraint_ratdens); -EXPORT_SYMBOL(snd_pcm_hw_constraint_msbits); -EXPORT_SYMBOL(snd_pcm_hw_constraint_minmax); -EXPORT_SYMBOL(snd_pcm_hw_constraint_integer); -EXPORT_SYMBOL(snd_pcm_hw_constraint_pow2); -EXPORT_SYMBOL(snd_pcm_hw_rule_add); -EXPORT_SYMBOL(snd_pcm_set_ops); -EXPORT_SYMBOL(snd_pcm_set_sync); -EXPORT_SYMBOL(snd_pcm_lib_ioctl); -EXPORT_SYMBOL(snd_pcm_stop); -EXPORT_SYMBOL(snd_pcm_period_elapsed); -EXPORT_SYMBOL(snd_pcm_lib_write); -EXPORT_SYMBOL(snd_pcm_lib_read); -EXPORT_SYMBOL(snd_pcm_lib_writev); EXPORT_SYMBOL(snd_pcm_lib_readv); -EXPORT_SYMBOL(snd_pcm_lib_buffer_bytes); -EXPORT_SYMBOL(snd_pcm_lib_period_bytes); -/* pcm_memory.c */ -EXPORT_SYMBOL(snd_pcm_lib_preallocate_free_for_all); -EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages); -EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages_for_all); -EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page); -EXPORT_SYMBOL(snd_pcm_lib_malloc_pages); -EXPORT_SYMBOL(snd_pcm_lib_free_pages); diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index 428f8c169ee1..eb56167d3bb4 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -126,6 +126,8 @@ int snd_pcm_lib_preallocate_free_for_all(struct snd_pcm *pcm) return 0; } +EXPORT_SYMBOL(snd_pcm_lib_preallocate_free_for_all); + #ifdef CONFIG_SND_VERBOSE_PROCFS /* * read callback for prealloc proc file @@ -253,6 +255,8 @@ int snd_pcm_lib_preallocate_pages(struct snd_pcm_substream *substream, return snd_pcm_lib_preallocate_pages1(substream, size, max); } +EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages); + /** * snd_pcm_lib_preallocate_pages_for_all - pre-allocation for continous memory type (all substreams) * @pcm: the pcm instance @@ -280,6 +284,8 @@ int snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm, return 0; } +EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages_for_all); + /** * snd_pcm_sgbuf_ops_page - get the page struct at the given offset * @substream: the pcm substream instance @@ -298,6 +304,8 @@ struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, unsigne return sgbuf->page_table[idx]; } +EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page); + /** * snd_pcm_lib_malloc_pages - allocate the DMA buffer * @substream: the substream to allocate the DMA buffer to @@ -349,6 +357,8 @@ int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size) return 1; /* area was changed */ } +EXPORT_SYMBOL(snd_pcm_lib_malloc_pages); + /** * snd_pcm_lib_free_pages - release the allocated DMA buffer. * @substream: the substream to release the DMA buffer @@ -374,3 +384,5 @@ int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream) snd_pcm_set_runtime_buffer(substream, NULL); return 0; } + +EXPORT_SYMBOL(snd_pcm_lib_free_pages); diff --git a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c index 593c77f4d181..0019c59a779d 100644 --- a/sound/core/pcm_misc.c +++ b/sound/core/pcm_misc.c @@ -207,6 +207,8 @@ int snd_pcm_format_signed(snd_pcm_format_t format) return val; } +EXPORT_SYMBOL(snd_pcm_format_signed); + /** * snd_pcm_format_unsigned - Check the PCM format is unsigned linear * @format: the format to check @@ -224,6 +226,8 @@ int snd_pcm_format_unsigned(snd_pcm_format_t format) return !val; } +EXPORT_SYMBOL(snd_pcm_format_unsigned); + /** * snd_pcm_format_linear - Check the PCM format is linear * @format: the format to check @@ -235,6 +239,8 @@ int snd_pcm_format_linear(snd_pcm_format_t format) return snd_pcm_format_signed(format) >= 0; } +EXPORT_SYMBOL(snd_pcm_format_linear); + /** * snd_pcm_format_little_endian - Check the PCM format is little-endian * @format: the format to check @@ -252,6 +258,8 @@ int snd_pcm_format_little_endian(snd_pcm_format_t format) return val; } +EXPORT_SYMBOL(snd_pcm_format_little_endian); + /** * snd_pcm_format_big_endian - Check the PCM format is big-endian * @format: the format to check @@ -269,6 +277,8 @@ int snd_pcm_format_big_endian(snd_pcm_format_t format) return !val; } +EXPORT_SYMBOL(snd_pcm_format_big_endian); + /** * snd_pcm_format_width - return the bit-width of the format * @format: the format to check @@ -286,6 +296,8 @@ int snd_pcm_format_width(snd_pcm_format_t format) return val; } +EXPORT_SYMBOL(snd_pcm_format_width); + /** * snd_pcm_format_physical_width - return the physical bit-width of the format * @format: the format to check @@ -303,6 +315,8 @@ int snd_pcm_format_physical_width(snd_pcm_format_t format) return val; } +EXPORT_SYMBOL(snd_pcm_format_physical_width); + /** * snd_pcm_format_size - return the byte size of samples on the given format * @format: the format to check @@ -318,6 +332,8 @@ ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples) return samples * phys_width / 8; } +EXPORT_SYMBOL(snd_pcm_format_size); + /** * snd_pcm_format_silence_64 - return the silent data in 8 bytes array * @format: the format to check @@ -333,6 +349,8 @@ const unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format) return pcm_formats[format].silence; } +EXPORT_SYMBOL(snd_pcm_format_silence_64); + /** * snd_pcm_format_set_silence - set the silence data on the buffer * @format: the PCM format @@ -402,6 +420,8 @@ int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int return 0; } +EXPORT_SYMBOL(snd_pcm_format_set_silence); + /* [width][unsigned][bigendian] */ static int linear_formats[4][2][2] = { {{ SNDRV_PCM_FORMAT_S8, SNDRV_PCM_FORMAT_S8}, @@ -432,6 +452,8 @@ snd_pcm_format_t snd_pcm_build_linear_format(int width, int unsignd, int big_end return linear_formats[width][!!unsignd][!!big_endian]; } +EXPORT_SYMBOL(snd_pcm_build_linear_format); + /** * snd_pcm_limit_hw_rates - determine rate_min/rate_max fields * @runtime: the runtime instance @@ -463,3 +485,5 @@ int snd_pcm_limit_hw_rates(struct snd_pcm_runtime *runtime) } return 0; } + +EXPORT_SYMBOL(snd_pcm_limit_hw_rates); diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 0860c5a84502..7b5729c4b213 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -71,8 +71,9 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream); */ DEFINE_RWLOCK(snd_pcm_link_rwlock); -static DECLARE_RWSEM(snd_pcm_link_rwsem); +EXPORT_SYMBOL(snd_pcm_link_rwlock); +static DECLARE_RWSEM(snd_pcm_link_rwsem); static inline mm_segment_t snd_enter_user(void) { @@ -319,6 +320,8 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream, return 0; } +EXPORT_SYMBOL(snd_pcm_hw_refine); + static int snd_pcm_hw_refine_user(struct snd_pcm_substream *substream, struct snd_pcm_hw_params __user * _params) { @@ -936,6 +939,8 @@ int snd_pcm_stop(struct snd_pcm_substream *substream, int state) return snd_pcm_action(&snd_pcm_action_stop, substream, state); } +EXPORT_SYMBOL(snd_pcm_stop); + /** * snd_pcm_drain_done * @substream: the PCM substream @@ -1085,6 +1090,8 @@ int snd_pcm_suspend(struct snd_pcm_substream *substream) return err; } +EXPORT_SYMBOL(snd_pcm_suspend); + /** * snd_pcm_suspend_all * @pcm: the PCM instance @@ -1114,6 +1121,8 @@ int snd_pcm_suspend_all(struct snd_pcm *pcm) return 0; } +EXPORT_SYMBOL(snd_pcm_suspend_all); + /* resume */ static int snd_pcm_pre_resume(struct snd_pcm_substream *substream, int state) @@ -2020,6 +2029,8 @@ void snd_pcm_release_substream(struct snd_pcm_substream *substream) snd_pcm_detach_substream(substream); } +EXPORT_SYMBOL(snd_pcm_release_substream); + int snd_pcm_open_substream(struct snd_pcm *pcm, int stream, struct file *file, struct snd_pcm_substream **rsubstream) @@ -2056,6 +2067,8 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream, return err; } +EXPORT_SYMBOL(snd_pcm_open_substream); + static int snd_pcm_open_file(struct file *file, struct snd_pcm *pcm, int stream, @@ -2768,6 +2781,8 @@ int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream, return result; } +EXPORT_SYMBOL(snd_pcm_kernel_ioctl); + static ssize_t snd_pcm_read(struct file *file, char __user *buf, size_t count, loff_t * offset) { @@ -3169,6 +3184,8 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, atomic_inc(&substream->runtime->mmap_count); return 0; } + +EXPORT_SYMBOL(snd_pcm_lib_mmap_iomem); #endif /* SNDRV_PCM_INFO_MMAP */ /* @@ -3212,6 +3229,8 @@ int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file, return snd_pcm_default_mmap(substream, area); } +EXPORT_SYMBOL(snd_pcm_mmap_data); + static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area) { struct snd_pcm_file * pcm_file; -- cgit v1.2.3 From 7e4eeec8a30fa9e00cac67a37ca9ddf6cbdb79c4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 28 Apr 2006 15:13:40 +0200 Subject: [ALSA] Make buffer size of proc text interface variable Make the read/write buffer size of proc text interface variable. Signed-off-by: Takashi Iwai --- include/sound/info.h | 6 +-- sound/core/info.c | 149 +++++++++++++++++++++++++++------------------------ 2 files changed, 82 insertions(+), 73 deletions(-) (limited to 'include') diff --git a/include/sound/info.h b/include/sound/info.h index f23d8381c216..481284389855 100644 --- a/include/sound/info.h +++ b/include/sound/info.h @@ -27,9 +27,9 @@ /* buffer for information */ struct snd_info_buffer { char *buffer; /* pointer to begin of buffer */ - char *curr; /* current position in buffer */ - unsigned long size; /* current size */ - unsigned long len; /* total length of buffer */ + unsigned int curr; /* current position in buffer */ + unsigned int size; /* current size */ + unsigned int len; /* total length of buffer */ int stop; /* stop flag */ int error; /* error code */ }; diff --git a/sound/core/info.c b/sound/core/info.c index 9c288539e99d..86366839c4bb 100644 --- a/sound/core/info.c +++ b/sound/core/info.c @@ -21,7 +21,6 @@ #include #include -#include #include #include #include @@ -82,6 +81,24 @@ static int snd_info_version_init(void); static int snd_info_version_done(void); +/* resize the proc r/w buffer */ +static int resize_info_buffer(struct snd_info_buffer *buffer, + unsigned int nsize) +{ + char *nbuf; + + nsize = PAGE_ALIGN(nsize); + nbuf = kmalloc(nsize, GFP_KERNEL); + if (! nbuf) + return -ENOMEM; + + memcpy(nbuf, buffer->buffer, buffer->len); + kfree(buffer->buffer); + buffer->buffer = nbuf; + buffer->len = nsize; + return 0; +} + /** * snd_iprintf - printf on the procfs buffer * @buffer: the procfs buffer @@ -95,17 +112,25 @@ int snd_iprintf(struct snd_info_buffer *buffer, char *fmt,...) { va_list args; int len, res; + int err = 0; if (buffer->stop || buffer->error) return 0; len = buffer->len - buffer->size; va_start(args, fmt); - res = vsnprintf(buffer->curr, len, fmt, args); - va_end(args); - if (res >= len) { - buffer->stop = 1; - return 0; + for (;;) { + res = vsnprintf(buffer->buffer + buffer->curr, len, fmt, args); + if (res < len) + break; + err = resize_info_buffer(buffer, buffer->len + PAGE_SIZE); + if (err < 0) + break; + len = buffer->len - buffer->size; } + va_end(args); + + if (err < 0) + return err; buffer->curr += res; buffer->size += res; return res; @@ -225,7 +250,7 @@ static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer struct snd_info_private_data *data; struct snd_info_entry *entry; struct snd_info_buffer *buf; - size_t size = 0; + ssize_t size = 0; loff_t pos; data = file->private_data; @@ -241,14 +266,20 @@ static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer buf = data->wbuffer; if (buf == NULL) return -EIO; - if (pos >= buf->len) - return -ENOMEM; - size = buf->len - pos; - size = min(count, size); - if (copy_from_user(buf->buffer + pos, buffer, size)) + mutex_unlock(&entry->access); + if (pos + count >= buf->len) { + if (resize_info_buffer(buf, pos + count)) { + mutex_unlock(&entry->access); + return -ENOMEM; + } + } + if (copy_from_user(buf->buffer + pos, buffer, count)) { + mutex_unlock(&entry->access); return -EFAULT; - if ((long)buf->size < pos + size) - buf->size = pos + size; + } + buf->size = pos + count; + mutex_unlock(&entry->access); + size = count; break; case SNDRV_INFO_CONTENT_DATA: if (entry->c.ops->write) @@ -283,18 +314,14 @@ static int snd_info_entry_open(struct inode *inode, struct file *file) } mode = file->f_flags & O_ACCMODE; if (mode == O_RDONLY || mode == O_RDWR) { - if ((entry->content == SNDRV_INFO_CONTENT_TEXT && - !entry->c.text.read_size) || - (entry->content == SNDRV_INFO_CONTENT_DATA && + if ((entry->content == SNDRV_INFO_CONTENT_DATA && entry->c.ops->read == NULL)) { err = -ENODEV; goto __error; } } if (mode == O_WRONLY || mode == O_RDWR) { - if ((entry->content == SNDRV_INFO_CONTENT_TEXT && - !entry->c.text.write_size) || - (entry->content == SNDRV_INFO_CONTENT_DATA && + if ((entry->content == SNDRV_INFO_CONTENT_DATA && entry->c.ops->write == NULL)) { err = -ENODEV; goto __error; @@ -310,49 +337,23 @@ static int snd_info_entry_open(struct inode *inode, struct file *file) case SNDRV_INFO_CONTENT_TEXT: if (mode == O_RDONLY || mode == O_RDWR) { buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); - if (buffer == NULL) { - kfree(data); - err = -ENOMEM; - goto __error; - } - buffer->len = (entry->c.text.read_size + - (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1); - buffer->buffer = vmalloc(buffer->len); - if (buffer->buffer == NULL) { - kfree(buffer); - kfree(data); - err = -ENOMEM; - goto __error; - } - buffer->curr = buffer->buffer; + if (buffer == NULL) + goto __nomem; data->rbuffer = buffer; + buffer->len = PAGE_SIZE; + buffer->buffer = kmalloc(buffer->len, GFP_KERNEL); + if (buffer->buffer == NULL) + goto __nomem; } if (mode == O_WRONLY || mode == O_RDWR) { buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); - if (buffer == NULL) { - if (mode == O_RDWR) { - vfree(data->rbuffer->buffer); - kfree(data->rbuffer); - } - kfree(data); - err = -ENOMEM; - goto __error; - } - buffer->len = (entry->c.text.write_size + - (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1); - buffer->buffer = vmalloc(buffer->len); - if (buffer->buffer == NULL) { - if (mode == O_RDWR) { - vfree(data->rbuffer->buffer); - kfree(data->rbuffer); - } - kfree(buffer); - kfree(data); - err = -ENOMEM; - goto __error; - } - buffer->curr = buffer->buffer; + if (buffer == NULL) + goto __nomem; data->wbuffer = buffer; + buffer->len = PAGE_SIZE; + buffer->buffer = kmalloc(buffer->len, GFP_KERNEL); + if (buffer->buffer == NULL) + goto __nomem; } break; case SNDRV_INFO_CONTENT_DATA: /* data */ @@ -377,6 +378,17 @@ static int snd_info_entry_open(struct inode *inode, struct file *file) } return 0; + __nomem: + if (data->rbuffer) { + kfree(data->rbuffer->buffer); + kfree(data->rbuffer); + } + if (data->wbuffer) { + kfree(data->wbuffer->buffer); + kfree(data->wbuffer); + } + kfree(data); + err = -ENOMEM; __error: module_put(entry->module); __error1: @@ -395,11 +407,11 @@ static int snd_info_entry_release(struct inode *inode, struct file *file) entry = data->entry; switch (entry->content) { case SNDRV_INFO_CONTENT_TEXT: - if (mode == O_RDONLY || mode == O_RDWR) { - vfree(data->rbuffer->buffer); + if (data->rbuffer) { + kfree(data->rbuffer->buffer); kfree(data->rbuffer); } - if (mode == O_WRONLY || mode == O_RDWR) { + if (data->wbuffer) { if (entry->c.text.write) { entry->c.text.write(entry, data->wbuffer); if (data->wbuffer->error) { @@ -408,7 +420,7 @@ static int snd_info_entry_release(struct inode *inode, struct file *file) data->wbuffer->error); } } - vfree(data->wbuffer->buffer); + kfree(data->wbuffer->buffer); kfree(data->wbuffer); } break; @@ -668,24 +680,22 @@ int snd_info_get_line(struct snd_info_buffer *buffer, char *line, int len) if (len <= 0 || buffer->stop || buffer->error) return 1; while (--len > 0) { - c = *buffer->curr++; + c = buffer->buffer[buffer->curr++]; if (c == '\n') { - if ((buffer->curr - buffer->buffer) >= (long)buffer->size) { + if (buffer->curr >= buffer->size) buffer->stop = 1; - } break; } *line++ = c; - if ((buffer->curr - buffer->buffer) >= (long)buffer->size) { + if (buffer->curr >= buffer->size) { buffer->stop = 1; break; } } while (c != '\n' && !buffer->stop) { - c = *buffer->curr++; - if ((buffer->curr - buffer->buffer) >= (long)buffer->size) { + c = buffer->buffer[buffer->curr++]; + if (buffer->curr >= buffer->size) buffer->stop = 1; - } } *line = '\0'; return 0; @@ -978,7 +988,6 @@ static int __init snd_info_version_init(void) entry = snd_info_create_module_entry(THIS_MODULE, "version", NULL); if (entry == NULL) return -ENOMEM; - entry->c.text.read_size = 256; entry->c.text.read = snd_info_version_read; if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); -- cgit v1.2.3 From bf850204a71a97eb5a6afaf27263bb667f9cab0a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 28 Apr 2006 15:13:41 +0200 Subject: [ALSA] Remove unneeded read/write_size fields in proc text ops Remove unneeded read/write_size fields in proc text ops. snd_info_set_text_ops() is fixed, too. Signed-off-by: Takashi Iwai --- .../sound/alsa/DocBook/writing-an-alsa-driver.tmpl | 19 +-------------- include/sound/info.h | 5 ---- sound/core/hwdep.c | 1 - sound/core/info_oss.c | 1 - sound/core/init.c | 3 --- sound/core/oss/mixer_oss.c | 2 -- sound/core/oss/pcm_oss.c | 2 -- sound/core/pcm.c | 19 +++++++-------- sound/core/pcm_memory.c | 2 -- sound/core/rawmidi.c | 1 - sound/core/seq/oss/seq_oss.c | 1 - sound/core/seq/seq_device.c | 1 - sound/core/seq/seq_info.c | 11 ++++----- sound/core/sound.c | 1 - sound/core/sound_oss.c | 1 - sound/core/timer.c | 1 - sound/drivers/vx/vx_core.c | 2 +- sound/i2c/l3/uda1341.c | 4 ++-- sound/isa/gus/gus_irq.c | 2 +- sound/isa/gus/gus_mem.c | 6 ++--- sound/isa/opti9xx/miro.c | 2 +- sound/isa/sb/sb16_csp.c | 2 +- sound/pci/ac97/ac97_proc.c | 5 ++-- sound/pci/ac97/ak4531_codec.c | 2 +- sound/pci/ad1889.c | 2 +- sound/pci/ali5451/ali5451.c | 2 +- sound/pci/atiixp.c | 2 +- sound/pci/atiixp_modem.c | 2 +- sound/pci/ca0106/ca0106_proc.c | 17 ++++++-------- sound/pci/cmipci.c | 2 +- sound/pci/cs4281.c | 2 +- sound/pci/cs46xx/dsp_spos.c | 7 ------ sound/pci/cs46xx/dsp_spos_scb_lib.c | 1 - sound/pci/emu10k1/emu10k1x.c | 3 +-- sound/pci/emu10k1/emuproc.c | 27 ++++++++-------------- sound/pci/ens1370.c | 2 +- sound/pci/hda/hda_proc.c | 2 +- sound/pci/ice1712/ice1712.c | 2 +- sound/pci/ice1712/ice1724.c | 2 +- sound/pci/ice1712/pontis.c | 8 +++---- sound/pci/intel8x0.c | 2 +- sound/pci/intel8x0m.c | 2 +- sound/pci/korg1212/korg1212.c | 2 +- sound/pci/mixart/mixart.c | 1 - sound/pci/pcxhr/pcxhr.c | 4 ++-- sound/pci/riptide/riptide.c | 2 +- sound/pci/rme32.c | 2 +- sound/pci/rme96.c | 2 +- sound/pci/rme9652/hdsp.c | 2 +- sound/pci/rme9652/hdspm.c | 2 +- sound/pci/rme9652/rme9652.c | 2 +- sound/pci/sonicvibes.c | 2 +- sound/pci/trident/trident_main.c | 2 +- sound/pci/via82xx.c | 2 +- sound/pci/via82xx_modem.c | 2 +- sound/pci/ymfpci/ymfpci_main.c | 2 +- sound/pcmcia/pdaudiocf/pdaudiocf_core.c | 2 +- sound/sparc/dbri.c | 4 ++-- sound/synth/emux/emux_proc.c | 1 - sound/usb/usbaudio.c | 6 ++--- sound/usb/usbmixer.c | 2 +- 61 files changed, 81 insertions(+), 146 deletions(-) (limited to 'include') diff --git a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl index 1faf76383bab..db557f91ab79 100644 --- a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl +++ b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl @@ -5333,7 +5333,7 @@ struct _snd_pcm_runtime { @@ -5394,29 +5394,12 @@ struct _snd_pcm_runtime { c.text.write_size = 256; entry->c.text.write = my_proc_write; ]]> - - The buffer size for read is set to 1024 implicitly by - snd_info_set_text_ops(). It should suffice - in most cases (the size will be aligned to - PAGE_SIZE anyway), but if you need to handle - very large text files, you can set it explicitly, too. - - - -c.text.read_size = 65536; -]]> - - - - For the write callback, you can use snd_info_get_line() to get a text line, and diff --git a/include/sound/info.h b/include/sound/info.h index 481284389855..74f6996769c7 100644 --- a/include/sound/info.h +++ b/include/sound/info.h @@ -40,8 +40,6 @@ struct snd_info_buffer { struct snd_info_entry; struct snd_info_entry_text { - unsigned long read_size; - unsigned long write_size; void (*read) (struct snd_info_entry *entry, struct snd_info_buffer *buffer); void (*write) (struct snd_info_entry *entry, struct snd_info_buffer *buffer); }; @@ -132,11 +130,9 @@ int snd_card_proc_new(struct snd_card *card, const char *name, struct snd_info_e static inline void snd_info_set_text_ops(struct snd_info_entry *entry, void *private_data, - long read_size, void (*read)(struct snd_info_entry *, struct snd_info_buffer *)) { entry->private_data = private_data; - entry->c.text.read_size = read_size; entry->c.text.read = read; } @@ -167,7 +163,6 @@ static inline int snd_card_proc_new(struct snd_card *card, const char *name, struct snd_info_entry **entryp) { return -EINVAL; } static inline void snd_info_set_text_ops(struct snd_info_entry *entry __attribute__((unused)), void *private_data, - long read_size, void (*read)(struct snd_info_entry *, struct snd_info_buffer *)) {} static inline int snd_info_check_reserved_words(const char *str) { return 1; } diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c index 2524e66eccdd..8bd0dcc93eba 100644 --- a/sound/core/hwdep.c +++ b/sound/core/hwdep.c @@ -486,7 +486,6 @@ static void __init snd_hwdep_proc_init(void) struct snd_info_entry *entry; if ((entry = snd_info_create_module_entry(THIS_MODULE, "hwdep", NULL)) != NULL) { - entry->c.text.read_size = PAGE_SIZE; entry->c.text.read = snd_hwdep_proc_read; if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); diff --git a/sound/core/info_oss.c b/sound/core/info_oss.c index f2efca18728c..bb2c40d0ab66 100644 --- a/sound/core/info_oss.c +++ b/sound/core/info_oss.c @@ -119,7 +119,6 @@ int snd_info_minor_register(void) memset(snd_sndstat_strings, 0, sizeof(snd_sndstat_strings)); if ((entry = snd_info_create_module_entry(THIS_MODULE, "sndstat", snd_oss_root)) != NULL) { - entry->c.text.read_size = 2048; entry->c.text.read = snd_sndstat_proc_read; if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); diff --git a/sound/core/init.c b/sound/core/init.c index b145d17ba3b2..2ff0e5e90865 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -69,7 +69,6 @@ static inline int init_info_for_card(struct snd_card *card) snd_printd("unable to create card entry\n"); return err; } - entry->c.text.read_size = PAGE_SIZE; entry->c.text.read = snd_card_id_read; if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); @@ -592,7 +591,6 @@ int __init snd_card_info_init(void) entry = snd_info_create_module_entry(THIS_MODULE, "cards", NULL); if (! entry) return -ENOMEM; - entry->c.text.read_size = PAGE_SIZE; entry->c.text.read = snd_card_info_read; if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); @@ -603,7 +601,6 @@ int __init snd_card_info_init(void) #ifdef MODULE entry = snd_info_create_module_entry(THIS_MODULE, "modules", NULL); if (entry) { - entry->c.text.read_size = PAGE_SIZE; entry->c.text.read = snd_card_module_info_read; if (snd_info_register(entry) < 0) snd_info_free_entry(entry); diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index 9c68bc3f97aa..71b5080fa66d 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c @@ -1182,9 +1182,7 @@ static void snd_mixer_oss_proc_init(struct snd_mixer_oss *mixer) return; entry->content = SNDRV_INFO_CONTENT_TEXT; entry->mode = S_IFREG | S_IRUGO | S_IWUSR; - entry->c.text.read_size = 8192; entry->c.text.read = snd_mixer_oss_proc_read; - entry->c.text.write_size = 8192; entry->c.text.write = snd_mixer_oss_proc_write; entry->private_data = mixer; if (snd_info_register(entry) < 0) { diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 0d2e232afe6c..d8b7416ee003 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -2823,9 +2823,7 @@ static void snd_pcm_oss_proc_init(struct snd_pcm *pcm) if ((entry = snd_info_create_card_entry(pcm->card, "oss", pstr->proc_root)) != NULL) { entry->content = SNDRV_INFO_CONTENT_TEXT; entry->mode = S_IFREG | S_IRUGO | S_IWUSR; - entry->c.text.read_size = 8192; entry->c.text.read = snd_pcm_oss_proc_read; - entry->c.text.write_size = 8192; entry->c.text.write = snd_pcm_oss_proc_write; entry->private_data = pstr; if (snd_info_register(entry) < 0) { diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 8c15c01907f4..08223783cfa3 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -472,7 +472,7 @@ static int snd_pcm_stream_proc_init(struct snd_pcm_str *pstr) pstr->proc_root = entry; if ((entry = snd_info_create_card_entry(pcm->card, "info", pstr->proc_root)) != NULL) { - snd_info_set_text_ops(entry, pstr, 256, snd_pcm_stream_proc_info_read); + snd_info_set_text_ops(entry, pstr, snd_pcm_stream_proc_info_read); if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); entry = NULL; @@ -483,9 +483,7 @@ static int snd_pcm_stream_proc_init(struct snd_pcm_str *pstr) #ifdef CONFIG_SND_PCM_XRUN_DEBUG if ((entry = snd_info_create_card_entry(pcm->card, "xrun_debug", pstr->proc_root)) != NULL) { - entry->c.text.read_size = 64; entry->c.text.read = snd_pcm_xrun_debug_read; - entry->c.text.write_size = 64; entry->c.text.write = snd_pcm_xrun_debug_write; entry->mode |= S_IWUSR; entry->private_data = pstr; @@ -537,7 +535,8 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream) substream->proc_root = entry; if ((entry = snd_info_create_card_entry(card, "info", substream->proc_root)) != NULL) { - snd_info_set_text_ops(entry, substream, 256, snd_pcm_substream_proc_info_read); + snd_info_set_text_ops(entry, substream, + snd_pcm_substream_proc_info_read); if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); entry = NULL; @@ -546,7 +545,8 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream) substream->proc_info_entry = entry; if ((entry = snd_info_create_card_entry(card, "hw_params", substream->proc_root)) != NULL) { - snd_info_set_text_ops(entry, substream, 256, snd_pcm_substream_proc_hw_params_read); + snd_info_set_text_ops(entry, substream, + snd_pcm_substream_proc_hw_params_read); if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); entry = NULL; @@ -555,7 +555,8 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream) substream->proc_hw_params_entry = entry; if ((entry = snd_info_create_card_entry(card, "sw_params", substream->proc_root)) != NULL) { - snd_info_set_text_ops(entry, substream, 256, snd_pcm_substream_proc_sw_params_read); + snd_info_set_text_ops(entry, substream, + snd_pcm_substream_proc_sw_params_read); if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); entry = NULL; @@ -564,7 +565,8 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream) substream->proc_sw_params_entry = entry; if ((entry = snd_info_create_card_entry(card, "status", substream->proc_root)) != NULL) { - snd_info_set_text_ops(entry, substream, 256, snd_pcm_substream_proc_status_read); + snd_info_set_text_ops(entry, substream, + snd_pcm_substream_proc_status_read); if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); entry = NULL; @@ -1062,8 +1064,7 @@ static void snd_pcm_proc_init(void) struct snd_info_entry *entry; if ((entry = snd_info_create_module_entry(THIS_MODULE, "pcm", NULL)) != NULL) { - snd_info_set_text_ops(entry, NULL, SNDRV_CARDS * SNDRV_PCM_DEVICES * 128, - snd_pcm_proc_read); + snd_info_set_text_ops(entry, NULL, snd_pcm_proc_read); if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); entry = NULL; diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index eb56167d3bb4..067d2056db9a 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -193,9 +193,7 @@ static inline void preallocate_info_init(struct snd_pcm_substream *substream) struct snd_info_entry *entry; if ((entry = snd_info_create_card_entry(substream->pcm->card, "prealloc", substream->proc_root)) != NULL) { - entry->c.text.read_size = 64; entry->c.text.read = snd_pcm_lib_preallocate_proc_read; - entry->c.text.write_size = 64; entry->c.text.write = snd_pcm_lib_preallocate_proc_write; entry->mode |= S_IWUSR; entry->private_data = substream; diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 87b47c9564f7..08a41e5023cd 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -1561,7 +1561,6 @@ static int snd_rawmidi_dev_register(struct snd_device *device) entry = snd_info_create_card_entry(rmidi->card, name, rmidi->card->proc_root); if (entry) { entry->private_data = rmidi; - entry->c.text.read_size = 1024; entry->c.text.read = snd_rawmidi_proc_info_read; if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); diff --git a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c index b9919785180b..e7234135641c 100644 --- a/sound/core/seq/oss/seq_oss.c +++ b/sound/core/seq/oss/seq_oss.c @@ -291,7 +291,6 @@ register_proc(void) entry->content = SNDRV_INFO_CONTENT_TEXT; entry->private_data = NULL; - entry->c.text.read_size = 1024; entry->c.text.read = info_read; if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c index d9a3e5a18d6a..1e4bc402f00f 100644 --- a/sound/core/seq/seq_device.c +++ b/sound/core/seq/seq_device.c @@ -555,7 +555,6 @@ static int __init alsa_seq_device_init(void) if (info_entry == NULL) return -ENOMEM; info_entry->content = SNDRV_INFO_CONTENT_TEXT; - info_entry->c.text.read_size = 2048; info_entry->c.text.read = snd_seq_device_info; if (snd_info_register(info_entry) < 0) { snd_info_free_entry(info_entry); diff --git a/sound/core/seq/seq_info.c b/sound/core/seq/seq_info.c index acce21afdaa4..142e9e6882c9 100644 --- a/sound/core/seq/seq_info.c +++ b/sound/core/seq/seq_info.c @@ -34,8 +34,8 @@ static struct snd_info_entry *timer_entry; static struct snd_info_entry * __init -create_info_entry(char *name, int size, void (*read)(struct snd_info_entry *, - struct snd_info_buffer *)) +create_info_entry(char *name, void (*read)(struct snd_info_entry *, + struct snd_info_buffer *)) { struct snd_info_entry *entry; @@ -43,7 +43,6 @@ create_info_entry(char *name, int size, void (*read)(struct snd_info_entry *, if (entry == NULL) return NULL; entry->content = SNDRV_INFO_CONTENT_TEXT; - entry->c.text.read_size = size; entry->c.text.read = read; if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); @@ -55,11 +54,11 @@ create_info_entry(char *name, int size, void (*read)(struct snd_info_entry *, /* create all our /proc entries */ int __init snd_seq_info_init(void) { - queues_entry = create_info_entry("queues", 512 + (256 * SNDRV_SEQ_MAX_QUEUES), + queues_entry = create_info_entry("queues", snd_seq_info_queues_read); - clients_entry = create_info_entry("clients", 512 + (256 * SNDRV_SEQ_MAX_CLIENTS), + clients_entry = create_info_entry("clients", snd_seq_info_clients_read); - timer_entry = create_info_entry("timer", 1024, snd_seq_info_timer_read); + timer_entry = create_info_entry("timer", snd_seq_info_timer_read); return 0; } diff --git a/sound/core/sound.c b/sound/core/sound.c index 67cfa06062b8..8313f97907d8 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c @@ -392,7 +392,6 @@ int __init snd_minor_info_init(void) entry = snd_info_create_module_entry(THIS_MODULE, "devices", NULL); if (entry) { - entry->c.text.read_size = PAGE_SIZE; entry->c.text.read = snd_minor_info_read; if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); diff --git a/sound/core/sound_oss.c b/sound/core/sound_oss.c index c18f6a45e4d9..0043c9a97de6 100644 --- a/sound/core/sound_oss.c +++ b/sound/core/sound_oss.c @@ -258,7 +258,6 @@ int __init snd_minor_info_oss_init(void) entry = snd_info_create_module_entry(THIS_MODULE, "devices", snd_oss_root); if (entry) { - entry->c.text.read_size = PAGE_SIZE; entry->c.text.read = snd_minor_info_oss_read; if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); diff --git a/sound/core/timer.c b/sound/core/timer.c index cdeeb639b675..9a1e51c7c230 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -1117,7 +1117,6 @@ static void __init snd_timer_proc_init(void) entry = snd_info_create_module_entry(THIS_MODULE, "timers", NULL); if (entry != NULL) { - entry->c.text.read_size = SNDRV_TIMER_DEVICES * 128; entry->c.text.read = snd_timer_proc_read; if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); diff --git a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c index e1c3dda15774..a60168268ddd 100644 --- a/sound/drivers/vx/vx_core.c +++ b/sound/drivers/vx/vx_core.c @@ -640,7 +640,7 @@ static void vx_proc_init(struct vx_core *chip) struct snd_info_entry *entry; if (! snd_card_proc_new(chip->card, "vx-status", &entry)) - snd_info_set_text_ops(entry, chip, 1024, vx_proc_read); + snd_info_set_text_ops(entry, chip, vx_proc_read); } diff --git a/sound/i2c/l3/uda1341.c b/sound/i2c/l3/uda1341.c index 746500e06950..b074fdddea55 100644 --- a/sound/i2c/l3/uda1341.c +++ b/sound/i2c/l3/uda1341.c @@ -517,9 +517,9 @@ static void __devinit snd_uda1341_proc_init(struct snd_card *card, struct l3_cli struct snd_info_entry *entry; if (! snd_card_proc_new(card, "uda1341", &entry)) - snd_info_set_text_ops(entry, clnt, 1024, snd_uda1341_proc_read); + snd_info_set_text_ops(entry, clnt, snd_uda1341_proc_read); if (! snd_card_proc_new(card, "uda1341-regs", &entry)) - snd_info_set_text_ops(entry, clnt, 1024, snd_uda1341_proc_regs_read); + snd_info_set_text_ops(entry, clnt, snd_uda1341_proc_regs_read); } /* }}} */ diff --git a/sound/isa/gus/gus_irq.c b/sound/isa/gus/gus_irq.c index c19ba2910b72..42db37552efb 100644 --- a/sound/isa/gus/gus_irq.c +++ b/sound/isa/gus/gus_irq.c @@ -136,7 +136,7 @@ void snd_gus_irq_profile_init(struct snd_gus_card *gus) struct snd_info_entry *entry; if (! snd_card_proc_new(gus->card, "gusirq", &entry)) - snd_info_set_text_ops(entry, gus, 1024, snd_gus_irq_info_read); + snd_info_set_text_ops(entry, gus, snd_gus_irq_info_read); } #endif diff --git a/sound/isa/gus/gus_mem.c b/sound/isa/gus/gus_mem.c index 3c0d27aa08b3..f50c276caee8 100644 --- a/sound/isa/gus/gus_mem.c +++ b/sound/isa/gus/gus_mem.c @@ -264,10 +264,8 @@ int snd_gf1_mem_init(struct snd_gus_card * gus) if (snd_gf1_mem_xalloc(alloc, &block) == NULL) return -ENOMEM; #ifdef CONFIG_SND_DEBUG - if (! snd_card_proc_new(gus->card, "gusmem", &entry)) { - snd_info_set_text_ops(entry, gus, 1024, snd_gf1_mem_info_read); - entry->c.text.read_size = 256 * 1024; - } + if (! snd_card_proc_new(gus->card, "gusmem", &entry)) + snd_info_set_text_ops(entry, gus, snd_gf1_mem_info_read); #endif return 0; } diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c index e6bfcf74c1c1..283817f2de75 100644 --- a/sound/isa/opti9xx/miro.c +++ b/sound/isa/opti9xx/miro.c @@ -967,7 +967,7 @@ static void __init snd_miro_proc_init(struct snd_miro * miro) struct snd_info_entry *entry; if (! snd_card_proc_new(miro->card, "miro", &entry)) - snd_info_set_text_ops(entry, miro, 1024, snd_miro_proc_read); + snd_info_set_text_ops(entry, miro, snd_miro_proc_read); } /* diff --git a/sound/isa/sb/sb16_csp.c b/sound/isa/sb/sb16_csp.c index 9703c68e4e08..fcd638090a9e 100644 --- a/sound/isa/sb/sb16_csp.c +++ b/sound/isa/sb/sb16_csp.c @@ -1101,7 +1101,7 @@ static int init_proc_entry(struct snd_sb_csp * p, int device) struct snd_info_entry *entry; sprintf(name, "cspD%d", device); if (! snd_card_proc_new(p->chip->card, name, &entry)) - snd_info_set_text_ops(entry, p, 1024, info_read); + snd_info_set_text_ops(entry, p, info_read); return 0; } diff --git a/sound/pci/ac97/ac97_proc.c b/sound/pci/ac97/ac97_proc.c index 4d523df79cc7..2118df50b9d6 100644 --- a/sound/pci/ac97/ac97_proc.c +++ b/sound/pci/ac97/ac97_proc.c @@ -433,7 +433,7 @@ void snd_ac97_proc_init(struct snd_ac97 * ac97) prefix = ac97_is_audio(ac97) ? "ac97" : "mc97"; sprintf(name, "%s#%d-%d", prefix, ac97->addr, ac97->num); if ((entry = snd_info_create_card_entry(ac97->bus->card, name, ac97->bus->proc)) != NULL) { - snd_info_set_text_ops(entry, ac97, 1024, snd_ac97_proc_read); + snd_info_set_text_ops(entry, ac97, snd_ac97_proc_read); if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); entry = NULL; @@ -442,10 +442,9 @@ void snd_ac97_proc_init(struct snd_ac97 * ac97) ac97->proc = entry; sprintf(name, "%s#%d-%d+regs", prefix, ac97->addr, ac97->num); if ((entry = snd_info_create_card_entry(ac97->bus->card, name, ac97->bus->proc)) != NULL) { - snd_info_set_text_ops(entry, ac97, 1024, snd_ac97_proc_regs_read); + snd_info_set_text_ops(entry, ac97, snd_ac97_proc_regs_read); #ifdef CONFIG_SND_DEBUG entry->mode |= S_IWUSR; - entry->c.text.write_size = 1024; entry->c.text.write = snd_ac97_proc_regs_write; #endif if (snd_info_register(entry) < 0) { diff --git a/sound/pci/ac97/ak4531_codec.c b/sound/pci/ac97/ak4531_codec.c index 0fb7b3407312..94c26ec05882 100644 --- a/sound/pci/ac97/ak4531_codec.c +++ b/sound/pci/ac97/ak4531_codec.c @@ -453,7 +453,7 @@ static void snd_ak4531_proc_init(struct snd_card *card, struct snd_ak4531 *ak453 struct snd_info_entry *entry; if (! snd_card_proc_new(card, "ak4531", &entry)) - snd_info_set_text_ops(entry, ak4531, 1024, snd_ak4531_proc_read); + snd_info_set_text_ops(entry, ak4531, snd_ak4531_proc_read); } #endif diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c index eece1c7e55a0..d42bf4570367 100644 --- a/sound/pci/ad1889.c +++ b/sound/pci/ad1889.c @@ -753,7 +753,7 @@ snd_ad1889_proc_init(struct snd_ad1889 *chip) struct snd_info_entry *entry; if (!snd_card_proc_new(chip->card, chip->card->driver, &entry)) - snd_info_set_text_ops(entry, chip, 1024, snd_ad1889_proc_read); + snd_info_set_text_ops(entry, chip, snd_ad1889_proc_read); } static struct ac97_quirk ac97_quirks[] = { diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c index e2dbc2118902..4f01ef10fac2 100644 --- a/sound/pci/ali5451/ali5451.c +++ b/sound/pci/ali5451/ali5451.c @@ -2173,7 +2173,7 @@ static void __devinit snd_ali_proc_init(struct snd_ali *codec) { struct snd_info_entry *entry; if(!snd_card_proc_new(codec->card, "ali5451", &entry)) - snd_info_set_text_ops(entry, codec, 1024, snd_ali_proc_read); + snd_info_set_text_ops(entry, codec, snd_ali_proc_read); } static int __devinit snd_ali_resources(struct snd_ali *codec) diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index d0f759d86d3d..f18a8c0e4688 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c @@ -1504,7 +1504,7 @@ static void __devinit snd_atiixp_proc_init(struct atiixp *chip) struct snd_info_entry *entry; if (! snd_card_proc_new(chip->card, "atiixp", &entry)) - snd_info_set_text_ops(entry, chip, 1024, snd_atiixp_proc_read); + snd_info_set_text_ops(entry, chip, snd_atiixp_proc_read); } #else /* !CONFIG_PROC_FS */ #define snd_atiixp_proc_init(chip) diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c index 12a34c39caa7..40739057076b 100644 --- a/sound/pci/atiixp_modem.c +++ b/sound/pci/atiixp_modem.c @@ -1177,7 +1177,7 @@ static void __devinit snd_atiixp_proc_init(struct atiixp_modem *chip) struct snd_info_entry *entry; if (! snd_card_proc_new(chip->card, "atiixp-modem", &entry)) - snd_info_set_text_ops(entry, chip, 1024, snd_atiixp_proc_read); + snd_info_set_text_ops(entry, chip, snd_atiixp_proc_read); } #else #define snd_atiixp_proc_init(chip) diff --git a/sound/pci/ca0106/ca0106_proc.c b/sound/pci/ca0106/ca0106_proc.c index 63757273bfb7..75ca421eb3a1 100644 --- a/sound/pci/ca0106/ca0106_proc.c +++ b/sound/pci/ca0106/ca0106_proc.c @@ -431,33 +431,30 @@ int __devinit snd_ca0106_proc_init(struct snd_ca0106 * emu) struct snd_info_entry *entry; if(! snd_card_proc_new(emu->card, "iec958", &entry)) - snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_iec958); + snd_info_set_text_ops(entry, emu, snd_ca0106_proc_iec958); if(! snd_card_proc_new(emu->card, "ca0106_reg32", &entry)) { - snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_reg_read32); - entry->c.text.write_size = 64; + snd_info_set_text_ops(entry, emu, snd_ca0106_proc_reg_read32); entry->c.text.write = snd_ca0106_proc_reg_write32; entry->mode |= S_IWUSR; } if(! snd_card_proc_new(emu->card, "ca0106_reg16", &entry)) - snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_reg_read16); + snd_info_set_text_ops(entry, emu, snd_ca0106_proc_reg_read16); if(! snd_card_proc_new(emu->card, "ca0106_reg8", &entry)) - snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_reg_read8); + snd_info_set_text_ops(entry, emu, snd_ca0106_proc_reg_read8); if(! snd_card_proc_new(emu->card, "ca0106_regs1", &entry)) { - snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_reg_read1); - entry->c.text.write_size = 64; + snd_info_set_text_ops(entry, emu, snd_ca0106_proc_reg_read1); entry->c.text.write = snd_ca0106_proc_reg_write; entry->mode |= S_IWUSR; // entry->private_data = emu; } if(! snd_card_proc_new(emu->card, "ca0106_i2c", &entry)) { - snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_i2c_write); - entry->c.text.write_size = 64; + snd_info_set_text_ops(entry, emu, snd_ca0106_proc_i2c_write); entry->c.text.write = snd_ca0106_proc_i2c_write; entry->mode |= S_IWUSR; // entry->private_data = emu; } if(! snd_card_proc_new(emu->card, "ca0106_regs2", &entry)) - snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_reg_read2); + snd_info_set_text_ops(entry, emu, snd_ca0106_proc_reg_read2); return 0; } diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index e5ce2dabd081..42ca92be18f9 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -2602,7 +2602,7 @@ static void __devinit snd_cmipci_proc_init(struct cmipci *cm) struct snd_info_entry *entry; if (! snd_card_proc_new(cm->card, "cmipci", &entry)) - snd_info_set_text_ops(entry, cm, 1024, snd_cmipci_proc_read); + snd_info_set_text_ops(entry, cm, snd_cmipci_proc_read); } #else /* !CONFIG_PROC_FS */ static inline void snd_cmipci_proc_init(struct cmipci *cm) {} diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index b3c94d83450a..8c150eab45b6 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c @@ -1184,7 +1184,7 @@ static void __devinit snd_cs4281_proc_init(struct cs4281 * chip) struct snd_info_entry *entry; if (! snd_card_proc_new(chip->card, "cs4281", &entry)) - snd_info_set_text_ops(entry, chip, 1024, snd_cs4281_proc_read); + snd_info_set_text_ops(entry, chip, snd_cs4281_proc_read); if (! snd_card_proc_new(chip->card, "cs4281_BA0", &entry)) { entry->content = SNDRV_INFO_CONTENT_DATA; entry->private_data = chip; diff --git a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c index f407d2a5ce3b..5c9711c0265c 100644 --- a/sound/pci/cs46xx/dsp_spos.c +++ b/sound/pci/cs46xx/dsp_spos.c @@ -767,7 +767,6 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip) if ((entry = snd_info_create_card_entry(card, "dsp", card->proc_root)) != NULL) { entry->content = SNDRV_INFO_CONTENT_TEXT; entry->mode = S_IFDIR | S_IRUGO | S_IXUGO; - entry->c.text.read_size = 512; if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); @@ -784,7 +783,6 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip) entry->content = SNDRV_INFO_CONTENT_TEXT; entry->private_data = chip; entry->mode = S_IFREG | S_IRUGO | S_IWUSR; - entry->c.text.read_size = 512; entry->c.text.read = cs46xx_dsp_proc_symbol_table_read; if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); @@ -797,7 +795,6 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip) entry->content = SNDRV_INFO_CONTENT_TEXT; entry->private_data = chip; entry->mode = S_IFREG | S_IRUGO | S_IWUSR; - entry->c.text.read_size = 512; entry->c.text.read = cs46xx_dsp_proc_modules_read; if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); @@ -810,7 +807,6 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip) entry->content = SNDRV_INFO_CONTENT_TEXT; entry->private_data = chip; entry->mode = S_IFREG | S_IRUGO | S_IWUSR; - entry->c.text.read_size = 512; entry->c.text.read = cs46xx_dsp_proc_parameter_dump_read; if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); @@ -823,7 +819,6 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip) entry->content = SNDRV_INFO_CONTENT_TEXT; entry->private_data = chip; entry->mode = S_IFREG | S_IRUGO | S_IWUSR; - entry->c.text.read_size = 512; entry->c.text.read = cs46xx_dsp_proc_sample_dump_read; if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); @@ -836,7 +831,6 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip) entry->content = SNDRV_INFO_CONTENT_TEXT; entry->private_data = chip; entry->mode = S_IFREG | S_IRUGO | S_IWUSR; - entry->c.text.read_size = 512; entry->c.text.read = cs46xx_dsp_proc_task_tree_read; if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); @@ -849,7 +843,6 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip) entry->content = SNDRV_INFO_CONTENT_TEXT; entry->private_data = chip; entry->mode = S_IFREG | S_IRUGO | S_IWUSR; - entry->c.text.read_size = 1024; entry->c.text.read = cs46xx_dsp_proc_scb_read; if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); diff --git a/sound/pci/cs46xx/dsp_spos_scb_lib.c b/sound/pci/cs46xx/dsp_spos_scb_lib.c index 2c4ee45fe10c..3844d18af19c 100644 --- a/sound/pci/cs46xx/dsp_spos_scb_lib.c +++ b/sound/pci/cs46xx/dsp_spos_scb_lib.c @@ -267,7 +267,6 @@ void cs46xx_dsp_proc_register_scb_desc (struct snd_cs46xx *chip, entry->private_data = scb_info; entry->mode = S_IFREG | S_IRUGO | S_IWUSR; - entry->c.text.read_size = 512; entry->c.text.read = cs46xx_dsp_proc_scb_info_read; if (snd_info_register(entry) < 0) { diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index d51290c18167..0fb27e4be07b 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c @@ -1055,8 +1055,7 @@ static int __devinit snd_emu10k1x_proc_init(struct emu10k1x * emu) struct snd_info_entry *entry; if(! snd_card_proc_new(emu->card, "emu10k1x_regs", &entry)) { - snd_info_set_text_ops(entry, emu, 1024, snd_emu10k1x_proc_reg_read); - entry->c.text.write_size = 64; + snd_info_set_text_ops(entry, emu, snd_emu10k1x_proc_reg_read); entry->c.text.write = snd_emu10k1x_proc_reg_write; entry->mode |= S_IWUSR; entry->private_data = emu; diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c index 90f1c52703a1..b939e03aaedf 100644 --- a/sound/pci/emu10k1/emuproc.c +++ b/sound/pci/emu10k1/emuproc.c @@ -532,57 +532,51 @@ int __devinit snd_emu10k1_proc_init(struct snd_emu10k1 * emu) struct snd_info_entry *entry; #ifdef CONFIG_SND_DEBUG if (! snd_card_proc_new(emu->card, "io_regs", &entry)) { - snd_info_set_text_ops(entry, emu, 1024, snd_emu_proc_io_reg_read); - entry->c.text.write_size = 64; + snd_info_set_text_ops(entry, emu, snd_emu_proc_io_reg_read); entry->c.text.write = snd_emu_proc_io_reg_write; entry->mode |= S_IWUSR; } if (! snd_card_proc_new(emu->card, "ptr_regs00a", &entry)) { - snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read00a); - entry->c.text.write_size = 64; + snd_info_set_text_ops(entry, emu, snd_emu_proc_ptr_reg_read00a); entry->c.text.write = snd_emu_proc_ptr_reg_write00; entry->mode |= S_IWUSR; } if (! snd_card_proc_new(emu->card, "ptr_regs00b", &entry)) { - snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read00b); - entry->c.text.write_size = 64; + snd_info_set_text_ops(entry, emu, snd_emu_proc_ptr_reg_read00b); entry->c.text.write = snd_emu_proc_ptr_reg_write00; entry->mode |= S_IWUSR; } if (! snd_card_proc_new(emu->card, "ptr_regs20a", &entry)) { - snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read20a); - entry->c.text.write_size = 64; + snd_info_set_text_ops(entry, emu, snd_emu_proc_ptr_reg_read20a); entry->c.text.write = snd_emu_proc_ptr_reg_write20; entry->mode |= S_IWUSR; } if (! snd_card_proc_new(emu->card, "ptr_regs20b", &entry)) { - snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read20b); - entry->c.text.write_size = 64; + snd_info_set_text_ops(entry, emu, snd_emu_proc_ptr_reg_read20b); entry->c.text.write = snd_emu_proc_ptr_reg_write20; entry->mode |= S_IWUSR; } if (! snd_card_proc_new(emu->card, "ptr_regs20c", &entry)) { - snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read20c); - entry->c.text.write_size = 64; + snd_info_set_text_ops(entry, emu, snd_emu_proc_ptr_reg_read20c); entry->c.text.write = snd_emu_proc_ptr_reg_write20; entry->mode |= S_IWUSR; } #endif if (! snd_card_proc_new(emu->card, "emu10k1", &entry)) - snd_info_set_text_ops(entry, emu, 2048, snd_emu10k1_proc_read); + snd_info_set_text_ops(entry, emu, snd_emu10k1_proc_read); if (emu->card_capabilities->emu10k2_chip) { if (! snd_card_proc_new(emu->card, "spdif-in", &entry)) - snd_info_set_text_ops(entry, emu, 2048, snd_emu10k1_proc_spdif_read); + snd_info_set_text_ops(entry, emu, snd_emu10k1_proc_spdif_read); } if (emu->card_capabilities->ca0151_chip) { if (! snd_card_proc_new(emu->card, "capture-rates", &entry)) - snd_info_set_text_ops(entry, emu, 2048, snd_emu10k1_proc_rates_read); + snd_info_set_text_ops(entry, emu, snd_emu10k1_proc_rates_read); } if (! snd_card_proc_new(emu->card, "voices", &entry)) - snd_info_set_text_ops(entry, emu, 2048, snd_emu10k1_proc_voices_read); + snd_info_set_text_ops(entry, emu, snd_emu10k1_proc_voices_read); if (! snd_card_proc_new(emu->card, "fx8010_gpr", &entry)) { entry->content = SNDRV_INFO_CONTENT_DATA; @@ -616,7 +610,6 @@ int __devinit snd_emu10k1_proc_init(struct snd_emu10k1 * emu) entry->content = SNDRV_INFO_CONTENT_TEXT; entry->private_data = emu; entry->mode = S_IFREG | S_IRUGO /*| S_IWUSR*/; - entry->c.text.read_size = 128*1024; entry->c.text.read = snd_emu10k1_proc_acode_read; } return 0; diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index ca9e34e88f62..9d46bbee2a40 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c @@ -1915,7 +1915,7 @@ static void __devinit snd_ensoniq_proc_init(struct ensoniq * ensoniq) struct snd_info_entry *entry; if (! snd_card_proc_new(ensoniq->card, "audiopci", &entry)) - snd_info_set_text_ops(entry, ensoniq, 1024, snd_ensoniq_proc_read); + snd_info_set_text_ops(entry, ensoniq, snd_ensoniq_proc_read); } /* diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index ca514a6a5875..3db009990c5f 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -318,7 +318,7 @@ int snd_hda_codec_proc_new(struct hda_codec *codec) if (err < 0) return err; - snd_info_set_text_ops(entry, codec, 32 * 1024, print_codec_info); + snd_info_set_text_ops(entry, codec, print_codec_info); return 0; } diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index 2821014b26e9..52de85e21b95 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c @@ -1596,7 +1596,7 @@ static void __devinit snd_ice1712_proc_init(struct snd_ice1712 * ice) struct snd_info_entry *entry; if (! snd_card_proc_new(ice->card, "ice1712", &entry)) - snd_info_set_text_ops(entry, ice, 1024, snd_ice1712_proc_read); + snd_info_set_text_ops(entry, ice, snd_ice1712_proc_read); } /* diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index b1c007e022d2..1031bcbf7064 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -1293,7 +1293,7 @@ static void __devinit snd_vt1724_proc_init(struct snd_ice1712 * ice) struct snd_info_entry *entry; if (! snd_card_proc_new(ice->card, "ice1724", &entry)) - snd_info_set_text_ops(entry, ice, 1024, snd_vt1724_proc_read); + snd_info_set_text_ops(entry, ice, snd_vt1724_proc_read); } /* diff --git a/sound/pci/ice1712/pontis.c b/sound/pci/ice1712/pontis.c index d23fb3fc2133..0efcad9260a5 100644 --- a/sound/pci/ice1712/pontis.c +++ b/sound/pci/ice1712/pontis.c @@ -680,9 +680,8 @@ static void wm_proc_init(struct snd_ice1712 *ice) { struct snd_info_entry *entry; if (! snd_card_proc_new(ice->card, "wm_codec", &entry)) { - snd_info_set_text_ops(entry, ice, 1024, wm_proc_regs_read); + snd_info_set_text_ops(entry, ice, wm_proc_regs_read); entry->mode |= S_IWUSR; - entry->c.text.write_size = 1024; entry->c.text.write = wm_proc_regs_write; } } @@ -705,9 +704,8 @@ static void cs_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buff static void cs_proc_init(struct snd_ice1712 *ice) { struct snd_info_entry *entry; - if (! snd_card_proc_new(ice->card, "cs_codec", &entry)) { - snd_info_set_text_ops(entry, ice, 1024, cs_proc_regs_read); - } + if (! snd_card_proc_new(ice->card, "cs_codec", &entry)) + snd_info_set_text_ops(entry, ice, cs_proc_regs_read); } diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 0df7602568e2..a4e5b8115a6c 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -2645,7 +2645,7 @@ static void __devinit snd_intel8x0_proc_init(struct intel8x0 * chip) struct snd_info_entry *entry; if (! snd_card_proc_new(chip->card, "intel8x0", &entry)) - snd_info_set_text_ops(entry, chip, 1024, snd_intel8x0_proc_read); + snd_info_set_text_ops(entry, chip, snd_intel8x0_proc_read); } #else #define snd_intel8x0_proc_init(x) diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index 720635f0cb81..20acb1a7e92c 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c @@ -1092,7 +1092,7 @@ static void __devinit snd_intel8x0m_proc_init(struct intel8x0m * chip) struct snd_info_entry *entry; if (! snd_card_proc_new(chip->card, "intel8x0m", &entry)) - snd_info_set_text_ops(entry, chip, 1024, snd_intel8x0m_proc_read); + snd_info_set_text_ops(entry, chip, snd_intel8x0m_proc_read); } #else /* !CONFIG_PROC_FS */ #define snd_intel8x0m_proc_init(chip) diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c index e39fad1a4200..6e97932de34f 100644 --- a/sound/pci/korg1212/korg1212.c +++ b/sound/pci/korg1212/korg1212.c @@ -2085,7 +2085,7 @@ static void __devinit snd_korg1212_proc_init(struct snd_korg1212 *korg1212) struct snd_info_entry *entry; if (! snd_card_proc_new(korg1212->card, "korg1212", &entry)) - snd_info_set_text_ops(entry, korg1212, 1024, snd_korg1212_proc_read); + snd_info_set_text_ops(entry, korg1212, snd_korg1212_proc_read); } static int diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c index 09cc0786495a..366c4a7e65c6 100644 --- a/sound/pci/mixart/mixart.c +++ b/sound/pci/mixart/mixart.c @@ -1244,7 +1244,6 @@ static void __devinit snd_mixart_proc_init(struct snd_mixart *chip) /* text interface to read perf and temp meters */ if (! snd_card_proc_new(chip->card, "board_info", &entry)) { entry->private_data = chip; - entry->c.text.read_size = 1024; entry->c.text.read = snd_mixart_proc_read; } diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c index dafa2235abaa..8198884b51ee 100644 --- a/sound/pci/pcxhr/pcxhr.c +++ b/sound/pci/pcxhr/pcxhr.c @@ -1150,9 +1150,9 @@ static void __devinit pcxhr_proc_init(struct snd_pcxhr *chip) struct snd_info_entry *entry; if (! snd_card_proc_new(chip->card, "info", &entry)) - snd_info_set_text_ops(entry, chip, 1024, pcxhr_proc_info); + snd_info_set_text_ops(entry, chip, pcxhr_proc_info); if (! snd_card_proc_new(chip->card, "sync", &entry)) - snd_info_set_text_ops(entry, chip, 1024, pcxhr_proc_sync); + snd_info_set_text_ops(entry, chip, pcxhr_proc_sync); } /* end of proc interface */ diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index d8cc985d7241..c27cd4999777 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c @@ -1992,7 +1992,7 @@ static void __devinit snd_riptide_proc_init(struct snd_riptide *chip) struct snd_info_entry *entry; if (!snd_card_proc_new(chip->card, "riptide", &entry)) - snd_info_set_text_ops(entry, chip, 4096, snd_riptide_proc_read); + snd_info_set_text_ops(entry, chip, snd_riptide_proc_read); } static int __devinit snd_riptide_mixer(struct snd_riptide *chip) diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c index 55b1d4838d97..4dd53bfe0308 100644 --- a/sound/pci/rme32.c +++ b/sound/pci/rme32.c @@ -1578,7 +1578,7 @@ static void __devinit snd_rme32_proc_init(struct rme32 * rme32) struct snd_info_entry *entry; if (! snd_card_proc_new(rme32->card, "rme32", &entry)) - snd_info_set_text_ops(entry, rme32, 1024, snd_rme32_proc_read); + snd_info_set_text_ops(entry, rme32, snd_rme32_proc_read); } /* diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index 3c1bc533d511..75a8b754ef28 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c @@ -1805,7 +1805,7 @@ snd_rme96_proc_init(struct rme96 *rme96) struct snd_info_entry *entry; if (! snd_card_proc_new(rme96->card, "rme96", &entry)) - snd_info_set_text_ops(entry, rme96, 1024, snd_rme96_proc_read); + snd_info_set_text_ops(entry, rme96, snd_rme96_proc_read); } /* diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 61f82f0d5cc6..da63a1a19958 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -3470,7 +3470,7 @@ static void __devinit snd_hdsp_proc_init(struct hdsp *hdsp) struct snd_info_entry *entry; if (! snd_card_proc_new(hdsp->card, "hdsp", &entry)) - snd_info_set_text_ops(entry, hdsp, 1024, snd_hdsp_proc_read); + snd_info_set_text_ops(entry, hdsp, snd_hdsp_proc_read); } static void snd_hdsp_free_buffers(struct hdsp *hdsp) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 722b9e6ce54a..bba1615504d3 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -2489,7 +2489,7 @@ static void __devinit snd_hdspm_proc_init(struct hdspm * hdspm) struct snd_info_entry *entry; if (!snd_card_proc_new(hdspm->card, "hdspm", &entry)) - snd_info_set_text_ops(entry, hdspm, 1024, + snd_info_set_text_ops(entry, hdspm, snd_hdspm_proc_read); } diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c index 75d6406303d3..ac14b2733f7c 100644 --- a/sound/pci/rme9652/rme9652.c +++ b/sound/pci/rme9652/rme9652.c @@ -1787,7 +1787,7 @@ static void __devinit snd_rme9652_proc_init(struct snd_rme9652 *rme9652) struct snd_info_entry *entry; if (! snd_card_proc_new(rme9652->card, "rme9652", &entry)) - snd_info_set_text_ops(entry, rme9652, 1024, snd_rme9652_proc_read); + snd_info_set_text_ops(entry, rme9652, snd_rme9652_proc_read); } static void snd_rme9652_free_buffers(struct snd_rme9652 *rme9652) diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c index 91f8bf3ae9fa..a78304172921 100644 --- a/sound/pci/sonicvibes.c +++ b/sound/pci/sonicvibes.c @@ -1144,7 +1144,7 @@ static void __devinit snd_sonicvibes_proc_init(struct sonicvibes * sonic) struct snd_info_entry *entry; if (! snd_card_proc_new(sonic->card, "sonicvibes", &entry)) - snd_info_set_text_ops(entry, sonic, 1024, snd_sonicvibes_proc_read); + snd_info_set_text_ops(entry, sonic, snd_sonicvibes_proc_read); } /* diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c index 850579208e49..d99ed7237750 100644 --- a/sound/pci/trident/trident_main.c +++ b/sound/pci/trident/trident_main.c @@ -3338,7 +3338,7 @@ static void __devinit snd_trident_proc_init(struct snd_trident * trident) if (trident->device == TRIDENT_DEVICE_ID_SI7018) s = "sis7018"; if (! snd_card_proc_new(trident->card, s, &entry)) - snd_info_set_text_ops(entry, trident, 1024, snd_trident_proc_read); + snd_info_set_text_ops(entry, trident, snd_trident_proc_read); } static int snd_trident_dev_free(struct snd_device *device) diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 39daf62d2bad..a1b777e79c59 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -2015,7 +2015,7 @@ static void __devinit snd_via82xx_proc_init(struct via82xx *chip) struct snd_info_entry *entry; if (! snd_card_proc_new(chip->card, "via82xx", &entry)) - snd_info_set_text_ops(entry, chip, 1024, snd_via82xx_proc_read); + snd_info_set_text_ops(entry, chip, snd_via82xx_proc_read); } /* diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c index ef97e50cd6c2..577a2b03759f 100644 --- a/sound/pci/via82xx_modem.c +++ b/sound/pci/via82xx_modem.c @@ -929,7 +929,7 @@ static void __devinit snd_via82xx_proc_init(struct via82xx_modem *chip) struct snd_info_entry *entry; if (! snd_card_proc_new(chip->card, "via82xx", &entry)) - snd_info_set_text_ops(entry, chip, 1024, snd_via82xx_proc_read); + snd_info_set_text_ops(entry, chip, snd_via82xx_proc_read); } /* diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index 8ac5ab50b5c7..f894752523bb 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c @@ -1919,7 +1919,7 @@ static int __devinit snd_ymfpci_proc_init(struct snd_card *card, struct snd_ymfp struct snd_info_entry *entry; if (! snd_card_proc_new(card, "ymfpci", &entry)) - snd_info_set_text_ops(entry, chip, 1024, snd_ymfpci_proc_read); + snd_info_set_text_ops(entry, chip, snd_ymfpci_proc_read); return 0; } diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_core.c b/sound/pcmcia/pdaudiocf/pdaudiocf_core.c index bd0d70ff3019..1dfe29b863d3 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf_core.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf_core.c @@ -144,7 +144,7 @@ static void pdacf_proc_init(struct snd_pdacf *chip) struct snd_info_entry *entry; if (! snd_card_proc_new(chip->card, "pdaudiocf", &entry)) - snd_info_set_text_ops(entry, chip, 1024, pdacf_proc_read); + snd_info_set_text_ops(entry, chip, pdacf_proc_read); } struct snd_pdacf *snd_pdacf_create(struct snd_card *card) diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c index e622d08215c9..db6539126d27 100644 --- a/sound/sparc/dbri.c +++ b/sound/sparc/dbri.c @@ -2521,11 +2521,11 @@ void snd_dbri_proc(struct snd_dbri * dbri) struct snd_info_entry *entry; if (! snd_card_proc_new(dbri->card, "regs", &entry)) - snd_info_set_text_ops(entry, dbri, 1024, dbri_regs_read); + snd_info_set_text_ops(entry, dbri, dbri_regs_read); #ifdef DBRI_DEBUG if (! snd_card_proc_new(dbri->card, "debug", &entry)) { - snd_info_set_text_ops(entry, dbri, 4096, dbri_debug_read); + snd_info_set_text_ops(entry, dbri, dbri_debug_read); entry->mode = S_IFREG | S_IRUGO; /* Readable only. */ } #endif diff --git a/sound/synth/emux/emux_proc.c b/sound/synth/emux/emux_proc.c index 1ba68ce30279..58b9601f3ad0 100644 --- a/sound/synth/emux/emux_proc.c +++ b/sound/synth/emux/emux_proc.c @@ -119,7 +119,6 @@ void snd_emux_proc_init(struct snd_emux *emu, struct snd_card *card, int device) entry->content = SNDRV_INFO_CONTENT_TEXT; entry->private_data = emu; - entry->c.text.read_size = 1024; entry->c.text.read = snd_emux_proc_info_read; if (snd_info_register(entry) < 0) snd_info_free_entry(entry); diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 4e614ac39f21..8100516e1f79 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -2138,7 +2138,7 @@ static void proc_pcm_format_add(struct snd_usb_stream *stream) sprintf(name, "stream%d", stream->pcm_index); if (! snd_card_proc_new(card, name, &entry)) - snd_info_set_text_ops(entry, stream, 1024, proc_pcm_format_read); + snd_info_set_text_ops(entry, stream, proc_pcm_format_read); } #else @@ -3197,9 +3197,9 @@ static void snd_usb_audio_create_proc(struct snd_usb_audio *chip) { struct snd_info_entry *entry; if (! snd_card_proc_new(chip->card, "usbbus", &entry)) - snd_info_set_text_ops(entry, chip, 1024, proc_audio_usbbus_read); + snd_info_set_text_ops(entry, chip, proc_audio_usbbus_read); if (! snd_card_proc_new(chip->card, "usbid", &entry)) - snd_info_set_text_ops(entry, chip, 1024, proc_audio_usbid_read); + snd_info_set_text_ops(entry, chip, proc_audio_usbid_read); } /* diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index ce86283ee0fa..ab921aa9d77a 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -1998,7 +1998,7 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif) if ((err = snd_audigy2nx_controls_create(mixer)) < 0) goto _error; if (!snd_card_proc_new(chip->card, "audigy2nx", &entry)) - snd_info_set_text_ops(entry, mixer, 1024, + snd_info_set_text_ops(entry, mixer, snd_audigy2nx_proc_read); } -- cgit v1.2.3 From 0df63e44c3e315ec0fe427ae62558231864108bd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 28 Apr 2006 15:13:41 +0200 Subject: [ALSA] Add O_APPEND flag support to PCM Added O_APPEND flag support to PCM to enable shared substreams among multiple processes. This mechanism is used by dmix and dsnoop plugins. Signed-off-by: Takashi Iwai --- include/sound/asound.h | 2 +- include/sound/pcm.h | 5 ++- sound/core/oss/pcm_oss.c | 17 +++++---- sound/core/pcm.c | 25 ++++++++++++- sound/core/pcm_compat.c | 4 +- sound/core/pcm_lib.c | 8 ++-- sound/core/pcm_native.c | 81 ++++++++++++++++++++++++++++------------- sound/usb/usx2y/usx2yhwdeppcm.c | 2 +- 8 files changed, 99 insertions(+), 45 deletions(-) (limited to 'include') diff --git a/include/sound/asound.h b/include/sound/asound.h index 9cc021c7ee11..41885f48ad91 100644 --- a/include/sound/asound.h +++ b/include/sound/asound.h @@ -137,7 +137,7 @@ enum { * * *****************************************************************************/ -#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 7) +#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 8) typedef unsigned long snd_pcm_uframes_t; typedef signed long snd_pcm_sframes_t; diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 998bacefc8f8..cebf0310a8dc 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -368,7 +368,8 @@ struct snd_pcm_substream { struct snd_pcm_group *group; /* pointer to current group */ /* -- assigned files -- */ void *file; - struct file *ffile; + int ref_count; + unsigned int f_flags; void (*pcm_release)(struct snd_pcm_substream *); #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) /* -- OSS things -- */ @@ -387,7 +388,7 @@ struct snd_pcm_substream { unsigned int hw_opened: 1; }; -#define SUBSTREAM_BUSY(substream) ((substream)->file != NULL) +#define SUBSTREAM_BUSY(substream) ((substream)->ref_count > 0) struct snd_pcm_str { diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index d8b7416ee003..9803a6ce3d46 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -1331,7 +1331,7 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha if (runtime->oss.period_ptr == 0 || runtime->oss.period_ptr == runtime->oss.buffer_used) runtime->oss.buffer_used = 0; - else if ((substream->ffile->f_flags & O_NONBLOCK) != 0) + else if ((substream->f_flags & O_NONBLOCK) != 0) return xfer > 0 ? xfer : -EAGAIN; } } else { @@ -1344,7 +1344,7 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha buf += tmp; bytes -= tmp; xfer += tmp; - if ((substream->ffile->f_flags & O_NONBLOCK) != 0 && + if ((substream->f_flags & O_NONBLOCK) != 0 && tmp != runtime->oss.period_bytes) break; } @@ -1582,10 +1582,10 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file) * finish sync: drain the buffer */ __direct: - saved_f_flags = substream->ffile->f_flags; - substream->ffile->f_flags &= ~O_NONBLOCK; + saved_f_flags = substream->f_flags; + substream->f_flags &= ~O_NONBLOCK; err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL); - substream->ffile->f_flags = saved_f_flags; + substream->f_flags = saved_f_flags; if (err < 0) return err; runtime->oss.prepare = 1; @@ -2164,9 +2164,9 @@ static void snd_pcm_oss_init_substream(struct snd_pcm_substream *substream, substream->oss.oss = 1; substream->oss.setup = *setup; if (setup->nonblock) - substream->ffile->f_flags |= O_NONBLOCK; + substream->f_flags |= O_NONBLOCK; else if (setup->block) - substream->ffile->f_flags &= ~O_NONBLOCK; + substream->f_flags &= ~O_NONBLOCK; runtime = substream->runtime; runtime->oss.params = 1; runtime->oss.trigger = 1; @@ -2223,6 +2223,7 @@ static int snd_pcm_oss_open_file(struct file *file, (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX)) f_mode = FMODE_WRITE; + file->f_flags &= ~O_APPEND; for (idx = 0; idx < 2; idx++) { if (setup[idx].disable) continue; @@ -2540,6 +2541,7 @@ static ssize_t snd_pcm_oss_read(struct file *file, char __user *buf, size_t coun substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE]; if (substream == NULL) return -ENXIO; + substream->f_flags = file->f_flags & O_NONBLOCK; #ifndef OSS_DEBUG return snd_pcm_oss_read1(substream, buf, count); #else @@ -2561,6 +2563,7 @@ static ssize_t snd_pcm_oss_write(struct file *file, const char __user *buf, size substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; if (substream == NULL) return -ENXIO; + substream->f_flags = file->f_flags & O_NONBLOCK; result = snd_pcm_oss_write1(substream, buf, count); #ifdef OSS_DEBUG printk("pcm_oss: write %li bytes (wrote %li bytes)\n", (long)count, (long)result); diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 4f5204175d37..8136be2e6066 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -829,6 +829,26 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, return -EINVAL; } + if (file->f_flags & O_APPEND) { + if (prefer_subdevice < 0) { + if (pstr->substream_count > 1) + return -EINVAL; /* must be unique */ + substream = pstr->substream; + } else { + for (substream = pstr->substream; substream; + substream = substream->next) + if (substream->number == prefer_subdevice) + break; + } + if (! substream) + return -ENODEV; + if (! SUBSTREAM_BUSY(substream)) + return -EBADFD; + substream->ref_count++; + *rsubstream = substream; + return 0; + } + if (prefer_subdevice >= 0) { for (substream = pstr->substream; substream; substream = substream->next) if (!SUBSTREAM_BUSY(substream) && substream->number == prefer_subdevice) @@ -873,7 +893,8 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, substream->runtime = runtime; substream->private_data = pcm->private_data; - substream->ffile = file; + substream->ref_count = 1; + substream->f_flags = file->f_flags; pstr->substream_opened++; *rsubstream = substream; return 0; @@ -882,7 +903,7 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, void snd_pcm_detach_substream(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime; - substream->file = NULL; + runtime = substream->runtime; snd_assert(runtime != NULL, return); if (runtime->private_free != NULL) diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c index e5133033de5e..2b8aab6fd6cd 100644 --- a/sound/core/pcm_compat.c +++ b/sound/core/pcm_compat.c @@ -497,9 +497,9 @@ static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned l case SNDRV_PCM_IOCTL_LINK: case SNDRV_PCM_IOCTL_UNLINK: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - return snd_pcm_playback_ioctl1(substream, cmd, argp); + return snd_pcm_playback_ioctl1(file, substream, cmd, argp); else - return snd_pcm_capture_ioctl1(substream, cmd, argp); + return snd_pcm_capture_ioctl1(file, substream, cmd, argp); case SNDRV_PCM_IOCTL_HW_REFINE32: return snd_pcm_ioctl_hw_params_compat(substream, 1, argp); case SNDRV_PCM_IOCTL_HW_PARAMS32: diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index a21aa0050e4d..0bb142a28539 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -1782,7 +1782,7 @@ snd_pcm_sframes_t snd_pcm_lib_write(struct snd_pcm_substream *substream, const v if (runtime->status->state == SNDRV_PCM_STATE_OPEN) return -EBADFD; - nonblock = !!(substream->ffile->f_flags & O_NONBLOCK); + nonblock = !!(substream->f_flags & O_NONBLOCK); if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED && runtime->channels > 1) @@ -1847,7 +1847,7 @@ snd_pcm_sframes_t snd_pcm_lib_writev(struct snd_pcm_substream *substream, if (runtime->status->state == SNDRV_PCM_STATE_OPEN) return -EBADFD; - nonblock = !!(substream->ffile->f_flags & O_NONBLOCK); + nonblock = !!(substream->f_flags & O_NONBLOCK); if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) return -EINVAL; @@ -2059,7 +2059,7 @@ snd_pcm_sframes_t snd_pcm_lib_read(struct snd_pcm_substream *substream, void __u if (runtime->status->state == SNDRV_PCM_STATE_OPEN) return -EBADFD; - nonblock = !!(substream->ffile->f_flags & O_NONBLOCK); + nonblock = !!(substream->f_flags & O_NONBLOCK); if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED) return -EINVAL; return snd_pcm_lib_read1(substream, (unsigned long)buf, size, nonblock, snd_pcm_lib_read_transfer); @@ -2118,7 +2118,7 @@ snd_pcm_sframes_t snd_pcm_lib_readv(struct snd_pcm_substream *substream, if (runtime->status->state == SNDRV_PCM_STATE_OPEN) return -EBADFD; - nonblock = !!(substream->ffile->f_flags & O_NONBLOCK); + nonblock = !!(substream->f_flags & O_NONBLOCK); if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) return -EINVAL; return snd_pcm_lib_read1(substream, (unsigned long)bufs, frames, nonblock, snd_pcm_lib_readv_transfer); diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 7b5729c4b213..36d6765618a4 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1284,13 +1284,16 @@ static int snd_pcm_reset(struct snd_pcm_substream *substream) /* * prepare ioctl */ -static int snd_pcm_pre_prepare(struct snd_pcm_substream *substream, int state) +/* we use the second argument for updating f_flags */ +static int snd_pcm_pre_prepare(struct snd_pcm_substream *substream, + int f_flags) { struct snd_pcm_runtime *runtime = substream->runtime; if (runtime->status->state == SNDRV_PCM_STATE_OPEN) return -EBADFD; if (snd_pcm_running(substream)) return -EBUSY; + substream->f_flags = f_flags; return 0; } @@ -1319,17 +1322,26 @@ static struct action_ops snd_pcm_action_prepare = { /** * snd_pcm_prepare * @substream: the PCM substream instance + * @file: file to refer f_flags * * Prepare the PCM substream to be triggerable. */ -static int snd_pcm_prepare(struct snd_pcm_substream *substream) +static int snd_pcm_prepare(struct snd_pcm_substream *substream, + struct file *file) { int res; struct snd_card *card = substream->pcm->card; + int f_flags; + + if (file) + f_flags = file->f_flags; + else + f_flags = substream->f_flags; snd_power_lock(card); if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0)) >= 0) - res = snd_pcm_action_nonatomic(&snd_pcm_action_prepare, substream, 0); + res = snd_pcm_action_nonatomic(&snd_pcm_action_prepare, + substream, f_flags); snd_power_unlock(card); return res; } @@ -1340,7 +1352,7 @@ static int snd_pcm_prepare(struct snd_pcm_substream *substream) static int snd_pcm_pre_drain_init(struct snd_pcm_substream *substream, int state) { - if (substream->ffile->f_flags & O_NONBLOCK) + if (substream->f_flags & O_NONBLOCK) return -EAGAIN; substream->runtime->trigger_master = substream; return 0; @@ -2015,6 +2027,10 @@ static void pcm_release_private(struct snd_pcm_substream *substream) void snd_pcm_release_substream(struct snd_pcm_substream *substream) { + substream->ref_count--; + if (substream->ref_count > 0) + return; + snd_pcm_drop(substream); if (substream->hw_opened) { if (substream->ops->hw_free != NULL) @@ -2041,6 +2057,11 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream, err = snd_pcm_attach_substream(pcm, stream, file, &substream); if (err < 0) return err; + if (substream->ref_count > 1) { + *rsubstream = substream; + return 0; + } + substream->no_mmap_ctrl = 0; err = snd_pcm_hw_constraints_init(substream); if (err < 0) { @@ -2086,17 +2107,20 @@ static int snd_pcm_open_file(struct file *file, if (err < 0) return err; - pcm_file = kzalloc(sizeof(*pcm_file), GFP_KERNEL); - if (pcm_file == NULL) { - snd_pcm_release_substream(substream); - return -ENOMEM; + if (substream->ref_count > 1) + pcm_file = substream->file; + else { + pcm_file = kzalloc(sizeof(*pcm_file), GFP_KERNEL); + if (pcm_file == NULL) { + snd_pcm_release_substream(substream); + return -ENOMEM; + } + str = substream->pstr; + substream->file = pcm_file; + substream->pcm_release = pcm_release_private; + pcm_file->substream = substream; + snd_pcm_add_file(str, pcm_file); } - str = substream->pstr; - substream->file = pcm_file; - substream->pcm_release = pcm_release_private; - pcm_file->substream = substream; - snd_pcm_add_file(str, pcm_file); - file->private_data = pcm_file; *rpcm_file = pcm_file; return 0; @@ -2506,7 +2530,8 @@ static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream, return 0; } -static int snd_pcm_common_ioctl1(struct snd_pcm_substream *substream, +static int snd_pcm_common_ioctl1(struct file *file, + struct snd_pcm_substream *substream, unsigned int cmd, void __user *arg) { snd_assert(substream != NULL, return -ENXIO); @@ -2531,7 +2556,7 @@ static int snd_pcm_common_ioctl1(struct snd_pcm_substream *substream, case SNDRV_PCM_IOCTL_CHANNEL_INFO: return snd_pcm_channel_info_user(substream, arg); case SNDRV_PCM_IOCTL_PREPARE: - return snd_pcm_prepare(substream); + return snd_pcm_prepare(substream, file); case SNDRV_PCM_IOCTL_RESET: return snd_pcm_reset(substream); case SNDRV_PCM_IOCTL_START: @@ -2573,7 +2598,8 @@ static int snd_pcm_common_ioctl1(struct snd_pcm_substream *substream, return -ENOTTY; } -static int snd_pcm_playback_ioctl1(struct snd_pcm_substream *substream, +static int snd_pcm_playback_ioctl1(struct file *file, + struct snd_pcm_substream *substream, unsigned int cmd, void __user *arg) { snd_assert(substream != NULL, return -ENXIO); @@ -2649,10 +2675,11 @@ static int snd_pcm_playback_ioctl1(struct snd_pcm_substream *substream, return result < 0 ? result : 0; } } - return snd_pcm_common_ioctl1(substream, cmd, arg); + return snd_pcm_common_ioctl1(file, substream, cmd, arg); } -static int snd_pcm_capture_ioctl1(struct snd_pcm_substream *substream, +static int snd_pcm_capture_ioctl1(struct file *file, + struct snd_pcm_substream *substream, unsigned int cmd, void __user *arg) { snd_assert(substream != NULL, return -ENXIO); @@ -2728,7 +2755,7 @@ static int snd_pcm_capture_ioctl1(struct snd_pcm_substream *substream, return result < 0 ? result : 0; } } - return snd_pcm_common_ioctl1(substream, cmd, arg); + return snd_pcm_common_ioctl1(file, substream, cmd, arg); } static long snd_pcm_playback_ioctl(struct file *file, unsigned int cmd, @@ -2741,7 +2768,8 @@ static long snd_pcm_playback_ioctl(struct file *file, unsigned int cmd, if (((cmd >> 8) & 0xff) != 'A') return -ENOTTY; - return snd_pcm_playback_ioctl1(pcm_file->substream, cmd, (void __user *)arg); + return snd_pcm_playback_ioctl1(file, pcm_file->substream, cmd, + (void __user *)arg); } static long snd_pcm_capture_ioctl(struct file *file, unsigned int cmd, @@ -2754,7 +2782,8 @@ static long snd_pcm_capture_ioctl(struct file *file, unsigned int cmd, if (((cmd >> 8) & 0xff) != 'A') return -ENOTTY; - return snd_pcm_capture_ioctl1(pcm_file->substream, cmd, (void __user *)arg); + return snd_pcm_capture_ioctl1(file, pcm_file->substream, cmd, + (void __user *)arg); } int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream, @@ -2766,12 +2795,12 @@ int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream, fs = snd_enter_user(); switch (substream->stream) { case SNDRV_PCM_STREAM_PLAYBACK: - result = snd_pcm_playback_ioctl1(substream, - cmd, (void __user *)arg); + result = snd_pcm_playback_ioctl1(NULL, substream, cmd, + (void __user *)arg); break; case SNDRV_PCM_STREAM_CAPTURE: - result = snd_pcm_capture_ioctl1(substream, - cmd, (void __user *)arg); + result = snd_pcm_capture_ioctl1(NULL, substream, cmd, + (void __user *)arg); break; default: result = -EINVAL; diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c index fe67a92e2a1a..88b72b52590f 100644 --- a/sound/usb/usx2y/usx2yhwdeppcm.c +++ b/sound/usb/usx2y/usx2yhwdeppcm.c @@ -632,7 +632,7 @@ static int usX2Y_pcms_lock_check(struct snd_card *card) for (s = 0; s < 2; ++s) { struct snd_pcm_substream *substream; substream = pcm->streams[s].substream; - if (substream && substream->ffile != NULL) + if (SUBSTREAM_BUSY(substream)) err = -EBUSY; } } -- cgit v1.2.3 From 9c323fcbc51493f79f9700cb20830d0857c72d99 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 28 Apr 2006 15:13:41 +0200 Subject: [ALSA] Fix mmap_count with O_APPEND opened streams Move mmap_count to snd_pcm_substream instead of runtime struct so that multiplly opened substreams via O_APPEND can be handled correctly. Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 6 +++--- sound/core/oss/pcm_oss.c | 27 ++++++++++++++------------- sound/core/pcm.c | 2 +- sound/core/pcm_native.c | 10 +++++----- 4 files changed, 23 insertions(+), 22 deletions(-) (limited to 'include') diff --git a/include/sound/pcm.h b/include/sound/pcm.h index cebf0310a8dc..f84d84993a31 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -300,7 +300,6 @@ struct snd_pcm_runtime { /* -- mmap -- */ volatile struct snd_pcm_mmap_status *status; volatile struct snd_pcm_mmap_control *control; - atomic_t mmap_count; /* -- locking / scheduling -- */ wait_queue_head_t sleep; @@ -369,6 +368,7 @@ struct snd_pcm_substream { /* -- assigned files -- */ void *file; int ref_count; + atomic_t mmap_count; unsigned int f_flags; void (*pcm_release)(struct snd_pcm_substream *); #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) @@ -972,13 +972,13 @@ struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, unsigne static inline void snd_pcm_mmap_data_open(struct vm_area_struct *area) { struct snd_pcm_substream *substream = (struct snd_pcm_substream *)area->vm_private_data; - atomic_inc(&substream->runtime->mmap_count); + atomic_inc(&substream->mmap_count); } static inline void snd_pcm_mmap_data_close(struct vm_area_struct *area) { struct snd_pcm_substream *substream = (struct snd_pcm_substream *)area->vm_private_data; - atomic_dec(&substream->runtime->mmap_count); + atomic_dec(&substream->mmap_count); } /* mmap for io-memory area */ diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 9803a6ce3d46..4395285aa6a3 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -684,7 +684,7 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream, oss_buffer_size = snd_pcm_plug_client_size(substream, snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, NULL)) * oss_frame_size; oss_buffer_size = 1 << ld2(oss_buffer_size); - if (atomic_read(&runtime->mmap_count)) { + if (atomic_read(&substream->mmap_count)) { if (oss_buffer_size > runtime->oss.mmap_bytes) oss_buffer_size = runtime->oss.mmap_bytes; } @@ -819,7 +819,7 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream) goto failure; } - if (atomic_read(&runtime->mmap_count)) + if (atomic_read(&substream->mmap_count)) direct = 1; else direct = substream->oss.setup.direct; @@ -828,7 +828,7 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream) _snd_pcm_hw_param_setinteger(sparams, SNDRV_PCM_HW_PARAM_PERIODS); _snd_pcm_hw_param_min(sparams, SNDRV_PCM_HW_PARAM_PERIODS, 2, 0); snd_mask_none(&mask); - if (atomic_read(&runtime->mmap_count)) + if (atomic_read(&substream->mmap_count)) snd_mask_set(&mask, SNDRV_PCM_ACCESS_MMAP_INTERLEAVED); else { snd_mask_set(&mask, SNDRV_PCM_ACCESS_RW_INTERLEAVED); @@ -947,7 +947,8 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream) } else { sw_params->start_threshold = runtime->boundary; } - if (atomic_read(&runtime->mmap_count) || substream->stream == SNDRV_PCM_STREAM_CAPTURE) + if (atomic_read(&substream->mmap_count) || + substream->stream == SNDRV_PCM_STREAM_CAPTURE) sw_params->stop_threshold = runtime->boundary; else sw_params->stop_threshold = runtime->buffer_size; @@ -957,7 +958,7 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream) sw_params->avail_min = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 1 : runtime->period_size; sw_params->xfer_align = 1; - if (atomic_read(&runtime->mmap_count) || + if (atomic_read(&substream->mmap_count) || substream->oss.setup.nosilence) { sw_params->silence_threshold = 0; sw_params->silence_size = 0; @@ -1301,7 +1302,7 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha ssize_t tmp; struct snd_pcm_runtime *runtime = substream->runtime; - if (atomic_read(&runtime->mmap_count)) + if (atomic_read(&substream->mmap_count)) return -ENXIO; if ((tmp = snd_pcm_oss_make_ready(substream)) < 0) @@ -1391,7 +1392,7 @@ static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __use ssize_t tmp; struct snd_pcm_runtime *runtime = substream->runtime; - if (atomic_read(&runtime->mmap_count)) + if (atomic_read(&substream->mmap_count)) return -ENXIO; if ((tmp = snd_pcm_oss_make_ready(substream)) < 0) @@ -1521,7 +1522,7 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file) substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; if (substream != NULL) { runtime = substream->runtime; - if (atomic_read(&runtime->mmap_count)) + if (atomic_read(&substream->mmap_count)) goto __direct; if ((err = snd_pcm_oss_make_ready(substream)) < 0) return err; @@ -1690,7 +1691,7 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file) if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0) return err; - if (atomic_read(&substream->runtime->mmap_count)) + if (atomic_read(&substream->mmap_count)) direct = 1; else direct = substream->oss.setup.direct; @@ -1900,7 +1901,7 @@ static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int tr if (trigger & PCM_ENABLE_OUTPUT) { if (runtime->oss.trigger) goto _skip1; - if (atomic_read(&psubstream->runtime->mmap_count)) + if (atomic_read(&psubstream->mmap_count)) snd_pcm_oss_simulate_fill(psubstream, runtime->hw_ptr_interrupt); runtime->oss.trigger = 1; runtime->start_threshold = 1; @@ -2018,7 +2019,7 @@ static int snd_pcm_oss_get_ptr(struct snd_pcm_oss_file *pcm_oss_file, int stream if (err < 0) return err; info.ptr = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr % runtime->buffer_size); - if (atomic_read(&runtime->mmap_count)) { + if (atomic_read(&substream->mmap_count)) { snd_pcm_sframes_t n; n = (delay = runtime->hw_ptr_interrupt) - runtime->oss.prev_hw_ptr_interrupt; if (n < 0) @@ -2574,7 +2575,7 @@ static ssize_t snd_pcm_oss_write(struct file *file, const char __user *buf, size static int snd_pcm_oss_playback_ready(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; - if (atomic_read(&runtime->mmap_count)) + if (atomic_read(&substream->mmap_count)) return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt; else return snd_pcm_playback_avail(runtime) >= runtime->oss.period_frames; @@ -2583,7 +2584,7 @@ static int snd_pcm_oss_playback_ready(struct snd_pcm_substream *substream) static int snd_pcm_oss_capture_ready(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; - if (atomic_read(&runtime->mmap_count)) + if (atomic_read(&substream->mmap_count)) return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt; else return snd_pcm_capture_avail(runtime) >= runtime->oss.period_frames; diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 8136be2e6066..bc00f9b00cbd 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -662,6 +662,7 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count) INIT_LIST_HEAD(&substream->self_group.substreams); list_add_tail(&substream->link_list, &substream->self_group.substreams); spin_lock_init(&substream->timer_lock); + atomic_set(&substream->mmap_count, 0); prev = substream; } return 0; @@ -884,7 +885,6 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, memset((void*)runtime->control, 0, size); init_waitqueue_head(&runtime->sleep); - atomic_set(&runtime->mmap_count, 0); init_timer(&runtime->tick_timer); runtime->tick_timer.function = snd_pcm_tick_timer_func; runtime->tick_timer.data = (unsigned long) substream; diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 36d6765618a4..a998f88e3f30 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -372,7 +372,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) if (!substream->oss.oss) #endif - if (atomic_read(&runtime->mmap_count)) + if (atomic_read(&substream->mmap_count)) return -EBADFD; params->rmask = ~0U; @@ -485,7 +485,7 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream) return -EBADFD; } snd_pcm_stream_unlock_irq(substream); - if (atomic_read(&runtime->mmap_count)) + if (atomic_read(&substream->mmap_count)) return -EBADFD; if (substream->ops->hw_free) result = substream->ops->hw_free(substream); @@ -2207,7 +2207,7 @@ static int snd_pcm_release(struct inode *inode, struct file *file) pcm_file = file->private_data; substream = pcm_file->substream; snd_assert(substream != NULL, return -ENXIO); - snd_assert(!atomic_read(&substream->runtime->mmap_count), ); + snd_assert(!atomic_read(&substream->mmap_count), ); pcm = substream->pcm; fasync_helper(-1, file, 0, &substream->runtime->fasync); mutex_lock(&pcm->open_mutex); @@ -3178,7 +3178,7 @@ static int snd_pcm_default_mmap(struct snd_pcm_substream *substream, area->vm_ops = &snd_pcm_vm_ops_data; area->vm_private_data = substream; area->vm_flags |= VM_RESERVED; - atomic_inc(&substream->runtime->mmap_count); + atomic_inc(&substream->mmap_count); return 0; } @@ -3210,7 +3210,7 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, (substream->runtime->dma_addr + offset) >> PAGE_SHIFT, size, area->vm_page_prot)) return -EAGAIN; - atomic_inc(&substream->runtime->mmap_count); + atomic_inc(&substream->mmap_count); return 0; } -- cgit v1.2.3 From 450047a78f3c35a905576e121abfbee2ccd45993 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Tue, 2 May 2006 16:08:41 +0200 Subject: [ALSA] add more sequencer port type information bits Add four new information flags SNDRV_SEQ_PORT_TYPE_HARDWARE, _SOFTWARE, _SYNTHESIZER, _PORT for sequencer ports. This makes it easier for apps like Rosegarden to make policy decisions based on the port type. Signed-off-by: Clemens Ladisch --- include/sound/asequencer.h | 4 ++++ sound/core/seq/seq_dummy.c | 4 +++- sound/core/seq/seq_midi.c | 4 +++- sound/core/seq/seq_virmidi.c | 4 +++- sound/drivers/opl3/opl3_oss.c | 4 +++- sound/drivers/opl3/opl3_seq.c | 4 +++- sound/drivers/opl4/opl4_seq.c | 4 +++- sound/isa/gus/gus_synth.c | 4 +++- sound/pci/trident/trident_synth.c | 4 +++- sound/synth/emux/emux_seq.c | 4 +++- 10 files changed, 31 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/include/sound/asequencer.h b/include/sound/asequencer.h index 6691e4aa4ea7..3f2f4042a20d 100644 --- a/include/sound/asequencer.h +++ b/include/sound/asequencer.h @@ -605,6 +605,10 @@ struct snd_seq_remove_events { #define SNDRV_SEQ_PORT_TYPE_DIRECT_SAMPLE (1<<11) /* Sampling device (support sample download) */ #define SNDRV_SEQ_PORT_TYPE_SAMPLE (1<<12) /* Sampling device (sample can be downloaded at any time) */ /*...*/ +#define SNDRV_SEQ_PORT_TYPE_HARDWARE (1<<16) /* driver for a hardware device */ +#define SNDRV_SEQ_PORT_TYPE_SOFTWARE (1<<17) /* implemented in software */ +#define SNDRV_SEQ_PORT_TYPE_SYNTHESIZER (1<<18) /* generates sound */ +#define SNDRV_SEQ_PORT_TYPE_PORT (1<<19) /* connects to other device(s) */ #define SNDRV_SEQ_PORT_TYPE_APPLICATION (1<<20) /* application (sequencer/editor) */ /* misc. conditioning flags */ diff --git a/sound/core/seq/seq_dummy.c b/sound/core/seq/seq_dummy.c index 2a283a59ea4d..9eb1c744f77b 100644 --- a/sound/core/seq/seq_dummy.c +++ b/sound/core/seq/seq_dummy.c @@ -171,7 +171,9 @@ create_port(int idx, int type) pinfo.capability |= SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE; if (duplex) pinfo.capability |= SNDRV_SEQ_PORT_CAP_DUPLEX; - pinfo.type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC; + pinfo.type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC + | SNDRV_SEQ_PORT_TYPE_SOFTWARE + | SNDRV_SEQ_PORT_TYPE_PORT; memset(&pcb, 0, sizeof(pcb)); pcb.owner = THIS_MODULE; pcb.unuse = dummy_unuse; diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c index 3b316da25eff..f873742c6532 100644 --- a/sound/core/seq/seq_midi.c +++ b/sound/core/seq/seq_midi.c @@ -376,7 +376,9 @@ snd_seq_midisynth_register_port(struct snd_seq_device *dev) if ((port->capability & (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_READ)) == (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_READ) && info->flags & SNDRV_RAWMIDI_INFO_DUPLEX) port->capability |= SNDRV_SEQ_PORT_CAP_DUPLEX; - port->type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC; + port->type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC + | SNDRV_SEQ_PORT_TYPE_HARDWARE + | SNDRV_SEQ_PORT_TYPE_PORT; port->midi_channels = 16; memset(&pcallbacks, 0, sizeof(pcallbacks)); pcallbacks.owner = THIS_MODULE; diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c index f4edec603b8f..0cfa06c6b81f 100644 --- a/sound/core/seq/seq_virmidi.c +++ b/sound/core/seq/seq_virmidi.c @@ -390,7 +390,9 @@ static int snd_virmidi_dev_attach_seq(struct snd_virmidi_dev *rdev) pinfo->capability |= SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SYNC_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE; pinfo->capability |= SNDRV_SEQ_PORT_CAP_READ | SNDRV_SEQ_PORT_CAP_SYNC_READ | SNDRV_SEQ_PORT_CAP_SUBS_READ; pinfo->capability |= SNDRV_SEQ_PORT_CAP_DUPLEX; - pinfo->type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC; + pinfo->type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC + | SNDRV_SEQ_PORT_TYPE_SOFTWARE + | SNDRV_SEQ_PORT_TYPE_PORT; pinfo->midi_channels = 16; memset(&pcallbacks, 0, sizeof(pcallbacks)); pcallbacks.owner = THIS_MODULE; diff --git a/sound/drivers/opl3/opl3_oss.c b/sound/drivers/opl3/opl3_oss.c index d48f8dee2d98..5fd3a4c95626 100644 --- a/sound/drivers/opl3/opl3_oss.c +++ b/sound/drivers/opl3/opl3_oss.c @@ -99,7 +99,9 @@ static int snd_opl3_oss_create_port(struct snd_opl3 * opl3) opl3->oss_chset->port = snd_seq_event_port_attach(opl3->seq_client, &callbacks, SNDRV_SEQ_PORT_CAP_WRITE, SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | - SNDRV_SEQ_PORT_TYPE_MIDI_GM, + SNDRV_SEQ_PORT_TYPE_MIDI_GM | + SNDRV_SEQ_PORT_TYPE_HARDWARE | + SNDRV_SEQ_PORT_TYPE_SYNTHESIZER, voices, voices, name); if (opl3->oss_chset->port < 0) { diff --git a/sound/drivers/opl3/opl3_seq.c b/sound/drivers/opl3/opl3_seq.c index 2aece1b18660..96762c9d4855 100644 --- a/sound/drivers/opl3/opl3_seq.c +++ b/sound/drivers/opl3/opl3_seq.c @@ -203,7 +203,9 @@ static int snd_opl3_synth_create_port(struct snd_opl3 * opl3) SNDRV_SEQ_PORT_CAP_SUBS_WRITE, SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | SNDRV_SEQ_PORT_TYPE_MIDI_GM | - SNDRV_SEQ_PORT_TYPE_DIRECT_SAMPLE, + SNDRV_SEQ_PORT_TYPE_DIRECT_SAMPLE | + SNDRV_SEQ_PORT_TYPE_HARDWARE | + SNDRV_SEQ_PORT_TYPE_SYNTHESIZER, 16, voices, name); if (opl3->chset->port < 0) { diff --git a/sound/drivers/opl4/opl4_seq.c b/sound/drivers/opl4/opl4_seq.c index dc0dcdc6c313..43d8a2bdd280 100644 --- a/sound/drivers/opl4/opl4_seq.c +++ b/sound/drivers/opl4/opl4_seq.c @@ -164,7 +164,9 @@ static int snd_opl4_seq_new_device(struct snd_seq_device *dev) SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE, SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | - SNDRV_SEQ_PORT_TYPE_MIDI_GM, + SNDRV_SEQ_PORT_TYPE_MIDI_GM | + SNDRV_SEQ_PORT_TYPE_HARDWARE | + SNDRV_SEQ_PORT_TYPE_SYNTHESIZER, 16, 24, "OPL4 Wavetable Port"); if (opl4->chset->port < 0) { diff --git a/sound/isa/gus/gus_synth.c b/sound/isa/gus/gus_synth.c index 2767cc187ae3..3e4d4d6edd8b 100644 --- a/sound/isa/gus/gus_synth.c +++ b/sound/isa/gus/gus_synth.c @@ -194,7 +194,9 @@ static int snd_gus_synth_create_port(struct snd_gus_card * gus, int idx) &callbacks, SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE, SNDRV_SEQ_PORT_TYPE_DIRECT_SAMPLE | - SNDRV_SEQ_PORT_TYPE_SYNTH, + SNDRV_SEQ_PORT_TYPE_SYNTH | + SNDRV_SEQ_PORT_TYPE_HARDWARE | + SNDRV_SEQ_PORT_TYPE_SYNTHESIZER, 16, 0, name); if (p->chset->port < 0) { diff --git a/sound/pci/trident/trident_synth.c b/sound/pci/trident/trident_synth.c index cc7af8bc55a0..9b7dee84743b 100644 --- a/sound/pci/trident/trident_synth.c +++ b/sound/pci/trident/trident_synth.c @@ -914,7 +914,9 @@ static int snd_trident_synth_create_port(struct snd_trident * trident, int idx) &callbacks, SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE, SNDRV_SEQ_PORT_TYPE_DIRECT_SAMPLE | - SNDRV_SEQ_PORT_TYPE_SYNTH, + SNDRV_SEQ_PORT_TYPE_SYNTH | + SNDRV_SEQ_PORT_TYPE_HARDWARE | + SNDRV_SEQ_PORT_TYPE_SYNTHESIZER, 16, 0, name); if (p->chset->port < 0) { diff --git a/sound/synth/emux/emux_seq.c b/sound/synth/emux/emux_seq.c index 58838f7c95f0..d176cc01742d 100644 --- a/sound/synth/emux/emux_seq.c +++ b/sound/synth/emux/emux_seq.c @@ -54,7 +54,9 @@ static struct snd_midi_op emux_ops = { #define DEFAULT_MIDI_TYPE (SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC |\ SNDRV_SEQ_PORT_TYPE_MIDI_GM |\ SNDRV_SEQ_PORT_TYPE_MIDI_GS |\ - SNDRV_SEQ_PORT_TYPE_MIDI_XG) + SNDRV_SEQ_PORT_TYPE_MIDI_XG |\ + SNDRV_SEQ_PORT_TYPE_HARDWARE |\ + SNDRV_SEQ_PORT_TYPE_SYNTHESIZER) /* * Initialise the EMUX Synth by creating a client and registering -- cgit v1.2.3 From a7b928ac5fcd8e1b5c7c69926d8845b1d0500af3 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Tue, 2 May 2006 16:22:12 +0200 Subject: [ALSA] rawmidi: add get_port_info callback for sequencer information flags Add a get_port_info callback to the snd_rawmidi_global_ops structure to allow the USB MIDI driver to supply information flags for the sequencer ports created by seq_midi. Signed-off-by: Clemens Ladisch --- include/sound/rawmidi.h | 3 + sound/core/seq/seq_midi.c | 3 + sound/usb/usbmidi.c | 200 ++++++++++++++++++++++++++++++---------------- 3 files changed, 136 insertions(+), 70 deletions(-) (limited to 'include') diff --git a/include/sound/rawmidi.h b/include/sound/rawmidi.h index 584e73dd4793..7dbcd10fa215 100644 --- a/include/sound/rawmidi.h +++ b/include/sound/rawmidi.h @@ -46,6 +46,7 @@ struct snd_rawmidi; struct snd_rawmidi_substream; +struct snd_seq_port_info; struct snd_rawmidi_ops { int (*open) (struct snd_rawmidi_substream * substream); @@ -57,6 +58,8 @@ struct snd_rawmidi_ops { struct snd_rawmidi_global_ops { int (*dev_register) (struct snd_rawmidi * rmidi); int (*dev_unregister) (struct snd_rawmidi * rmidi); + void (*get_port_info)(struct snd_rawmidi *rmidi, int number, + struct snd_seq_port_info *info); }; struct snd_rawmidi_runtime { diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c index f873742c6532..1daa5b069c79 100644 --- a/sound/core/seq/seq_midi.c +++ b/sound/core/seq/seq_midi.c @@ -278,6 +278,7 @@ snd_seq_midisynth_register_port(struct snd_seq_device *dev) struct seq_midisynth *msynth, *ms; struct snd_seq_port_info *port; struct snd_rawmidi_info *info; + struct snd_rawmidi *rmidi = dev->private_data; int newclient = 0; unsigned int p, ports; struct snd_seq_port_callback pcallbacks; @@ -389,6 +390,8 @@ snd_seq_midisynth_register_port(struct snd_seq_device *dev) pcallbacks.unuse = midisynth_unuse; pcallbacks.event_input = event_process_midi; port->kernel = &pcallbacks; + if (rmidi->ops && rmidi->ops->get_port_info) + rmidi->ops->get_port_info(rmidi, p, port); if (snd_seq_kernel_client_ctl(client->seq_client, SNDRV_SEQ_IOCTL_CREATE_PORT, port)<0) goto __nomem; ms->seq_client = client->seq_client; diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index 2b9d940c8064..5c53ec8a13bf 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c @@ -48,6 +48,7 @@ #include #include #include +#include #include "usbaudio.h" @@ -1010,97 +1011,157 @@ static struct snd_rawmidi_substream *snd_usbmidi_find_substream(struct snd_usb_m * "(product) MIDI (n)" schema because they aren't external MIDI ports, * such as internal control or synthesizer ports. */ -static struct { +static struct port_info { u32 id; - int port; - const char *name_format; -} snd_usbmidi_port_names[] = { + short int port; + short int voices; + const char *name; + unsigned int seq_flags; +} snd_usbmidi_port_info[] = { +#define PORT_INFO(vendor, product, num, name_, voices_, flags) \ + { .id = USB_ID(vendor, product), \ + .port = num, .voices = voices_, \ + .name = name_, .seq_flags = flags } +#define EXTERNAL_PORT(vendor, product, num, name) \ + PORT_INFO(vendor, product, num, name, 0, \ + SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | \ + SNDRV_SEQ_PORT_TYPE_HARDWARE | \ + SNDRV_SEQ_PORT_TYPE_PORT) +#define CONTROL_PORT(vendor, product, num, name) \ + PORT_INFO(vendor, product, num, name, 0, \ + SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | \ + SNDRV_SEQ_PORT_TYPE_HARDWARE) +#define ROLAND_SYNTH_PORT(vendor, product, num, name, voices) \ + PORT_INFO(vendor, product, num, name, voices, \ + SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | \ + SNDRV_SEQ_PORT_TYPE_MIDI_GM | \ + SNDRV_SEQ_PORT_TYPE_MIDI_GM2 | \ + SNDRV_SEQ_PORT_TYPE_MIDI_GS | \ + SNDRV_SEQ_PORT_TYPE_MIDI_XG | \ + SNDRV_SEQ_PORT_TYPE_HARDWARE | \ + SNDRV_SEQ_PORT_TYPE_SYNTHESIZER) +#define SOUNDCANVAS_PORT(vendor, product, num, name, voices) \ + PORT_INFO(vendor, product, num, name, voices, \ + SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | \ + SNDRV_SEQ_PORT_TYPE_MIDI_GM | \ + SNDRV_SEQ_PORT_TYPE_MIDI_GM2 | \ + SNDRV_SEQ_PORT_TYPE_MIDI_GS | \ + SNDRV_SEQ_PORT_TYPE_MIDI_XG | \ + SNDRV_SEQ_PORT_TYPE_MIDI_MT32 | \ + SNDRV_SEQ_PORT_TYPE_HARDWARE | \ + SNDRV_SEQ_PORT_TYPE_SYNTHESIZER) /* Roland UA-100 */ - { USB_ID(0x0582, 0x0000), 2, "%s Control" }, + CONTROL_PORT(0x0582, 0x0000, 2, "%s Control"), /* Roland SC-8850 */ - { USB_ID(0x0582, 0x0003), 0, "%s Part A" }, - { USB_ID(0x0582, 0x0003), 1, "%s Part B" }, - { USB_ID(0x0582, 0x0003), 2, "%s Part C" }, - { USB_ID(0x0582, 0x0003), 3, "%s Part D" }, - { USB_ID(0x0582, 0x0003), 4, "%s MIDI 1" }, - { USB_ID(0x0582, 0x0003), 5, "%s MIDI 2" }, + SOUNDCANVAS_PORT(0x0582, 0x0003, 0, "%s Part A", 128), + SOUNDCANVAS_PORT(0x0582, 0x0003, 1, "%s Part B", 128), + SOUNDCANVAS_PORT(0x0582, 0x0003, 2, "%s Part C", 128), + SOUNDCANVAS_PORT(0x0582, 0x0003, 3, "%s Part D", 128), + EXTERNAL_PORT(0x0582, 0x0003, 4, "%s MIDI 1"), + EXTERNAL_PORT(0x0582, 0x0003, 5, "%s MIDI 2"), /* Roland U-8 */ - { USB_ID(0x0582, 0x0004), 0, "%s MIDI" }, - { USB_ID(0x0582, 0x0004), 1, "%s Control" }, + EXTERNAL_PORT(0x0582, 0x0004, 0, "%s MIDI"), + CONTROL_PORT(0x0582, 0x0004, 1, "%s Control"), /* Roland SC-8820 */ - { USB_ID(0x0582, 0x0007), 0, "%s Part A" }, - { USB_ID(0x0582, 0x0007), 1, "%s Part B" }, - { USB_ID(0x0582, 0x0007), 2, "%s MIDI" }, + SOUNDCANVAS_PORT(0x0582, 0x0007, 0, "%s Part A", 64), + SOUNDCANVAS_PORT(0x0582, 0x0007, 1, "%s Part B", 64), + EXTERNAL_PORT(0x0582, 0x0007, 2, "%s MIDI"), /* Roland SK-500 */ - { USB_ID(0x0582, 0x000b), 0, "%s Part A" }, - { USB_ID(0x0582, 0x000b), 1, "%s Part B" }, - { USB_ID(0x0582, 0x000b), 2, "%s MIDI" }, + SOUNDCANVAS_PORT(0x0582, 0x000b, 0, "%s Part A", 64), + SOUNDCANVAS_PORT(0x0582, 0x000b, 1, "%s Part B", 64), + EXTERNAL_PORT(0x0582, 0x000b, 2, "%s MIDI"), /* Roland SC-D70 */ - { USB_ID(0x0582, 0x000c), 0, "%s Part A" }, - { USB_ID(0x0582, 0x000c), 1, "%s Part B" }, - { USB_ID(0x0582, 0x000c), 2, "%s MIDI" }, + SOUNDCANVAS_PORT(0x0582, 0x000c, 0, "%s Part A", 64), + SOUNDCANVAS_PORT(0x0582, 0x000c, 1, "%s Part B", 64), + EXTERNAL_PORT(0x0582, 0x000c, 2, "%s MIDI"), /* Edirol UM-880 */ - { USB_ID(0x0582, 0x0014), 8, "%s Control" }, + CONTROL_PORT(0x0582, 0x0014, 8, "%s Control"), /* Edirol SD-90 */ - { USB_ID(0x0582, 0x0016), 0, "%s Part A" }, - { USB_ID(0x0582, 0x0016), 1, "%s Part B" }, - { USB_ID(0x0582, 0x0016), 2, "%s MIDI 1" }, - { USB_ID(0x0582, 0x0016), 3, "%s MIDI 2" }, + ROLAND_SYNTH_PORT(0x0582, 0x0016, 0, "%s Part A", 128), + ROLAND_SYNTH_PORT(0x0582, 0x0016, 1, "%s Part B", 128), + EXTERNAL_PORT(0x0582, 0x0016, 2, "%s MIDI 1"), + EXTERNAL_PORT(0x0582, 0x0016, 3, "%s MIDI 2"), /* Edirol UM-550 */ - { USB_ID(0x0582, 0x0023), 5, "%s Control" }, + CONTROL_PORT(0x0582, 0x0023, 5, "%s Control"), /* Edirol SD-20 */ - { USB_ID(0x0582, 0x0027), 0, "%s Part A" }, - { USB_ID(0x0582, 0x0027), 1, "%s Part B" }, - { USB_ID(0x0582, 0x0027), 2, "%s MIDI" }, + ROLAND_SYNTH_PORT(0x0582, 0x0027, 0, "%s Part A", 64), + ROLAND_SYNTH_PORT(0x0582, 0x0027, 1, "%s Part B", 64), + EXTERNAL_PORT(0x0582, 0x0027, 2, "%s MIDI"), /* Edirol SD-80 */ - { USB_ID(0x0582, 0x0029), 0, "%s Part A" }, - { USB_ID(0x0582, 0x0029), 1, "%s Part B" }, - { USB_ID(0x0582, 0x0029), 2, "%s MIDI 1" }, - { USB_ID(0x0582, 0x0029), 3, "%s MIDI 2" }, + ROLAND_SYNTH_PORT(0x0582, 0x0029, 0, "%s Part A", 128), + ROLAND_SYNTH_PORT(0x0582, 0x0029, 1, "%s Part B", 128), + EXTERNAL_PORT(0x0582, 0x0029, 2, "%s MIDI 1"), + EXTERNAL_PORT(0x0582, 0x0029, 3, "%s MIDI 2"), /* Edirol UA-700 */ - { USB_ID(0x0582, 0x002b), 0, "%s MIDI" }, - { USB_ID(0x0582, 0x002b), 1, "%s Control" }, + EXTERNAL_PORT(0x0582, 0x002b, 0, "%s MIDI"), + CONTROL_PORT(0x0582, 0x002b, 1, "%s Control"), /* Roland VariOS */ - { USB_ID(0x0582, 0x002f), 0, "%s MIDI" }, - { USB_ID(0x0582, 0x002f), 1, "%s External MIDI" }, - { USB_ID(0x0582, 0x002f), 2, "%s Sync" }, + EXTERNAL_PORT(0x0582, 0x002f, 0, "%s MIDI"), + EXTERNAL_PORT(0x0582, 0x002f, 1, "%s External MIDI"), + EXTERNAL_PORT(0x0582, 0x002f, 2, "%s Sync"), /* Edirol PCR */ - { USB_ID(0x0582, 0x0033), 0, "%s MIDI" }, - { USB_ID(0x0582, 0x0033), 1, "%s 1" }, - { USB_ID(0x0582, 0x0033), 2, "%s 2" }, + EXTERNAL_PORT(0x0582, 0x0033, 0, "%s MIDI"), + EXTERNAL_PORT(0x0582, 0x0033, 1, "%s 1"), + EXTERNAL_PORT(0x0582, 0x0033, 2, "%s 2"), /* BOSS GS-10 */ - { USB_ID(0x0582, 0x003b), 0, "%s MIDI" }, - { USB_ID(0x0582, 0x003b), 1, "%s Control" }, + EXTERNAL_PORT(0x0582, 0x003b, 0, "%s MIDI"), + CONTROL_PORT(0x0582, 0x003b, 1, "%s Control"), /* Edirol UA-1000 */ - { USB_ID(0x0582, 0x0044), 0, "%s MIDI" }, - { USB_ID(0x0582, 0x0044), 1, "%s Control" }, + EXTERNAL_PORT(0x0582, 0x0044, 0, "%s MIDI"), + CONTROL_PORT(0x0582, 0x0044, 1, "%s Control"), /* Edirol UR-80 */ - { USB_ID(0x0582, 0x0048), 0, "%s MIDI" }, - { USB_ID(0x0582, 0x0048), 1, "%s 1" }, - { USB_ID(0x0582, 0x0048), 2, "%s 2" }, + EXTERNAL_PORT(0x0582, 0x0048, 0, "%s MIDI"), + EXTERNAL_PORT(0x0582, 0x0048, 1, "%s 1"), + EXTERNAL_PORT(0x0582, 0x0048, 2, "%s 2"), /* Edirol PCR-A */ - { USB_ID(0x0582, 0x004d), 0, "%s MIDI" }, - { USB_ID(0x0582, 0x004d), 1, "%s 1" }, - { USB_ID(0x0582, 0x004d), 2, "%s 2" }, + EXTERNAL_PORT(0x0582, 0x004d, 0, "%s MIDI"), + EXTERNAL_PORT(0x0582, 0x004d, 1, "%s 1"), + EXTERNAL_PORT(0x0582, 0x004d, 2, "%s 2"), /* Edirol UM-3EX */ - { USB_ID(0x0582, 0x009a), 3, "%s Control" }, + CONTROL_PORT(0x0582, 0x009a, 3, "%s Control"), /* M-Audio MidiSport 8x8 */ - { USB_ID(0x0763, 0x1031), 8, "%s Control" }, - { USB_ID(0x0763, 0x1033), 8, "%s Control" }, + CONTROL_PORT(0x0763, 0x1031, 8, "%s Control"), + CONTROL_PORT(0x0763, 0x1033, 8, "%s Control"), /* MOTU Fastlane */ - { USB_ID(0x07fd, 0x0001), 0, "%s MIDI A" }, - { USB_ID(0x07fd, 0x0001), 1, "%s MIDI B" }, + EXTERNAL_PORT(0x07fd, 0x0001, 0, "%s MIDI A"), + EXTERNAL_PORT(0x07fd, 0x0001, 1, "%s MIDI B"), /* Emagic Unitor8/AMT8/MT4 */ - { USB_ID(0x086a, 0x0001), 8, "%s Broadcast" }, - { USB_ID(0x086a, 0x0002), 8, "%s Broadcast" }, - { USB_ID(0x086a, 0x0003), 4, "%s Broadcast" }, + EXTERNAL_PORT(0x086a, 0x0001, 8, "%s Broadcast"), + EXTERNAL_PORT(0x086a, 0x0002, 8, "%s Broadcast"), + EXTERNAL_PORT(0x086a, 0x0003, 4, "%s Broadcast"), }; +static struct port_info *find_port_info(struct snd_usb_midi* umidi, int number) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(snd_usbmidi_port_info); ++i) { + if (snd_usbmidi_port_info[i].id == umidi->chip->usb_id && + snd_usbmidi_port_info[i].port == number) + return &snd_usbmidi_port_info[i]; + } + return NULL; +} + +static void snd_usbmidi_get_port_info(struct snd_rawmidi *rmidi, int number, + struct snd_seq_port_info *seq_port_info) +{ + struct snd_usb_midi *umidi = rmidi->private_data; + struct port_info *port_info; + + /* TODO: read port flags from descriptors */ + port_info = find_port_info(umidi, number); + if (port_info) { + seq_port_info->type = port_info->seq_flags; + seq_port_info->midi_voices = port_info->voices; + } +} + static void snd_usbmidi_init_substream(struct snd_usb_midi* umidi, int stream, int number, struct snd_rawmidi_substream ** rsubstream) { - int i; + struct port_info *port_info; const char *name_format; struct snd_rawmidi_substream *substream = snd_usbmidi_find_substream(umidi, stream, number); @@ -1110,14 +1171,8 @@ static void snd_usbmidi_init_substream(struct snd_usb_midi* umidi, } /* TODO: read port name from jack descriptor */ - name_format = "%s MIDI %d"; - for (i = 0; i < ARRAY_SIZE(snd_usbmidi_port_names); ++i) { - if (snd_usbmidi_port_names[i].id == umidi->chip->usb_id && - snd_usbmidi_port_names[i].port == number) { - name_format = snd_usbmidi_port_names[i].name_format; - break; - } - } + port_info = find_port_info(umidi, number); + name_format = port_info ? port_info->name : "%s MIDI %d"; snprintf(substream->name, sizeof(substream->name), name_format, umidi->chip->card->shortname, number + 1); @@ -1457,6 +1512,10 @@ static int snd_usbmidi_create_endpoints_midiman(struct snd_usb_midi* umidi, return 0; } +static struct snd_rawmidi_global_ops snd_usbmidi_ops = { + .get_port_info = snd_usbmidi_get_port_info, +}; + static int snd_usbmidi_create_rawmidi(struct snd_usb_midi* umidi, int out_ports, int in_ports) { @@ -1472,6 +1531,7 @@ static int snd_usbmidi_create_rawmidi(struct snd_usb_midi* umidi, rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX; + rmidi->ops = &snd_usbmidi_ops; rmidi->private_data = umidi; rmidi->private_free = snd_usbmidi_rawmidi_free; snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_usbmidi_output_ops); -- cgit v1.2.3 From 746df94898554b3d8e91d855e934852e626c701c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 15 May 2006 19:49:05 +0200 Subject: [ALSA] Fix rwlock around snd_iprintf() in sound core Fixed rwlock around snd_iprintf() in sound core part. Replaced with mutex. Also, make mutex and flags static variables with addition of snd_card_locked() function (just for sound.c). Signed-off-by: Takashi Iwai --- include/sound/core.h | 3 +-- sound/core/init.c | 51 +++++++++++++++++++++++++++++++-------------------- sound/core/sound.c | 7 +------ 3 files changed, 33 insertions(+), 28 deletions(-) (limited to 'include') diff --git a/include/sound/core.h b/include/sound/core.h index 5135147f20e8..5d184be0ff72 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -233,9 +233,8 @@ int copy_from_user_toio(volatile void __iomem *dst, const void __user *src, size /* init.c */ -extern unsigned int snd_cards_lock; extern struct snd_card *snd_cards[SNDRV_CARDS]; -extern rwlock_t snd_card_rwlock; +int snd_card_locked(int card); #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) #define SND_MIXER_OSS_NOTIFY_REGISTER 0 #define SND_MIXER_OSS_NOTIFY_DISCONNECT 1 diff --git a/sound/core/init.c b/sound/core/init.c index 2ff0e5e90865..38b2d4a9d672 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -38,11 +38,11 @@ struct snd_shutdown_f_ops { struct snd_shutdown_f_ops *next; }; -unsigned int snd_cards_lock = 0; /* locked for registering/using */ +static unsigned int snd_cards_lock = 0; /* locked for registering/using */ struct snd_card *snd_cards[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = NULL}; EXPORT_SYMBOL(snd_cards); -DEFINE_RWLOCK(snd_card_rwlock); +static DEFINE_MUTEX(snd_card_mutex); #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) int (*snd_mixer_oss_notify_callback)(struct snd_card *card, int free_flag); @@ -112,7 +112,7 @@ struct snd_card *snd_card_new(int idx, const char *xid, strlcpy(card->id, xid, sizeof(card->id)); } err = 0; - write_lock(&snd_card_rwlock); + mutex_lock(&snd_card_mutex); if (idx < 0) { int idx2; for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++) @@ -130,12 +130,12 @@ struct snd_card *snd_card_new(int idx, const char *xid, else err = -ENODEV; if (idx < 0 || err < 0) { - write_unlock(&snd_card_rwlock); + mutex_unlock(&snd_card_mutex); snd_printk(KERN_ERR "cannot find the slot for index %d (range 0-%i)\n", idx, snd_ecards_limit - 1); goto __error; } snd_cards_lock |= 1 << idx; /* lock it */ - write_unlock(&snd_card_rwlock); + mutex_unlock(&snd_card_mutex); card->number = idx; card->module = module; INIT_LIST_HEAD(&card->devices); @@ -173,6 +173,17 @@ struct snd_card *snd_card_new(int idx, const char *xid, EXPORT_SYMBOL(snd_card_new); +/* return non-zero if a card is already locked */ +int snd_card_locked(int card) +{ + int locked; + + mutex_lock(&snd_card_mutex); + locked = snd_cards_lock & (1 << card); + mutex_unlock(&snd_card_mutex); + return locked; +} + static loff_t snd_disconnect_llseek(struct file *file, loff_t offset, int orig) { return -ENODEV; @@ -240,9 +251,9 @@ int snd_card_disconnect(struct snd_card *card) spin_unlock(&card->files_lock); /* phase 1: disable fops (user space) operations for ALSA API */ - write_lock(&snd_card_rwlock); + mutex_lock(&snd_card_mutex); snd_cards[card->number] = NULL; - write_unlock(&snd_card_rwlock); + mutex_unlock(&snd_card_mutex); /* phase 2: replace file->f_op with special dummy operations */ @@ -321,9 +332,9 @@ int snd_card_free(struct snd_card *card) if (card == NULL) return -EINVAL; - write_lock(&snd_card_rwlock); + mutex_lock(&snd_card_mutex); snd_cards[card->number] = NULL; - write_unlock(&snd_card_rwlock); + mutex_unlock(&snd_card_mutex); #ifdef CONFIG_PM wake_up(&card->power_sleep); @@ -359,9 +370,9 @@ int snd_card_free(struct snd_card *card) card->s_f_ops = s_f_ops->next; kfree(s_f_ops); } - write_lock(&snd_card_rwlock); + mutex_lock(&snd_card_mutex); snd_cards_lock &= ~(1 << card->number); - write_unlock(&snd_card_rwlock); + mutex_unlock(&snd_card_mutex); kfree(card); return 0; } @@ -497,16 +508,16 @@ int snd_card_register(struct snd_card *card) snd_assert(card != NULL, return -EINVAL); if ((err = snd_device_register_all(card)) < 0) return err; - write_lock(&snd_card_rwlock); + mutex_lock(&snd_card_mutex); if (snd_cards[card->number]) { /* already registered */ - write_unlock(&snd_card_rwlock); + mutex_unlock(&snd_card_mutex); return 0; } if (card->id[0] == '\0') choose_default_id(card); snd_cards[card->number] = card; - write_unlock(&snd_card_rwlock); + mutex_unlock(&snd_card_mutex); init_info_for_card(card); #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) if (snd_mixer_oss_notify_callback) @@ -527,7 +538,7 @@ static void snd_card_info_read(struct snd_info_entry *entry, struct snd_card *card; for (idx = count = 0; idx < SNDRV_CARDS; idx++) { - read_lock(&snd_card_rwlock); + mutex_lock(&snd_card_mutex); if ((card = snd_cards[idx]) != NULL) { count++; snd_iprintf(buffer, "%2i [%-15s]: %s - %s\n", @@ -538,7 +549,7 @@ static void snd_card_info_read(struct snd_info_entry *entry, snd_iprintf(buffer, " %s\n", card->longname); } - read_unlock(&snd_card_rwlock); + mutex_unlock(&snd_card_mutex); } if (!count) snd_iprintf(buffer, "--- no soundcards ---\n"); @@ -552,12 +563,12 @@ void snd_card_info_read_oss(struct snd_info_buffer *buffer) struct snd_card *card; for (idx = count = 0; idx < SNDRV_CARDS; idx++) { - read_lock(&snd_card_rwlock); + mutex_lock(&snd_card_mutex); if ((card = snd_cards[idx]) != NULL) { count++; snd_iprintf(buffer, "%s\n", card->longname); } - read_unlock(&snd_card_rwlock); + mutex_unlock(&snd_card_mutex); } if (!count) { snd_iprintf(buffer, "--- no soundcards ---\n"); @@ -575,11 +586,11 @@ static void snd_card_module_info_read(struct snd_info_entry *entry, struct snd_card *card; for (idx = 0; idx < SNDRV_CARDS; idx++) { - read_lock(&snd_card_rwlock); + mutex_lock(&snd_card_mutex); if ((card = snd_cards[idx]) != NULL) snd_iprintf(buffer, "%2i %s\n", idx, card->module->name); - read_unlock(&snd_card_rwlock); + mutex_unlock(&snd_card_mutex); } } #endif diff --git a/sound/core/sound.c b/sound/core/sound.c index 8313f97907d8..02c8cc4ebffe 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c @@ -81,14 +81,9 @@ extern struct class *sound_class; */ void snd_request_card(int card) { - int locked; - if (! current->fs->root) return; - read_lock(&snd_card_rwlock); - locked = snd_cards_lock & (1 << card); - read_unlock(&snd_card_rwlock); - if (locked) + if (snd_card_locked(card)) return; if (card < 0 || card >= cards_limit) return; -- cgit v1.2.3 From 302e4c2f9e2b9f07c69649782330a61c60001ac4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 23 May 2006 13:24:30 +0200 Subject: [ALSA] Change an arugment of snd_mpu401_uart_new() to bit flags Change the 5th argument of snd_mpu401_uart_new() to bit flags instead of a boolean. The argument takes bits that consist of MPU401_INFO_XXX flags. The callers that used the value 1 there are replaced with MPU401_INFO_INTEGRATED. Signed-off-by: Takashi Iwai --- .../sound/alsa/DocBook/writing-an-alsa-driver.tmpl | 29 ++++++- include/sound/mpu401.h | 14 +++- sound/drivers/mpu401/mpu401_uart.c | 96 +++++++++++++++------- sound/isa/sscape.c | 3 +- sound/pci/als4000.c | 4 +- sound/pci/au88x0/au88x0_mpu401.c | 3 +- sound/pci/azt3328.c | 4 +- sound/pci/cmipci.c | 4 +- sound/pci/cs5535audio/cs5535audio.c | 21 +++-- sound/pci/es1938.c | 3 +- sound/pci/es1968.c | 3 +- sound/pci/fm801.c | 3 +- sound/pci/ice1712/ice1712.c | 6 +- sound/pci/ice1712/ice1724.c | 3 +- sound/pci/maestro3.c | 3 +- sound/pci/sonicvibes.c | 2 +- sound/pci/trident/trident.c | 3 +- sound/pci/via82xx.c | 2 +- sound/pci/ymfpci/ymfpci.c | 3 +- 19 files changed, 147 insertions(+), 62 deletions(-) (limited to 'include') diff --git a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl index 23c6c7cde4e6..635cbb94357c 100644 --- a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl +++ b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl @@ -4215,7 +4215,7 @@ struct _snd_pcm_runtime { @@ -4242,15 +4242,36 @@ struct _snd_pcm_runtime { + The 5th argument is bitflags for additional information. When the i/o port address above is a part of the PCI i/o region, the MPU401 i/o port might have been already allocated - (reserved) by the driver itself. In such a case, pass non-zero - to the 5th argument - (integrated). Otherwise, pass 0 to it, + (reserved) by the driver itself. In such a case, pass a bit flag + MPU401_INFO_INTEGRATED, and the mpu401-uart layer will allocate the i/o ports by itself. + + When the controller supports only the input or output MIDI stream, + pass MPU401_INFO_INPUT or + MPU401_INFO_OUTPUT bitflag, respectively. + Then the rawmidi instance is created as a single stream. + + + + MPU401_INFO_MMIO bitflag is used to change + the access method to MMIO (via readb and writeb) instead of + iob and outb. In this case, you have to pass the iomapped address + to snd_mpu401_uart_new(). + + + + When MPU401_INFO_TX_IRQ is set, the output + stream isn't checked in the default interrupt handler. The driver + needs to call snd_mpu401_uart_interrupt_tx() + by itself to start processing the output stream in irq handler. + + Usually, the port address corresponds to the command port and port + 1 corresponds to the data port. If not, you may change diff --git a/include/sound/mpu401.h b/include/sound/mpu401.h index 8e97ace78f16..ac504321ea56 100644 --- a/include/sound/mpu401.h +++ b/include/sound/mpu401.h @@ -45,6 +45,12 @@ #define MPU401_HW_PC98II 18 /* Roland PC98II */ #define MPU401_HW_AUREAL 19 /* Aureal Vortex */ +#define MPU401_INFO_INPUT (1 << 0) /* input stream */ +#define MPU401_INFO_OUTPUT (1 << 1) /* output stream */ +#define MPU401_INFO_INTEGRATED (1 << 2) /* integrated h/w port */ +#define MPU401_INFO_MMIO (1 << 3) /* MMIO access */ +#define MPU401_INFO_TX_IRQ (1 << 4) /* independent TX irq */ + #define MPU401_MODE_BIT_INPUT 0 #define MPU401_MODE_BIT_OUTPUT 1 #define MPU401_MODE_BIT_INPUT_TRIGGER 2 @@ -62,6 +68,7 @@ struct snd_mpu401 { struct snd_rawmidi *rmidi; unsigned short hardware; /* MPU401_HW_XXXX */ + unsigned int info_flags; /* MPU401_INFO_XXX */ unsigned long port; /* base port of MPU-401 chip */ unsigned long cport; /* port + 1 (usually) */ struct resource *res; /* port resource */ @@ -99,13 +106,16 @@ struct snd_mpu401 { */ -irqreturn_t snd_mpu401_uart_interrupt(int irq, void *dev_id, struct pt_regs *regs); +irqreturn_t snd_mpu401_uart_interrupt(int irq, void *dev_id, + struct pt_regs *regs); +irqreturn_t snd_mpu401_uart_interrupt_tx(int irq, void *dev_id, + struct pt_regs *regs); int snd_mpu401_uart_new(struct snd_card *card, int device, unsigned short hardware, unsigned long port, - int integrated, + unsigned int info_flags, int irq, int irq_flags, struct snd_rawmidi ** rrawmidi); diff --git a/sound/drivers/mpu401/mpu401_uart.c b/sound/drivers/mpu401/mpu401_uart.c index cd64d3eb9ec8..4bf07ca9b17d 100644 --- a/sound/drivers/mpu401/mpu401_uart.c +++ b/sound/drivers/mpu401/mpu401_uart.c @@ -95,17 +95,8 @@ static void snd_mpu401_uart_clear_rx(struct snd_mpu401 *mpu) #endif } -static void _snd_mpu401_uart_interrupt(struct snd_mpu401 *mpu) +static void uart_interrupt_tx(struct snd_mpu401 *mpu) { - spin_lock(&mpu->input_lock); - if (test_bit(MPU401_MODE_BIT_INPUT, &mpu->mode)) - snd_mpu401_uart_input_read(mpu); - else - snd_mpu401_uart_clear_rx(mpu); - spin_unlock(&mpu->input_lock); - /* ok. for better Tx performance try do some output when - * input is done - */ if (test_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode) && test_bit(MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode)) { spin_lock(&mpu->output_lock); @@ -114,6 +105,22 @@ static void _snd_mpu401_uart_interrupt(struct snd_mpu401 *mpu) } } +static void _snd_mpu401_uart_interrupt(struct snd_mpu401 *mpu) +{ + if (mpu->info_flags & MPU401_INFO_INPUT) { + spin_lock(&mpu->input_lock); + if (test_bit(MPU401_MODE_BIT_INPUT, &mpu->mode)) + snd_mpu401_uart_input_read(mpu); + else + snd_mpu401_uart_clear_rx(mpu); + spin_unlock(&mpu->input_lock); + } + if (! (mpu->info_flags & MPU401_INFO_TX_IRQ)) + /* ok. for better Tx performance try do some output + when input is done */ + uart_interrupt_tx(mpu); +} + /** * snd_mpu401_uart_interrupt - generic MPU401-UART interrupt handler * @irq: the irq number @@ -135,6 +142,27 @@ irqreturn_t snd_mpu401_uart_interrupt(int irq, void *dev_id, EXPORT_SYMBOL(snd_mpu401_uart_interrupt); +/** + * snd_mpu401_uart_interrupt_tx - generic MPU401-UART transmit irq handler + * @irq: the irq number + * @dev_id: mpu401 instance + * @regs: the reigster + * + * Processes the interrupt for MPU401-UART output. + */ +irqreturn_t snd_mpu401_uart_interrupt_tx(int irq, void *dev_id, + struct pt_regs *regs) +{ + struct snd_mpu401 *mpu = dev_id; + + if (mpu == NULL) + return IRQ_NONE; + uart_interrupt_tx(mpu); + return IRQ_HANDLED; +} + +EXPORT_SYMBOL(snd_mpu401_uart_interrupt_tx); + /* * timer callback * reprogram the timer and call the interrupt job @@ -430,14 +458,16 @@ snd_mpu401_uart_output_trigger(struct snd_rawmidi_substream *substream, int up) * since the output timer might have been removed in * snd_mpu401_uart_output_write(). */ - snd_mpu401_uart_add_timer(mpu, 0); + if (! (mpu->info_flags & MPU401_INFO_TX_IRQ)) + snd_mpu401_uart_add_timer(mpu, 0); /* output pending data */ spin_lock_irqsave(&mpu->output_lock, flags); snd_mpu401_uart_output_write(mpu); spin_unlock_irqrestore(&mpu->output_lock, flags); } else { - snd_mpu401_uart_remove_timer(mpu, 0); + if (! (mpu->info_flags & MPU401_INFO_TX_IRQ)) + snd_mpu401_uart_remove_timer(mpu, 0); clear_bit(MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode); } } @@ -475,7 +505,7 @@ static void snd_mpu401_uart_free(struct snd_rawmidi *rmidi) * @device: the device index, zero-based * @hardware: the hardware type, MPU401_HW_XXXX * @port: the base address of MPU401 port - * @integrated: non-zero if the port was already reserved by the chip + * @info_flags: bitflags MPU401_INFO_XXX * @irq: the irq number, -1 if no interrupt for mpu * @irq_flags: the irq request flags (SA_XXX), 0 if irq was already reserved. * @rrawmidi: the pointer to store the new rawmidi instance @@ -490,17 +520,24 @@ static void snd_mpu401_uart_free(struct snd_rawmidi *rmidi) */ int snd_mpu401_uart_new(struct snd_card *card, int device, unsigned short hardware, - unsigned long port, int integrated, + unsigned long port, + unsigned int info_flags, int irq, int irq_flags, struct snd_rawmidi ** rrawmidi) { struct snd_mpu401 *mpu; struct snd_rawmidi *rmidi; + int in_enable, out_enable; int err; if (rrawmidi) *rrawmidi = NULL; - if ((err = snd_rawmidi_new(card, "MPU-401U", device, 1, 1, &rmidi)) < 0) + if (! (info_flags & (MPU401_INFO_INPUT | MPU401_INFO_OUTPUT))) + info_flags |= MPU401_INFO_INPUT | MPU401_INFO_OUTPUT; + in_enable = (info_flags & MPU401_INFO_INPUT) ? 1 : 0; + out_enable = (info_flags & MPU401_INFO_OUTPUT) ? 1 : 0; + if ((err = snd_rawmidi_new(card, "MPU-401U", device, + out_enable, in_enable, &rmidi)) < 0) return err; mpu = kzalloc(sizeof(*mpu), GFP_KERNEL); if (mpu == NULL) { @@ -514,7 +551,7 @@ int snd_mpu401_uart_new(struct snd_card *card, int device, spin_lock_init(&mpu->output_lock); spin_lock_init(&mpu->timer_lock); mpu->hardware = hardware; - if (!integrated) { + if (! (info_flags & MPU401_INFO_INTEGRATED)) { int res_size = hardware == MPU401_HW_PC98II ? 4 : 2; mpu->res = request_region(port, res_size, "MPU401 UART"); if (mpu->res == NULL) { @@ -525,15 +562,12 @@ int snd_mpu401_uart_new(struct snd_card *card, int device, return -EBUSY; } } - switch (hardware) { - case MPU401_HW_AUREAL: + if (info_flags & MPU401_INFO_MMIO) { mpu->write = mpu401_write_mmio; mpu->read = mpu401_read_mmio; - break; - default: + } else { mpu->write = mpu401_write_port; mpu->read = mpu401_read_port; - break; } mpu->port = port; if (hardware == MPU401_HW_PC98II) @@ -549,6 +583,7 @@ int snd_mpu401_uart_new(struct snd_card *card, int device, return -EBUSY; } } + mpu->info_flags = info_flags; mpu->irq = irq; mpu->irq_flags = irq_flags; if (card->shortname[0]) @@ -556,13 +591,18 @@ int snd_mpu401_uart_new(struct snd_card *card, int device, card->shortname); else sprintf(rmidi->name, "MPU-401 MIDI %d-%d",card->number, device); - snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, - &snd_mpu401_uart_output); - snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, - &snd_mpu401_uart_input); - rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | - SNDRV_RAWMIDI_INFO_INPUT | - SNDRV_RAWMIDI_INFO_DUPLEX; + if (out_enable) { + snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, + &snd_mpu401_uart_output); + rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT; + } + if (in_enable) { + snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, + &snd_mpu401_uart_input); + rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT; + if (out_enable) + rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX; + } mpu->rmidi = rmidi; if (rrawmidi) *rrawmidi = rmidi; diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c index d2a856f0fde2..27271c9446dc 100644 --- a/sound/isa/sscape.c +++ b/sound/isa/sscape.c @@ -897,10 +897,9 @@ static int __devinit create_mpu401(struct snd_card *card, int devnum, unsigned l struct snd_rawmidi *rawmidi; int err; -#define MPU401_SHARE_HARDWARE 1 if ((err = snd_mpu401_uart_new(card, devnum, MPU401_HW_MPU401, - port, MPU401_SHARE_HARDWARE, + port, MPU401_INFO_INTEGRATED, irq, SA_INTERRUPT, &rawmidi)) == 0) { struct snd_mpu401 *mpu = (struct snd_mpu401 *) rawmidi->private_data; diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c index 60423b1c678b..a9f08066459a 100644 --- a/sound/pci/als4000.c +++ b/sound/pci/als4000.c @@ -746,8 +746,8 @@ static int __devinit snd_card_als4000_probe(struct pci_dev *pci, card->shortname, chip->alt_port, chip->irq); if ((err = snd_mpu401_uart_new( card, 0, MPU401_HW_ALS4000, - gcr+0x30, 1, pci->irq, 0, - &chip->rmidi)) < 0) { + gcr+0x30, MPU401_INFO_INTEGRATED, + pci->irq, 0, &chip->rmidi)) < 0) { printk(KERN_ERR "als4000: no MPU-401 device at 0x%lx?\n", gcr+0x30); goto out_err; } diff --git a/sound/pci/au88x0/au88x0_mpu401.c b/sound/pci/au88x0/au88x0_mpu401.c index 1e128a3c8d89..5a0c53530fae 100644 --- a/sound/pci/au88x0/au88x0_mpu401.c +++ b/sound/pci/au88x0/au88x0_mpu401.c @@ -95,7 +95,8 @@ static int __devinit snd_vortex_midi(vortex_t * vortex) port = (unsigned long)(vortex->mmio + VORTEX_MIDI_DATA); if ((temp = snd_mpu401_uart_new(vortex->card, 0, MPU401_HW_AUREAL, port, - 1, 0, 0, &rmidi)) != 0) { + MPU401_INFO_INTEGRATED | MPU401_INFO_MMIO, + 0, 0, &rmidi)) != 0) { hwwrite(vortex->mmio, VORTEX_CTRL, (hwread(vortex->mmio, VORTEX_CTRL) & ~CTRL_MIDI_PORT) & ~CTRL_MIDI_EN); diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index e68056c81580..6e62dafb66cd 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c @@ -1806,8 +1806,8 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) card->private_data = chip; if ((err = snd_mpu401_uart_new( card, 0, MPU401_HW_MPU401, - chip->mpu_port, 1, pci->irq, 0, - &chip->rmidi)) < 0) { + chip->mpu_port, MPU401_INFO_INTEGRATED, + pci->irq, 0, &chip->rmidi)) < 0) { snd_printk(KERN_ERR "azf3328: no MPU-401 device at 0x%lx?\n", chip->mpu_port); goto out_err; } diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index cb475ada2ef1..79bc60a5204e 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -2981,7 +2981,9 @@ static int __devinit snd_cmipci_create(struct snd_card *card, struct pci_dev *pc if (iomidi > 0) { if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_CMIPCI, - iomidi, integrated_midi, + iomidi, + (integrated_midi ? + MPU401_INFO_INTEGRATED : 0), cm->irq, 0, &cm->rmidi)) < 0) { printk(KERN_ERR "cmipci: no UART401 device at 0x%lx\n", iomidi); } diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c index 8f46190f24ad..f61c4fa4ed62 100644 --- a/sound/pci/cs5535audio/cs5535audio.c +++ b/sound/pci/cs5535audio/cs5535audio.c @@ -56,17 +56,16 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = { {} }; -static int index = SNDRV_DEFAULT_IDX1; -static char *id = SNDRV_DEFAULT_STR1; -/* for backward compatibility */ -static int enable; +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; +static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; -module_param(index, int, 0444); +module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index value for " DRIVER_NAME); -module_param(id, charp, 0444); +module_param_array(id, charp, NULL, 0444); MODULE_PARM_DESC(id, "ID string for " DRIVER_NAME); -module_param(enable, bool, 0444); -MODULE_PARM_DESC(enable, "Enable for " DRIVER_NAME); +module_param_array(enable, bool, NULL, 0444); +MODULE_PARM_DESC(enable, "Enable " DRIVER_NAME); static struct pci_device_id snd_cs5535audio_ids[] __devinitdata = { { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_AUDIO) }, @@ -358,8 +357,12 @@ static int __devinit snd_cs5535audio_probe(struct pci_dev *pci, if (dev >= SNDRV_CARDS) return -ENODEV; + if (!enable[dev]) { + dev++; + return -ENOENT; + } - card = snd_card_new(index, id, THIS_MODULE, 0); + card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); if (card == NULL) return -ENOMEM; diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index 6f9094ca4fb4..ca6603fe0b11 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c @@ -1756,7 +1756,8 @@ static int __devinit snd_es1938_probe(struct pci_dev *pci, } } if (snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, - chip->mpu_port, 1, chip->irq, 0, &chip->rmidi) < 0) { + chip->mpu_port, MPU401_INFO_INTEGRATED, + chip->irq, 0, &chip->rmidi) < 0) { printk(KERN_ERR "es1938: unable to initialize MPU-401\n"); } else { // this line is vital for MIDI interrupt handling on ess-solo1 diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index f43bd380ac28..bfa0876e715e 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c @@ -2727,7 +2727,8 @@ static int __devinit snd_es1968_probe(struct pci_dev *pci, } if (enable_mpu[dev]) { if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, - chip->io_port + ESM_MPU401_PORT, 1, + chip->io_port + ESM_MPU401_PORT, + MPU401_INFO_INTEGRATED, chip->irq, 0, &chip->rmidi)) < 0) { printk(KERN_WARNING "es1968: skipping MPU-401 MIDI support..\n"); } diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index 0ec90f377319..0afa573dd244 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -1448,7 +1448,8 @@ static int __devinit snd_card_fm801_probe(struct pci_dev *pci, return err; } if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_FM801, - FM801_REG(chip, MPU401_DATA), 1, + FM801_REG(chip, MPU401_DATA), + MPU401_INFO_INTEGRATED, chip->irq, 0, &chip->rmidi)) < 0) { snd_card_free(card); return err; diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index 52de85e21b95..00e565e1db3a 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c @@ -2737,7 +2737,8 @@ static int __devinit snd_ice1712_probe(struct pci_dev *pci, if (! c->no_mpu401) { if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_ICE1712, - ICEREG(ice, MPU1_CTRL), 1, + ICEREG(ice, MPU1_CTRL), + MPU401_INFO_INTEGRATED, ice->irq, 0, &ice->rmidi[0])) < 0) { snd_card_free(card); @@ -2752,7 +2753,8 @@ static int __devinit snd_ice1712_probe(struct pci_dev *pci, if (ice->eeprom.data[ICE_EEP1_CODEC] & ICE1712_CFG_2xMPU401) { /* 2nd port used */ if ((err = snd_mpu401_uart_new(card, 1, MPU401_HW_ICE1712, - ICEREG(ice, MPU2_CTRL), 1, + ICEREG(ice, MPU2_CTRL), + MPU401_INFO_INTEGRATED, ice->irq, 0, &ice->rmidi[1])) < 0) { snd_card_free(card); diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 1031bcbf7064..34a58c629f47 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -2388,7 +2388,8 @@ static int __devinit snd_vt1724_probe(struct pci_dev *pci, if (! c->no_mpu401) { if (ice->eeprom.data[ICE_EEP2_SYSCONF] & VT1724_CFG_MPU401) { if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_ICE1712, - ICEREG1724(ice, MPU_CTRL), 1, + ICEREG1724(ice, MPU_CTRL), + MPU401_INFO_INTEGRATED, ice->irq, 0, &ice->rmidi[0])) < 0) { snd_card_free(card); diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index 1928e06b6d82..1c344fbd964d 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -2861,7 +2861,8 @@ snd_m3_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) #if 0 /* TODO: not supported yet */ /* TODO enable MIDI IRQ and I/O */ err = snd_mpu401_uart_new(chip->card, 0, MPU401_HW_MPU401, - chip->iobase + MPU401_DATA_PORT, 1, + chip->iobase + MPU401_DATA_PORT, + MPU401_INFO_INTEGRATED, chip->irq, 0, &chip->rmidi); if (err < 0) printk(KERN_WARNING "maestro3: no MIDI support.\n"); diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c index 51775706c843..dcf402948347 100644 --- a/sound/pci/sonicvibes.c +++ b/sound/pci/sonicvibes.c @@ -1456,7 +1456,7 @@ static int __devinit snd_sonic_probe(struct pci_dev *pci, return err; } if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_SONICVIBES, - sonic->midi_port, 1, + sonic->midi_port, MPU401_INFO_INTEGRATED, sonic->irq, 0, &midi_uart)) < 0) { snd_card_free(card); diff --git a/sound/pci/trident/trident.c b/sound/pci/trident/trident.c index 9624a5f2b875..5629b7eba96d 100644 --- a/sound/pci/trident/trident.c +++ b/sound/pci/trident/trident.c @@ -148,7 +148,8 @@ static int __devinit snd_trident_probe(struct pci_dev *pci, } if (trident->device != TRIDENT_DEVICE_ID_SI7018 && (err = snd_mpu401_uart_new(card, 0, MPU401_HW_TRID4DWAVE, - trident->midi_port, 1, + trident->midi_port, + MPU401_INFO_INTEGRATED, trident->irq, 0, &trident->rmidi)) < 0) { snd_card_free(card); return err; diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index a1b777e79c59..12ce22ef16e3 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -1973,7 +1973,7 @@ static int __devinit snd_via686_init_misc(struct via82xx *chip) pci_write_config_byte(chip->pci, VIA_PNP_CONTROL, legacy_cfg); if (chip->mpu_res) { if (snd_mpu401_uart_new(chip->card, 0, MPU401_HW_VIA686A, - mpu_port, 1, + mpu_port, MPU401_INFO_INTEGRATED, chip->irq, 0, &chip->rmidi) < 0) { printk(KERN_WARNING "unable to initialize MPU-401" " at 0x%lx, skipping\n", mpu_port); diff --git a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c index 65ebf5f1933a..26aa775b7b69 100644 --- a/sound/pci/ymfpci/ymfpci.c +++ b/sound/pci/ymfpci/ymfpci.c @@ -308,7 +308,8 @@ static int __devinit snd_card_ymfpci_probe(struct pci_dev *pci, } if (chip->mpu_res) { if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_YMFPCI, - mpu_port[dev], 1, + mpu_port[dev], + MPU401_INFO_INTEGRATED, pci->irq, 0, &chip->rawmidi)) < 0) { printk(KERN_WARNING "ymfpci: cannot initialize MPU401 at 0x%lx, skipping...\n", mpu_port[dev]); legacy_ctrl &= ~YMFPCI_LEGACY_MIEN; /* disable MPU401 irq */ -- cgit v1.2.3 From 1459c7849ea24fd71e4d2e678caa1cc3fef754e2 Mon Sep 17 00:00:00 2001 From: Rodolfo Giometti Date: Mon, 19 Jun 2006 15:04:54 +0200 Subject: [ALSA] Disable AC97 AUX and VIDEO controls for WM9705 touchscreen This patch by Rodolfo Giometti disables the AC97 AUX and VIDEO controls on the WM9705 when the touchscreen is selected as the AUX and VIDEO lines are shared with the touch controller. Changes:- o Added AC97_HAS_NO_AUX flag o Test for AC97_HAS_NO_AUX flag in snd_ac97_mixer_build() o Sets AC97_HAS_NO_VIDEO and AC97_HAS_NO_AUX in patch_wolfson05() when WM9705 touch driver is selected. Signed-off-by: Rodolfo Giometti Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai --- include/sound/ac97_codec.h | 1 + sound/pci/ac97/ac97_codec.c | 8 +++++--- sound/pci/ac97/ac97_patch.c | 4 ++++ 3 files changed, 10 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h index b45a73712748..446afc3ea27f 100644 --- a/include/sound/ac97_codec.h +++ b/include/sound/ac97_codec.h @@ -378,6 +378,7 @@ #define AC97_HAS_NO_MIC (1<<15) /* no MIC volume */ #define AC97_HAS_NO_TONE (1<<16) /* no Tone volume */ #define AC97_HAS_NO_STD_PCM (1<<17) /* no standard AC97 PCM volume and mute */ +#define AC97_HAS_NO_AUX (1<<18) /* no standard AC97 AUX volume and mute */ /* rates indexes */ #define AC97_RATES_FRONT_DAC 0 diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index f8389c2d3e60..0abf2808d59f 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -1348,9 +1348,11 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) } /* build Aux controls */ - if (snd_ac97_try_volume_mix(ac97, AC97_AUX)) { - if ((err = snd_ac97_cmix_new(card, "Aux Playback", AC97_AUX, ac97)) < 0) - return err; + if (!(ac97->flags & AC97_HAS_NO_AUX)) { + if (snd_ac97_try_volume_mix(ac97, AC97_AUX)) { + if ((err = snd_ac97_cmix_new(card, "Aux Playback", AC97_AUX, ac97)) < 0) + return err; + } } /* build PCM controls */ diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 1c47ee3d7ef8..cc93ee619086 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -464,6 +464,10 @@ int patch_wolfson05(struct snd_ac97 * ac97) { /* WM9705, WM9710 */ ac97->build_ops = &patch_wolfson_wm9705_ops; +#ifdef CONFIG_TOUCHSCREEN_WM9705 + /* WM9705 touchscreen uses AUX and VIDEO for touch */ + ac97->flags |=3D AC97_HAS_NO_VIDEO | AC97_HAS_NO_AUX; +#endif return 0; } -- cgit v1.2.3 From 0dad31d2da706ef114bc5c21123123be2f405d5b Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Thu, 22 Jun 2006 21:35:11 +0200 Subject: [ALSA] version 1.0.12rc1 --- include/sound/version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/sound/version.h b/include/sound/version.h index 4f0e65808cf1..2ee849d0e198 100644 --- a/include/sound/version.h +++ b/include/sound/version.h @@ -1,3 +1,3 @@ /* include/version.h. Generated by configure. */ -#define CONFIG_SND_VERSION "1.0.11rc4" -#define CONFIG_SND_DATE " (Wed Mar 22 10:27:24 2006 UTC)" +#define CONFIG_SND_VERSION "1.0.12rc1" +#define CONFIG_SND_DATE " (Thu Jun 22 13:55:50 2006 UTC)" -- cgit v1.2.3 From fa3e686a34f4c33de31a128cc36def0b466bfe1a Mon Sep 17 00:00:00 2001 From: Pavel Pisa Date: Thu, 22 Jun 2006 22:21:03 +0100 Subject: [ARM] 3601/1: i.MX/MX1 DMA error handling for signaled channels only Patch from Pavel Pisa There has been bug, that dma_err_handler() touches even channels not signaling error condition. Problem noticed by Andrea Paterniani. Signed-off-by: Pavel Pisa Signed-off-by: Russell King --- arch/arm/mach-imx/dma.c | 65 +++++++++++++++++++++++--------------- include/asm-arm/arch-imx/imx-dma.h | 8 +++-- 2 files changed, 45 insertions(+), 28 deletions(-) (limited to 'include') diff --git a/arch/arm/mach-imx/dma.c b/arch/arm/mach-imx/dma.c index 4ca51dcf13ac..36578871ecc8 100644 --- a/arch/arm/mach-imx/dma.c +++ b/arch/arm/mach-imx/dma.c @@ -15,6 +15,9 @@ * Changed to support scatter gather DMA * by taking Russell's code from RiscPC * + * 2006-05-31 Pavel Pisa + * Corrected error handling code. + * */ #undef DEBUG @@ -277,7 +280,7 @@ imx_dma_setup_sg(imx_dmach_t dma_ch, int imx_dma_setup_handlers(imx_dmach_t dma_ch, void (*irq_handler) (int, void *, struct pt_regs *), - void (*err_handler) (int, void *, struct pt_regs *), + void (*err_handler) (int, void *, struct pt_regs *, int), void *data) { struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch]; @@ -463,43 +466,53 @@ static irqreturn_t dma_err_handler(int irq, void *dev_id, struct pt_regs *regs) int i, disr = DISR; struct imx_dma_channel *channel; unsigned int err_mask = DBTOSR | DRTOSR | DSESR | DBOSR; + int errcode; - DISR = disr; + DISR = disr & err_mask; for (i = 0; i < IMX_DMA_CHANNELS; i++) { - channel = &imx_dma_channels[i]; - - if ((err_mask & 1 << i) && channel->name - && channel->err_handler) { - channel->err_handler(i, channel->data, regs); + if(!(err_mask & (1 << i))) continue; - } - - imx_dma_channels[i].sg = NULL; + channel = &imx_dma_channels[i]; + errcode = 0; if (DBTOSR & (1 << i)) { - printk(KERN_WARNING - "Burst timeout on channel %d (%s)\n", - i, channel->name); - DBTOSR |= (1 << i); + DBTOSR = (1 << i); + errcode |= IMX_DMA_ERR_BURST; } if (DRTOSR & (1 << i)) { - printk(KERN_WARNING - "Request timeout on channel %d (%s)\n", - i, channel->name); - DRTOSR |= (1 << i); + DRTOSR = (1 << i); + errcode |= IMX_DMA_ERR_REQUEST; } if (DSESR & (1 << i)) { - printk(KERN_WARNING - "Transfer timeout on channel %d (%s)\n", - i, channel->name); - DSESR |= (1 << i); + DSESR = (1 << i); + errcode |= IMX_DMA_ERR_TRANSFER; } if (DBOSR & (1 << i)) { - printk(KERN_WARNING - "Buffer overflow timeout on channel %d (%s)\n", - i, channel->name); - DBOSR |= (1 << i); + DBOSR = (1 << i); + errcode |= IMX_DMA_ERR_BUFFER; } + + /* + * The cleaning of @sg field would be questionable + * there, because its value can help to compute + * remaining/transfered bytes count in the handler + */ + /*imx_dma_channels[i].sg = NULL;*/ + + if (channel->name && channel->err_handler) { + channel->err_handler(i, channel->data, regs, errcode); + continue; + } + + imx_dma_channels[i].sg = NULL; + + printk(KERN_WARNING + "DMA timeout on channel %d (%s) -%s%s%s%s\n", + i, channel->name, + errcode&IMX_DMA_ERR_BURST? " burst":"", + errcode&IMX_DMA_ERR_REQUEST? " request":"", + errcode&IMX_DMA_ERR_TRANSFER? " transfer":"", + errcode&IMX_DMA_ERR_BUFFER? " buffer":""); } return IRQ_HANDLED; } diff --git a/include/asm-arm/arch-imx/imx-dma.h b/include/asm-arm/arch-imx/imx-dma.h index f2063c1d610d..599f03e5a9ef 100644 --- a/include/asm-arm/arch-imx/imx-dma.h +++ b/include/asm-arm/arch-imx/imx-dma.h @@ -46,7 +46,7 @@ struct imx_dma_channel { const char *name; void (*irq_handler) (int, void *, struct pt_regs *); - void (*err_handler) (int, void *, struct pt_regs *); + void (*err_handler) (int, void *, struct pt_regs *, int errcode); void *data; dmamode_t dma_mode; struct scatterlist *sg; @@ -58,6 +58,10 @@ struct imx_dma_channel { extern struct imx_dma_channel imx_dma_channels[IMX_DMA_CHANNELS]; +#define IMX_DMA_ERR_BURST 1 +#define IMX_DMA_ERR_REQUEST 2 +#define IMX_DMA_ERR_TRANSFER 4 +#define IMX_DMA_ERR_BUFFER 8 /* The type to distinguish channel numbers parameter from ordinal int type */ typedef int imx_dmach_t; @@ -74,7 +78,7 @@ imx_dma_setup_sg(imx_dmach_t dma_ch, int imx_dma_setup_handlers(imx_dmach_t dma_ch, void (*irq_handler) (int, void *, struct pt_regs *), - void (*err_handler) (int, void *, struct pt_regs *), void *data); + void (*err_handler) (int, void *, struct pt_regs *, int), void *data); void imx_dma_enable(imx_dmach_t dma_ch); -- cgit v1.2.3 From 02916526133aebc0b3b6c486d1b0af95221033bd Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 22 Jun 2006 22:57:54 +0100 Subject: [ARM] 3629/1: S3C24XX: fix missing bracket in regs-dsc.h Patch from Ben Dooks Fix missing bracket in include/asm-arm/arch-s3c2410/regs-dsc.h Signed-off-by: Ben Dooks Signed-off-by: Russell King --- include/asm-arm/arch-s3c2410/regs-dsc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/asm-arm/arch-s3c2410/regs-dsc.h b/include/asm-arm/arch-s3c2410/regs-dsc.h index a023b0434efe..ba13a2c9e547 100644 --- a/include/asm-arm/arch-s3c2410/regs-dsc.h +++ b/include/asm-arm/arch-s3c2410/regs-dsc.h @@ -170,7 +170,7 @@ #define S3C2440_DSC1_CS1_4mA (3<<2) #define S3C2440_DSC1_CS1_MASK (3<<2) -#define S3C2440_DSC1_CS0 (S3C2440_SELECT_DSC1 | 0 +#define S3C2440_DSC1_CS0 (S3C2440_SELECT_DSC1 | 0) #define S3C2440_DSC1_CS0_10mA (0<<0) #define S3C2440_DSC1_CS0_8mA (1<<0) #define S3C2440_DSC1_CS0_6mA (2<<0) -- cgit v1.2.3 From d720024e94de4e8b7f10ee83c532926f3ad5d708 Mon Sep 17 00:00:00 2001 From: Michael LeMay Date: Thu, 22 Jun 2006 14:47:17 -0700 Subject: [PATCH] selinux: add hooks for key subsystem Introduce SELinux hooks to support the access key retention subsystem within the kernel. Incorporate new flask headers from a modified version of the SELinux reference policy, with support for the new security class representing retained keys. Extend the "key_alloc" security hook with a task parameter representing the intended ownership context for the key being allocated. Attach security information to root's default keyrings within the SELinux initialization routine. Has passed David's testsuite. Signed-off-by: Michael LeMay Signed-off-by: David Howells Signed-off-by: James Morris Acked-by: Chris Wright Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/keys.txt | 29 +++++++++++++ include/linux/key.h | 18 +++++--- include/linux/security.h | 10 +++-- kernel/user.c | 2 +- security/dummy.c | 2 +- security/keys/key.c | 8 ++-- security/keys/keyring.c | 5 ++- security/keys/process_keys.c | 15 ++++--- security/keys/request_key.c | 6 ++- security/keys/request_key_auth.c | 2 +- security/selinux/hooks.c | 64 ++++++++++++++++++++++++++++ security/selinux/include/av_perm_to_string.h | 6 +++ security/selinux/include/av_permissions.h | 8 ++++ security/selinux/include/class_to_string.h | 1 + security/selinux/include/flask.h | 1 + security/selinux/include/objsec.h | 5 +++ 16 files changed, 155 insertions(+), 27 deletions(-) (limited to 'include') diff --git a/Documentation/keys.txt b/Documentation/keys.txt index aaa01b0e3ee9..703020012708 100644 --- a/Documentation/keys.txt +++ b/Documentation/keys.txt @@ -19,6 +19,7 @@ This document has the following sections: - Key overview - Key service overview - Key access permissions + - SELinux support - New procfs files - Userspace system call interface - Kernel services @@ -232,6 +233,34 @@ For changing the ownership, group ID or permissions mask, being the owner of the key or having the sysadmin capability is sufficient. +=============== +SELINUX SUPPORT +=============== + +The security class "key" has been added to SELinux so that mandatory access +controls can be applied to keys created within various contexts. This support +is preliminary, and is likely to change quite significantly in the near future. +Currently, all of the basic permissions explained above are provided in SELinux +as well; SE Linux is simply invoked after all basic permission checks have been +performed. + +Each key is labeled with the same context as the task to which it belongs. +Typically, this is the same task that was running when the key was created. +The default keyrings are handled differently, but in a way that is very +intuitive: + + (*) The user and user session keyrings that are created when the user logs in + are currently labeled with the context of the login manager. + + (*) The keyrings associated with new threads are each labeled with the context + of their associated thread, and both session and process keyrings are + handled similarly. + +Note, however, that the default keyrings associated with the root user are +labeled with the default kernel context, since they are created early in the +boot process, before root has a chance to log in. + + ================ NEW PROCFS FILES ================ diff --git a/include/linux/key.h b/include/linux/key.h index cbf464ad9589..8c275d12ef63 100644 --- a/include/linux/key.h +++ b/include/linux/key.h @@ -241,8 +241,9 @@ extern void unregister_key_type(struct key_type *ktype); extern struct key *key_alloc(struct key_type *type, const char *desc, - uid_t uid, gid_t gid, key_perm_t perm, - int not_in_quota); + uid_t uid, gid_t gid, + struct task_struct *ctx, + key_perm_t perm, int not_in_quota); extern int key_payload_reserve(struct key *key, size_t datalen); extern int key_instantiate_and_link(struct key *key, const void *data, @@ -292,7 +293,9 @@ extern int key_unlink(struct key *keyring, struct key *key); extern struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid, - int not_in_quota, struct key *dest); + struct task_struct *ctx, + int not_in_quota, + struct key *dest); extern int keyring_clear(struct key *keyring); @@ -313,7 +316,8 @@ extern void keyring_replace_payload(struct key *key, void *replacement); * the userspace interface */ extern struct key root_user_keyring, root_session_keyring; -extern int alloc_uid_keyring(struct user_struct *user); +extern int alloc_uid_keyring(struct user_struct *user, + struct task_struct *ctx); extern void switch_uid_keyring(struct user_struct *new_user); extern int copy_keys(unsigned long clone_flags, struct task_struct *tsk); extern int copy_thread_group_keys(struct task_struct *tsk); @@ -342,7 +346,7 @@ extern void key_init(void); #define make_key_ref(k) ({ NULL; }) #define key_ref_to_ptr(k) ({ NULL; }) #define is_key_possessed(k) 0 -#define alloc_uid_keyring(u) 0 +#define alloc_uid_keyring(u,c) 0 #define switch_uid_keyring(u) do { } while(0) #define __install_session_keyring(t, k) ({ NULL; }) #define copy_keys(f,t) 0 @@ -355,6 +359,10 @@ extern void key_init(void); #define key_fsgid_changed(t) do { } while(0) #define key_init() do { } while(0) +/* Initial keyrings */ +extern struct key root_user_keyring; +extern struct key root_session_keyring; + #endif /* CONFIG_KEYS */ #endif /* __KERNEL__ */ #endif /* _LINUX_KEY_H */ diff --git a/include/linux/security.h b/include/linux/security.h index 4dfb1b84a9b3..47722d355532 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -1313,7 +1313,7 @@ struct security_operations { /* key management security hooks */ #ifdef CONFIG_KEYS - int (*key_alloc)(struct key *key); + int (*key_alloc)(struct key *key, struct task_struct *tsk); void (*key_free)(struct key *key); int (*key_permission)(key_ref_t key_ref, struct task_struct *context, @@ -3008,9 +3008,10 @@ static inline int security_xfrm_policy_lookup(struct xfrm_policy *xp, u32 sk_sid #ifdef CONFIG_KEYS #ifdef CONFIG_SECURITY -static inline int security_key_alloc(struct key *key) +static inline int security_key_alloc(struct key *key, + struct task_struct *tsk) { - return security_ops->key_alloc(key); + return security_ops->key_alloc(key, tsk); } static inline void security_key_free(struct key *key) @@ -3027,7 +3028,8 @@ static inline int security_key_permission(key_ref_t key_ref, #else -static inline int security_key_alloc(struct key *key) +static inline int security_key_alloc(struct key *key, + struct task_struct *tsk) { return 0; } diff --git a/kernel/user.c b/kernel/user.c index 4b1eb745afa1..6408c0424291 100644 --- a/kernel/user.c +++ b/kernel/user.c @@ -148,7 +148,7 @@ struct user_struct * alloc_uid(uid_t uid) new->mq_bytes = 0; new->locked_shm = 0; - if (alloc_uid_keyring(new) < 0) { + if (alloc_uid_keyring(new, current) < 0) { kmem_cache_free(uid_cachep, new); return NULL; } diff --git a/security/dummy.c b/security/dummy.c index 64f6da0f422e..6de4a4a5eb13 100644 --- a/security/dummy.c +++ b/security/dummy.c @@ -860,7 +860,7 @@ static int dummy_setprocattr(struct task_struct *p, char *name, void *value, siz } #ifdef CONFIG_KEYS -static inline int dummy_key_alloc(struct key *key) +static inline int dummy_key_alloc(struct key *key, struct task_struct *ctx) { return 0; } diff --git a/security/keys/key.c b/security/keys/key.c index 3fdc49c6a02c..14a15abb7735 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -247,8 +247,8 @@ static inline void key_alloc_serial(struct key *key) * instantiate the key or discard it before returning */ struct key *key_alloc(struct key_type *type, const char *desc, - uid_t uid, gid_t gid, key_perm_t perm, - int not_in_quota) + uid_t uid, gid_t gid, struct task_struct *ctx, + key_perm_t perm, int not_in_quota) { struct key_user *user = NULL; struct key *key; @@ -318,7 +318,7 @@ struct key *key_alloc(struct key_type *type, const char *desc, #endif /* let the security module know about the key */ - ret = security_key_alloc(key); + ret = security_key_alloc(key, ctx); if (ret < 0) goto security_error; @@ -822,7 +822,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, /* allocate a new key */ key = key_alloc(ktype, description, current->fsuid, current->fsgid, - perm, not_in_quota); + current, perm, not_in_quota); if (IS_ERR(key)) { key_ref = ERR_PTR(PTR_ERR(key)); goto error_3; diff --git a/security/keys/keyring.c b/security/keys/keyring.c index bffa924c1f88..1357207fc9df 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c @@ -240,13 +240,14 @@ static long keyring_read(const struct key *keyring, * allocate a keyring and link into the destination keyring */ struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid, - int not_in_quota, struct key *dest) + struct task_struct *ctx, int not_in_quota, + struct key *dest) { struct key *keyring; int ret; keyring = key_alloc(&key_type_keyring, description, - uid, gid, + uid, gid, ctx, (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL, not_in_quota); diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index 217a0bef3c82..a50a91332fe1 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c @@ -67,7 +67,8 @@ struct key root_session_keyring = { /* * allocate the keyrings to be associated with a UID */ -int alloc_uid_keyring(struct user_struct *user) +int alloc_uid_keyring(struct user_struct *user, + struct task_struct *ctx) { struct key *uid_keyring, *session_keyring; char buf[20]; @@ -76,7 +77,7 @@ int alloc_uid_keyring(struct user_struct *user) /* concoct a default session keyring */ sprintf(buf, "_uid_ses.%u", user->uid); - session_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, 0, NULL); + session_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, ctx, 0, NULL); if (IS_ERR(session_keyring)) { ret = PTR_ERR(session_keyring); goto error; @@ -86,7 +87,7 @@ int alloc_uid_keyring(struct user_struct *user) * keyring */ sprintf(buf, "_uid.%u", user->uid); - uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, 0, + uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, ctx, 0, session_keyring); if (IS_ERR(uid_keyring)) { key_put(session_keyring); @@ -143,7 +144,7 @@ int install_thread_keyring(struct task_struct *tsk) sprintf(buf, "_tid.%u", tsk->pid); - keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL); + keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk, 1, NULL); if (IS_ERR(keyring)) { ret = PTR_ERR(keyring); goto error; @@ -177,7 +178,7 @@ int install_process_keyring(struct task_struct *tsk) if (!tsk->signal->process_keyring) { sprintf(buf, "_pid.%u", tsk->tgid); - keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL); + keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk, 1, NULL); if (IS_ERR(keyring)) { ret = PTR_ERR(keyring); goto error; @@ -217,7 +218,7 @@ static int install_session_keyring(struct task_struct *tsk, if (!keyring) { sprintf(buf, "_ses.%u", tsk->tgid); - keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL); + keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk, 1, NULL); if (IS_ERR(keyring)) return PTR_ERR(keyring); } @@ -717,7 +718,7 @@ long join_session_keyring(const char *name) keyring = find_keyring_by_name(name, 0); if (PTR_ERR(keyring) == -ENOKEY) { /* not found - try and create a new one */ - keyring = keyring_alloc(name, tsk->uid, tsk->gid, 0, NULL); + keyring = keyring_alloc(name, tsk->uid, tsk->gid, tsk, 0, NULL); if (IS_ERR(keyring)) { ret = PTR_ERR(keyring); goto error2; diff --git a/security/keys/request_key.c b/security/keys/request_key.c index f030a0ccbb93..eab66a06ca53 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c @@ -48,7 +48,8 @@ static int call_sbin_request_key(struct key *key, /* allocate a new session keyring */ sprintf(desc, "_req.%u", key->serial); - keyring = keyring_alloc(desc, current->fsuid, current->fsgid, 1, NULL); + keyring = keyring_alloc(desc, current->fsuid, current->fsgid, + current, 1, NULL); if (IS_ERR(keyring)) { ret = PTR_ERR(keyring); goto error_alloc; @@ -137,7 +138,8 @@ static struct key *__request_key_construction(struct key_type *type, /* create a key and add it to the queue */ key = key_alloc(type, description, - current->fsuid, current->fsgid, KEY_POS_ALL, 0); + current->fsuid, current->fsgid, + current, KEY_POS_ALL, 0); if (IS_ERR(key)) goto alloc_failed; diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c index cce6ba6b0323..0ecc2e8d2bd0 100644 --- a/security/keys/request_key_auth.c +++ b/security/keys/request_key_auth.c @@ -148,7 +148,7 @@ struct key *request_key_auth_new(struct key *target, const char *callout_info) sprintf(desc, "%x", target->serial); authkey = key_alloc(&key_type_request_key_auth, desc, - current->fsuid, current->fsgid, + current->fsuid, current->fsgid, current, KEY_POS_VIEW | KEY_POS_READ | KEY_POS_SEARCH | KEY_USR_VIEW, 1); if (IS_ERR(authkey)) { diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 54adc9d31e92..524915dfda64 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -4252,6 +4252,57 @@ static int selinux_setprocattr(struct task_struct *p, return size; } +#ifdef CONFIG_KEYS + +static int selinux_key_alloc(struct key *k, struct task_struct *tsk) +{ + struct task_security_struct *tsec = tsk->security; + struct key_security_struct *ksec; + + ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL); + if (!ksec) + return -ENOMEM; + + ksec->obj = k; + ksec->sid = tsec->sid; + k->security = ksec; + + return 0; +} + +static void selinux_key_free(struct key *k) +{ + struct key_security_struct *ksec = k->security; + + k->security = NULL; + kfree(ksec); +} + +static int selinux_key_permission(key_ref_t key_ref, + struct task_struct *ctx, + key_perm_t perm) +{ + struct key *key; + struct task_security_struct *tsec; + struct key_security_struct *ksec; + + key = key_ref_to_ptr(key_ref); + + tsec = ctx->security; + ksec = key->security; + + /* if no specific permissions are requested, we skip the + permission check. No serious, additional covert channels + appear to be created. */ + if (perm == 0) + return 0; + + return avc_has_perm(tsec->sid, ksec->sid, + SECCLASS_KEY, perm, NULL); +} + +#endif + static struct security_operations selinux_ops = { .ptrace = selinux_ptrace, .capget = selinux_capget, @@ -4406,6 +4457,12 @@ static struct security_operations selinux_ops = { .xfrm_state_delete_security = selinux_xfrm_state_delete, .xfrm_policy_lookup = selinux_xfrm_policy_lookup, #endif + +#ifdef CONFIG_KEYS + .key_alloc = selinux_key_alloc, + .key_free = selinux_key_free, + .key_permission = selinux_key_permission, +#endif }; static __init int selinux_init(void) @@ -4441,6 +4498,13 @@ static __init int selinux_init(void) } else { printk(KERN_INFO "SELinux: Starting in permissive mode\n"); } + +#ifdef CONFIG_KEYS + /* Add security information to initial keyrings */ + security_key_alloc(&root_user_keyring, current); + security_key_alloc(&root_session_keyring, current); +#endif + return 0; } diff --git a/security/selinux/include/av_perm_to_string.h b/security/selinux/include/av_perm_to_string.h index 70ee65a58817..bc020bde6c86 100644 --- a/security/selinux/include/av_perm_to_string.h +++ b/security/selinux/include/av_perm_to_string.h @@ -242,3 +242,9 @@ S_(SECCLASS_PACKET, PACKET__SEND, "send") S_(SECCLASS_PACKET, PACKET__RECV, "recv") S_(SECCLASS_PACKET, PACKET__RELABELTO, "relabelto") + S_(SECCLASS_KEY, KEY__VIEW, "view") + S_(SECCLASS_KEY, KEY__READ, "read") + S_(SECCLASS_KEY, KEY__WRITE, "write") + S_(SECCLASS_KEY, KEY__SEARCH, "search") + S_(SECCLASS_KEY, KEY__LINK, "link") + S_(SECCLASS_KEY, KEY__SETATTR, "setattr") diff --git a/security/selinux/include/av_permissions.h b/security/selinux/include/av_permissions.h index 1d9cf3d306bc..1205227a3a33 100644 --- a/security/selinux/include/av_permissions.h +++ b/security/selinux/include/av_permissions.h @@ -959,3 +959,11 @@ #define PACKET__SEND 0x00000001UL #define PACKET__RECV 0x00000002UL #define PACKET__RELABELTO 0x00000004UL + +#define KEY__VIEW 0x00000001UL +#define KEY__READ 0x00000002UL +#define KEY__WRITE 0x00000004UL +#define KEY__SEARCH 0x00000008UL +#define KEY__LINK 0x00000010UL +#define KEY__SETATTR 0x00000020UL + diff --git a/security/selinux/include/class_to_string.h b/security/selinux/include/class_to_string.h index 3aec75fee4f7..24303b61309f 100644 --- a/security/selinux/include/class_to_string.h +++ b/security/selinux/include/class_to_string.h @@ -60,3 +60,4 @@ S_("netlink_kobject_uevent_socket") S_("appletalk_socket") S_("packet") + S_("key") diff --git a/security/selinux/include/flask.h b/security/selinux/include/flask.h index a0eb9e281d18..95887aed2a68 100644 --- a/security/selinux/include/flask.h +++ b/security/selinux/include/flask.h @@ -62,6 +62,7 @@ #define SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET 55 #define SECCLASS_APPLETALK_SOCKET 56 #define SECCLASS_PACKET 57 +#define SECCLASS_KEY 58 /* * Security identifier indices for initial entities diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index 54c030778882..8f5547ad1856 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h @@ -99,6 +99,11 @@ struct sk_security_struct { u32 peer_sid; /* SID of peer */ }; +struct key_security_struct { + struct key *obj; /* back pointer */ + u32 sid; /* SID of key */ +}; + extern unsigned int selinux_checkreqprot; #endif /* _SELINUX_OBJSEC_H_ */ -- cgit v1.2.3 From 04c567d9313e4927b9835361d8ac0318ce65af6b Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 22 Jun 2006 14:47:18 -0700 Subject: [PATCH] Keys: Fix race between two instantiators of a key Add a revocation notification method to the key type and calls it whilst the key's semaphore is still write-locked after setting the revocation flag. The patch then uses this to maintain a reference on the task_struct of the process that calls request_key() for as long as the authorisation key remains unrevoked. This fixes a potential race between two processes both of which have assumed the authority to instantiate a key (one may have forked the other for example). The problem is that there's no locking around the check for revocation of the auth key and the use of the task_struct it points to, nor does the auth key keep a reference on the task_struct. Access to the "context" pointer in the auth key must thenceforth be done with the auth key semaphore held. The revocation method is called with the target key semaphore held write-locked and the search of the context process's keyrings is done with the auth key semaphore read-locked. The check for the revocation state of the auth key just prior to searching it is done after the auth key is read-locked for the search. This ensures that the auth key can't be revoked between the check and the search. The revocation notification method is added so that the context task_struct can be released as soon as instantiation happens rather than waiting for the auth key to be destroyed, thus avoiding the unnecessary pinning of the requesting process. Signed-off-by: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/keys.txt | 10 +++++++++ include/linux/key.h | 5 +++++ security/keys/key.c | 4 ++++ security/keys/process_keys.c | 42 +++++++++++++++++++++++-------------- security/keys/request_key_auth.c | 45 +++++++++++++++++++++++++++++++++++++++- 5 files changed, 89 insertions(+), 17 deletions(-) (limited to 'include') diff --git a/Documentation/keys.txt b/Documentation/keys.txt index 703020012708..3bbe157b45e4 100644 --- a/Documentation/keys.txt +++ b/Documentation/keys.txt @@ -964,6 +964,16 @@ The structure has a number of fields, some of which are mandatory: It is not safe to sleep in this method; the caller may hold spinlocks. + (*) void (*revoke)(struct key *key); + + This method is optional. It is called to discard part of the payload + data upon a key being revoked. The caller will have the key semaphore + write-locked. + + It is safe to sleep in this method, though care should be taken to avoid + a deadlock against the key semaphore. + + (*) void (*destroy)(struct key *key); This method is optional. It is called to discard the payload data on a key diff --git a/include/linux/key.h b/include/linux/key.h index 8c275d12ef63..e81ebf910d0b 100644 --- a/include/linux/key.h +++ b/include/linux/key.h @@ -205,6 +205,11 @@ struct key_type { /* match a key against a description */ int (*match)(const struct key *key, const void *desc); + /* clear some of the data from a key on revokation (optional) + * - the key's semaphore will be write-locked by the caller + */ + void (*revoke)(struct key *key); + /* clear the data from a key (optional) */ void (*destroy)(struct key *key); diff --git a/security/keys/key.c b/security/keys/key.c index 14a15abb7735..51f851557389 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -907,6 +907,10 @@ void key_revoke(struct key *key) * it */ down_write(&key->sem); set_bit(KEY_FLAG_REVOKED, &key->flags); + + if (key->type->revoke) + key->type->revoke(key); + up_write(&key->sem); } /* end key_revoke() */ diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index a50a91332fe1..4d9825f9962c 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c @@ -391,6 +391,8 @@ key_ref_t search_process_keyrings(struct key_type *type, struct request_key_auth *rka; key_ref_t key_ref, ret, err; + might_sleep(); + /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were * searchable, but we failed to find a key or we found a negative key; * otherwise we want to return a sample error (probably -EACCES) if @@ -496,27 +498,35 @@ key_ref_t search_process_keyrings(struct key_type *type, */ if (context->request_key_auth && context == current && - type != &key_type_request_key_auth && - key_validate(context->request_key_auth) == 0 + type != &key_type_request_key_auth ) { - rka = context->request_key_auth->payload.data; + /* defend against the auth key being revoked */ + down_read(&context->request_key_auth->sem); - key_ref = search_process_keyrings(type, description, match, - rka->context); + if (key_validate(context->request_key_auth) == 0) { + rka = context->request_key_auth->payload.data; - if (!IS_ERR(key_ref)) - goto found; + key_ref = search_process_keyrings(type, description, + match, rka->context); - switch (PTR_ERR(key_ref)) { - case -EAGAIN: /* no key */ - if (ret) + up_read(&context->request_key_auth->sem); + + if (!IS_ERR(key_ref)) + goto found; + + switch (PTR_ERR(key_ref)) { + case -EAGAIN: /* no key */ + if (ret) + break; + case -ENOKEY: /* negative key */ + ret = key_ref; break; - case -ENOKEY: /* negative key */ - ret = key_ref; - break; - default: - err = key_ref; - break; + default: + err = key_ref; + break; + } + } else { + up_read(&context->request_key_auth->sem); } } diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c index 0ecc2e8d2bd0..cb9817ced3fd 100644 --- a/security/keys/request_key_auth.c +++ b/security/keys/request_key_auth.c @@ -20,6 +20,7 @@ static int request_key_auth_instantiate(struct key *, const void *, size_t); static void request_key_auth_describe(const struct key *, struct seq_file *); +static void request_key_auth_revoke(struct key *); static void request_key_auth_destroy(struct key *); static long request_key_auth_read(const struct key *, char __user *, size_t); @@ -31,6 +32,7 @@ struct key_type key_type_request_key_auth = { .def_datalen = sizeof(struct request_key_auth), .instantiate = request_key_auth_instantiate, .describe = request_key_auth_describe, + .revoke = request_key_auth_revoke, .destroy = request_key_auth_destroy, .read = request_key_auth_read, }; @@ -91,6 +93,24 @@ static long request_key_auth_read(const struct key *key, } /* end request_key_auth_read() */ +/*****************************************************************************/ +/* + * handle revocation of an authorisation token key + * - called with the key sem write-locked + */ +static void request_key_auth_revoke(struct key *key) +{ + struct request_key_auth *rka = key->payload.data; + + kenter("{%d}", key->serial); + + if (rka->context) { + put_task_struct(rka->context); + rka->context = NULL; + } + +} /* end request_key_auth_revoke() */ + /*****************************************************************************/ /* * destroy an instantiation authorisation token key @@ -101,6 +121,11 @@ static void request_key_auth_destroy(struct key *key) kenter("{%d}", key->serial); + if (rka->context) { + put_task_struct(rka->context); + rka->context = NULL; + } + key_put(rka->target_key); kfree(rka); @@ -131,14 +156,26 @@ struct key *request_key_auth_new(struct key *target, const char *callout_info) * another process */ if (current->request_key_auth) { /* it is - use that instantiation context here too */ + down_read(¤t->request_key_auth->sem); + + /* if the auth key has been revoked, then the key we're + * servicing is already instantiated */ + if (test_bit(KEY_FLAG_REVOKED, + ¤t->request_key_auth->flags)) + goto auth_key_revoked; + irka = current->request_key_auth->payload.data; rka->context = irka->context; rka->pid = irka->pid; + get_task_struct(rka->context); + + up_read(¤t->request_key_auth->sem); } else { /* it isn't - use this process as the context */ rka->context = current; rka->pid = current->pid; + get_task_struct(rka->context); } rka->target_key = key_get(target); @@ -161,9 +198,15 @@ struct key *request_key_auth_new(struct key *target, const char *callout_info) if (ret < 0) goto error_inst; - kleave(" = {%d})", authkey->serial); + kleave(" = {%d}", authkey->serial); return authkey; +auth_key_revoked: + up_read(¤t->request_key_auth->sem); + kfree(rka); + kleave("= -EKEYREVOKED"); + return ERR_PTR(-EKEYREVOKED); + error_inst: key_revoke(authkey); key_put(authkey); -- cgit v1.2.3 From 0e5b3781591cc954037c08ef78edf7f1192d38c5 Mon Sep 17 00:00:00 2001 From: Brice Goglin Date: Thu, 22 Jun 2006 14:47:20 -0700 Subject: [PATCH] PCI: Add PCI_CAP_ID_VNDR Add the vendor-specific extended capability PCI_CAP_ID_VNDR. It is required by the Myri-10G Ethernet driver. Signed-off-by: Brice Goglin Signed-off-by: Greg Kroah-Hartman Cc: Jeff Garzik Cc: "David S. Miller" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/pci_regs.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h index d27a78b71297..6bce4a240364 100644 --- a/include/linux/pci_regs.h +++ b/include/linux/pci_regs.h @@ -197,6 +197,7 @@ #define PCI_CAP_ID_CHSWP 0x06 /* CompactPCI HotSwap */ #define PCI_CAP_ID_PCIX 0x07 /* PCI-X */ #define PCI_CAP_ID_HT_IRQCONF 0x08 /* HyperTransport IRQ Configuration */ +#define PCI_CAP_ID_VNDR 0x09 /* Vendor specific capability */ #define PCI_CAP_ID_SHPC 0x0C /* PCI Standard Hot-Plug Controller */ #define PCI_CAP_ID_EXP 0x10 /* PCI Express */ #define PCI_CAP_ID_MSIX 0x11 /* MSI-X */ -- cgit v1.2.3 From c89681ed7d0e4a61d35bdc12c06c6733b718b2cb Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Thu, 22 Jun 2006 14:47:22 -0700 Subject: [PATCH] remove steal_locks() This patch removes the steal_locks() function. steal_locks() doesn't work correctly with any filesystem that does it's own lock management, including NFS, CIFS, etc. In addition it has weird semantics on local filesystems in case tasks sharing file-descriptor tables are doing POSIX locking operations in parallel to execve(). The steal_locks() function has an effect on applications doing: clone(CLONE_FILES) /* in child */ lock execve lock POSIX locks acquired before execve (by "child", "parent" or any further task sharing files_struct) will after the execve be owned exclusively by "child". According to Chris Wright some LSB/LTP kind of suite triggers without the stealing behavior, but there's no known real-world application that would also fail. Apps using NPTL are not affected, since all other threads are killed before execve. Apps using LinuxThreads are only affected if they - have multiple threads during exec (LinuxThreads doesn't kill other threads, the app may do it with pthread_kill_other_threads_np()) - rely on POSIX locks being inherited across exec Both conditions are documented, but not their interaction. Apps using clone() natively are affected if they - use clone(CLONE_FILES) - rely on POSIX locks being inherited across exec The above scenarios are unlikely, but possible. If the patch is vetoed, there's a plan B, that involves mostly keeping the weird stealing semantics, but changing the way lock ownership is handled so that network and local filesystems work consistently. That would add more complexity though, so this solution seems to be preferred by most people. Signed-off-by: Miklos Szeredi Cc: Trond Myklebust Cc: Matthew Wilcox Cc: Chris Wright Cc: Christoph Hellwig Cc: Steven French Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/binfmt_elf.c | 1 - fs/binfmt_misc.c | 1 - fs/exec.c | 1 - fs/locks.c | 57 ------------------------------------------------------ include/linux/fs.h | 1 - 5 files changed, 61 deletions(-) (limited to 'include') diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 537893a16014..8a04216e8b4d 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -759,7 +759,6 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) /* Discard our unneeded old files struct */ if (files) { - steal_locks(files); put_files_struct(files); files = NULL; } diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index d73d75591a39..599f36fd0f67 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c @@ -203,7 +203,6 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs) goto _error; if (files) { - steal_locks(files); put_files_struct(files); files = NULL; } diff --git a/fs/exec.c b/fs/exec.c index d07858c0b7c4..0b88bf646143 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -866,7 +866,6 @@ int flush_old_exec(struct linux_binprm * bprm) bprm->mm = NULL; /* We're using it now */ /* This is the point of no return */ - steal_locks(files); put_files_struct(files); current->sas_ss_sp = current->sas_ss_size = 0; diff --git a/fs/locks.c b/fs/locks.c index ab61a8b54829..69435c68c1ed 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -2206,63 +2206,6 @@ int lock_may_write(struct inode *inode, loff_t start, unsigned long len) EXPORT_SYMBOL(lock_may_write); -static inline void __steal_locks(struct file *file, fl_owner_t from) -{ - struct inode *inode = file->f_dentry->d_inode; - struct file_lock *fl = inode->i_flock; - - while (fl) { - if (fl->fl_file == file && fl->fl_owner == from) - fl->fl_owner = current->files; - fl = fl->fl_next; - } -} - -/* When getting ready for executing a binary, we make sure that current - * has a files_struct on its own. Before dropping the old files_struct, - * we take over ownership of all locks for all file descriptors we own. - * Note that we may accidentally steal a lock for a file that a sibling - * has created since the unshare_files() call. - */ -void steal_locks(fl_owner_t from) -{ - struct files_struct *files = current->files; - int i, j; - struct fdtable *fdt; - - if (from == files) - return; - - lock_kernel(); - j = 0; - - /* - * We are not taking a ref to the file structures, so - * we need to acquire ->file_lock. - */ - spin_lock(&files->file_lock); - fdt = files_fdtable(files); - for (;;) { - unsigned long set; - i = j * __NFDBITS; - if (i >= fdt->max_fdset || i >= fdt->max_fds) - break; - set = fdt->open_fds->fds_bits[j++]; - while (set) { - if (set & 1) { - struct file *file = fdt->fd[i]; - if (file) - __steal_locks(file, from); - } - i++; - set >>= 1; - } - } - spin_unlock(&files->file_lock); - unlock_kernel(); -} -EXPORT_SYMBOL(steal_locks); - static int __init filelock_init(void) { filelock_cache = kmem_cache_create("file_lock_cache", diff --git a/include/linux/fs.h b/include/linux/fs.h index ecc8c2c3d8ca..73c7d6f04b31 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -782,7 +782,6 @@ extern int setlease(struct file *, long, struct file_lock **); extern int lease_modify(struct file_lock **, int); extern int lock_may_read(struct inode *, loff_t start, unsigned long count); extern int lock_may_write(struct inode *, loff_t start, unsigned long count); -extern void steal_locks(fl_owner_t from); struct fasync_struct { int magic; -- cgit v1.2.3 From 0feae5c47aabdde59cbbec32d150e17102de37f0 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 22 Jun 2006 14:47:28 -0700 Subject: [PATCH] Fix dcache race during umount The race is that the shrink_dcache_memory shrinker could get called while a filesystem is being unmounted, and could try to prune a dentry belonging to that filesystem. If it does, then it will call in to iput on the inode while the dentry is no longer able to be found by the umounting process. If iput takes a while, generic_shutdown_super could get all the way though shrink_dcache_parent and shrink_dcache_anon and invalidate_inodes without ever waiting on this particular inode. Eventually the superblock gets freed anyway and if the iput tried to touch it (which some filesystems certainly do), it will lose. The promised "Self-destruct in 5 seconds" doesn't lead to a nice day. The race is closed by holding s_umount while calling prune_one_dentry on someone else's dentry. As a down_read_trylock is used, shrink_dcache_memory will no longer try to prune the dentry of a filesystem that is being unmounted, and unmount will not be able to start until any such active prune_one_dentry completes. This requires that prune_dcache *knows* which filesystem (if any) it is doing the prune on behalf of so that it can be careful of other filesystems. shrink_dcache_memory isn't called it on behalf of any filesystem, and so is careful of everything. shrink_dcache_anon is now passed a super_block rather than the s_anon list out of the superblock, so it can get the s_anon list itself, and can pass the superblock down to prune_dcache. If prune_dcache finds a dentry that it cannot free, it leaves it where it is (at the tail of the list) and exits, on the assumption that some other thread will be removing that dentry soon. To try to make sure that some work gets done, a limited number of dnetries which are untouchable are skipped over while choosing the dentry to work on. I believe this race was first found by Kirill Korotaev. Cc: Jan Blunck Acked-by: Kirill Korotaev Cc: Olaf Hering Acked-by: Balbir Singh Signed-off-by: Neil Brown Signed-off-by: Balbir Singh Acked-by: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/dcache.c | 66 +++++++++++++++++++++++++++++++++++++++++++++----- fs/super.c | 2 +- include/linux/dcache.h | 2 +- 3 files changed, 62 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/fs/dcache.c b/fs/dcache.c index 940d188e5d14..385f5dbc4b0c 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -382,6 +382,8 @@ static inline void prune_one_dentry(struct dentry * dentry) /** * prune_dcache - shrink the dcache * @count: number of entries to try and free + * @sb: if given, ignore dentries for other superblocks + * which are being unmounted. * * Shrink the dcache. This is done when we need * more memory, or simply when we need to unmount @@ -392,16 +394,29 @@ static inline void prune_one_dentry(struct dentry * dentry) * all the dentries are in use. */ -static void prune_dcache(int count) +static void prune_dcache(int count, struct super_block *sb) { spin_lock(&dcache_lock); for (; count ; count--) { struct dentry *dentry; struct list_head *tmp; + struct rw_semaphore *s_umount; cond_resched_lock(&dcache_lock); tmp = dentry_unused.prev; + if (unlikely(sb)) { + /* Try to find a dentry for this sb, but don't try + * too hard, if they aren't near the tail they will + * be moved down again soon + */ + int skip = count; + while (skip && tmp != &dentry_unused && + list_entry(tmp, struct dentry, d_lru)->d_sb != sb) { + skip--; + tmp = tmp->prev; + } + } if (tmp == &dentry_unused) break; list_del_init(tmp); @@ -427,7 +442,45 @@ static void prune_dcache(int count) spin_unlock(&dentry->d_lock); continue; } - prune_one_dentry(dentry); + /* + * If the dentry is not DCACHED_REFERENCED, it is time + * to remove it from the dcache, provided the super block is + * NULL (which means we are trying to reclaim memory) + * or this dentry belongs to the same super block that + * we want to shrink. + */ + /* + * If this dentry is for "my" filesystem, then I can prune it + * without taking the s_umount lock (I already hold it). + */ + if (sb && dentry->d_sb == sb) { + prune_one_dentry(dentry); + continue; + } + /* + * ...otherwise we need to be sure this filesystem isn't being + * unmounted, otherwise we could race with + * generic_shutdown_super(), and end up holding a reference to + * an inode while the filesystem is unmounted. + * So we try to get s_umount, and make sure s_root isn't NULL. + * (Take a local copy of s_umount to avoid a use-after-free of + * `dentry'). + */ + s_umount = &dentry->d_sb->s_umount; + if (down_read_trylock(s_umount)) { + if (dentry->d_sb->s_root != NULL) { + prune_one_dentry(dentry); + up_read(s_umount); + continue; + } + up_read(s_umount); + } + spin_unlock(&dentry->d_lock); + /* Cannot remove the first dentry, and it isn't appropriate + * to move it to the head of the list, so give up, and try + * later + */ + break; } spin_unlock(&dcache_lock); } @@ -630,7 +683,7 @@ void shrink_dcache_parent(struct dentry * parent) int found; while ((found = select_parent(parent)) != 0) - prune_dcache(found); + prune_dcache(found, parent->d_sb); } /** @@ -643,9 +696,10 @@ void shrink_dcache_parent(struct dentry * parent) * done under dcache_lock. * */ -void shrink_dcache_anon(struct hlist_head *head) +void shrink_dcache_anon(struct super_block *sb) { struct hlist_node *lp; + struct hlist_head *head = &sb->s_anon; int found; do { found = 0; @@ -668,7 +722,7 @@ void shrink_dcache_anon(struct hlist_head *head) } } spin_unlock(&dcache_lock); - prune_dcache(found); + prune_dcache(found, sb); } while(found); } @@ -689,7 +743,7 @@ static int shrink_dcache_memory(int nr, gfp_t gfp_mask) if (nr) { if (!(gfp_mask & __GFP_FS)) return -1; - prune_dcache(nr); + prune_dcache(nr, NULL); } return (dentry_stat.nr_unused / 100) * sysctl_vfs_cache_pressure; } diff --git a/fs/super.c b/fs/super.c index a66f66bb8049..9d5c2add7228 100644 --- a/fs/super.c +++ b/fs/super.c @@ -231,7 +231,7 @@ void generic_shutdown_super(struct super_block *sb) if (root) { sb->s_root = NULL; shrink_dcache_parent(root); - shrink_dcache_anon(&sb->s_anon); + shrink_dcache_anon(sb); dput(root); fsync_super(sb); lock_super(sb); diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 836325ee0931..46d0e079735d 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -217,7 +217,7 @@ extern struct dentry * d_alloc_anon(struct inode *); extern struct dentry * d_splice_alias(struct inode *, struct dentry *); extern void shrink_dcache_sb(struct super_block *); extern void shrink_dcache_parent(struct dentry *); -extern void shrink_dcache_anon(struct hlist_head *); +extern void shrink_dcache_anon(struct super_block *); extern int d_invalidate(struct dentry *); /* only used at mount-time */ -- cgit v1.2.3 From 4f1bcaf094ccc512c23e10104c05a6f8e5b7a9e4 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 22 Jun 2006 14:47:32 -0700 Subject: [PATCH] vgacon: make VGA_MAP_MEM take size, remove extra use VGA_MAP_MEM translates to ioremap() on some architectures. It makes sense to do this to vga_vram_base, because we're going to access memory between vga_vram_base and vga_vram_end. But it doesn't really make sense to map starting at vga_vram_end, because we aren't going to access memory starting there. On ia64, which always has to be different, ioremapping vga_vram_end gives you something completely incompatible with ioremapped vga_vram_start, so vga_vram_size ends up being nonsense. As a bonus, we often know the size up front, so we can use ioremap() correctly, rather than giving it a zero size. Signed-off-by: Bjorn Helgaas Cc: "Antonino A. Daplas" Cc: "Luck, Tony" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/console/mdacon.c | 2 +- drivers/video/console/vgacon.c | 19 +++++++++---------- drivers/video/vga16fb.c | 2 +- include/asm-alpha/vga.h | 2 +- include/asm-arm/vga.h | 2 +- include/asm-i386/vga.h | 2 +- include/asm-ia64/vga.h | 2 +- include/asm-m32r/vga.h | 2 +- include/asm-mips/vga.h | 2 +- include/asm-powerpc/vga.h | 4 ++-- include/asm-sparc64/vga.h | 2 +- include/asm-x86_64/vga.h | 2 +- include/asm-xtensa/vga.h | 2 +- 13 files changed, 22 insertions(+), 23 deletions(-) (limited to 'include') diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c index 989e4d49e5bb..7f939d066a5a 100644 --- a/drivers/video/console/mdacon.c +++ b/drivers/video/console/mdacon.c @@ -313,8 +313,8 @@ static const char __init *mdacon_startup(void) mda_num_columns = 80; mda_num_lines = 25; - mda_vram_base = VGA_MAP_MEM(0xb0000); mda_vram_len = 0x01000; + mda_vram_base = VGA_MAP_MEM(0xb0000, mda_vram_len); mda_index_port = 0x3b4; mda_value_port = 0x3b5; diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index d5a04b68c4d4..e64d42e2449e 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -391,7 +391,7 @@ static const char __init *vgacon_startup(void) static struct resource ega_console_resource = { "ega", 0x3B0, 0x3BF }; vga_video_type = VIDEO_TYPE_EGAM; - vga_vram_end = 0xb8000; + vga_vram_size = 0x8000; display_desc = "EGA+"; request_resource(&ioport_resource, &ega_console_resource); @@ -401,7 +401,7 @@ static const char __init *vgacon_startup(void) static struct resource mda2_console_resource = { "mda", 0x3BF, 0x3BF }; vga_video_type = VIDEO_TYPE_MDA; - vga_vram_end = 0xb2000; + vga_vram_size = 0x2000; display_desc = "*MDA"; request_resource(&ioport_resource, &mda1_console_resource); @@ -418,7 +418,7 @@ static const char __init *vgacon_startup(void) if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) { int i; - vga_vram_end = 0xc0000; + vga_vram_size = 0x8000; if (!ORIG_VIDEO_ISVGA) { static struct resource ega_console_resource @@ -443,7 +443,7 @@ static const char __init *vgacon_startup(void) * and COE=1 isn't necessarily a good idea) */ vga_vram_base = 0xa0000; - vga_vram_end = 0xb0000; + vga_vram_size = 0x10000; outb_p(6, VGA_GFX_I); outb_p(6, VGA_GFX_D); #endif @@ -475,7 +475,7 @@ static const char __init *vgacon_startup(void) static struct resource cga_console_resource = { "cga", 0x3D4, 0x3D5 }; vga_video_type = VIDEO_TYPE_CGA; - vga_vram_end = 0xba000; + vga_vram_size = 0x2000; display_desc = "*CGA"; request_resource(&ioport_resource, &cga_console_resource); @@ -483,9 +483,8 @@ static const char __init *vgacon_startup(void) } } - vga_vram_base = VGA_MAP_MEM(vga_vram_base); - vga_vram_end = VGA_MAP_MEM(vga_vram_end); - vga_vram_size = vga_vram_end - vga_vram_base; + vga_vram_base = VGA_MAP_MEM(vga_vram_base, vga_vram_size); + vga_vram_end = vga_vram_base + vga_vram_size; /* * Find out if there is a graphics card present. @@ -1020,14 +1019,14 @@ static int vgacon_do_font_op(struct vgastate *state,char *arg,int set,int ch512) char *charmap; if (vga_video_type != VIDEO_TYPE_EGAM) { - charmap = (char *) VGA_MAP_MEM(colourmap); + charmap = (char *) VGA_MAP_MEM(colourmap, 0); beg = 0x0e; #ifdef VGA_CAN_DO_64KB if (vga_video_type == VIDEO_TYPE_VGAC) beg = 0x06; #endif } else { - charmap = (char *) VGA_MAP_MEM(blackwmap); + charmap = (char *) VGA_MAP_MEM(blackwmap, 0); beg = 0x0a; } diff --git a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c index f3f16fd9f231..4fd2a272e03d 100644 --- a/drivers/video/vga16fb.c +++ b/drivers/video/vga16fb.c @@ -1351,7 +1351,7 @@ static int __init vga16fb_probe(struct device *device) } /* XXX share VGA_FB_PHYS and I/O region with vgacon and others */ - info->screen_base = (void __iomem *)VGA_MAP_MEM(VGA_FB_PHYS); + info->screen_base = (void __iomem *)VGA_MAP_MEM(VGA_FB_PHYS, 0); if (!info->screen_base) { printk(KERN_ERR "vga16fb: unable to map device\n"); diff --git a/include/asm-alpha/vga.h b/include/asm-alpha/vga.h index 8ca4f6b2da19..ed06f59b544d 100644 --- a/include/asm-alpha/vga.h +++ b/include/asm-alpha/vga.h @@ -46,6 +46,6 @@ extern void scr_memcpyw(u16 *d, const u16 *s, unsigned int count); #define vga_readb(a) readb((u8 __iomem *)(a)) #define vga_writeb(v,a) writeb(v, (u8 __iomem *)(a)) -#define VGA_MAP_MEM(x) ((unsigned long) ioremap(x, 0)) +#define VGA_MAP_MEM(x,s) ((unsigned long) ioremap(x, s)) #endif diff --git a/include/asm-arm/vga.h b/include/asm-arm/vga.h index 926e5ee128e9..1e0b913c3d71 100644 --- a/include/asm-arm/vga.h +++ b/include/asm-arm/vga.h @@ -4,7 +4,7 @@ #include #include -#define VGA_MAP_MEM(x) (PCIMEM_BASE + (x)) +#define VGA_MAP_MEM(x,s) (PCIMEM_BASE + (x)) #define vga_readb(x) (*((volatile unsigned char *)x)) #define vga_writeb(x,y) (*((volatile unsigned char *)y) = (x)) diff --git a/include/asm-i386/vga.h b/include/asm-i386/vga.h index ef0c0e50cc95..0ecf68ac03aa 100644 --- a/include/asm-i386/vga.h +++ b/include/asm-i386/vga.h @@ -12,7 +12,7 @@ * access the videoram directly without any black magic. */ -#define VGA_MAP_MEM(x) (unsigned long)phys_to_virt(x) +#define VGA_MAP_MEM(x,s) (unsigned long)phys_to_virt(x) #define vga_readb(x) (*(x)) #define vga_writeb(x,y) (*(y) = (x)) diff --git a/include/asm-ia64/vga.h b/include/asm-ia64/vga.h index 091177cda223..02184ecd8208 100644 --- a/include/asm-ia64/vga.h +++ b/include/asm-ia64/vga.h @@ -17,7 +17,7 @@ extern unsigned long vga_console_iobase; extern unsigned long vga_console_membase; -#define VGA_MAP_MEM(x) ((unsigned long) ioremap_nocache(vga_console_membase + (x), 0)) +#define VGA_MAP_MEM(x,s) ((unsigned long) ioremap_nocache(vga_console_membase + (x), s)) #define vga_readb(x) (*(x)) #define vga_writeb(x,y) (*(y) = (x)) diff --git a/include/asm-m32r/vga.h b/include/asm-m32r/vga.h index d0f4b6eed7a3..533163447cc9 100644 --- a/include/asm-m32r/vga.h +++ b/include/asm-m32r/vga.h @@ -14,7 +14,7 @@ * access the videoram directly without any black magic. */ -#define VGA_MAP_MEM(x) (unsigned long)phys_to_virt(x) +#define VGA_MAP_MEM(x,s) (unsigned long)phys_to_virt(x) #define vga_readb(x) (*(x)) #define vga_writeb(x,y) (*(y) = (x)) diff --git a/include/asm-mips/vga.h b/include/asm-mips/vga.h index 34755c0a6398..c1dd0b10bc27 100644 --- a/include/asm-mips/vga.h +++ b/include/asm-mips/vga.h @@ -13,7 +13,7 @@ * access the videoram directly without any black magic. */ -#define VGA_MAP_MEM(x) (0xb0000000L + (unsigned long)(x)) +#define VGA_MAP_MEM(x,s) (0xb0000000L + (unsigned long)(x)) #define vga_readb(x) (*(x)) #define vga_writeb(x,y) (*(y) = (x)) diff --git a/include/asm-powerpc/vga.h b/include/asm-powerpc/vga.h index eadaf2f3d032..a2eac409c1ec 100644 --- a/include/asm-powerpc/vga.h +++ b/include/asm-powerpc/vga.h @@ -41,9 +41,9 @@ static inline u16 scr_readw(volatile const u16 *addr) extern unsigned long vgacon_remap_base; #ifdef __powerpc64__ -#define VGA_MAP_MEM(x) ((unsigned long) ioremap((x), 0)) +#define VGA_MAP_MEM(x,s) ((unsigned long) ioremap((x), s)) #else -#define VGA_MAP_MEM(x) (x + vgacon_remap_base) +#define VGA_MAP_MEM(x,s) (x + vgacon_remap_base) #endif #define vga_readb(x) (*(x)) diff --git a/include/asm-sparc64/vga.h b/include/asm-sparc64/vga.h index 9c57eb363b40..c69d5b2ba19a 100644 --- a/include/asm-sparc64/vga.h +++ b/include/asm-sparc64/vga.h @@ -28,6 +28,6 @@ static inline u16 scr_readw(const u16 *addr) return *addr; } -#define VGA_MAP_MEM(x) (x) +#define VGA_MAP_MEM(x,s) (x) #endif diff --git a/include/asm-x86_64/vga.h b/include/asm-x86_64/vga.h index ef0c0e50cc95..0ecf68ac03aa 100644 --- a/include/asm-x86_64/vga.h +++ b/include/asm-x86_64/vga.h @@ -12,7 +12,7 @@ * access the videoram directly without any black magic. */ -#define VGA_MAP_MEM(x) (unsigned long)phys_to_virt(x) +#define VGA_MAP_MEM(x,s) (unsigned long)phys_to_virt(x) #define vga_readb(x) (*(x)) #define vga_writeb(x,y) (*(y) = (x)) diff --git a/include/asm-xtensa/vga.h b/include/asm-xtensa/vga.h index 23d82f6acb57..1fd8cab3a297 100644 --- a/include/asm-xtensa/vga.h +++ b/include/asm-xtensa/vga.h @@ -11,7 +11,7 @@ #ifndef _XTENSA_VGA_H #define _XTENSA_VGA_H -#define VGA_MAP_MEM(x) (unsigned long)phys_to_virt(x) +#define VGA_MAP_MEM(x,s) (unsigned long)phys_to_virt(x) #define vga_readb(x) (*(x)) #define vga_writeb(x,y) (*(y) = (x)) -- cgit v1.2.3 From 4f3865fb57a04db7cca068fed1c15badc064a302 Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Thu, 22 Jun 2006 14:47:34 -0700 Subject: [PATCH] zlib_inflate: Upgrade library code to a recent version Upgrade the zlib_inflate implementation in the kernel from a patched version 1.1.3/4 to a patched 1.2.3. The code in the kernel is about seven years old and I noticed that the external zlib library's inflate performance was significantly faster (~50%) than the code in the kernel on ARM (and faster again on x86_32). For comparison the newer deflate code is 20% slower on ARM and 50% slower on x86_32 but gives an approx 1% compression ratio improvement. I don't consider this to be an improvement for kernel use so have no plans to change the zlib_deflate code. Various changes have been made to the zlib code in the kernel, the most significant being the extra functions/flush option used by ppp_deflate. This update reimplements the features PPP needs to ensure it continues to work. This code has been tested on ARM under both JFFS2 (with zlib compression enabled) and ppp_deflate and on x86_32. JFFS2 sees an approx. 10% real world file read speed improvement. This patch also removes ZLIB_VERSION as it no longer has a correct value. We don't need version checks anyway as the kernel's module handling will take care of that for us. This removal is also more in keeping with the zlib author's wishes (http://www.zlib.net/zlib_faq.html#faq24) and I've added something to the zlib.h header to note its a modified version. Signed-off-by: Richard Purdie Acked-by: Joern Engel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/powerpc/boot/Makefile | 4 +- arch/ppc/boot/lib/Makefile | 2 +- arch/xtensa/boot/lib/Makefile | 2 +- include/linux/zconf.h | 12 + include/linux/zlib.h | 209 +++++--- include/linux/zutil.h | 12 - lib/zlib_deflate/deflate.c | 25 +- lib/zlib_deflate/deflate_syms.c | 3 +- lib/zlib_inflate/Makefile | 4 +- lib/zlib_inflate/infblock.c | 365 ------------- lib/zlib_inflate/infblock.h | 48 -- lib/zlib_inflate/infcodes.c | 202 -------- lib/zlib_inflate/infcodes.h | 33 -- lib/zlib_inflate/inffast.c | 462 +++++++++++------ lib/zlib_inflate/inffast.h | 12 +- lib/zlib_inflate/inffixed.h | 94 ++++ lib/zlib_inflate/inflate.c | 1086 +++++++++++++++++++++++++++++++-------- lib/zlib_inflate/inflate.h | 107 ++++ lib/zlib_inflate/inflate_syms.c | 3 +- lib/zlib_inflate/inflate_sync.c | 152 ------ lib/zlib_inflate/inftrees.c | 683 +++++++++++------------- lib/zlib_inflate/inftrees.h | 99 ++-- lib/zlib_inflate/infutil.c | 88 ---- lib/zlib_inflate/infutil.h | 176 +------ 24 files changed, 1877 insertions(+), 2006 deletions(-) delete mode 100644 lib/zlib_inflate/infblock.c delete mode 100644 lib/zlib_inflate/infblock.h delete mode 100644 lib/zlib_inflate/infcodes.c delete mode 100644 lib/zlib_inflate/infcodes.h create mode 100644 lib/zlib_inflate/inffixed.h create mode 100644 lib/zlib_inflate/inflate.h delete mode 100644 lib/zlib_inflate/inflate_sync.c delete mode 100644 lib/zlib_inflate/infutil.c (limited to 'include') diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index 840ae595a617..d961bfeed05f 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -29,8 +29,8 @@ OBJCOPYFLAGS := contents,alloc,load,readonly,data OBJCOPY_COFF_ARGS := -O aixcoff-rs6000 --set-start 0x500000 OBJCOPY_MIB_ARGS := -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment -zlib := infblock.c infcodes.c inffast.c inflate.c inftrees.c infutil.c -zlibheader := infblock.h infcodes.h inffast.h inftrees.h infutil.h +zlib := inffast.c inflate.c inftrees.c +zlibheader := inffast.h inffixed.h inflate.h inftrees.h infutil.h zliblinuxheader := zlib.h zconf.h zutil.h $(addprefix $(obj)/,$(zlib) main.o): $(addprefix $(obj)/,$(zliblinuxheader)) $(addprefix $(obj)/,$(zlibheader)) diff --git a/arch/ppc/boot/lib/Makefile b/arch/ppc/boot/lib/Makefile index 80c84d562fa4..2f995f712ec5 100644 --- a/arch/ppc/boot/lib/Makefile +++ b/arch/ppc/boot/lib/Makefile @@ -5,7 +5,7 @@ CFLAGS_kbd.o := -Idrivers/char CFLAGS_vreset.o := -Iarch/ppc/boot/include -zlib := infblock.c infcodes.c inffast.c inflate.c inftrees.c infutil.c +zlib := inffast.c inflate.c inftrees.c lib-y += $(zlib:.c=.o) div64.o lib-$(CONFIG_VGA_CONSOLE) += vreset.o kbd.o diff --git a/arch/xtensa/boot/lib/Makefile b/arch/xtensa/boot/lib/Makefile index 9e73bb8aeb7a..d3d2aa2d883a 100644 --- a/arch/xtensa/boot/lib/Makefile +++ b/arch/xtensa/boot/lib/Makefile @@ -2,7 +2,7 @@ # Makefile for some libs needed by zImage. # -zlib := infblock.c infcodes.c inffast.c inflate.c inftrees.c infutil.c +zlib := inffast.c inflate.c inftrees.c lib-y += $(zlib:.c=.o) zmem.o diff --git a/include/linux/zconf.h b/include/linux/zconf.h index f1cfd66b9554..0beb75e38caa 100644 --- a/include/linux/zconf.h +++ b/include/linux/zconf.h @@ -33,6 +33,18 @@ */ #ifndef MAX_WBITS # define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* default windowBits for decompression. MAX_WBITS is for compression only */ +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif + +/* default memLevel */ +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL #endif /* Type declarations */ diff --git a/include/linux/zlib.h b/include/linux/zlib.h index 4fa32f0d4df8..9e3192a7dc6f 100644 --- a/include/linux/zlib.h +++ b/include/linux/zlib.h @@ -1,7 +1,6 @@ /* zlib.h -- interface of the 'zlib' general purpose compression library - version 1.1.3, July 9th, 1998 - Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler + Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -24,7 +23,7 @@ The data format used by the zlib library is described by RFCs (Request for - Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt + Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). */ @@ -33,7 +32,22 @@ #include -#define ZLIB_VERSION "1.1.3" +/* zlib deflate based on ZLIB_VERSION "1.1.3" */ +/* zlib inflate based on ZLIB_VERSION "1.2.3" */ + +/* + This is a modified version of zlib for use inside the Linux kernel. + The main changes are to perform all memory allocation in advance. + + Inflation Changes: + * Z_PACKET_FLUSH is added and used by ppp_deflate. Before returning + this checks there is no more input data available and the next data + is a STORED block. It also resets the mode to be read for the next + data, all as per PPP requirements. + * Addition of zlib_inflateIncomp which copies incompressible data into + the history window and adjusts the accoutning without calling + zlib_inflate itself to inflate the data. +*/ /* The 'zlib' compression library provides in-memory compression and @@ -48,9 +62,18 @@ application must provide more input and/or consume the output (providing more output space) before each call. + The compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + The library also supports reading and writing files in gzip (.gz) format with an interface similar to that of stdio. + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + The library does not install any signal handler. The decoder checks the consistency of the compressed data, so the library should never crash even in case of corrupted input. @@ -119,7 +142,8 @@ typedef z_stream *z_streamp; #define Z_SYNC_FLUSH 3 #define Z_FULL_FLUSH 4 #define Z_FINISH 5 -/* Allowed flush values; see deflate() below for details */ +#define Z_BLOCK 6 /* Only for inflate at present */ +/* Allowed flush values; see deflate() and inflate() below for details */ #define Z_OK 0 #define Z_STREAM_END 1 @@ -155,13 +179,6 @@ typedef z_stream *z_streamp; /* basic functions */ -extern const char * zlib_zlibVersion (void); -/* The application can compare zlibVersion and ZLIB_VERSION for consistency. - If the first character differs, the library code actually used is - not compatible with the zlib.h header file used by the application. - This check is automatically made by deflateInit and inflateInit. - */ - extern int zlib_deflate_workspacesize (void); /* Returns the number of bytes that needs to be allocated for a per- @@ -315,9 +332,9 @@ extern int zlib_inflateInit (z_streamp strm); extern int zlib_inflate (z_streamp strm, int flush); /* inflate decompresses as much data as possible, and stops when the input - buffer becomes empty or the output buffer becomes full. It may some - introduce some output latency (reading input without producing any output) - except when forced to flush. + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. The detailed semantics are as follows. inflate performs one or both of the following actions: @@ -341,11 +358,26 @@ extern int zlib_inflate (z_streamp strm, int flush); must be called again after making room in the output buffer because there might be more output pending. - If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much - output as possible to the output buffer. The flushing behavior of inflate is - not specified for values of the flush parameter other than Z_SYNC_FLUSH - and Z_FINISH, but the current implementation actually flushes as much output - as possible anyway. + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, + Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() stop + if and when it gets to the next deflate block boundary. When decoding the + zlib or gzip format, this will cause inflate() to return immediately after + the header and before the first block. When doing a raw inflate, inflate() + will go ahead and process the first block, and will return when it gets to + the end of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + Also to assist in this, on return inflate() will set strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 + if inflate() is currently decoding the last block in the deflate stream, + plus 128 if inflate() returned immediately after decoding an end-of-block + code or decoding the complete header up to just before the first byte of the + deflate stream. The end-of-block will not be indicated until all of the + uncompressed data from that block has been written to strm->next_out. The + number of unused bits may in general be greater than seven, except when + bit 7 of data_type is set, in which case the number of unused bits will be + less than eight. inflate() should normally be called until it returns Z_STREAM_END or an error. However if all decompression is to be performed in a single step @@ -355,29 +387,44 @@ extern int zlib_inflate (z_streamp strm, int flush); uncompressed data. (The size of the uncompressed data may have been saved by the compressor for this purpose.) The next operation on this stream must be inflateEnd to deallocate the decompression state. The use of Z_FINISH - is never required, but can be used to inform inflate that a faster routine + is never required, but can be used to inform inflate that a faster approach may be used for the single inflate() call. - If a preset dictionary is needed at this point (see inflateSetDictionary - below), inflate sets strm-adler to the adler32 checksum of the - dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise - it sets strm->adler to the adler32 checksum of all output produced - so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or - an error code as described below. At the end of the stream, inflate() - checks that its computed adler32 checksum is equal to that saved by the - compressor and returns Z_STREAM_END only if the checksum is correct. + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the only effect of the flush parameter in this implementation + is on the return value of inflate(), as noted below, or when it returns early + because Z_BLOCK is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm->adler to the adler32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the adler32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed adler32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() will decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically. Any information + contained in the gzip header is not retained, so applications that need that + information should instead use raw inflate, see inflateInit2() below, or + inflateBack() and perform their own processing of the gzip header and + trailer. inflate() returns Z_OK if some progress has been made (more input processed or more output produced), Z_STREAM_END if the end of the compressed data has been reached and all uncompressed output has been produced, Z_NEED_DICT if a preset dictionary is needed at this point, Z_DATA_ERROR if the input data was - corrupted (input stream not conforming to the zlib format or incorrect - adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent - (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if no progress is possible or if there was not - enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR - case, the application may then call inflateSync to look for a good - compression block. + corrupted (input stream not conforming to the zlib format or incorrect check + value), Z_STREAM_ERROR if the stream structure was inconsistent (for example + if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, + Z_BUF_ERROR if no progress is possible or if there was not enough room in the + output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may then + call inflateSync() to look for a good compression block if a partial recovery + of the data is desired. */ @@ -547,16 +594,36 @@ extern int inflateInit2 (z_streamp strm, int windowBits); The windowBits parameter is the base two logarithm of the maximum window size (the size of the history buffer). It should be in the range 8..15 for this version of the library. The default value is 15 if inflateInit is used - instead. If a compressed stream with a larger window size is given as - input, inflate() will return with the error code Z_DATA_ERROR instead of - trying to allocate a larger window. - - inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative - memLevel). msg is set to null if there is no error message. inflateInit2 - does not perform any decompression apart from reading the zlib header if - present: this will be done by inflate(). (So next_in and avail_in may be - modified, but next_out and avail_out are unchanged.) + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an adler32 or a crc32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is + a crc32 instead of an adler32. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg + is set to null if there is no error message. inflateInit2 does not perform + any decompression apart from reading the zlib header if present: this will + be done by inflate(). (So next_in and avail_in may be modified, but next_out + and avail_out are unchanged.) */ extern int zlib_inflateSetDictionary (z_streamp strm, @@ -564,16 +631,19 @@ extern int zlib_inflateSetDictionary (z_streamp strm, uInt dictLength); /* Initializes the decompression dictionary from the given uncompressed byte - sequence. This function must be called immediately after a call of inflate - if this call returned Z_NEED_DICT. The dictionary chosen by the compressor - can be determined from the Adler32 value returned by this call of - inflate. The compressor and decompressor must use exactly the same - dictionary (see deflateSetDictionary). + sequence. This function must be called immediately after a call of inflate, + if that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the adler32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called + immediately after inflateInit2() or inflateReset() and before any call of + inflate() to set the dictionary. The application must insure that the + dictionary that was used for compression is provided. inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a parameter is invalid (such as NULL dictionary) or the stream state is inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the - expected one (incorrect Adler32 value). inflateSetDictionary does not + expected one (incorrect adler32 value). inflateSetDictionary does not perform any decompression: this will be done by subsequent calls of inflate(). */ @@ -614,40 +684,19 @@ extern int zlib_inflateIncomp (z_stream *strm); containing the data at next_in (except that the data is not output). */ - /* various hacks, don't look :) */ - -/* deflateInit and inflateInit are macros to allow checking the zlib version - * and the compiler's view of z_stream: - */ -extern int zlib_deflateInit_ (z_streamp strm, int level, - const char *version, int stream_size); -extern int zlib_inflateInit_ (z_streamp strm, - const char *version, int stream_size); -extern int zlib_deflateInit2_ (z_streamp strm, int level, int method, - int windowBits, int memLevel, - int strategy, const char *version, - int stream_size); -extern int zlib_inflateInit2_ (z_streamp strm, int windowBits, - const char *version, int stream_size); #define zlib_deflateInit(strm, level) \ - zlib_deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) + zlib_deflateInit2((strm), (level), Z_DEFLATED, MAX_WBITS, \ + DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY) #define zlib_inflateInit(strm) \ - zlib_inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) -#define zlib_deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ - zlib_deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ - (strategy), ZLIB_VERSION, sizeof(z_stream)) -#define zlib_inflateInit2(strm, windowBits) \ - zlib_inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) + zlib_inflateInit2((strm), DEF_WBITS) +extern int zlib_deflateInit2(z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy); +extern int zlib_inflateInit2(z_streamp strm, int windowBits); #if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL) struct internal_state {int dummy;}; /* hack for buggy compilers */ #endif -extern const char * zlib_zError (int err); -#if 0 -extern int zlib_inflateSyncPoint (z_streamp z); -#endif -extern const uLong * zlib_get_crc_table (void); - #endif /* _ZLIB_H */ diff --git a/include/linux/zutil.h b/include/linux/zutil.h index ee0c59cf2136..6adfa9a6ffe9 100644 --- a/include/linux/zutil.h +++ b/include/linux/zutil.h @@ -23,18 +23,6 @@ typedef unsigned long ulg; /* common constants */ -#ifndef DEF_WBITS -# define DEF_WBITS MAX_WBITS -#endif -/* default windowBits for decompression. MAX_WBITS is for compression only */ - -#if MAX_MEM_LEVEL >= 8 -# define DEF_MEM_LEVEL 8 -#else -# define DEF_MEM_LEVEL MAX_MEM_LEVEL -#endif -/* default memLevel */ - #define STORED_BLOCK 0 #define STATIC_TREES 1 #define DYN_TREES 2 diff --git a/lib/zlib_deflate/deflate.c b/lib/zlib_deflate/deflate.c index 1653dd9bb01a..c3e4a2baf835 100644 --- a/lib/zlib_deflate/deflate.c +++ b/lib/zlib_deflate/deflate.c @@ -164,34 +164,17 @@ static const config configuration_table[10] = { memset((char *)s->head, 0, (unsigned)(s->hash_size-1)*sizeof(*s->head)); /* ========================================================================= */ -int zlib_deflateInit_( - z_streamp strm, - int level, - const char *version, - int stream_size -) -{ - return zlib_deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, - DEF_MEM_LEVEL, - Z_DEFAULT_STRATEGY, version, stream_size); - /* To do: ignore strm->next_in if we use it as window */ -} - -/* ========================================================================= */ -int zlib_deflateInit2_( +int zlib_deflateInit2( z_streamp strm, int level, int method, int windowBits, int memLevel, - int strategy, - const char *version, - int stream_size + int strategy ) { deflate_state *s; int noheader = 0; - static char* my_version = ZLIB_VERSION; deflate_workspace *mem; ush *overlay; @@ -199,10 +182,6 @@ int zlib_deflateInit2_( * output size for (length,distance) codes is <= 24 bits. */ - if (version == NULL || version[0] != my_version[0] || - stream_size != sizeof(z_stream)) { - return Z_VERSION_ERROR; - } if (strm == NULL) return Z_STREAM_ERROR; strm->msg = NULL; diff --git a/lib/zlib_deflate/deflate_syms.c b/lib/zlib_deflate/deflate_syms.c index 767b573d1ef6..ccfe25f3920f 100644 --- a/lib/zlib_deflate/deflate_syms.c +++ b/lib/zlib_deflate/deflate_syms.c @@ -12,8 +12,7 @@ EXPORT_SYMBOL(zlib_deflate_workspacesize); EXPORT_SYMBOL(zlib_deflate); -EXPORT_SYMBOL(zlib_deflateInit_); -EXPORT_SYMBOL(zlib_deflateInit2_); +EXPORT_SYMBOL(zlib_deflateInit2); EXPORT_SYMBOL(zlib_deflateEnd); EXPORT_SYMBOL(zlib_deflateReset); MODULE_LICENSE("GPL"); diff --git a/lib/zlib_inflate/Makefile b/lib/zlib_inflate/Makefile index 221c139e0df1..bf065482fa67 100644 --- a/lib/zlib_inflate/Makefile +++ b/lib/zlib_inflate/Makefile @@ -15,5 +15,5 @@ obj-$(CONFIG_ZLIB_INFLATE) += zlib_inflate.o -zlib_inflate-objs := infblock.o infcodes.o inffast.o inflate.o \ - inflate_sync.o inftrees.o infutil.o inflate_syms.o +zlib_inflate-objs := inffast.o inflate.o \ + inftrees.o inflate_syms.o diff --git a/lib/zlib_inflate/infblock.c b/lib/zlib_inflate/infblock.c deleted file mode 100644 index c16cdeff51aa..000000000000 --- a/lib/zlib_inflate/infblock.c +++ /dev/null @@ -1,365 +0,0 @@ -/* infblock.c -- interpret and process block types to last block - * Copyright (C) 1995-1998 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include -#include "infblock.h" -#include "inftrees.h" -#include "infcodes.h" -#include "infutil.h" - -struct inflate_codes_state; - -/* simplify the use of the inflate_huft type with some defines */ -#define exop word.what.Exop -#define bits word.what.Bits - -/* Table for deflate from PKZIP's appnote.txt. */ -static const uInt border[] = { /* Order of the bit length code lengths */ - 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; - -/* - Notes beyond the 1.93a appnote.txt: - - 1. Distance pointers never point before the beginning of the output - stream. - 2. Distance pointers can point back across blocks, up to 32k away. - 3. There is an implied maximum of 7 bits for the bit length table and - 15 bits for the actual data. - 4. If only one code exists, then it is encoded using one bit. (Zero - would be more efficient, but perhaps a little confusing.) If two - codes exist, they are coded using one bit each (0 and 1). - 5. There is no way of sending zero distance codes--a dummy must be - sent if there are none. (History: a pre 2.0 version of PKZIP would - store blocks with no distance codes, but this was discovered to be - too harsh a criterion.) Valid only for 1.93a. 2.04c does allow - zero distance codes, which is sent as one code of zero bits in - length. - 6. There are up to 286 literal/length codes. Code 256 represents the - end-of-block. Note however that the static length tree defines - 288 codes just to fill out the Huffman codes. Codes 286 and 287 - cannot be used though, since there is no length base or extra bits - defined for them. Similarily, there are up to 30 distance codes. - However, static trees define 32 codes (all 5 bits) to fill out the - Huffman codes, but the last two had better not show up in the data. - 7. Unzip can check dynamic Huffman blocks for complete code sets. - The exception is that a single code would not be complete (see #4). - 8. The five bits following the block type is really the number of - literal codes sent minus 257. - 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits - (1+6+6). Therefore, to output three times the length, you output - three codes (1+1+1), whereas to output four times the same length, - you only need two codes (1+3). Hmm. - 10. In the tree reconstruction algorithm, Code = Code + Increment - only if BitLength(i) is not zero. (Pretty obvious.) - 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) - 12. Note: length code 284 can represent 227-258, but length code 285 - really is 258. The last length deserves its own, short code - since it gets used a lot in very redundant files. The length - 258 is special since 258 - 3 (the min match length) is 255. - 13. The literal/length and distance code bit lengths are read as a - single stream of lengths. It is possible (and advantageous) for - a repeat code (16, 17, or 18) to go across the boundary between - the two sets of lengths. - */ - - -void zlib_inflate_blocks_reset( - inflate_blocks_statef *s, - z_streamp z, - uLong *c -) -{ - if (c != NULL) - *c = s->check; - if (s->mode == CODES) - zlib_inflate_codes_free(s->sub.decode.codes, z); - s->mode = TYPE; - s->bitk = 0; - s->bitb = 0; - s->read = s->write = s->window; - if (s->checkfn != NULL) - z->adler = s->check = (*s->checkfn)(0L, NULL, 0); -} - -inflate_blocks_statef *zlib_inflate_blocks_new( - z_streamp z, - check_func c, - uInt w -) -{ - inflate_blocks_statef *s; - - s = &WS(z)->working_blocks_state; - s->hufts = WS(z)->working_hufts; - s->window = WS(z)->working_window; - s->end = s->window + w; - s->checkfn = c; - s->mode = TYPE; - zlib_inflate_blocks_reset(s, z, NULL); - return s; -} - - -int zlib_inflate_blocks( - inflate_blocks_statef *s, - z_streamp z, - int r -) -{ - uInt t; /* temporary storage */ - uLong b; /* bit buffer */ - uInt k; /* bits in bit buffer */ - Byte *p; /* input data pointer */ - uInt n; /* bytes available there */ - Byte *q; /* output window write pointer */ - uInt m; /* bytes to end of window or read pointer */ - - /* copy input/output information to locals (UPDATE macro restores) */ - LOAD - - /* process input based on current state */ - while (1) switch (s->mode) - { - case TYPE: - NEEDBITS(3) - t = (uInt)b & 7; - s->last = t & 1; - switch (t >> 1) - { - case 0: /* stored */ - DUMPBITS(3) - t = k & 7; /* go to byte boundary */ - DUMPBITS(t) - s->mode = LENS; /* get length of stored block */ - break; - case 1: /* fixed */ - { - uInt bl, bd; - inflate_huft *tl, *td; - - zlib_inflate_trees_fixed(&bl, &bd, &tl, &td, s->hufts, z); - s->sub.decode.codes = zlib_inflate_codes_new(bl, bd, tl, td, z); - if (s->sub.decode.codes == NULL) - { - r = Z_MEM_ERROR; - LEAVE - } - } - DUMPBITS(3) - s->mode = CODES; - break; - case 2: /* dynamic */ - DUMPBITS(3) - s->mode = TABLE; - break; - case 3: /* illegal */ - DUMPBITS(3) - s->mode = B_BAD; - z->msg = (char*)"invalid block type"; - r = Z_DATA_ERROR; - LEAVE - } - break; - case LENS: - NEEDBITS(32) - if ((((~b) >> 16) & 0xffff) != (b & 0xffff)) - { - s->mode = B_BAD; - z->msg = (char*)"invalid stored block lengths"; - r = Z_DATA_ERROR; - LEAVE - } - s->sub.left = (uInt)b & 0xffff; - b = k = 0; /* dump bits */ - s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE); - break; - case STORED: - if (n == 0) - LEAVE - NEEDOUT - t = s->sub.left; - if (t > n) t = n; - if (t > m) t = m; - memcpy(q, p, t); - p += t; n -= t; - q += t; m -= t; - if ((s->sub.left -= t) != 0) - break; - s->mode = s->last ? DRY : TYPE; - break; - case TABLE: - NEEDBITS(14) - s->sub.trees.table = t = (uInt)b & 0x3fff; -#ifndef PKZIP_BUG_WORKAROUND - if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) - { - s->mode = B_BAD; - z->msg = (char*)"too many length or distance symbols"; - r = Z_DATA_ERROR; - LEAVE - } -#endif - { - s->sub.trees.blens = WS(z)->working_blens; - } - DUMPBITS(14) - s->sub.trees.index = 0; - s->mode = BTREE; - case BTREE: - while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10)) - { - NEEDBITS(3) - s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7; - DUMPBITS(3) - } - while (s->sub.trees.index < 19) - s->sub.trees.blens[border[s->sub.trees.index++]] = 0; - s->sub.trees.bb = 7; - t = zlib_inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb, - &s->sub.trees.tb, s->hufts, z); - if (t != Z_OK) - { - r = t; - if (r == Z_DATA_ERROR) - s->mode = B_BAD; - LEAVE - } - s->sub.trees.index = 0; - s->mode = DTREE; - case DTREE: - while (t = s->sub.trees.table, - s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f)) - { - inflate_huft *h; - uInt i, j, c; - - t = s->sub.trees.bb; - NEEDBITS(t) - h = s->sub.trees.tb + ((uInt)b & zlib_inflate_mask[t]); - t = h->bits; - c = h->base; - if (c < 16) - { - DUMPBITS(t) - s->sub.trees.blens[s->sub.trees.index++] = c; - } - else /* c == 16..18 */ - { - i = c == 18 ? 7 : c - 14; - j = c == 18 ? 11 : 3; - NEEDBITS(t + i) - DUMPBITS(t) - j += (uInt)b & zlib_inflate_mask[i]; - DUMPBITS(i) - i = s->sub.trees.index; - t = s->sub.trees.table; - if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || - (c == 16 && i < 1)) - { - s->mode = B_BAD; - z->msg = (char*)"invalid bit length repeat"; - r = Z_DATA_ERROR; - LEAVE - } - c = c == 16 ? s->sub.trees.blens[i - 1] : 0; - do { - s->sub.trees.blens[i++] = c; - } while (--j); - s->sub.trees.index = i; - } - } - s->sub.trees.tb = NULL; - { - uInt bl, bd; - inflate_huft *tl, *td; - inflate_codes_statef *c; - - bl = 9; /* must be <= 9 for lookahead assumptions */ - bd = 6; /* must be <= 9 for lookahead assumptions */ - t = s->sub.trees.table; - t = zlib_inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), - s->sub.trees.blens, &bl, &bd, &tl, &td, - s->hufts, z); - if (t != Z_OK) - { - if (t == (uInt)Z_DATA_ERROR) - s->mode = B_BAD; - r = t; - LEAVE - } - if ((c = zlib_inflate_codes_new(bl, bd, tl, td, z)) == NULL) - { - r = Z_MEM_ERROR; - LEAVE - } - s->sub.decode.codes = c; - } - s->mode = CODES; - case CODES: - UPDATE - if ((r = zlib_inflate_codes(s, z, r)) != Z_STREAM_END) - return zlib_inflate_flush(s, z, r); - r = Z_OK; - zlib_inflate_codes_free(s->sub.decode.codes, z); - LOAD - if (!s->last) - { - s->mode = TYPE; - break; - } - s->mode = DRY; - case DRY: - FLUSH - if (s->read != s->write) - LEAVE - s->mode = B_DONE; - case B_DONE: - r = Z_STREAM_END; - LEAVE - case B_BAD: - r = Z_DATA_ERROR; - LEAVE - default: - r = Z_STREAM_ERROR; - LEAVE - } -} - - -int zlib_inflate_blocks_free( - inflate_blocks_statef *s, - z_streamp z -) -{ - zlib_inflate_blocks_reset(s, z, NULL); - return Z_OK; -} - - -#if 0 -void zlib_inflate_set_dictionary( - inflate_blocks_statef *s, - const Byte *d, - uInt n -) -{ - memcpy(s->window, d, n); - s->read = s->write = s->window + n; -} -#endif /* 0 */ - - -/* Returns true if inflate is currently at the end of a block generated - * by Z_SYNC_FLUSH or Z_FULL_FLUSH. - * IN assertion: s != NULL - */ -#if 0 -int zlib_inflate_blocks_sync_point( - inflate_blocks_statef *s -) -{ - return s->mode == LENS; -} -#endif /* 0 */ diff --git a/lib/zlib_inflate/infblock.h b/lib/zlib_inflate/infblock.h deleted file mode 100644 index ceee60b5107c..000000000000 --- a/lib/zlib_inflate/infblock.h +++ /dev/null @@ -1,48 +0,0 @@ -/* infblock.h -- header to use infblock.c - * Copyright (C) 1995-1998 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -#ifndef _INFBLOCK_H -#define _INFBLOCK_H - -struct inflate_blocks_state; -typedef struct inflate_blocks_state inflate_blocks_statef; - -extern inflate_blocks_statef * zlib_inflate_blocks_new ( - z_streamp z, - check_func c, /* check function */ - uInt w); /* window size */ - -extern int zlib_inflate_blocks ( - inflate_blocks_statef *, - z_streamp , - int); /* initial return code */ - -extern void zlib_inflate_blocks_reset ( - inflate_blocks_statef *, - z_streamp , - uLong *); /* check value on output */ - -extern int zlib_inflate_blocks_free ( - inflate_blocks_statef *, - z_streamp); - -#if 0 -extern void zlib_inflate_set_dictionary ( - inflate_blocks_statef *s, - const Byte *d, /* dictionary */ - uInt n); /* dictionary length */ -#endif /* 0 */ - -#if 0 -extern int zlib_inflate_blocks_sync_point ( - inflate_blocks_statef *s); -#endif /* 0 */ - -#endif /* _INFBLOCK_H */ diff --git a/lib/zlib_inflate/infcodes.c b/lib/zlib_inflate/infcodes.c deleted file mode 100644 index 07cd7591cbb7..000000000000 --- a/lib/zlib_inflate/infcodes.c +++ /dev/null @@ -1,202 +0,0 @@ -/* infcodes.c -- process literals and length/distance pairs - * Copyright (C) 1995-1998 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include -#include "inftrees.h" -#include "infblock.h" -#include "infcodes.h" -#include "infutil.h" -#include "inffast.h" - -/* simplify the use of the inflate_huft type with some defines */ -#define exop word.what.Exop -#define bits word.what.Bits - -inflate_codes_statef *zlib_inflate_codes_new( - uInt bl, - uInt bd, - inflate_huft *tl, - inflate_huft *td, /* need separate declaration for Borland C++ */ - z_streamp z -) -{ - inflate_codes_statef *c; - - c = &WS(z)->working_state; - { - c->mode = START; - c->lbits = (Byte)bl; - c->dbits = (Byte)bd; - c->ltree = tl; - c->dtree = td; - } - return c; -} - - -int zlib_inflate_codes( - inflate_blocks_statef *s, - z_streamp z, - int r -) -{ - uInt j; /* temporary storage */ - inflate_huft *t; /* temporary pointer */ - uInt e; /* extra bits or operation */ - uLong b; /* bit buffer */ - uInt k; /* bits in bit buffer */ - Byte *p; /* input data pointer */ - uInt n; /* bytes available there */ - Byte *q; /* output window write pointer */ - uInt m; /* bytes to end of window or read pointer */ - Byte *f; /* pointer to copy strings from */ - inflate_codes_statef *c = s->sub.decode.codes; /* codes state */ - - /* copy input/output information to locals (UPDATE macro restores) */ - LOAD - - /* process input and output based on current state */ - while (1) switch (c->mode) - { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ - case START: /* x: set up for LEN */ -#ifndef SLOW - if (m >= 258 && n >= 10) - { - UPDATE - r = zlib_inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z); - LOAD - if (r != Z_OK) - { - c->mode = r == Z_STREAM_END ? WASH : BADCODE; - break; - } - } -#endif /* !SLOW */ - c->sub.code.need = c->lbits; - c->sub.code.tree = c->ltree; - c->mode = LEN; - case LEN: /* i: get length/literal/eob next */ - j = c->sub.code.need; - NEEDBITS(j) - t = c->sub.code.tree + ((uInt)b & zlib_inflate_mask[j]); - DUMPBITS(t->bits) - e = (uInt)(t->exop); - if (e == 0) /* literal */ - { - c->sub.lit = t->base; - c->mode = LIT; - break; - } - if (e & 16) /* length */ - { - c->sub.copy.get = e & 15; - c->len = t->base; - c->mode = LENEXT; - break; - } - if ((e & 64) == 0) /* next table */ - { - c->sub.code.need = e; - c->sub.code.tree = t + t->base; - break; - } - if (e & 32) /* end of block */ - { - c->mode = WASH; - break; - } - c->mode = BADCODE; /* invalid code */ - z->msg = (char*)"invalid literal/length code"; - r = Z_DATA_ERROR; - LEAVE - case LENEXT: /* i: getting length extra (have base) */ - j = c->sub.copy.get; - NEEDBITS(j) - c->len += (uInt)b & zlib_inflate_mask[j]; - DUMPBITS(j) - c->sub.code.need = c->dbits; - c->sub.code.tree = c->dtree; - c->mode = DIST; - case DIST: /* i: get distance next */ - j = c->sub.code.need; - NEEDBITS(j) - t = c->sub.code.tree + ((uInt)b & zlib_inflate_mask[j]); - DUMPBITS(t->bits) - e = (uInt)(t->exop); - if (e & 16) /* distance */ - { - c->sub.copy.get = e & 15; - c->sub.copy.dist = t->base; - c->mode = DISTEXT; - break; - } - if ((e & 64) == 0) /* next table */ - { - c->sub.code.need = e; - c->sub.code.tree = t + t->base; - break; - } - c->mode = BADCODE; /* invalid code */ - z->msg = (char*)"invalid distance code"; - r = Z_DATA_ERROR; - LEAVE - case DISTEXT: /* i: getting distance extra */ - j = c->sub.copy.get; - NEEDBITS(j) - c->sub.copy.dist += (uInt)b & zlib_inflate_mask[j]; - DUMPBITS(j) - c->mode = COPY; - case COPY: /* o: copying bytes in window, waiting for space */ - f = q - c->sub.copy.dist; - while (f < s->window) /* modulo window size-"while" instead */ - f += s->end - s->window; /* of "if" handles invalid distances */ - while (c->len) - { - NEEDOUT - OUTBYTE(*f++) - if (f == s->end) - f = s->window; - c->len--; - } - c->mode = START; - break; - case LIT: /* o: got literal, waiting for output space */ - NEEDOUT - OUTBYTE(c->sub.lit) - c->mode = START; - break; - case WASH: /* o: got eob, possibly more output */ - if (k > 7) /* return unused byte, if any */ - { - k -= 8; - n++; - p--; /* can always return one */ - } - FLUSH - if (s->read != s->write) - LEAVE - c->mode = END; - case END: - r = Z_STREAM_END; - LEAVE - case BADCODE: /* x: got error */ - r = Z_DATA_ERROR; - LEAVE - default: - r = Z_STREAM_ERROR; - LEAVE - } -#ifdef NEED_DUMMY_RETURN - return Z_STREAM_ERROR; /* Some dumb compilers complain without this */ -#endif -} - - -void zlib_inflate_codes_free( - inflate_codes_statef *c, - z_streamp z -) -{ -} diff --git a/lib/zlib_inflate/infcodes.h b/lib/zlib_inflate/infcodes.h deleted file mode 100644 index 5cff417523b0..000000000000 --- a/lib/zlib_inflate/infcodes.h +++ /dev/null @@ -1,33 +0,0 @@ -/* infcodes.h -- header to use infcodes.c - * Copyright (C) 1995-1998 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -#ifndef _INFCODES_H -#define _INFCODES_H - -#include "infblock.h" - -struct inflate_codes_state; -typedef struct inflate_codes_state inflate_codes_statef; - -extern inflate_codes_statef *zlib_inflate_codes_new ( - uInt, uInt, - inflate_huft *, inflate_huft *, - z_streamp ); - -extern int zlib_inflate_codes ( - inflate_blocks_statef *, - z_streamp , - int); - -extern void zlib_inflate_codes_free ( - inflate_codes_statef *, - z_streamp ); - -#endif /* _INFCODES_H */ diff --git a/lib/zlib_inflate/inffast.c b/lib/zlib_inflate/inffast.c index 0bd7623fc85a..02a16eacb72d 100644 --- a/lib/zlib_inflate/inffast.c +++ b/lib/zlib_inflate/inffast.c @@ -1,176 +1,312 @@ -/* inffast.c -- process literals and length/distance pairs fast - * Copyright (C) 1995-1998 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h +/* inffast.c -- fast decoding + * Copyright (C) 1995-2004 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h */ #include #include "inftrees.h" -#include "infblock.h" -#include "infcodes.h" -#include "infutil.h" +#include "inflate.h" #include "inffast.h" -struct inflate_codes_state; - -/* simplify the use of the inflate_huft type with some defines */ -#define exop word.what.Exop -#define bits word.what.Bits - -/* macros for bit input with no checking and for returning unused bytes */ -#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3;} - -/* Called with number of bytes left to write in window at least 258 - (the maximum string length) and number of input bytes available - at least ten. The ten bytes are six bytes for the longest length/ - distance pair plus four bytes for overloading the bit buffer. */ - -int zlib_inflate_fast( - uInt bl, - uInt bd, - inflate_huft *tl, - inflate_huft *td, /* need separate declaration for Borland C++ */ - inflate_blocks_statef *s, - z_streamp z -) +#ifndef ASMINF + +/* Allow machine dependent optimization for post-increment or pre-increment. + Based on testing to date, + Pre-increment preferred for: + - PowerPC G3 (Adler) + - MIPS R5000 (Randers-Pehrson) + Post-increment preferred for: + - none + No measurable difference: + - Pentium III (Anderson) + - M68060 (Nikl) + */ +#ifdef POSTINC +# define OFF 0 +# define PUP(a) *(a)++ +#else +# define OFF 1 +# define PUP(a) *++(a) +#endif + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state->mode == LEN + strm->avail_in >= 6 + strm->avail_out >= 258 + start >= strm->avail_out + state->bits < 8 + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + output space. + */ +void inflate_fast(strm, start) +z_streamp strm; +unsigned start; /* inflate()'s starting value for strm->avail_out */ { - inflate_huft *t; /* temporary pointer */ - uInt e; /* extra bits or operation */ - uLong b; /* bit buffer */ - uInt k; /* bits in bit buffer */ - Byte *p; /* input data pointer */ - uInt n; /* bytes available there */ - Byte *q; /* output window write pointer */ - uInt m; /* bytes to end of window or read pointer */ - uInt ml; /* mask for literal/length tree */ - uInt md; /* mask for distance tree */ - uInt c; /* bytes to copy */ - uInt d; /* distance back to copy from */ - Byte *r; /* copy source pointer */ - - /* load input, output, bit values */ - LOAD - - /* initialize masks */ - ml = zlib_inflate_mask[bl]; - md = zlib_inflate_mask[bd]; - - /* do until not enough input or output space for fast loop */ - do { /* assume called with m >= 258 && n >= 10 */ - /* get literal/length code */ - GRABBITS(20) /* max bits for literal/length code */ - if ((e = (t = tl + ((uInt)b & ml))->exop) == 0) - { - DUMPBITS(t->bits) - *q++ = (Byte)t->base; - m--; - continue; - } + struct inflate_state *state; + unsigned char *in; /* local strm->next_in */ + unsigned char *last; /* while in < last, enough input available */ + unsigned char *out; /* local strm->next_out */ + unsigned char *beg; /* inflate()'s initial strm->next_out */ + unsigned char *end; /* while out < end, enough space available */ +#ifdef INFLATE_STRICT + unsigned dmax; /* maximum distance from zlib header */ +#endif + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char *window; /* allocated sliding window, if wsize != 0 */ + unsigned long hold; /* local strm->hold */ + unsigned bits; /* local strm->bits */ + code const *lcode; /* local strm->lencode */ + code const *dcode; /* local strm->distcode */ + unsigned lmask; /* mask for first level of length codes */ + unsigned dmask; /* mask for first level of distance codes */ + code this; /* retrieved table entry */ + unsigned op; /* code bits, operation, extra bits, or */ + /* window position, window bytes to copy */ + unsigned len; /* match length, unused bytes */ + unsigned dist; /* match distance */ + unsigned char *from; /* where to copy match from */ + + /* copy state to local variables */ + state = (struct inflate_state *)strm->state; + in = strm->next_in - OFF; + last = in + (strm->avail_in - 5); + out = strm->next_out - OFF; + beg = out - (start - strm->avail_out); + end = out + (strm->avail_out - 257); +#ifdef INFLATE_STRICT + dmax = state->dmax; +#endif + wsize = state->wsize; + whave = state->whave; + write = state->write; + window = state->window; + hold = state->hold; + bits = state->bits; + lcode = state->lencode; + dcode = state->distcode; + lmask = (1U << state->lenbits) - 1; + dmask = (1U << state->distbits) - 1; + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ do { - DUMPBITS(t->bits) - if (e & 16) - { - /* get extra bits for length */ - e &= 15; - c = t->base + ((uInt)b & zlib_inflate_mask[e]); - DUMPBITS(e) - - /* decode distance base of block to copy */ - GRABBITS(15); /* max bits for distance code */ - e = (t = td + ((uInt)b & md))->exop; - do { - DUMPBITS(t->bits) - if (e & 16) - { - /* get extra bits to add to distance base */ - e &= 15; - GRABBITS(e) /* get extra bits (up to 13) */ - d = t->base + ((uInt)b & zlib_inflate_mask[e]); - DUMPBITS(e) - - /* do the copy */ - m -= c; - r = q - d; - if (r < s->window) /* wrap if needed */ - { - do { - r += s->end - s->window; /* force pointer in window */ - } while (r < s->window); /* covers invalid distances */ - e = s->end - r; - if (c > e) - { - c -= e; /* wrapped copy */ - do { - *q++ = *r++; - } while (--e); - r = s->window; - do { - *q++ = *r++; - } while (--c); - } - else /* normal copy */ - { - *q++ = *r++; c--; - *q++ = *r++; c--; - do { - *q++ = *r++; - } while (--c); - } + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + this = lcode[hold & lmask]; + dolen: + op = (unsigned)(this.bits); + hold >>= op; + bits -= op; + op = (unsigned)(this.op); + if (op == 0) { /* literal */ + PUP(out) = (unsigned char)(this.val); + } + else if (op & 16) { /* length base */ + len = (unsigned)(this.val); + op &= 15; /* number of extra bits */ + if (op) { + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + len += (unsigned)hold & ((1U << op) - 1); + hold >>= op; + bits -= op; + } + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + this = dcode[hold & dmask]; + dodist: + op = (unsigned)(this.bits); + hold >>= op; + bits -= op; + op = (unsigned)(this.op); + if (op & 16) { /* distance base */ + dist = (unsigned)(this.val); + op &= 15; /* number of extra bits */ + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + } + dist += (unsigned)hold & ((1U << op) - 1); +#ifdef INFLATE_STRICT + if (dist > dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + hold >>= op; + bits -= op; + op = (unsigned)(out - beg); /* max distance in output */ + if (dist > op) { /* see if copy from window */ + op = dist - op; /* distance back in window */ + if (op > whave) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + from = window - OFF; + if (write == 0) { /* very common case */ + from += wsize - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + else if (write < op) { /* wrap around window */ + from += wsize + write - op; + op -= write; + if (op < len) { /* some from end of window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = window - OFF; + if (write < len) { /* some from start of window */ + op = write; + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + } + else { /* contiguous in window */ + from += write - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + while (len > 2) { + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + else { + from = out - dist; /* copy direct from output */ + do { /* minimum length is three */ + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } while (len > 2); + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + } + else if ((op & 64) == 0) { /* 2nd level distance code */ + this = dcode[this.val + (hold & ((1U << op) - 1))]; + goto dodist; } - else /* normal copy */ - { - *q++ = *r++; c--; - *q++ = *r++; c--; - do { - *q++ = *r++; - } while (--c); + else { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; } + } + else if ((op & 64) == 0) { /* 2nd level length code */ + this = lcode[this.val + (hold & ((1U << op) - 1))]; + goto dolen; + } + else if (op & 32) { /* end-of-block */ + state->mode = TYPE; break; - } - else if ((e & 64) == 0) - { - t += t->base; - e = (t += ((uInt)b & zlib_inflate_mask[e]))->exop; - } - else - { - z->msg = (char*)"invalid distance code"; - UNGRAB - UPDATE - return Z_DATA_ERROR; - } - } while (1); - break; - } - if ((e & 64) == 0) - { - t += t->base; - if ((e = (t += ((uInt)b & zlib_inflate_mask[e]))->exop) == 0) - { - DUMPBITS(t->bits) - *q++ = (Byte)t->base; - m--; - break; } - } - else if (e & 32) - { - UNGRAB - UPDATE - return Z_STREAM_END; - } - else - { - z->msg = (char*)"invalid literal/length code"; - UNGRAB - UPDATE - return Z_DATA_ERROR; - } - } while (1); - } while (m >= 258 && n >= 10); - - /* not enough input or output--restore pointers and return */ - UNGRAB - UPDATE - return Z_OK; + else { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + } while (in < last && out < end); + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + len = bits >> 3; + in -= len; + bits -= len << 3; + hold &= (1U << bits) - 1; + + /* update state and return */ + strm->next_in = in + OFF; + strm->next_out = out + OFF; + strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); + strm->avail_out = (unsigned)(out < end ? + 257 + (end - out) : 257 - (out - end)); + state->hold = hold; + state->bits = bits; + return; } + +/* + inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): + - Using bit fields for code structure + - Different op definition to avoid & for extra bits (do & for table bits) + - Three separate decoding do-loops for direct, window, and write == 0 + - Special case for distance > 1 copies to do overlapped load and store copy + - Explicit branch predictions (based on measured branch probabilities) + - Deferring match copy and interspersed it with decoding subsequent codes + - Swapping literal/length else + - Swapping window/direct else + - Larger unrolled copy loops (three is about right) + - Moving len -= 3 statement into middle of loop + */ + +#endif /* !ASMINF */ diff --git a/lib/zlib_inflate/inffast.h b/lib/zlib_inflate/inffast.h index fc720f0fa7f5..40315d9fddc4 100644 --- a/lib/zlib_inflate/inffast.h +++ b/lib/zlib_inflate/inffast.h @@ -1,6 +1,6 @@ /* inffast.h -- header to use inffast.c - * Copyright (C) 1995-1998 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is @@ -8,10 +8,4 @@ subject to change. Applications should only use zlib.h. */ -extern int zlib_inflate_fast ( - uInt, - uInt, - inflate_huft *, - inflate_huft *, - inflate_blocks_statef *, - z_streamp ); +void inflate_fast (z_streamp strm, unsigned start); diff --git a/lib/zlib_inflate/inffixed.h b/lib/zlib_inflate/inffixed.h new file mode 100644 index 000000000000..75ed4b5978de --- /dev/null +++ b/lib/zlib_inflate/inffixed.h @@ -0,0 +1,94 @@ + /* inffixed.h -- table for decoding fixed codes + * Generated automatically by makefixed(). + */ + + /* WARNING: this file should *not* be used by applications. It + is part of the implementation of the compression library and + is subject to change. Applications should only use zlib.h. + */ + + static const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, + {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, + {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, + {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, + {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, + {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, + {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, + {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, + {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, + {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, + {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, + {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, + {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, + {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, + {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, + {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, + {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, + {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, + {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, + {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, + {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, + {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, + {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, + {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, + {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, + {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, + {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, + {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, + {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, + {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, + {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, + {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, + {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, + {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, + {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, + {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, + {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, + {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, + {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, + {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, + {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, + {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, + {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, + {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, + {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, + {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, + {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, + {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, + {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, + {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, + {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, + {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, + {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, + {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, + {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, + {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, + {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, + {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, + {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, + {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, + {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, + {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, + {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, + {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, + {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, + {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, + {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, + {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, + {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, + {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, + {0,9,255} + }; + + static const code distfix[32] = { + {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, + {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, + {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, + {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, + {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, + {22,5,193},{64,5,0} + }; diff --git a/lib/zlib_inflate/inflate.c b/lib/zlib_inflate/inflate.c index 31b9e9054bf7..7f922dccf1a5 100644 --- a/lib/zlib_inflate/inflate.c +++ b/lib/zlib_inflate/inflate.c @@ -1,89 +1,148 @@ -/* inflate.c -- zlib interface to inflate modules - * Copyright (C) 1995-1998 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h +/* inflate.c -- zlib decompression + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Based on zlib 1.2.3 but modified for the Linux Kernel by + * Richard Purdie + * + * Changes mainly for static instead of dynamic memory allocation + * */ #include -#include "infblock.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" #include "infutil.h" int zlib_inflate_workspacesize(void) { - return sizeof(struct inflate_workspace); + return sizeof(struct inflate_workspace); } +int zlib_inflateReset(z_streamp strm) +{ + struct inflate_state *state; + + if (strm == NULL || strm->state == NULL) return Z_STREAM_ERROR; + state = (struct inflate_state *)strm->state; + strm->total_in = strm->total_out = state->total = 0; + strm->msg = NULL; + strm->adler = 1; /* to support ill-conceived Java test suite */ + state->mode = HEAD; + state->last = 0; + state->havedict = 0; + state->dmax = 32768U; + state->hold = 0; + state->bits = 0; + state->lencode = state->distcode = state->next = state->codes; -int zlib_inflateReset( - z_streamp z -) + /* Initialise Window */ + state->wsize = 1U << state->wbits; + state->write = 0; + state->whave = 0; + + return Z_OK; +} + +#if 0 +int zlib_inflatePrime(z_streamp strm, int bits, int value) { - if (z == NULL || z->state == NULL || z->workspace == NULL) - return Z_STREAM_ERROR; - z->total_in = z->total_out = 0; - z->msg = NULL; - z->state->mode = z->state->nowrap ? BLOCKS : METHOD; - zlib_inflate_blocks_reset(z->state->blocks, z, NULL); - return Z_OK; + struct inflate_state *state; + + if (strm == NULL || strm->state == NULL) return Z_STREAM_ERROR; + state = (struct inflate_state *)strm->state; + if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR; + value &= (1L << bits) - 1; + state->hold += value << state->bits; + state->bits += bits; + return Z_OK; } +#endif + +int zlib_inflateInit2(z_streamp strm, int windowBits) +{ + struct inflate_state *state; + + if (strm == NULL) return Z_STREAM_ERROR; + strm->msg = NULL; /* in case we return an error */ + + state = &WS(strm)->inflate_state; + strm->state = (struct internal_state *)state; + + if (windowBits < 0) { + state->wrap = 0; + windowBits = -windowBits; + } + else { + state->wrap = (windowBits >> 4) + 1; + } + if (windowBits < 8 || windowBits > 15) { + return Z_STREAM_ERROR; + } + state->wbits = (unsigned)windowBits; + state->window = &WS(strm)->working_window[0]; + return zlib_inflateReset(strm); +} -int zlib_inflateEnd( - z_streamp z -) +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. This returns fixed tables from inffixed.h. + */ +static void zlib_fixedtables(struct inflate_state *state) { - if (z == NULL || z->state == NULL || z->workspace == NULL) - return Z_STREAM_ERROR; - if (z->state->blocks != NULL) - zlib_inflate_blocks_free(z->state->blocks, z); - z->state = NULL; - return Z_OK; +# include "inffixed.h" + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; } -int zlib_inflateInit2_( - z_streamp z, - int w, - const char *version, - int stream_size -) +/* + Update the window with the last wsize (normally 32K) bytes written before + returning. This is only called when a window is already in use, or when + output has been written during this inflate call, but the end of the deflate + stream has not been reached yet. It is also called to window dictionary data + when a dictionary is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ +static void zlib_updatewindow(z_streamp strm, unsigned out) { - if (version == NULL || version[0] != ZLIB_VERSION[0] || - stream_size != sizeof(z_stream) || z->workspace == NULL) - return Z_VERSION_ERROR; - - /* initialize state */ - z->msg = NULL; - z->state = &WS(z)->internal_state; - z->state->blocks = NULL; - - /* handle undocumented nowrap option (no zlib header or check) */ - z->state->nowrap = 0; - if (w < 0) - { - w = - w; - z->state->nowrap = 1; - } - - /* set window size */ - if (w < 8 || w > 15) - { - zlib_inflateEnd(z); - return Z_STREAM_ERROR; - } - z->state->wbits = (uInt)w; - - /* create inflate_blocks state */ - if ((z->state->blocks = - zlib_inflate_blocks_new(z, z->state->nowrap ? NULL : zlib_adler32, (uInt)1 << w)) - == NULL) - { - zlib_inflateEnd(z); - return Z_MEM_ERROR; - } - - /* reset state */ - zlib_inflateReset(z); - return Z_OK; + struct inflate_state *state; + unsigned copy, dist; + + state = (struct inflate_state *)strm->state; + + /* copy state->wsize or less output bytes into the circular window */ + copy = out - strm->avail_out; + if (copy >= state->wsize) { + memcpy(state->window, strm->next_out - state->wsize, state->wsize); + state->write = 0; + state->whave = state->wsize; + } + else { + dist = state->wsize - state->write; + if (dist > copy) dist = copy; + memcpy(state->window + state->write, strm->next_out - copy, dist); + copy -= dist; + if (copy) { + memcpy(state->window, strm->next_out - copy, copy); + state->write = copy; + state->whave = state->wsize; + } + else { + state->write += dist; + if (state->write == state->wsize) state->write = 0; + if (state->whave < state->wsize) state->whave += dist; + } + } } @@ -91,157 +150,764 @@ int zlib_inflateInit2_( * At the end of a Deflate-compressed PPP packet, we expect to have seen * a `stored' block type value but not the (zero) length bytes. */ -static int zlib_inflate_packet_flush(inflate_blocks_statef *s) +/* + Returns true if inflate is currently at the end of a block generated by + Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + implementation to provide an additional safety check. PPP uses + Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored + block. When decompressing, PPP checks that at the end of input packet, + inflate is waiting for these length bytes. + */ +static int zlib_inflateSyncPacket(z_streamp strm) { - if (s->mode != LENS) - return Z_DATA_ERROR; - s->mode = TYPE; + struct inflate_state *state; + + if (strm == NULL || strm->state == NULL) return Z_STREAM_ERROR; + state = (struct inflate_state *)strm->state; + + if (state->mode == STORED && state->bits == 0) { + state->mode = TYPE; + return Z_OK; + } + return Z_DATA_ERROR; +} + +/* Macros for inflate(): */ + +/* check function to use adler32() for zlib or crc32() for gzip */ +#define UPDATE(check, buf, len) zlib_adler32(check, buf, len) + +/* Load registers with state in inflate() for speed */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Restore state from registers in inflate() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflate() + if there is no input available. */ +#define PULLBYTE() \ + do { \ + if (have == 0) goto inf_leave; \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflate(). */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Reverse the bytes in a 32-bit value */ +#define REVERSE(q) \ + ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ + (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) + +/* + inflate() uses a state machine to process as much input data and generate as + much output data as possible before returning. The state machine is + structured roughly as follows: + + for (;;) switch (state) { + ... + case STATEn: + if (not enough input data or output space to make progress) + return; + ... make progress ... + state = STATEm; + break; + ... + } + + so when inflate() is called again, the same case is attempted again, and + if the appropriate resources are provided, the machine proceeds to the + next state. The NEEDBITS() macro is usually the way the state evaluates + whether it can proceed or should return. NEEDBITS() does the return if + the requested bits are not available. The typical use of the BITS macros + is: + + NEEDBITS(n); + ... do something with BITS(n) ... + DROPBITS(n); + + where NEEDBITS(n) either returns from inflate() if there isn't enough + input left to load n bits into the accumulator, or it continues. BITS(n) + gives the low n bits in the accumulator. When done, DROPBITS(n) drops + the low n bits off the accumulator. INITBITS() clears the accumulator + and sets the number of available bits to zero. BYTEBITS() discards just + enough bits to put the accumulator on a byte boundary. After BYTEBITS() + and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. + + NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return + if there is no input available. The decoding of variable length codes uses + PULLBYTE() directly in order to pull just enough bytes to decode the next + code, and no more. + + Some states loop until they get enough input, making sure that enough + state information is maintained to continue the loop where it left off + if NEEDBITS() returns in the loop. For example, want, need, and keep + would all have to actually be part of the saved state in case NEEDBITS() + returns: + + case STATEw: + while (want < need) { + NEEDBITS(n); + keep[want++] = BITS(n); + DROPBITS(n); + } + state = STATEx; + case STATEx: + + As shown above, if the next state is also the next case, then the break + is omitted. + + A state may also return if there is not enough output space available to + complete that state. Those states are copying stored data, writing a + literal byte, and copying a matching string. + + When returning, a "goto inf_leave" is used to update the total counters, + update the check value, and determine whether any progress has been made + during that inflate() call in order to return the proper return code. + Progress is defined as a change in either strm->avail_in or strm->avail_out. + When there is a window, goto inf_leave will update the window with the last + output written. If a goto inf_leave occurs in the middle of decompression + and there is no window currently, goto inf_leave will create one and copy + output to the window for the next call of inflate(). + + In this implementation, the flush parameter of inflate() only affects the + return code (per zlib.h). inflate() always writes as much as possible to + strm->next_out, given the space available and the provided input--the effect + documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers + the allocation of and copying into a sliding window until necessary, which + provides the effect documented in zlib.h for Z_FINISH when the entire input + stream available. So the only thing the flush parameter actually does is: + when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it + will return Z_BUF_ERROR if it has not reached the end of the stream. + */ + +int zlib_inflate(z_streamp strm, int flush) +{ + struct inflate_state *state; + unsigned char *next; /* next input */ + unsigned char *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned in, out; /* save starting available input and output */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char *from; /* where to copy match bytes from */ + code this; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + if (strm == NULL || strm->state == NULL || strm->next_out == NULL || + (strm->next_in == NULL && strm->avail_in != 0)) + return Z_STREAM_ERROR; + + state = (struct inflate_state *)strm->state; + + if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ + LOAD(); + in = have; + out = left; + ret = Z_OK; + for (;;) + switch (state->mode) { + case HEAD: + if (state->wrap == 0) { + state->mode = TYPEDO; + break; + } + NEEDBITS(16); + if ( + ((BITS(8) << 8) + (hold >> 8)) % 31) { + strm->msg = (char *)"incorrect header check"; + state->mode = BAD; + break; + } + if (BITS(4) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + DROPBITS(4); + len = BITS(4) + 8; + if (len > state->wbits) { + strm->msg = (char *)"invalid window size"; + state->mode = BAD; + break; + } + state->dmax = 1U << len; + strm->adler = state->check = zlib_adler32(0L, NULL, 0); + state->mode = hold & 0x200 ? DICTID : TYPE; + INITBITS(); + break; + case DICTID: + NEEDBITS(32); + strm->adler = state->check = REVERSE(hold); + INITBITS(); + state->mode = DICT; + case DICT: + if (state->havedict == 0) { + RESTORE(); + return Z_NEED_DICT; + } + strm->adler = state->check = zlib_adler32(0L, NULL, 0); + state->mode = TYPE; + case TYPE: + if (flush == Z_BLOCK) goto inf_leave; + case TYPEDO: + if (state->last) { + BYTEBITS(); + state->mode = CHECK; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + state->mode = STORED; + break; + case 1: /* fixed block */ + zlib_fixedtables(state); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + case STORED: + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + INITBITS(); + state->mode = COPY; + case COPY: + copy = state->length; + if (copy) { + if (copy > have) copy = have; + if (copy > left) copy = left; + if (copy == 0) goto inf_leave; + memcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + break; + } + state->mode = TYPE; + break; + case TABLE: + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + state->have = 0; + state->mode = LENLENS; + case LENLENS: + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const *)(state->next); + state->lenbits = 7; + ret = zlib_inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + state->have = 0; + state->mode = CODELENS; + case CODELENS: + while (state->have < state->nlen + state->ndist) { + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.val < 16) { + NEEDBITS(this.bits); + DROPBITS(this.bits); + state->lens[state->have++] = this.val; + } + else { + if (this.val == 16) { + NEEDBITS(this.bits + 2); + DROPBITS(this.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = state->lens[state->have - 1]; + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (this.val == 17) { + NEEDBITS(this.bits + 3); + DROPBITS(this.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(this.bits + 7); + DROPBITS(this.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* build code tables */ + state->next = state->codes; + state->lencode = (code const *)(state->next); + state->lenbits = 9; + ret = zlib_inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const *)(state->next); + state->distbits = 6; + ret = zlib_inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + state->mode = LEN; + case LEN: + if (have >= 6 && left >= 258) { + RESTORE(); + inflate_fast(strm, out); + LOAD(); + break; + } + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.op && (this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + state->length = (unsigned)this.val; + if ((int)(this.op) == 0) { + state->mode = LIT; + break; + } + if (this.op & 32) { + state->mode = TYPE; + break; + } + if (this.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + state->extra = (unsigned)(this.op) & 15; + state->mode = LENEXT; + case LENEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + state->mode = DIST; + case DIST: + for (;;) { + this = state->distcode[BITS(state->distbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if ((this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + if (this.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)this.val; + state->extra = (unsigned)(this.op) & 15; + state->mode = DISTEXT; + case DISTEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } +#ifdef INFLATE_STRICT + if (state->offset > state->dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + if (state->offset > state->whave + out - left) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + state->mode = MATCH; + case MATCH: + if (left == 0) goto inf_leave; + copy = out - left; + if (state->offset > copy) { /* copy from window */ + copy = state->offset - copy; + if (copy > state->write) { + copy -= state->write; + from = state->window + (state->wsize - copy); + } + else + from = state->window + (state->write - copy); + if (copy > state->length) copy = state->length; + } + else { /* copy from output */ + from = put - state->offset; + copy = state->length; + } + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = *from++; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; + case LIT: + if (left == 0) goto inf_leave; + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + case CHECK: + if (state->wrap) { + NEEDBITS(32); + out -= left; + strm->total_out += out; + state->total += out; + if (out) + strm->adler = state->check = + UPDATE(state->check, put - out, out); + out = left; + if (( + REVERSE(hold)) != state->check) { + strm->msg = (char *)"incorrect data check"; + state->mode = BAD; + break; + } + INITBITS(); + } + state->mode = DONE; + case DONE: + ret = Z_STREAM_END; + goto inf_leave; + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + case MEM: + return Z_MEM_ERROR; + case SYNC: + default: + return Z_STREAM_ERROR; + } + + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call zlib_updatewindow() to create and/or update the window state. + */ + inf_leave: + RESTORE(); + if (state->wsize || (state->mode < CHECK && out != strm->avail_out)) + zlib_updatewindow(strm, out); + + in -= strm->avail_in; + out -= strm->avail_out; + strm->total_in += in; + strm->total_out += out; + state->total += out; + if (state->wrap && out) + strm->adler = state->check = + UPDATE(state->check, strm->next_out - out, out); + + strm->data_type = state->bits + (state->last ? 64 : 0) + + (state->mode == TYPE ? 128 : 0); + if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) + ret = Z_BUF_ERROR; + + if (flush == Z_PACKET_FLUSH && ret == Z_OK && + (strm->avail_out != 0 || strm->avail_in == 0)) + return zlib_inflateSyncPacket(strm); + return ret; +} + +int zlib_inflateEnd(z_streamp strm) +{ + if (strm == NULL || strm->state == NULL) + return Z_STREAM_ERROR; return Z_OK; } +#if 0 +int zlib_inflateSetDictionary(z_streamp strm, const Byte *dictionary, + uInt dictLength) +{ + struct inflate_state *state; + unsigned long id; + + /* check state */ + if (strm == NULL || strm->state == NULL) return Z_STREAM_ERROR; + state = (struct inflate_state *)strm->state; + if (state->wrap != 0 && state->mode != DICT) + return Z_STREAM_ERROR; + + /* check for correct dictionary id */ + if (state->mode == DICT) { + id = zlib_adler32(0L, NULL, 0); + id = zlib_adler32(id, dictionary, dictLength); + if (id != state->check) + return Z_DATA_ERROR; + } + + /* copy dictionary to window */ + zlib_updatewindow(strm, strm->avail_out); -int zlib_inflateInit_( - z_streamp z, - const char *version, - int stream_size -) + if (dictLength > state->wsize) { + memcpy(state->window, dictionary + dictLength - state->wsize, + state->wsize); + state->whave = state->wsize; + } + else { + memcpy(state->window + state->wsize - dictLength, dictionary, + dictLength); + state->whave = dictLength; + } + state->havedict = 1; + return Z_OK; +} +#endif + +#if 0 +/* + Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found + or when out of input. When called, *have is the number of pattern bytes + found in order so far, in 0..3. On return *have is updated to the new + state. If on return *have equals four, then the pattern was found and the + return value is how many bytes were read including the last byte of the + pattern. If *have is less than four, then the pattern has not been found + yet and the return value is len. In the latter case, zlib_syncsearch() can be + called again with more data and the *have state. *have is initialized to + zero for the first call. + */ +static unsigned zlib_syncsearch(unsigned *have, unsigned char *buf, + unsigned len) { - return zlib_inflateInit2_(z, DEF_WBITS, version, stream_size); + unsigned got; + unsigned next; + + got = *have; + next = 0; + while (next < len && got < 4) { + if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) + got++; + else if (buf[next]) + got = 0; + else + got = 4 - got; + next++; + } + *have = got; + return next; } +#endif -#undef NEEDBYTE -#undef NEXTBYTE -#define NEEDBYTE {if(z->avail_in==0)goto empty;r=trv;} -#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++) +#if 0 +int zlib_inflateSync(z_streamp strm) +{ + unsigned len; /* number of bytes to look at or looked at */ + unsigned long in, out; /* temporary to save total_in and total_out */ + unsigned char buf[4]; /* to restore bit buffer to byte string */ + struct inflate_state *state; + + /* check parameters */ + if (strm == NULL || strm->state == NULL) return Z_STREAM_ERROR; + state = (struct inflate_state *)strm->state; + if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; + + /* if first time, start search in bit buffer */ + if (state->mode != SYNC) { + state->mode = SYNC; + state->hold <<= state->bits & 7; + state->bits -= state->bits & 7; + len = 0; + while (state->bits >= 8) { + buf[len++] = (unsigned char)(state->hold); + state->hold >>= 8; + state->bits -= 8; + } + state->have = 0; + zlib_syncsearch(&(state->have), buf, len); + } + + /* search available input */ + len = zlib_syncsearch(&(state->have), strm->next_in, strm->avail_in); + strm->avail_in -= len; + strm->next_in += len; + strm->total_in += len; + + /* return no joy or set up to restart inflate() on a new block */ + if (state->have != 4) return Z_DATA_ERROR; + in = strm->total_in; out = strm->total_out; + zlib_inflateReset(strm); + strm->total_in = in; strm->total_out = out; + state->mode = TYPE; + return Z_OK; +} +#endif -int zlib_inflate( - z_streamp z, - int f -) +/* + * This subroutine adds the data at next_in/avail_in to the output history + * without performing any output. The output buffer must be "caught up"; + * i.e. no pending output but this should always be the case. The state must + * be waiting on the start of a block (i.e. mode == TYPE or HEAD). On exit, + * the output will also be caught up, and the checksum will have been updated + * if need be. + */ +int zlib_inflateIncomp(z_stream *z) { - int r, trv; - uInt b; - - if (z == NULL || z->state == NULL || z->next_in == NULL) - return Z_STREAM_ERROR; - trv = f == Z_FINISH ? Z_BUF_ERROR : Z_OK; - r = Z_BUF_ERROR; - while (1) switch (z->state->mode) - { - case METHOD: - NEEDBYTE - if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED) - { - z->state->mode = I_BAD; - z->msg = (char*)"unknown compression method"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - if ((z->state->sub.method >> 4) + 8 > z->state->wbits) - { - z->state->mode = I_BAD; - z->msg = (char*)"invalid window size"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - z->state->mode = FLAG; - case FLAG: - NEEDBYTE - b = NEXTBYTE; - if (((z->state->sub.method << 8) + b) % 31) - { - z->state->mode = I_BAD; - z->msg = (char*)"incorrect header check"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - if (!(b & PRESET_DICT)) - { - z->state->mode = BLOCKS; - break; - } - z->state->mode = DICT4; - case DICT4: - NEEDBYTE - z->state->sub.check.need = (uLong)NEXTBYTE << 24; - z->state->mode = DICT3; - case DICT3: - NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE << 16; - z->state->mode = DICT2; - case DICT2: - NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE << 8; - z->state->mode = DICT1; - case DICT1: - NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE; - z->adler = z->state->sub.check.need; - z->state->mode = DICT0; - return Z_NEED_DICT; - case DICT0: - z->state->mode = I_BAD; - z->msg = (char*)"need dictionary"; - z->state->sub.marker = 0; /* can try inflateSync */ - return Z_STREAM_ERROR; - case BLOCKS: - r = zlib_inflate_blocks(z->state->blocks, z, r); - if (f == Z_PACKET_FLUSH && z->avail_in == 0 && z->avail_out != 0) - r = zlib_inflate_packet_flush(z->state->blocks); - if (r == Z_DATA_ERROR) - { - z->state->mode = I_BAD; - z->state->sub.marker = 0; /* can try inflateSync */ - break; - } - if (r == Z_OK) - r = trv; - if (r != Z_STREAM_END) - return r; - r = trv; - zlib_inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was); - if (z->state->nowrap) - { - z->state->mode = I_DONE; - break; - } - z->state->mode = CHECK4; - case CHECK4: - NEEDBYTE - z->state->sub.check.need = (uLong)NEXTBYTE << 24; - z->state->mode = CHECK3; - case CHECK3: - NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE << 16; - z->state->mode = CHECK2; - case CHECK2: - NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE << 8; - z->state->mode = CHECK1; - case CHECK1: - NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE; - - if (z->state->sub.check.was != z->state->sub.check.need) - { - z->state->mode = I_BAD; - z->msg = (char*)"incorrect data check"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - z->state->mode = I_DONE; - case I_DONE: - return Z_STREAM_END; - case I_BAD: - return Z_DATA_ERROR; - default: - return Z_STREAM_ERROR; - } - empty: - if (f != Z_PACKET_FLUSH) - return r; - z->state->mode = I_BAD; - z->msg = (char *)"need more for packet flush"; - z->state->sub.marker = 0; /* can try inflateSync */ - return Z_DATA_ERROR; + struct inflate_state *state = (struct inflate_state *)z->state; + Byte *saved_no = z->next_out; + uInt saved_ao = z->avail_out; + + if (state->mode != TYPE && state->mode != HEAD) + return Z_DATA_ERROR; + + /* Setup some variables to allow misuse of updateWindow */ + z->avail_out = 0; + z->next_out = z->next_in + z->avail_in; + + zlib_updatewindow(z, z->avail_in); + + /* Restore saved variables */ + z->avail_out = saved_ao; + z->next_out = saved_no; + + z->adler = state->check = + UPDATE(state->check, z->next_in, z->avail_in); + + z->total_out += z->avail_in; + z->total_in += z->avail_in; + z->next_in += z->avail_in; + state->total += z->avail_in; + z->avail_in = 0; + + return Z_OK; } diff --git a/lib/zlib_inflate/inflate.h b/lib/zlib_inflate/inflate.h new file mode 100644 index 000000000000..df8a6c92052d --- /dev/null +++ b/lib/zlib_inflate/inflate.h @@ -0,0 +1,107 @@ +/* inflate.h -- internal inflate state definition + * Copyright (C) 1995-2004 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Possible inflate modes between inflate() calls */ +typedef enum { + HEAD, /* i: waiting for magic header */ + FLAGS, /* i: waiting for method and flags (gzip) */ + TIME, /* i: waiting for modification time (gzip) */ + OS, /* i: waiting for extra flags and operating system (gzip) */ + EXLEN, /* i: waiting for extra length (gzip) */ + EXTRA, /* i: waiting for extra bytes (gzip) */ + NAME, /* i: waiting for end of file name (gzip) */ + COMMENT, /* i: waiting for end of comment (gzip) */ + HCRC, /* i: waiting for header crc (gzip) */ + DICTID, /* i: waiting for dictionary check value */ + DICT, /* waiting for inflateSetDictionary() call */ + TYPE, /* i: waiting for type bits, including last-flag bit */ + TYPEDO, /* i: same, but skip check to exit inflate on new block */ + STORED, /* i: waiting for stored size (length and complement) */ + COPY, /* i/o: waiting for input or output to copy stored block */ + TABLE, /* i: waiting for dynamic block table lengths */ + LENLENS, /* i: waiting for code length code lengths */ + CODELENS, /* i: waiting for length/lit and distance code lengths */ + LEN, /* i: waiting for length/lit code */ + LENEXT, /* i: waiting for length extra bits */ + DIST, /* i: waiting for distance code */ + DISTEXT, /* i: waiting for distance extra bits */ + MATCH, /* o: waiting for output space to copy string */ + LIT, /* o: waiting for output space to write literal */ + CHECK, /* i: waiting for 32-bit check value */ + LENGTH, /* i: waiting for 32-bit length (gzip) */ + DONE, /* finished check, done -- remain here until reset */ + BAD, /* got a data error -- remain here until reset */ + MEM, /* got an inflate() memory error -- remain here until reset */ + SYNC /* looking for synchronization bytes to restart inflate() */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to the BAD or MEM mode -- not shown for clarity) + + Process header: + HEAD -> (gzip) or (zlib) + (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME + NAME -> COMMENT -> HCRC -> TYPE + (zlib) -> DICTID or TYPE + DICTID -> DICT -> TYPE + Read deflate blocks: + TYPE -> STORED or TABLE or LEN or CHECK + STORED -> COPY -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN + Read deflate codes: + LEN -> LENEXT or LIT or TYPE + LENEXT -> DIST -> DISTEXT -> MATCH -> LEN + LIT -> LEN + Process trailer: + CHECK -> LENGTH -> DONE + */ + +/* state maintained between inflate() calls. Approximately 7K bytes. */ +struct inflate_state { + inflate_mode mode; /* current inflate mode */ + int last; /* true if processing last block */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + int havedict; /* true if dictionary provided */ + int flags; /* gzip header method and flags (0 if zlib) */ + unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ + unsigned long check; /* protected copy of check value */ + unsigned long total; /* protected copy of output count */ + /* gz_headerp head; */ /* where to save gzip header information */ + /* sliding window */ + unsigned wbits; /* log base 2 of requested window size */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char *window; /* allocated sliding window, if needed */ + /* bit accumulator */ + unsigned long hold; /* input bit accumulator */ + unsigned bits; /* number of bits in "in" */ + /* for string and stored block copying */ + unsigned length; /* literal or length of data to copy */ + unsigned offset; /* distance back to copy string from */ + /* for table and code decoding */ + unsigned extra; /* extra bits needed */ + /* fixed and dynamic code tables */ + code const *lencode; /* starting table for length/literal codes */ + code const *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + unsigned have; /* number of code lengths in lens[] */ + code *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ +}; diff --git a/lib/zlib_inflate/inflate_syms.c b/lib/zlib_inflate/inflate_syms.c index ef49738f57ec..2061d4f06765 100644 --- a/lib/zlib_inflate/inflate_syms.c +++ b/lib/zlib_inflate/inflate_syms.c @@ -12,8 +12,7 @@ EXPORT_SYMBOL(zlib_inflate_workspacesize); EXPORT_SYMBOL(zlib_inflate); -EXPORT_SYMBOL(zlib_inflateInit_); -EXPORT_SYMBOL(zlib_inflateInit2_); +EXPORT_SYMBOL(zlib_inflateInit2); EXPORT_SYMBOL(zlib_inflateEnd); EXPORT_SYMBOL(zlib_inflateReset); EXPORT_SYMBOL(zlib_inflateIncomp); diff --git a/lib/zlib_inflate/inflate_sync.c b/lib/zlib_inflate/inflate_sync.c deleted file mode 100644 index 61411ff89d61..000000000000 --- a/lib/zlib_inflate/inflate_sync.c +++ /dev/null @@ -1,152 +0,0 @@ -/* inflate.c -- zlib interface to inflate modules - * Copyright (C) 1995-1998 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include -#include "infblock.h" -#include "infutil.h" - -#if 0 -int zlib_inflateSync( - z_streamp z -) -{ - uInt n; /* number of bytes to look at */ - Byte *p; /* pointer to bytes */ - uInt m; /* number of marker bytes found in a row */ - uLong r, w; /* temporaries to save total_in and total_out */ - - /* set up */ - if (z == NULL || z->state == NULL) - return Z_STREAM_ERROR; - if (z->state->mode != I_BAD) - { - z->state->mode = I_BAD; - z->state->sub.marker = 0; - } - if ((n = z->avail_in) == 0) - return Z_BUF_ERROR; - p = z->next_in; - m = z->state->sub.marker; - - /* search */ - while (n && m < 4) - { - static const Byte mark[4] = {0, 0, 0xff, 0xff}; - if (*p == mark[m]) - m++; - else if (*p) - m = 0; - else - m = 4 - m; - p++, n--; - } - - /* restore */ - z->total_in += p - z->next_in; - z->next_in = p; - z->avail_in = n; - z->state->sub.marker = m; - - /* return no joy or set up to restart on a new block */ - if (m != 4) - return Z_DATA_ERROR; - r = z->total_in; w = z->total_out; - zlib_inflateReset(z); - z->total_in = r; z->total_out = w; - z->state->mode = BLOCKS; - return Z_OK; -} -#endif /* 0 */ - - -/* Returns true if inflate is currently at the end of a block generated - * by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP - * implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH - * but removes the length bytes of the resulting empty stored block. When - * decompressing, PPP checks that at the end of input packet, inflate is - * waiting for these length bytes. - */ -#if 0 -int zlib_inflateSyncPoint( - z_streamp z -) -{ - if (z == NULL || z->state == NULL || z->state->blocks == NULL) - return Z_STREAM_ERROR; - return zlib_inflate_blocks_sync_point(z->state->blocks); -} -#endif /* 0 */ - -/* - * This subroutine adds the data at next_in/avail_in to the output history - * without performing any output. The output buffer must be "caught up"; - * i.e. no pending output (hence s->read equals s->write), and the state must - * be BLOCKS (i.e. we should be willing to see the start of a series of - * BLOCKS). On exit, the output will also be caught up, and the checksum - * will have been updated if need be. - */ -static int zlib_inflate_addhistory(inflate_blocks_statef *s, - z_stream *z) -{ - uLong b; /* bit buffer */ /* NOT USED HERE */ - uInt k; /* bits in bit buffer */ /* NOT USED HERE */ - uInt t; /* temporary storage */ - Byte *p; /* input data pointer */ - uInt n; /* bytes available there */ - Byte *q; /* output window write pointer */ - uInt m; /* bytes to end of window or read pointer */ - - if (s->read != s->write) - return Z_STREAM_ERROR; - if (s->mode != TYPE) - return Z_DATA_ERROR; - - /* we're ready to rock */ - LOAD - /* while there is input ready, copy to output buffer, moving - * pointers as needed. - */ - while (n) { - t = n; /* how many to do */ - /* is there room until end of buffer? */ - if (t > m) t = m; - /* update check information */ - if (s->checkfn != NULL) - s->check = (*s->checkfn)(s->check, q, t); - memcpy(q, p, t); - q += t; - p += t; - n -= t; - z->total_out += t; - s->read = q; /* drag read pointer forward */ -/* WWRAP */ /* expand WWRAP macro by hand to handle s->read */ - if (q == s->end) { - s->read = q = s->window; - m = WAVAIL; - } - } - UPDATE - return Z_OK; -} - - -/* - * This subroutine adds the data at next_in/avail_in to the output history - * without performing any output. The output buffer must be "caught up"; - * i.e. no pending output (hence s->read equals s->write), and the state must - * be BLOCKS (i.e. we should be willing to see the start of a series of - * BLOCKS). On exit, the output will also be caught up, and the checksum - * will have been updated if need be. - */ - -int zlib_inflateIncomp( - z_stream *z - -) -{ - if (z->state->mode != BLOCKS) - return Z_DATA_ERROR; - return zlib_inflate_addhistory(z->state->blocks, z); -} diff --git a/lib/zlib_inflate/inftrees.c b/lib/zlib_inflate/inftrees.c index 874950ec4858..62343c53bf7e 100644 --- a/lib/zlib_inflate/inftrees.c +++ b/lib/zlib_inflate/inftrees.c @@ -1,412 +1,329 @@ /* inftrees.c -- generate Huffman trees for efficient decoding - * Copyright (C) 1995-1998 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h */ #include #include "inftrees.h" -#include "infutil.h" -static const char inflate_copyright[] __attribute_used__ = - " inflate 1.1.3 Copyright 1995-1998 Mark Adler "; +#define MAXBITS 15 + +const char inflate_copyright[] = + " inflate 1.2.3 Copyright 1995-2005 Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot include such an acknowledgment, I would appreciate that you keep this copyright string in the executable of your product. */ -struct internal_state; - -/* simplify the use of the inflate_huft type with some defines */ -#define exop word.what.Exop -#define bits word.what.Bits - - -static int huft_build ( - uInt *, /* code lengths in bits */ - uInt, /* number of codes */ - uInt, /* number of "simple" codes */ - const uInt *, /* list of base values for non-simple codes */ - const uInt *, /* list of extra bits for non-simple codes */ - inflate_huft **, /* result: starting table */ - uInt *, /* maximum lookup bits (returns actual) */ - inflate_huft *, /* space for trees */ - uInt *, /* hufts used in space */ - uInt * ); /* space for values */ - -/* Tables for deflate from PKZIP's appnote.txt. */ -static const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */ - 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, - 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; - /* see note #13 above about 258 */ -static const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */ - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, - 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */ -static const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */ - 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, - 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, - 8193, 12289, 16385, 24577}; -static const uInt cpdext[30] = { /* Extra bits for distance codes */ - 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, - 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, - 12, 12, 13, 13}; /* - Huffman code decoding is performed using a multi-level table lookup. - The fastest way to decode is to simply build a lookup table whose - size is determined by the longest code. However, the time it takes - to build this table can also be a factor if the data being decoded - is not very long. The most common codes are necessarily the - shortest codes, so those codes dominate the decoding time, and hence - the speed. The idea is you can have a shorter table that decodes the - shorter, more probable codes, and then point to subsidiary tables for - the longer codes. The time it costs to decode the longer codes is - then traded against the time it takes to make longer tables. - - This results of this trade are in the variables lbits and dbits - below. lbits is the number of bits the first level table for literal/ - length codes can decode in one step, and dbits is the same thing for - the distance codes. Subsequent tables are also less than or equal to - those sizes. These values may be adjusted either when all of the - codes are shorter than that, in which case the longest code length in - bits is used, or when the shortest code is *longer* than the requested - table size, in which case the length of the shortest code in bits is - used. - - There are two different values for the two tables, since they code a - different number of possibilities each. The literal/length table - codes 286 possible values, or in a flat code, a little over eight - bits. The distance table codes 30 possible values, or a little less - than five bits, flat. The optimum values for speed end up being - about one bit more than those, so lbits is 8+1 and dbits is 5+1. - The optimum values may differ though from machine to machine, and - possibly even between compilers. Your mileage may vary. + Build a set of tables to decode the provided canonical Huffman code. + The code lengths are lens[0..codes-1]. The result starts at *table, + whose indices are 0..2^bits-1. work is a writable array of at least + lens shorts, which is used as a work area. type is the type of code + to be generated, CODES, LENS, or DISTS. On return, zero is success, + -1 is an invalid code, and +1 means that ENOUGH isn't enough. table + on return points to the next available entry's address. bits is the + requested root table index bits, and on return it is the actual root + table index bits. It will differ if the request is greater than the + longest code or if it is less than the shortest code. */ - - -/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */ -#define BMAX 15 /* maximum bit length of any code */ - -static int huft_build( - uInt *b, /* code lengths in bits (all assumed <= BMAX) */ - uInt n, /* number of codes (assumed <= 288) */ - uInt s, /* number of simple-valued codes (0..s-1) */ - const uInt *d, /* list of base values for non-simple codes */ - const uInt *e, /* list of extra bits for non-simple codes */ - inflate_huft **t, /* result: starting table */ - uInt *m, /* maximum lookup bits, returns actual */ - inflate_huft *hp, /* space for trees */ - uInt *hn, /* hufts used in space */ - uInt *v /* working area: values in order of bit length */ -) -/* Given a list of code lengths and a maximum table size, make a set of - tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR - if the given code set is incomplete (the tables are still built in this - case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of - lengths), or Z_MEM_ERROR if not enough memory. */ +int zlib_inflate_table(type, lens, codes, table, bits, work) +codetype type; +unsigned short *lens; +unsigned codes; +code **table; +unsigned *bits; +unsigned short *work; { + unsigned len; /* a code's length in bits */ + unsigned sym; /* index of code symbols */ + unsigned min, max; /* minimum and maximum code lengths */ + unsigned root; /* number of index bits for root table */ + unsigned curr; /* number of index bits for current table */ + unsigned drop; /* code bits to drop for sub-table */ + int left; /* number of prefix codes available */ + unsigned used; /* code entries in table used */ + unsigned huff; /* Huffman code */ + unsigned incr; /* for incrementing code, index */ + unsigned fill; /* index for replicating entries */ + unsigned low; /* low bits for current root entry */ + unsigned mask; /* mask for low root bits */ + code this; /* table entry for duplication */ + code *next; /* next available space in table */ + const unsigned short *base; /* base value table to use */ + const unsigned short *extra; /* extra bits table to use */ + int end; /* use base and extra for symbol > end */ + unsigned short count[MAXBITS+1]; /* number of codes of each length */ + unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ + static const unsigned short lbase[31] = { /* Length codes 257..285 base */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + static const unsigned short lext[31] = { /* Length codes 257..285 extra */ + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 201, 196}; + static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577, 0, 0}; + static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ + 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 28, 28, 29, 29, 64, 64}; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for (len = 0; len <= MAXBITS; len++) + count[len] = 0; + for (sym = 0; sym < codes; sym++) + count[lens[sym]]++; + + /* bound code lengths, force root to be within code lengths */ + root = *bits; + for (max = MAXBITS; max >= 1; max--) + if (count[max] != 0) break; + if (root > max) root = max; + if (max == 0) { /* no symbols to code at all */ + this.op = (unsigned char)64; /* invalid code marker */ + this.bits = (unsigned char)1; + this.val = (unsigned short)0; + *(*table)++ = this; /* make a table to force an error */ + *(*table)++ = this; + *bits = 1; + return 0; /* no symbols, but wait for decoding to report error */ + } + for (min = 1; min <= MAXBITS; min++) + if (count[min] != 0) break; + if (root < min) root = min; + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= count[len]; + if (left < 0) return -1; /* over-subscribed */ + } + if (left > 0 && (type == CODES || max != 1)) + return -1; /* incomplete set */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + count[len]; + + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) + if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked when a LENS table is being made + against the space in *table, ENOUGH, minus the maximum space needed by + the worst case distance code, MAXD. This should never happen, but the + sufficiency of ENOUGH has not been proven exhaustively, hence the check. + This assumes that when type == LENS, bits == 9. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + switch (type) { + case CODES: + base = extra = work; /* dummy value--not used */ + end = 19; + break; + case LENS: + base = lbase; + base -= 257; + extra = lext; + extra -= 257; + end = 256; + break; + default: /* DISTS */ + base = dbase; + extra = dext; + end = -1; + } - uInt a; /* counter for codes of length k */ - uInt c[BMAX+1]; /* bit length count table */ - uInt f; /* i repeats in table every f entries */ - int g; /* maximum code length */ - int h; /* table level */ - register uInt i; /* counter, current code */ - register uInt j; /* counter */ - register int k; /* number of bits in current code */ - int l; /* bits per table (returned in m) */ - uInt mask; /* (1 << w) - 1, to avoid cc -O bug on HP */ - register uInt *p; /* pointer into c[], b[], or v[] */ - inflate_huft *q; /* points to current table */ - struct inflate_huft_s r; /* table entry for structure assignment */ - inflate_huft *u[BMAX]; /* table stack */ - register int w; /* bits before this table == (l * h) */ - uInt x[BMAX+1]; /* bit offsets, then code stack */ - uInt *xp; /* pointer into x */ - int y; /* number of dummy codes added */ - uInt z; /* number of entries in current table */ - - - /* Generate counts for each bit length */ - p = c; -#define C0 *p++ = 0; -#define C2 C0 C0 C0 C0 -#define C4 C2 C2 C2 C2 - C4 /* clear c[]--assume BMAX+1 is 16 */ - p = b; i = n; - do { - c[*p++]++; /* assume all entries <= BMAX */ - } while (--i); - if (c[0] == n) /* null input--all zero length codes */ - { - *t = NULL; - *m = 0; - return Z_OK; - } - - - /* Find minimum and maximum length, bound *m by those */ - l = *m; - for (j = 1; j <= BMAX; j++) - if (c[j]) - break; - k = j; /* minimum code length */ - if ((uInt)l < j) - l = j; - for (i = BMAX; i; i--) - if (c[i]) - break; - g = i; /* maximum code length */ - if ((uInt)l > i) - l = i; - *m = l; - - - /* Adjust last length count to fill out codes, if needed */ - for (y = 1 << j; j < i; j++, y <<= 1) - if ((y -= c[j]) < 0) - return Z_DATA_ERROR; - if ((y -= c[i]) < 0) - return Z_DATA_ERROR; - c[i] += y; - - - /* Generate starting offsets into the value table for each length */ - x[1] = j = 0; - p = c + 1; xp = x + 2; - while (--i) { /* note that i == g from above */ - *xp++ = (j += *p++); - } - - - /* Make a table of values in order of bit lengths */ - p = b; i = 0; - do { - if ((j = *p++) != 0) - v[x[j]++] = i; - } while (++i < n); - n = x[g]; /* set n to length of v */ - - - /* Generate the Huffman codes and for each, make the table entries */ - x[0] = i = 0; /* first Huffman code is zero */ - p = v; /* grab values in bit order */ - h = -1; /* no tables yet--level -1 */ - w = -l; /* bits decoded == (l * h) */ - u[0] = NULL; /* just to keep compilers happy */ - q = NULL; /* ditto */ - z = 0; /* ditto */ - - /* go through the bit lengths (k already is bits in shortest code) */ - for (; k <= g; k++) - { - a = c[k]; - while (a--) - { - /* here i is the Huffman code of length k bits for value *p */ - /* make tables up to required level */ - while (k > w + l) - { - h++; - w += l; /* previous table always l bits */ - - /* compute minimum size table less than or equal to l bits */ - z = g - w; - z = z > (uInt)l ? l : z; /* table size upper limit */ - if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ - { /* too few codes for k-w bit table */ - f -= a + 1; /* deduct codes from patterns left */ - xp = c + k; - if (j < z) - while (++j < z) /* try smaller tables up to z bits */ - { - if ((f <<= 1) <= *++xp) - break; /* enough codes to use up j bits */ - f -= *xp; /* else deduct codes from patterns */ - } + /* initialize state for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = *table; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = (unsigned)(-1); /* trigger new sub-table when len > root */ + used = 1U << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if (type == LENS && used >= ENOUGH - MAXD) + return 1; + + /* process all codes and make table entries */ + for (;;) { + /* create table entry */ + this.bits = (unsigned char)(len - drop); + if ((int)(work[sym]) < end) { + this.op = (unsigned char)0; + this.val = work[sym]; } - z = 1 << j; /* table entries for j-bit table */ - - /* allocate new table */ - if (*hn + z > MANY) /* (note: doesn't matter for fixed) */ - return Z_DATA_ERROR; /* overflow of MANY */ - u[h] = q = hp + *hn; - *hn += z; - - /* connect to last table, if there is one */ - if (h) - { - x[h] = i; /* save pattern for backing up */ - r.bits = (Byte)l; /* bits to dump before this table */ - r.exop = (Byte)j; /* bits in this table */ - j = i >> (w - l); - r.base = (uInt)(q - u[h-1] - j); /* offset to this table */ - u[h-1][j] = r; /* connect to last table */ + else if ((int)(work[sym]) > end) { + this.op = (unsigned char)(extra[work[sym]]); + this.val = base[work[sym]]; + } + else { + this.op = (unsigned char)(32 + 64); /* end of block */ + this.val = 0; } - else - *t = q; /* first table is returned result */ - } - - /* set up table entry in r */ - r.bits = (Byte)(k - w); - if (p >= v + n) - r.exop = 128 + 64; /* out of values--invalid code */ - else if (*p < s) - { - r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); /* 256 is end-of-block */ - r.base = *p++; /* simple code is just the value */ - } - else - { - r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */ - r.base = d[*p++ - s]; - } - - /* fill code-like entries with r */ - f = 1 << (k - w); - for (j = i >> w; j < z; j += f) - q[j] = r; - - /* backwards increment the k-bit code i */ - for (j = 1 << (k - 1); i & j; j >>= 1) - i ^= j; - i ^= j; - - /* backup over finished tables */ - mask = (1 << w) - 1; /* needed on HP, cc -O bug */ - while ((i & mask) != x[h]) - { - h--; /* don't need to update q */ - w -= l; - mask = (1 << w) - 1; - } - } - } + /* replicate for those indices with low len bits equal to huff */ + incr = 1U << (len - drop); + fill = 1U << curr; + min = fill; /* save offset to next table */ + do { + fill -= incr; + next[(huff >> drop) + fill] = this; + } while (fill != 0); + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; - /* Return Z_BUF_ERROR if we were given an incomplete table */ - return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; -} + /* go to next symbol, update count, len */ + sym++; + if (--(count[len]) == 0) { + if (len == max) break; + len = lens[work[sym]]; + } + /* create new sub-table if needed */ + if (len > root && (huff & mask) != low) { + /* if first time, transition to sub-tables */ + if (drop == 0) + drop = root; + + /* increment past last table */ + next += min; /* here min is 1 << curr */ + + /* determine length of next table */ + curr = len - drop; + left = (int)(1 << curr); + while (curr + drop < max) { + left -= count[curr + drop]; + if (left <= 0) break; + curr++; + left <<= 1; + } -int zlib_inflate_trees_bits( - uInt *c, /* 19 code lengths */ - uInt *bb, /* bits tree desired/actual depth */ - inflate_huft **tb, /* bits tree result */ - inflate_huft *hp, /* space for trees */ - z_streamp z /* for messages */ -) -{ - int r; - uInt hn = 0; /* hufts used in space */ - uInt *v; /* work area for huft_build */ - - v = WS(z)->tree_work_area_1; - r = huft_build(c, 19, 19, NULL, NULL, tb, bb, hp, &hn, v); - if (r == Z_DATA_ERROR) - z->msg = (char*)"oversubscribed dynamic bit lengths tree"; - else if (r == Z_BUF_ERROR || *bb == 0) - { - z->msg = (char*)"incomplete dynamic bit lengths tree"; - r = Z_DATA_ERROR; - } - return r; -} + /* check for enough space */ + used += 1U << curr; + if (type == LENS && used >= ENOUGH - MAXD) + return 1; -int zlib_inflate_trees_dynamic( - uInt nl, /* number of literal/length codes */ - uInt nd, /* number of distance codes */ - uInt *c, /* that many (total) code lengths */ - uInt *bl, /* literal desired/actual bit depth */ - uInt *bd, /* distance desired/actual bit depth */ - inflate_huft **tl, /* literal/length tree result */ - inflate_huft **td, /* distance tree result */ - inflate_huft *hp, /* space for trees */ - z_streamp z /* for messages */ -) -{ - int r; - uInt hn = 0; /* hufts used in space */ - uInt *v; /* work area for huft_build */ - - /* allocate work area */ - v = WS(z)->tree_work_area_2; - - /* build literal/length tree */ - r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v); - if (r != Z_OK || *bl == 0) - { - if (r == Z_DATA_ERROR) - z->msg = (char*)"oversubscribed literal/length tree"; - else if (r != Z_MEM_ERROR) - { - z->msg = (char*)"incomplete literal/length tree"; - r = Z_DATA_ERROR; - } - return r; - } - - /* build distance tree */ - r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v); - if (r != Z_OK || (*bd == 0 && nl > 257)) - { - if (r == Z_DATA_ERROR) - z->msg = (char*)"oversubscribed distance tree"; - else if (r == Z_BUF_ERROR) { -#ifdef PKZIP_BUG_WORKAROUND - r = Z_OK; - } -#else - z->msg = (char*)"incomplete distance tree"; - r = Z_DATA_ERROR; - } - else if (r != Z_MEM_ERROR) - { - z->msg = (char*)"empty distance tree with lengths"; - r = Z_DATA_ERROR; + /* point entry in root table to sub-table */ + low = huff & mask; + (*table)[low].op = (unsigned char)curr; + (*table)[low].bits = (unsigned char)root; + (*table)[low].val = (unsigned short)(next - *table); + } } - return r; -#endif - } - /* done */ - return Z_OK; -} + /* + Fill in rest of table for incomplete codes. This loop is similar to the + loop above in incrementing huff for table indices. It is assumed that + len is equal to curr + drop, so there is no loop needed to increment + through high index bits. When the current sub-table is filled, the loop + drops back to the root table to fill in any remaining entries there. + */ + this.op = (unsigned char)64; /* invalid code marker */ + this.bits = (unsigned char)(len - drop); + this.val = (unsigned short)0; + while (huff != 0) { + /* when done with sub-table, drop back to root table */ + if (drop != 0 && (huff & mask) != low) { + drop = 0; + len = root; + next = *table; + this.bits = (unsigned char)len; + } + /* put invalid code marker in table */ + next[huff >> drop] = this; -int zlib_inflate_trees_fixed( - uInt *bl, /* literal desired/actual bit depth */ - uInt *bd, /* distance desired/actual bit depth */ - inflate_huft **tl, /* literal/length tree result */ - inflate_huft **td, /* distance tree result */ - inflate_huft *hp, /* space for trees */ - z_streamp z /* for memory allocation */ -) -{ - int i; /* temporary variable */ - unsigned l[288]; /* length list for huft_build */ - uInt *v; /* work area for huft_build */ - - /* set up literal table */ - for (i = 0; i < 144; i++) - l[i] = 8; - for (; i < 256; i++) - l[i] = 9; - for (; i < 280; i++) - l[i] = 7; - for (; i < 288; i++) /* make a complete, but wrong code set */ - l[i] = 8; - *bl = 9; - v = WS(z)->tree_work_area_1; - if ((i = huft_build(l, 288, 257, cplens, cplext, tl, bl, hp, &i, v)) != 0) - return i; - - /* set up distance table */ - for (i = 0; i < 30; i++) /* make an incomplete code set */ - l[i] = 5; - *bd = 5; - if ((i = huft_build(l, 30, 0, cpdist, cpdext, td, bd, hp, &i, v)) > 1) - return i; - - return Z_OK; + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + } + + /* set return parameters */ + *table += used; + *bits = root; + return 0; } diff --git a/lib/zlib_inflate/inftrees.h b/lib/zlib_inflate/inftrees.h index e37705adc008..5f5219b1240e 100644 --- a/lib/zlib_inflate/inftrees.h +++ b/lib/zlib_inflate/inftrees.h @@ -1,6 +1,6 @@ /* inftrees.h -- header to use inftrees.c - * Copyright (C) 1995-1998 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is @@ -8,57 +8,48 @@ subject to change. Applications should only use zlib.h. */ -/* Huffman code lookup table entry--this entry is four bytes for machines - that have 16-bit pointers (e.g. PC's in the small or medium model). */ - -#ifndef _INFTREES_H -#define _INFTREES_H - -typedef struct inflate_huft_s inflate_huft; - -struct inflate_huft_s { - union { - struct { - Byte Exop; /* number of extra bits or operation */ - Byte Bits; /* number of bits in this code or subcode */ - } what; - uInt pad; /* pad structure to a power of 2 (4 bytes for */ - } word; /* 16-bit, 8 bytes for 32-bit int's) */ - uInt base; /* literal, length base, distance base, - or table offset */ -}; +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ +} code; + +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 0001eeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ /* Maximum size of dynamic tree. The maximum found in a long but non- - exhaustive search was 1004 huft structures (850 for length/literals - and 154 for distances, the latter actually the result of an - exhaustive search). The actual maximum is not known, but the - value below is more than safe. */ -#define MANY 1440 - -extern int zlib_inflate_trees_bits ( - uInt *, /* 19 code lengths */ - uInt *, /* bits tree desired/actual depth */ - inflate_huft **, /* bits tree result */ - inflate_huft *, /* space for trees */ - z_streamp); /* for messages */ - -extern int zlib_inflate_trees_dynamic ( - uInt, /* number of literal/length codes */ - uInt, /* number of distance codes */ - uInt *, /* that many (total) code lengths */ - uInt *, /* literal desired/actual bit depth */ - uInt *, /* distance desired/actual bit depth */ - inflate_huft **, /* literal/length tree result */ - inflate_huft **, /* distance tree result */ - inflate_huft *, /* space for trees */ - z_streamp); /* for messages */ - -extern int zlib_inflate_trees_fixed ( - uInt *, /* literal desired/actual bit depth */ - uInt *, /* distance desired/actual bit depth */ - inflate_huft **, /* literal/length tree result */ - inflate_huft **, /* distance tree result */ - inflate_huft *, /* space for trees */ - z_streamp); /* for memory allocation */ - -#endif /* _INFTREES_H */ + exhaustive search was 1444 code structures (852 for length/literals + and 592 for distances, the latter actually the result of an + exhaustive search). The true maximum is not known, but the value + below is more than safe. */ +#define ENOUGH 2048 +#define MAXD 592 + +/* Type of code to build for inftable() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +extern int zlib_inflate_table (codetype type, unsigned short *lens, + unsigned codes, code **table, + unsigned *bits, unsigned short *work); diff --git a/lib/zlib_inflate/infutil.c b/lib/zlib_inflate/infutil.c deleted file mode 100644 index 00202b3438e1..000000000000 --- a/lib/zlib_inflate/infutil.c +++ /dev/null @@ -1,88 +0,0 @@ -/* inflate_util.c -- data and routines common to blocks and codes - * Copyright (C) 1995-1998 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include -#include "infblock.h" -#include "inftrees.h" -#include "infcodes.h" -#include "infutil.h" - -struct inflate_codes_state; - -/* And'ing with mask[n] masks the lower n bits */ -uInt zlib_inflate_mask[17] = { - 0x0000, - 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, - 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff -}; - - -/* copy as much as possible from the sliding window to the output area */ -int zlib_inflate_flush( - inflate_blocks_statef *s, - z_streamp z, - int r -) -{ - uInt n; - Byte *p; - Byte *q; - - /* local copies of source and destination pointers */ - p = z->next_out; - q = s->read; - - /* compute number of bytes to copy as far as end of window */ - n = (uInt)((q <= s->write ? s->write : s->end) - q); - if (n > z->avail_out) n = z->avail_out; - if (n && r == Z_BUF_ERROR) r = Z_OK; - - /* update counters */ - z->avail_out -= n; - z->total_out += n; - - /* update check information */ - if (s->checkfn != NULL) - z->adler = s->check = (*s->checkfn)(s->check, q, n); - - /* copy as far as end of window */ - memcpy(p, q, n); - p += n; - q += n; - - /* see if more to copy at beginning of window */ - if (q == s->end) - { - /* wrap pointers */ - q = s->window; - if (s->write == s->end) - s->write = s->window; - - /* compute bytes to copy */ - n = (uInt)(s->write - q); - if (n > z->avail_out) n = z->avail_out; - if (n && r == Z_BUF_ERROR) r = Z_OK; - - /* update counters */ - z->avail_out -= n; - z->total_out += n; - - /* update check information */ - if (s->checkfn != NULL) - z->adler = s->check = (*s->checkfn)(s->check, q, n); - - /* copy */ - memcpy(p, q, n); - p += n; - q += n; - } - - /* update pointers */ - z->next_out = p; - s->read = q; - - /* done */ - return r; -} diff --git a/lib/zlib_inflate/infutil.h b/lib/zlib_inflate/infutil.h index a15875fc5f72..eb1a9007bd86 100644 --- a/lib/zlib_inflate/infutil.h +++ b/lib/zlib_inflate/infutil.h @@ -11,184 +11,12 @@ #ifndef _INFUTIL_H #define _INFUTIL_H -#include -#include "inftrees.h" -#include "infcodes.h" - -typedef enum { - TYPE, /* get type bits (3, including end bit) */ - LENS, /* get lengths for stored */ - STORED, /* processing stored block */ - TABLE, /* get table lengths */ - BTREE, /* get bit lengths tree for a dynamic block */ - DTREE, /* get length, distance trees for a dynamic block */ - CODES, /* processing fixed or dynamic block */ - DRY, /* output remaining window bytes */ - B_DONE, /* finished last block, done */ - B_BAD} /* got a data error--stuck here */ -inflate_block_mode; - -/* inflate blocks semi-private state */ -struct inflate_blocks_state { - - /* mode */ - inflate_block_mode mode; /* current inflate_block mode */ - - /* mode dependent information */ - union { - uInt left; /* if STORED, bytes left to copy */ - struct { - uInt table; /* table lengths (14 bits) */ - uInt index; /* index into blens (or border) */ - uInt *blens; /* bit lengths of codes */ - uInt bb; /* bit length tree depth */ - inflate_huft *tb; /* bit length decoding tree */ - } trees; /* if DTREE, decoding info for trees */ - struct { - inflate_codes_statef - *codes; - } decode; /* if CODES, current state */ - } sub; /* submode */ - uInt last; /* true if this block is the last block */ - - /* mode independent information */ - uInt bitk; /* bits in bit buffer */ - uLong bitb; /* bit buffer */ - inflate_huft *hufts; /* single malloc for tree space */ - Byte *window; /* sliding window */ - Byte *end; /* one byte after sliding window */ - Byte *read; /* window read pointer */ - Byte *write; /* window write pointer */ - check_func checkfn; /* check function */ - uLong check; /* check on output */ - -}; - - -/* defines for inflate input/output */ -/* update pointers and return */ -#define UPDBITS {s->bitb=b;s->bitk=k;} -#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;} -#define UPDOUT {s->write=q;} -#define UPDATE {UPDBITS UPDIN UPDOUT} -#define LEAVE {UPDATE return zlib_inflate_flush(s,z,r);} -/* get bytes and bits */ -#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;} -#define NEEDBYTE {if(n)r=Z_OK;else LEAVE} -#define NEXTBYTE (n--,*p++) -#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<>=(j);k-=(j);} -/* output bytes */ -#define WAVAIL (uInt)(qread?s->read-q-1:s->end-q) -#define LOADOUT {q=s->write;m=(uInt)WAVAIL;} -#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}} -#define FLUSH {UPDOUT r=zlib_inflate_flush(s,z,r); LOADOUT} -#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;} -#define OUTBYTE(a) {*q++=(Byte)(a);m--;} -/* load local pointers */ -#define LOAD {LOADIN LOADOUT} - -/* masks for lower bits (size given to avoid silly warnings with Visual C++) */ -extern uInt zlib_inflate_mask[17]; - -/* copy as much as possible from the sliding window to the output area */ -extern int zlib_inflate_flush ( - inflate_blocks_statef *, - z_streamp , - int); - -/* inflate private state */ -typedef enum { - METHOD, /* waiting for method byte */ - FLAG, /* waiting for flag byte */ - DICT4, /* four dictionary check bytes to go */ - DICT3, /* three dictionary check bytes to go */ - DICT2, /* two dictionary check bytes to go */ - DICT1, /* one dictionary check byte to go */ - DICT0, /* waiting for inflateSetDictionary */ - BLOCKS, /* decompressing blocks */ - CHECK4, /* four check bytes to go */ - CHECK3, /* three check bytes to go */ - CHECK2, /* two check bytes to go */ - CHECK1, /* one check byte to go */ - I_DONE, /* finished check, done */ - I_BAD} /* got an error--stay here */ -inflate_mode; - -struct internal_state { - - /* mode */ - inflate_mode mode; /* current inflate mode */ - - /* mode dependent information */ - union { - uInt method; /* if FLAGS, method byte */ - struct { - uLong was; /* computed check value */ - uLong need; /* stream check value */ - } check; /* if CHECK, check values to compare */ - uInt marker; /* if BAD, inflateSync's marker bytes count */ - } sub; /* submode */ - - /* mode independent information */ - int nowrap; /* flag for no wrapper */ - uInt wbits; /* log2(window size) (8..15, defaults to 15) */ - inflate_blocks_statef - *blocks; /* current inflate_blocks state */ - -}; - -/* inflate codes private state */ -typedef enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ - START, /* x: set up for LEN */ - LEN, /* i: get length/literal/eob next */ - LENEXT, /* i: getting length extra (have base) */ - DIST, /* i: get distance next */ - DISTEXT, /* i: getting distance extra */ - COPY, /* o: copying bytes in window, waiting for space */ - LIT, /* o: got literal, waiting for output space */ - WASH, /* o: got eob, possibly still output waiting */ - END, /* x: got eob and all data flushed */ - BADCODE} /* x: got error */ -inflate_codes_mode; - -struct inflate_codes_state { - - /* mode */ - inflate_codes_mode mode; /* current inflate_codes mode */ - - /* mode dependent information */ - uInt len; - union { - struct { - inflate_huft *tree; /* pointer into tree */ - uInt need; /* bits needed */ - } code; /* if LEN or DIST, where in tree */ - uInt lit; /* if LIT, literal */ - struct { - uInt get; /* bits to get for extra */ - uInt dist; /* distance back to copy from */ - } copy; /* if EXT or COPY, where and how much */ - } sub; /* submode */ - - /* mode independent information */ - Byte lbits; /* ltree bits decoded per branch */ - Byte dbits; /* dtree bits decoder per branch */ - inflate_huft *ltree; /* literal/length/eob tree */ - inflate_huft *dtree; /* distance tree */ - -}; +#include /* memory allocation for inflation */ struct inflate_workspace { - inflate_codes_statef working_state; - struct inflate_blocks_state working_blocks_state; - struct internal_state internal_state; - unsigned int tree_work_area_1[19]; - unsigned int tree_work_area_2[288]; - unsigned working_blens[258 + 0x1f + 0x1f]; - inflate_huft working_hufts[MANY]; + struct inflate_state inflate_state; unsigned char working_window[1 << MAX_WBITS]; }; -- cgit v1.2.3 From 92aa674d721d089c440301ab95cb6be19c78727e Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 22 Jun 2006 07:11:13 +0200 Subject: [PATCH] network driver for Hilscher netx This is a patch for the Hilscher netx builtin ethernet ports. The netx board support was merged into 2.6.17-git2. The netx is a arm926 based SoC. Signed-off-by: Robert Schwebel Signed-off-by: Sascha Hauer -- drivers/net/Kconfig | 11 drivers/net/Makefile | 1 drivers/net/netx-eth.c | 516 ++++++++++++++++++++++++++++++++++++++++ include/asm-arm/arch-netx/eth.h | 27 ++ 4 files changed, 555 insertions(+) Signed-off-by: Jeff Garzik --- drivers/net/Kconfig | 11 + drivers/net/Makefile | 1 + drivers/net/netx-eth.c | 516 ++++++++++++++++++++++++++++++++++++++++ include/asm-arm/arch-netx/eth.h | 27 +++ 4 files changed, 555 insertions(+) create mode 100644 drivers/net/netx-eth.c create mode 100644 include/asm-arm/arch-netx/eth.h (limited to 'include') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 67e812642c88..7fa24c51e40b 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -854,6 +854,17 @@ config SMC9194 . The module will be called smc9194. +config NET_NETX + tristate "NetX Ethernet support" + select MII + depends on NET_ETHERNET && ARCH_NETX + help + This is support for the Hilscher netX builtin Ethernet ports + + To compile this driver as a module, choose M here and read + . The module + will be called netx-eth. + config DM9000 tristate "DM9000 support" depends on (ARM || MIPS) && NET_ETHERNET diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 1eced3287507..c91e95126f78 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -187,6 +187,7 @@ obj-$(CONFIG_MACSONIC) += macsonic.o obj-$(CONFIG_MACMACE) += macmace.o obj-$(CONFIG_MAC89x0) += mac89x0.o obj-$(CONFIG_TUN) += tun.o +obj-$(CONFIG_NET_NETX) += netx-eth.o obj-$(CONFIG_DL2K) += dl2k.o obj-$(CONFIG_R8169) += r8169.o obj-$(CONFIG_AMD8111_ETH) += amd8111e.o diff --git a/drivers/net/netx-eth.c b/drivers/net/netx-eth.c new file mode 100644 index 000000000000..b92430c4e3ac --- /dev/null +++ b/drivers/net/netx-eth.c @@ -0,0 +1,516 @@ +/* + * drivers/net/netx-eth.c + * + * Copyright (c) 2005 Sascha Hauer , Pengutronix + * + * 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 published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* XC Fifo Offsets */ +#define EMPTY_PTR_FIFO(xcno) (0 + ((xcno) << 3)) /* Index of the empty pointer FIFO */ +#define IND_FIFO_PORT_HI(xcno) (1 + ((xcno) << 3)) /* Index of the FIFO where received */ + /* Data packages are indicated by XC */ +#define IND_FIFO_PORT_LO(xcno) (2 + ((xcno) << 3)) /* Index of the FIFO where received */ + /* Data packages are indicated by XC */ +#define REQ_FIFO_PORT_HI(xcno) (3 + ((xcno) << 3)) /* Index of the FIFO where Data packages */ + /* have to be indicated by ARM which */ + /* shall be sent */ +#define REQ_FIFO_PORT_LO(xcno) (4 + ((xcno) << 3)) /* Index of the FIFO where Data packages */ + /* have to be indicated by ARM which shall */ + /* be sent */ +#define CON_FIFO_PORT_HI(xcno) (5 + ((xcno) << 3)) /* Index of the FIFO where sent Data packages */ + /* are confirmed */ +#define CON_FIFO_PORT_LO(xcno) (6 + ((xcno) << 3)) /* Index of the FIFO where sent Data */ + /* packages are confirmed */ +#define PFIFO_MASK(xcno) (0x7f << (xcno*8)) + +#define FIFO_PTR_FRAMELEN_SHIFT 0 +#define FIFO_PTR_FRAMELEN_MASK (0x7ff << 0) +#define FIFO_PTR_FRAMELEN(len) (((len) << 0) & FIFO_PTR_FRAMELEN_MASK) +#define FIFO_PTR_TIMETRIG (1<<11) +#define FIFO_PTR_MULTI_REQ +#define FIFO_PTR_ORIGIN (1<<14) +#define FIFO_PTR_VLAN (1<<15) +#define FIFO_PTR_FRAMENO_SHIFT 16 +#define FIFO_PTR_FRAMENO_MASK (0x3f << 16) +#define FIFO_PTR_FRAMENO(no) (((no) << 16) & FIFO_PTR_FRAMENO_MASK) +#define FIFO_PTR_SEGMENT_SHIFT 22 +#define FIFO_PTR_SEGMENT_MASK (0xf << 22) +#define FIFO_PTR_SEGMENT(seg) (((seg) & 0xf) << 22) +#define FIFO_PTR_ERROR_SHIFT 28 +#define FIFO_PTR_ERROR_MASK (0xf << 28) + +#define ISR_LINK_STATUS_CHANGE (1<<4) +#define ISR_IND_LO (1<<3) +#define ISR_CON_LO (1<<2) +#define ISR_IND_HI (1<<1) +#define ISR_CON_HI (1<<0) + +#define ETH_MAC_LOCAL_CONFIG 0x1560 +#define ETH_MAC_4321 0x1564 +#define ETH_MAC_65 0x1568 + +#define MAC_TRAFFIC_CLASS_ARRANGEMENT_SHIFT 16 +#define MAC_TRAFFIC_CLASS_ARRANGEMENT_MASK (0xf<data; + unsigned int len = skb->len; + + spin_lock_irq(&priv->lock); + memcpy_toio(priv->sram_base + 1560, (void *)buf, len); + if (len < 60) { + memset_io(priv->sram_base + 1560 + len, 0, 60 - len); + len = 60; + } + + pfifo_push(REQ_FIFO_PORT_LO(priv->id), + FIFO_PTR_SEGMENT(priv->id) | + FIFO_PTR_FRAMENO(1) | + FIFO_PTR_FRAMELEN(len)); + + ndev->trans_start = jiffies; + priv->stats.tx_packets++; + priv->stats.tx_bytes += skb->len; + + netif_stop_queue(ndev); + spin_unlock_irq(&priv->lock); + dev_kfree_skb(skb); + + return 0; +} + +static void netx_eth_receive(struct net_device *ndev) +{ + struct netx_eth_priv *priv = netdev_priv(ndev); + unsigned int val, frameno, seg, len; + unsigned char *data; + struct sk_buff *skb; + + val = pfifo_pop(IND_FIFO_PORT_LO(priv->id)); + + frameno = (val & FIFO_PTR_FRAMENO_MASK) >> FIFO_PTR_FRAMENO_SHIFT; + seg = (val & FIFO_PTR_SEGMENT_MASK) >> FIFO_PTR_SEGMENT_SHIFT; + len = (val & FIFO_PTR_FRAMELEN_MASK) >> FIFO_PTR_FRAMELEN_SHIFT; + + skb = dev_alloc_skb(len); + if (unlikely(skb == NULL)) { + printk(KERN_NOTICE "%s: Low memory, packet dropped.\n", + ndev->name); + priv->stats.rx_dropped++; + return; + } + + data = skb_put(skb, len); + + memcpy_fromio(data, priv->sram_base + frameno * 1560, len); + + pfifo_push(EMPTY_PTR_FIFO(priv->id), + FIFO_PTR_SEGMENT(seg) | FIFO_PTR_FRAMENO(frameno)); + + ndev->last_rx = jiffies; + skb->dev = ndev; + skb->protocol = eth_type_trans(skb, ndev); + netif_rx(skb); + priv->stats.rx_packets++; + priv->stats.rx_bytes += len; +} + +static irqreturn_t +netx_eth_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *ndev = dev_id; + struct netx_eth_priv *priv = netdev_priv(ndev); + int status; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + + status = readl(NETX_PFIFO_XPEC_ISR(priv->id)); + while (status) { + int fill_level; + writel(status, NETX_PFIFO_XPEC_ISR(priv->id)); + + if ((status & ISR_CON_HI) || (status & ISR_IND_HI)) + printk("%s: unexpected status: 0x%08x\n", + __FUNCTION__, status); + + fill_level = + readl(NETX_PFIFO_FILL_LEVEL(IND_FIFO_PORT_LO(priv->id))); + while (fill_level--) + netx_eth_receive(ndev); + + if (status & ISR_CON_LO) + netif_wake_queue(ndev); + + if (status & ISR_LINK_STATUS_CHANGE) + mii_check_media(&priv->mii, netif_msg_link(priv), 1); + + status = readl(NETX_PFIFO_XPEC_ISR(priv->id)); + } + spin_unlock_irqrestore(&priv->lock, flags); + return IRQ_HANDLED; +} + +static struct net_device_stats *netx_eth_query_statistics(struct net_device *ndev) +{ + struct netx_eth_priv *priv = netdev_priv(ndev); + return &priv->stats; +} + +static int netx_eth_open(struct net_device *ndev) +{ + struct netx_eth_priv *priv = netdev_priv(ndev); + + if (request_irq + (ndev->irq, &netx_eth_interrupt, SA_SHIRQ, ndev->name, ndev)) + return -EAGAIN; + + writel(ndev->dev_addr[0] | + ndev->dev_addr[1]<<8 | + ndev->dev_addr[2]<<16 | + ndev->dev_addr[3]<<24, + priv->xpec_base + NETX_XPEC_RAM_START_OFS + ETH_MAC_4321); + writel(ndev->dev_addr[4] | + ndev->dev_addr[5]<<8, + priv->xpec_base + NETX_XPEC_RAM_START_OFS + ETH_MAC_65); + + writel(LOCAL_CONFIG_LINK_STATUS_IRQ_EN | + LOCAL_CONFIG_CON_LO_IRQ_EN | + LOCAL_CONFIG_CON_HI_IRQ_EN | + LOCAL_CONFIG_IND_LO_IRQ_EN | + LOCAL_CONFIG_IND_HI_IRQ_EN, + priv->xpec_base + NETX_XPEC_RAM_START_OFS + + ETH_MAC_LOCAL_CONFIG); + + mii_check_media(&priv->mii, netif_msg_link(priv), 1); + netif_start_queue(ndev); + + return 0; +} + +static int netx_eth_close(struct net_device *ndev) +{ + struct netx_eth_priv *priv = netdev_priv(ndev); + + netif_stop_queue(ndev); + + writel(0, + priv->xpec_base + NETX_XPEC_RAM_START_OFS + ETH_MAC_LOCAL_CONFIG); + + free_irq(ndev->irq, ndev); + + return 0; +} + +static void netx_eth_timeout(struct net_device *ndev) +{ + struct netx_eth_priv *priv = netdev_priv(ndev); + int i; + + printk(KERN_ERR "%s: transmit timed out, resetting\n", ndev->name); + + spin_lock_irq(&priv->lock); + + xc_reset(priv->xc); + xc_start(priv->xc); + + for (i=2; i<=18; i++) + pfifo_push(EMPTY_PTR_FIFO(priv->id), + FIFO_PTR_FRAMENO(i) | FIFO_PTR_SEGMENT(priv->id)); + + spin_unlock_irq(&priv->lock); + + netif_wake_queue(ndev); +} + +static int +netx_eth_phy_read(struct net_device *ndev, int phy_id, int reg) +{ + unsigned int val; + + val = MIIMU_SNRDY | MIIMU_PREAMBLE | MIIMU_PHYADDR(phy_id) | + MIIMU_REGADDR(reg) | MIIMU_PHY_NRES; + + writel(val, NETX_MIIMU); + while (readl(NETX_MIIMU) & MIIMU_SNRDY); + + return readl(NETX_MIIMU) >> 16; + +} + +static void +netx_eth_phy_write(struct net_device *ndev, int phy_id, int reg, int value) +{ + unsigned int val; + + val = MIIMU_SNRDY | MIIMU_PREAMBLE | MIIMU_PHYADDR(phy_id) | + MIIMU_REGADDR(reg) | MIIMU_PHY_NRES | MIIMU_OPMODE_WRITE | + MIIMU_DATA(value); + + writel(val, NETX_MIIMU); + while (readl(NETX_MIIMU) & MIIMU_SNRDY); +} + +static int netx_eth_enable(struct net_device *ndev) +{ + struct netx_eth_priv *priv = netdev_priv(ndev); + unsigned int mac4321, mac65; + int running, i; + + ether_setup(ndev); + + ndev->open = netx_eth_open; + ndev->stop = netx_eth_close; + ndev->hard_start_xmit = netx_eth_hard_start_xmit; + ndev->tx_timeout = netx_eth_timeout; + ndev->watchdog_timeo = msecs_to_jiffies(5000); + ndev->get_stats = netx_eth_query_statistics; + ndev->set_multicast_list = netx_eth_set_multicast_list; + + priv->msg_enable = NETIF_MSG_LINK; + priv->mii.phy_id_mask = 0x1f; + priv->mii.reg_num_mask = 0x1f; + priv->mii.force_media = 0; + priv->mii.full_duplex = 0; + priv->mii.dev = ndev; + priv->mii.mdio_read = netx_eth_phy_read; + priv->mii.mdio_write = netx_eth_phy_write; + priv->mii.phy_id = INTERNAL_PHY_ADR + priv->id; + + running = xc_running(priv->xc); + xc_stop(priv->xc); + + /* if the xc engine is already running, assume the bootloader has + * loaded the firmware for us + */ + if (running) { + /* get Node Address from hardware */ + mac4321 = readl(priv->xpec_base + + NETX_XPEC_RAM_START_OFS + ETH_MAC_4321); + mac65 = readl(priv->xpec_base + + NETX_XPEC_RAM_START_OFS + ETH_MAC_65); + + ndev->dev_addr[0] = mac4321 & 0xff; + ndev->dev_addr[1] = (mac4321 >> 8) & 0xff; + ndev->dev_addr[2] = (mac4321 >> 16) & 0xff; + ndev->dev_addr[3] = (mac4321 >> 24) & 0xff; + ndev->dev_addr[4] = mac65 & 0xff; + ndev->dev_addr[5] = (mac65 >> 8) & 0xff; + } else { + if (xc_request_firmware(priv->xc)) { + printk(CARDNAME ": requesting firmware failed\n"); + return -ENODEV; + } + } + + xc_reset(priv->xc); + xc_start(priv->xc); + + if (!is_valid_ether_addr(ndev->dev_addr)) + printk("%s: Invalid ethernet MAC address. Please " + "set using ifconfig\n", ndev->name); + + for (i=2; i<=18; i++) + pfifo_push(EMPTY_PTR_FIFO(priv->id), + FIFO_PTR_FRAMENO(i) | FIFO_PTR_SEGMENT(priv->id)); + + return register_netdev(ndev); + +} + +static int netx_eth_drv_probe(struct platform_device *pdev) +{ + struct netx_eth_priv *priv; + struct net_device *ndev; + struct netxeth_platform_data *pdata; + int ret; + + ndev = alloc_etherdev(sizeof (struct netx_eth_priv)); + if (!ndev) { + printk("%s: could not allocate device.\n", CARDNAME); + ret = -ENOMEM; + goto exit; + } + SET_MODULE_OWNER(ndev); + SET_NETDEV_DEV(ndev, &pdev->dev); + + platform_set_drvdata(pdev, ndev); + + priv = netdev_priv(ndev); + + pdata = (struct netxeth_platform_data *)pdev->dev.platform_data; + priv->xc = request_xc(pdata->xcno, &pdev->dev); + if (!priv->xc) { + dev_err(&pdev->dev, "unable to request xc engine\n"); + ret = -ENODEV; + goto exit_free_netdev; + } + + ndev->irq = priv->xc->irq; + priv->id = pdev->id; + priv->xpec_base = priv->xc->xpec_base; + priv->xmac_base = priv->xc->xmac_base; + priv->sram_base = priv->xc->sram_base; + + ret = pfifo_request(PFIFO_MASK(priv->id)); + if (ret) { + printk("unable to request PFIFO\n"); + goto exit_free_xc; + } + + ret = netx_eth_enable(ndev); + if (ret) + goto exit_free_pfifo; + + return 0; +exit_free_pfifo: + pfifo_free(PFIFO_MASK(priv->id)); +exit_free_xc: + free_xc(priv->xc); +exit_free_netdev: + platform_set_drvdata(pdev, NULL); + free_netdev(ndev); +exit: + return ret; +} + +static int netx_eth_drv_remove(struct platform_device *pdev) +{ + struct net_device *ndev = dev_get_drvdata(&pdev->dev); + struct netx_eth_priv *priv = netdev_priv(ndev); + + platform_set_drvdata(pdev, NULL); + + unregister_netdev(ndev); + xc_stop(priv->xc); + free_xc(priv->xc); + free_netdev(ndev); + pfifo_free(PFIFO_MASK(priv->id)); + + return 0; +} + +static int netx_eth_drv_suspend(struct platform_device *pdev, pm_message_t state) +{ + dev_err(&pdev->dev, "suspend not implemented\n"); + return 0; +} + +static int netx_eth_drv_resume(struct platform_device *pdev) +{ + dev_err(&pdev->dev, "resume not implemented\n"); + return 0; +} + +static struct platform_driver netx_eth_driver = { + .probe = netx_eth_drv_probe, + .remove = netx_eth_drv_remove, + .suspend = netx_eth_drv_suspend, + .resume = netx_eth_drv_resume, + .driver = { + .name = CARDNAME, + .owner = THIS_MODULE, + }, +}; + +static int __init netx_eth_init(void) +{ + unsigned int phy_control, val; + + printk("NetX Ethernet driver\n"); + + phy_control = PHY_CONTROL_PHY_ADDRESS(INTERNAL_PHY_ADR>>1) | + PHY_CONTROL_PHY1_MODE(PHY_MODE_ALL) | + PHY_CONTROL_PHY1_AUTOMDIX | + PHY_CONTROL_PHY1_EN | + PHY_CONTROL_PHY0_MODE(PHY_MODE_ALL) | + PHY_CONTROL_PHY0_AUTOMDIX | + PHY_CONTROL_PHY0_EN | + PHY_CONTROL_CLK_XLATIN; + + val = readl(NETX_SYSTEM_IOC_ACCESS_KEY); + writel(val, NETX_SYSTEM_IOC_ACCESS_KEY); + + writel(phy_control | PHY_CONTROL_RESET, NETX_SYSTEM_PHY_CONTROL); + udelay(100); + + val = readl(NETX_SYSTEM_IOC_ACCESS_KEY); + writel(val, NETX_SYSTEM_IOC_ACCESS_KEY); + + writel(phy_control, NETX_SYSTEM_PHY_CONTROL); + + return platform_driver_register(&netx_eth_driver); +} + +static void __exit netx_eth_cleanup(void) +{ + platform_driver_unregister(&netx_eth_driver); +} + +module_init(netx_eth_init); +module_exit(netx_eth_cleanup); + +MODULE_AUTHOR("Sascha Hauer, Pengutronix"); +MODULE_LICENSE("GPL"); + diff --git a/include/asm-arm/arch-netx/eth.h b/include/asm-arm/arch-netx/eth.h new file mode 100644 index 000000000000..643c90ef8b72 --- /dev/null +++ b/include/asm-arm/arch-netx/eth.h @@ -0,0 +1,27 @@ +/* + * include/asm-arm/arch-netx/eth.h + * + * Copyright (c) 2005 Sascha Hauer , Pengutronix + * + * 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 published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef ASMARM_ARCH_ETH_H +#define ASMARM_ARCH_ETH_H + +struct netxeth_platform_data { + unsigned int xcno; /* number of xmac/xpec engine this eth uses */ +}; + +#endif -- cgit v1.2.3 From 4a31e348e3ecaf54c50240109ac4574b180f8840 Mon Sep 17 00:00:00 2001 From: Krzysztof Halasa Date: Thu, 22 Jun 2006 22:20:19 +0200 Subject: [PATCH] WAN: register_hdlc_device() doesn't need dev_alloc_name() David Boggs noticed that register_hdlc_device() no longer needs to call dev_alloc_name() as it's called by register_netdev(). register_hdlc_device() is currently equivalent to register_netdev(). hdlc_setup() is now EXPORTed as per David's request. Signed-off-by: Krzysztof Halasa Signed-off-by: Jeff Garzik --- drivers/net/wan/hdlc_generic.c | 24 ++---------------------- include/linux/hdlc.h | 2 +- 2 files changed, 3 insertions(+), 23 deletions(-) (limited to 'include') diff --git a/drivers/net/wan/hdlc_generic.c b/drivers/net/wan/hdlc_generic.c index 46cef8f92133..57f9538b8fb5 100644 --- a/drivers/net/wan/hdlc_generic.c +++ b/drivers/net/wan/hdlc_generic.c @@ -259,7 +259,7 @@ int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) } } -static void hdlc_setup(struct net_device *dev) +void hdlc_setup(struct net_device *dev) { hdlc_device *hdlc = dev_to_hdlc(dev); @@ -288,26 +288,6 @@ struct net_device *alloc_hdlcdev(void *priv) return dev; } -int register_hdlc_device(struct net_device *dev) -{ - int result = dev_alloc_name(dev, "hdlc%d"); - if (result < 0) - return result; - - result = register_netdev(dev); - if (result != 0) - return -EIO; - -#if 0 - if (netif_carrier_ok(dev)) - netif_carrier_off(dev); /* no carrier until DCD goes up */ -#endif - - return 0; -} - - - void unregister_hdlc_device(struct net_device *dev) { rtnl_lock(); @@ -326,8 +306,8 @@ EXPORT_SYMBOL(hdlc_open); EXPORT_SYMBOL(hdlc_close); EXPORT_SYMBOL(hdlc_set_carrier); EXPORT_SYMBOL(hdlc_ioctl); +EXPORT_SYMBOL(hdlc_setup); EXPORT_SYMBOL(alloc_hdlcdev); -EXPORT_SYMBOL(register_hdlc_device); EXPORT_SYMBOL(unregister_hdlc_device); static struct packet_type hdlc_packet_type = { diff --git a/include/linux/hdlc.h b/include/linux/hdlc.h index df695e9ae327..4513f9e40937 100644 --- a/include/linux/hdlc.h +++ b/include/linux/hdlc.h @@ -188,7 +188,7 @@ int hdlc_x25_ioctl(struct net_device *dev, struct ifreq *ifr); int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); /* Must be used by hardware driver on module startup/exit */ -int register_hdlc_device(struct net_device *dev); +#define register_hdlc_device(dev) register_netdev(dev) void unregister_hdlc_device(struct net_device *dev); struct net_device *alloc_hdlcdev(void *priv); -- cgit v1.2.3 From 47005f255ed126a4b48a1a2f63164fb1d83bcb0a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 19 Jun 2006 18:27:23 +0900 Subject: [PATCH] libata: implement per-dev EH action mask eh_info->dev_action[] Currently, the only per-dev EH action is REVALIDATE. EH used to exploit ehi->dev to do selective revalidation on a ATA bus. However, this is a bit hacky and makes it impossible to request selective revalidation from outside of EH or add another per-dev EH action. This patch adds per-dev EH action mask eh_info->dev_action[] and update EH to use this field for REVALIDATE. Note that per-dev actions can still be specified at port-level and it has the same effect of specifying the action for all devices on the port. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/scsi/libata-eh.c | 85 +++++++++++++++++++++++++++++++++++++++--------- include/linux/libata.h | 2 ++ 2 files changed, 71 insertions(+), 16 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index 531a4e11c078..70b623988a9f 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c @@ -706,9 +706,35 @@ static void ata_eh_detach_dev(struct ata_device *dev) spin_unlock_irqrestore(&ap->host_set->lock, flags); } +static void ata_eh_clear_action(struct ata_device *dev, + struct ata_eh_info *ehi, unsigned int action) +{ + int i; + + if (!dev) { + ehi->action &= ~action; + for (i = 0; i < ATA_MAX_DEVICES; i++) + ehi->dev_action[i] &= ~action; + } else { + /* doesn't make sense for port-wide EH actions */ + WARN_ON(!(action & ATA_EH_PERDEV_MASK)); + + /* break ehi->action into ehi->dev_action */ + if (ehi->action & action) { + for (i = 0; i < ATA_MAX_DEVICES; i++) + ehi->dev_action[i] |= ehi->action & action; + ehi->action &= ~action; + } + + /* turn off the specified per-dev action */ + ehi->dev_action[dev->devno] &= ~action; + } +} + /** * ata_eh_about_to_do - about to perform eh_action * @ap: target ATA port + * @dev: target ATA dev for per-dev action (can be NULL) * @action: action about to be performed * * Called just before performing EH actions to clear related bits @@ -718,16 +744,35 @@ static void ata_eh_detach_dev(struct ata_device *dev) * LOCKING: * None. */ -static void ata_eh_about_to_do(struct ata_port *ap, unsigned int action) +static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev, + unsigned int action) { unsigned long flags; spin_lock_irqsave(&ap->host_set->lock, flags); - ap->eh_info.action &= ~action; + ata_eh_clear_action(dev, &ap->eh_info, action); ap->flags |= ATA_FLAG_RECOVERED; spin_unlock_irqrestore(&ap->host_set->lock, flags); } +/** + * ata_eh_done - EH action complete + * @ap: target ATA port + * @dev: target ATA dev for per-dev action (can be NULL) + * @action: action just completed + * + * Called right after performing EH actions to clear related bits + * in @ap->eh_context. + * + * LOCKING: + * None. + */ +static void ata_eh_done(struct ata_port *ap, struct ata_device *dev, + unsigned int action) +{ + ata_eh_clear_action(dev, &ap->eh_context.i, action); +} + /** * ata_err_string - convert err_mask to descriptive string * @err_mask: error mask to convert to string @@ -1271,10 +1316,6 @@ static void ata_eh_autopsy(struct ata_port *ap) is_io = 1; } - /* speed down iff command was in progress */ - if (failed_dev) - action |= ata_eh_speed_down(failed_dev, is_io, all_err_mask); - /* enforce default EH actions */ if (ap->flags & ATA_FLAG_FROZEN || all_err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT)) @@ -1282,6 +1323,17 @@ static void ata_eh_autopsy(struct ata_port *ap) else if (all_err_mask) action |= ATA_EH_REVALIDATE; + /* if we have offending qcs and the associated failed device */ + if (failed_dev) { + /* speed down */ + action |= ata_eh_speed_down(failed_dev, is_io, all_err_mask); + + /* perform per-dev EH action only on the offending device */ + ehc->i.dev_action[failed_dev->devno] |= + action & ATA_EH_PERDEV_MASK; + action &= ~ATA_EH_PERDEV_MASK; + } + /* record autopsy result */ ehc->i.dev = failed_dev; ehc->i.action = action; @@ -1457,7 +1509,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, reset == softreset ? "soft" : "hard"); /* reset */ - ata_eh_about_to_do(ap, ATA_EH_RESET_MASK); + ata_eh_about_to_do(ap, NULL, ATA_EH_RESET_MASK); ehc->i.flags |= ATA_EHI_DID_RESET; rc = ata_do_reset(ap, reset, classes); @@ -1476,7 +1528,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, return -EINVAL; } - ata_eh_about_to_do(ap, ATA_EH_RESET_MASK); + ata_eh_about_to_do(ap, NULL, ATA_EH_RESET_MASK); rc = ata_do_reset(ap, reset, classes); if (rc == 0 && classify && @@ -1520,8 +1572,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, postreset(ap, classes); /* reset successful, schedule revalidation */ - ehc->i.dev = NULL; - ehc->i.action &= ~ATA_EH_RESET_MASK; + ata_eh_done(ap, NULL, ATA_EH_RESET_MASK); ehc->i.action |= ATA_EH_REVALIDATE; } @@ -1539,21 +1590,25 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, DPRINTK("ENTER\n"); for (i = 0; i < ATA_MAX_DEVICES; i++) { + unsigned int action; + dev = &ap->device[i]; + action = ehc->i.action | ehc->i.dev_action[dev->devno]; - if (ehc->i.action & ATA_EH_REVALIDATE && ata_dev_enabled(dev) && - (!ehc->i.dev || ehc->i.dev == dev)) { + if (action & ATA_EH_REVALIDATE && ata_dev_enabled(dev)) { if (ata_port_offline(ap)) { rc = -EIO; break; } - ata_eh_about_to_do(ap, ATA_EH_REVALIDATE); + ata_eh_about_to_do(ap, dev, ATA_EH_REVALIDATE); rc = ata_dev_revalidate(dev, ehc->i.flags & ATA_EHI_DID_RESET); if (rc) break; + ata_eh_done(ap, dev, ATA_EH_REVALIDATE); + /* schedule the scsi_rescan_device() here */ queue_work(ata_aux_wq, &(ap->scsi_rescan_task)); } else if (dev->class == ATA_DEV_UNKNOWN && @@ -1576,9 +1631,7 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, } } - if (rc == 0) - ehc->i.action &= ~ATA_EH_REVALIDATE; - else + if (rc) *r_failed_dev = dev; DPRINTK("EXIT\n"); diff --git a/include/linux/libata.h b/include/linux/libata.h index f03b8664af11..6b3c3af2c75f 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -249,6 +249,7 @@ enum { ATA_EH_HARDRESET = (1 << 2), ATA_EH_RESET_MASK = ATA_EH_SOFTRESET | ATA_EH_HARDRESET, + ATA_EH_PERDEV_MASK = ATA_EH_REVALIDATE, /* ata_eh_info->flags */ ATA_EHI_HOTPLUGGED = (1 << 0), /* could have been hotplugged */ @@ -462,6 +463,7 @@ struct ata_eh_info { u32 serror; /* SError from LLDD */ unsigned int err_mask; /* port-wide err_mask */ unsigned int action; /* ATA_EH_* action mask */ + unsigned int dev_action[ATA_MAX_DEVICES]; /* dev EH action */ unsigned int flags; /* ATA_EHI_* flags */ unsigned long hotplug_timestamp; -- cgit v1.2.3 From ba6a13083c1b720a47c05bee7bedbb6ef06c4611 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 22 Jun 2006 23:46:10 -0400 Subject: [libata] Add host lock to struct ata_port Prepare for changes required to support SATA devices attached to SAS HBAs. For these devices we don't want to use host_set at all, since libata will not be the owner of struct scsi_host. Signed-off-by: Brian King (with slight merge modifications made by...) Signed-off-by: Jeff Garzik --- drivers/scsi/libata-bmdma.c | 5 ++-- drivers/scsi/libata-core.c | 55 +++++++++++++++++++------------------- drivers/scsi/libata-eh.c | 65 ++++++++++++++++++++++----------------------- drivers/scsi/libata-scsi.c | 20 +++++++------- include/linux/libata.h | 1 + 5 files changed, 73 insertions(+), 73 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libata-bmdma.c b/drivers/scsi/libata-bmdma.c index 13fab97c840e..004e1a0d8b71 100644 --- a/drivers/scsi/libata-bmdma.c +++ b/drivers/scsi/libata-bmdma.c @@ -715,7 +715,6 @@ void ata_bmdma_drive_eh(struct ata_port *ap, ata_prereset_fn_t prereset, ata_reset_fn_t softreset, ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) { - struct ata_host_set *host_set = ap->host_set; struct ata_eh_context *ehc = &ap->eh_context; struct ata_queued_cmd *qc; unsigned long flags; @@ -726,7 +725,7 @@ void ata_bmdma_drive_eh(struct ata_port *ap, ata_prereset_fn_t prereset, qc = NULL; /* reset PIO HSM and stop DMA engine */ - spin_lock_irqsave(&host_set->lock, flags); + spin_lock_irqsave(ap->lock, flags); ap->hsm_task_state = HSM_ST_IDLE; @@ -755,7 +754,7 @@ void ata_bmdma_drive_eh(struct ata_port *ap, ata_prereset_fn_t prereset, ata_chk_status(ap); ap->ops->irq_clear(ap); - spin_unlock_irqrestore(&host_set->lock, flags); + spin_unlock_irqrestore(ap->lock, flags); if (thaw) ata_eh_thaw_port(ap); diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 425ab1493fd3..24d340aeb518 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -933,9 +933,9 @@ void ata_port_flush_task(struct ata_port *ap) DPRINTK("ENTER\n"); - spin_lock_irqsave(&ap->host_set->lock, flags); + spin_lock_irqsave(ap->lock, flags); ap->flags |= ATA_FLAG_FLUSH_PORT_TASK; - spin_unlock_irqrestore(&ap->host_set->lock, flags); + spin_unlock_irqrestore(ap->lock, flags); DPRINTK("flush #1\n"); flush_workqueue(ata_wq); @@ -950,9 +950,9 @@ void ata_port_flush_task(struct ata_port *ap) flush_workqueue(ata_wq); } - spin_lock_irqsave(&ap->host_set->lock, flags); + spin_lock_irqsave(ap->lock, flags); ap->flags &= ~ATA_FLAG_FLUSH_PORT_TASK; - spin_unlock_irqrestore(&ap->host_set->lock, flags); + spin_unlock_irqrestore(ap->lock, flags); DPRINTK("EXIT\n"); } @@ -999,11 +999,11 @@ unsigned ata_exec_internal(struct ata_device *dev, unsigned int err_mask; int rc; - spin_lock_irqsave(&ap->host_set->lock, flags); + spin_lock_irqsave(ap->lock, flags); /* no internal command while frozen */ if (ap->flags & ATA_FLAG_FROZEN) { - spin_unlock_irqrestore(&ap->host_set->lock, flags); + spin_unlock_irqrestore(ap->lock, flags); return AC_ERR_SYSTEM; } @@ -1052,14 +1052,14 @@ unsigned ata_exec_internal(struct ata_device *dev, ata_qc_issue(qc); - spin_unlock_irqrestore(&ap->host_set->lock, flags); + spin_unlock_irqrestore(ap->lock, flags); rc = wait_for_completion_timeout(&wait, ATA_TMOUT_INTERNAL); ata_port_flush_task(ap); if (!rc) { - spin_lock_irqsave(&ap->host_set->lock, flags); + spin_lock_irqsave(ap->lock, flags); /* We're racing with irq here. If we lose, the * following test prevents us from completing the qc @@ -1078,7 +1078,7 @@ unsigned ata_exec_internal(struct ata_device *dev, "qc timeout (cmd 0x%x)\n", command); } - spin_unlock_irqrestore(&ap->host_set->lock, flags); + spin_unlock_irqrestore(ap->lock, flags); } /* do post_internal_cmd */ @@ -1092,7 +1092,7 @@ unsigned ata_exec_internal(struct ata_device *dev, } /* finish up */ - spin_lock_irqsave(&ap->host_set->lock, flags); + spin_lock_irqsave(ap->lock, flags); *tf = qc->result_tf; err_mask = qc->err_mask; @@ -1118,7 +1118,7 @@ unsigned ata_exec_internal(struct ata_device *dev, ata_port_probe(ap); } - spin_unlock_irqrestore(&ap->host_set->lock, flags); + spin_unlock_irqrestore(ap->lock, flags); return err_mask; } @@ -3912,7 +3912,7 @@ static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq) if (ap->ops->error_handler) { if (in_wq) { - spin_lock_irqsave(&ap->host_set->lock, flags); + spin_lock_irqsave(ap->lock, flags); /* EH might have kicked in while host_set lock * is released. @@ -3926,7 +3926,7 @@ static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq) ata_port_freeze(ap); } - spin_unlock_irqrestore(&ap->host_set->lock, flags); + spin_unlock_irqrestore(ap->lock, flags); } else { if (likely(!(qc->err_mask & AC_ERR_HSM))) ata_qc_complete(qc); @@ -3935,10 +3935,10 @@ static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq) } } else { if (in_wq) { - spin_lock_irqsave(&ap->host_set->lock, flags); + spin_lock_irqsave(ap->lock, flags); ata_irq_on(ap); ata_qc_complete(qc); - spin_unlock_irqrestore(&ap->host_set->lock, flags); + spin_unlock_irqrestore(ap->lock, flags); } else ata_qc_complete(qc); } @@ -4018,7 +4018,7 @@ fsm_start: * hsm_task_state is changed. Hence, the following locking. */ if (in_wq) - spin_lock_irqsave(&ap->host_set->lock, flags); + spin_lock_irqsave(ap->lock, flags); if (qc->tf.protocol == ATA_PROT_PIO) { /* PIO data out protocol. @@ -4037,7 +4037,7 @@ fsm_start: atapi_send_cdb(ap, qc); if (in_wq) - spin_unlock_irqrestore(&ap->host_set->lock, flags); + spin_unlock_irqrestore(ap->lock, flags); /* if polling, ata_pio_task() handles the rest. * otherwise, interrupt handler takes over from here. @@ -5130,9 +5130,9 @@ void ata_dev_init(struct ata_device *dev) * requests which occur asynchronously. Synchronize using * host_set lock. */ - spin_lock_irqsave(&ap->host_set->lock, flags); + spin_lock_irqsave(ap->lock, flags); dev->flags &= ~ATA_DFLAG_INIT_MASK; - spin_unlock_irqrestore(&ap->host_set->lock, flags); + spin_unlock_irqrestore(ap->lock, flags); memset((void *)dev + ATA_DEVICE_CLEAR_OFFSET, 0, sizeof(*dev) - ATA_DEVICE_CLEAR_OFFSET); @@ -5167,6 +5167,7 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host, host->unique_id = ata_unique_id++; host->max_cmd_len = 12; + ap->lock = &host_set->lock; ap->flags = ATA_FLAG_DISABLED; ap->id = host->unique_id; ap->host = host; @@ -5388,7 +5389,7 @@ int ata_device_add(const struct ata_probe_ent *ent) ata_port_probe(ap); /* kick EH for boot probing */ - spin_lock_irqsave(&ap->host_set->lock, flags); + spin_lock_irqsave(ap->lock, flags); ap->eh_info.probe_mask = (1 << ATA_MAX_DEVICES) - 1; ap->eh_info.action |= ATA_EH_SOFTRESET; @@ -5396,7 +5397,7 @@ int ata_device_add(const struct ata_probe_ent *ent) ap->flags |= ATA_FLAG_LOADING; ata_port_schedule_eh(ap); - spin_unlock_irqrestore(&ap->host_set->lock, flags); + spin_unlock_irqrestore(ap->lock, flags); /* wait for EH to finish */ ata_port_wait_eh(ap); @@ -5460,29 +5461,29 @@ void ata_port_detach(struct ata_port *ap) return; /* tell EH we're leaving & flush EH */ - spin_lock_irqsave(&ap->host_set->lock, flags); + spin_lock_irqsave(ap->lock, flags); ap->flags |= ATA_FLAG_UNLOADING; - spin_unlock_irqrestore(&ap->host_set->lock, flags); + spin_unlock_irqrestore(ap->lock, flags); ata_port_wait_eh(ap); /* EH is now guaranteed to see UNLOADING, so no new device * will be attached. Disable all existing devices. */ - spin_lock_irqsave(&ap->host_set->lock, flags); + spin_lock_irqsave(ap->lock, flags); for (i = 0; i < ATA_MAX_DEVICES; i++) ata_dev_disable(&ap->device[i]); - spin_unlock_irqrestore(&ap->host_set->lock, flags); + spin_unlock_irqrestore(ap->lock, flags); /* Final freeze & EH. All in-flight commands are aborted. EH * will be skipped and retrials will be terminated with bad * target. */ - spin_lock_irqsave(&ap->host_set->lock, flags); + spin_lock_irqsave(ap->lock, flags); ata_port_freeze(ap); /* won't be thawed */ - spin_unlock_irqrestore(&ap->host_set->lock, flags); + spin_unlock_irqrestore(ap->lock, flags); ata_port_wait_eh(ap); diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index 70b623988a9f..823385981a7a 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c @@ -128,7 +128,7 @@ enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd) } ret = EH_HANDLED; - spin_lock_irqsave(&ap->host_set->lock, flags); + spin_lock_irqsave(ap->lock, flags); qc = ata_qc_from_tag(ap, ap->active_tag); if (qc) { WARN_ON(qc->scsicmd != cmd); @@ -136,7 +136,7 @@ enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd) qc->err_mask |= AC_ERR_TIMEOUT; ret = EH_NOT_HANDLED; } - spin_unlock_irqrestore(&ap->host_set->lock, flags); + spin_unlock_irqrestore(ap->lock, flags); out: DPRINTK("EXIT, ret=%d\n", ret); @@ -158,7 +158,7 @@ enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd) void ata_scsi_error(struct Scsi_Host *host) { struct ata_port *ap = ata_shost_to_port(host); - spinlock_t *hs_lock = &ap->host_set->lock; + spinlock_t *ap_lock = ap->lock; int i, repeat_cnt = ATA_EH_MAX_REPEAT; unsigned long flags; @@ -185,7 +185,7 @@ void ata_scsi_error(struct Scsi_Host *host) struct scsi_cmnd *scmd, *tmp; int nr_timedout = 0; - spin_lock_irqsave(hs_lock, flags); + spin_lock_irqsave(ap_lock, flags); list_for_each_entry_safe(scmd, tmp, &host->eh_cmd_q, eh_entry) { struct ata_queued_cmd *qc; @@ -224,15 +224,15 @@ void ata_scsi_error(struct Scsi_Host *host) if (nr_timedout) __ata_port_freeze(ap); - spin_unlock_irqrestore(hs_lock, flags); + spin_unlock_irqrestore(ap_lock, flags); } else - spin_unlock_wait(hs_lock); + spin_unlock_wait(ap_lock); repeat: /* invoke error handler */ if (ap->ops->error_handler) { /* fetch & clear EH info */ - spin_lock_irqsave(hs_lock, flags); + spin_lock_irqsave(ap_lock, flags); memset(&ap->eh_context, 0, sizeof(ap->eh_context)); ap->eh_context.i = ap->eh_info; @@ -241,7 +241,7 @@ void ata_scsi_error(struct Scsi_Host *host) ap->flags |= ATA_FLAG_EH_IN_PROGRESS; ap->flags &= ~ATA_FLAG_EH_PENDING; - spin_unlock_irqrestore(hs_lock, flags); + spin_unlock_irqrestore(ap_lock, flags); /* invoke EH. if unloading, just finish failed qcs */ if (!(ap->flags & ATA_FLAG_UNLOADING)) @@ -253,14 +253,14 @@ void ata_scsi_error(struct Scsi_Host *host) * recovered the port but before this point. Repeat * EH in such case. */ - spin_lock_irqsave(hs_lock, flags); + spin_lock_irqsave(ap_lock, flags); if (ap->flags & ATA_FLAG_EH_PENDING) { if (--repeat_cnt) { ata_port_printk(ap, KERN_INFO, "EH pending after completion, " "repeating EH (cnt=%d)\n", repeat_cnt); - spin_unlock_irqrestore(hs_lock, flags); + spin_unlock_irqrestore(ap_lock, flags); goto repeat; } ata_port_printk(ap, KERN_ERR, "EH pending after %d " @@ -270,14 +270,14 @@ void ata_scsi_error(struct Scsi_Host *host) /* this run is complete, make sure EH info is clear */ memset(&ap->eh_info, 0, sizeof(ap->eh_info)); - /* Clear host_eh_scheduled while holding hs_lock such + /* Clear host_eh_scheduled while holding ap_lock such * that if exception occurs after this point but * before EH completion, SCSI midlayer will * re-initiate EH. */ host->host_eh_scheduled = 0; - spin_unlock_irqrestore(hs_lock, flags); + spin_unlock_irqrestore(ap_lock, flags); } else { WARN_ON(ata_qc_from_tag(ap, ap->active_tag) == NULL); ap->ops->eng_timeout(ap); @@ -289,7 +289,7 @@ void ata_scsi_error(struct Scsi_Host *host) scsi_eh_flush_done_q(&ap->eh_done_q); /* clean up */ - spin_lock_irqsave(hs_lock, flags); + spin_lock_irqsave(ap_lock, flags); if (ap->flags & ATA_FLAG_LOADING) { ap->flags &= ~ATA_FLAG_LOADING; @@ -306,7 +306,7 @@ void ata_scsi_error(struct Scsi_Host *host) ap->flags &= ~ATA_FLAG_EH_IN_PROGRESS; wake_up_all(&ap->eh_wait_q); - spin_unlock_irqrestore(hs_lock, flags); + spin_unlock_irqrestore(ap_lock, flags); DPRINTK("EXIT\n"); } @@ -326,17 +326,17 @@ void ata_port_wait_eh(struct ata_port *ap) DEFINE_WAIT(wait); retry: - spin_lock_irqsave(&ap->host_set->lock, flags); + spin_lock_irqsave(ap->lock, flags); while (ap->flags & (ATA_FLAG_EH_PENDING | ATA_FLAG_EH_IN_PROGRESS)) { prepare_to_wait(&ap->eh_wait_q, &wait, TASK_UNINTERRUPTIBLE); - spin_unlock_irqrestore(&ap->host_set->lock, flags); + spin_unlock_irqrestore(ap->lock, flags); schedule(); - spin_lock_irqsave(&ap->host_set->lock, flags); + spin_lock_irqsave(ap->lock, flags); } finish_wait(&ap->eh_wait_q, &wait); - spin_unlock_irqrestore(&ap->host_set->lock, flags); + spin_unlock_irqrestore(ap->lock, flags); /* make sure SCSI EH is complete */ if (scsi_host_in_recovery(ap->host)) { @@ -368,7 +368,6 @@ void ata_port_wait_eh(struct ata_port *ap) static void ata_qc_timeout(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; - struct ata_host_set *host_set = ap->host_set; u8 host_stat = 0, drv_stat; unsigned long flags; @@ -376,7 +375,7 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc) ap->hsm_task_state = HSM_ST_IDLE; - spin_lock_irqsave(&host_set->lock, flags); + spin_lock_irqsave(ap->lock, flags); switch (qc->tf.protocol) { @@ -405,7 +404,7 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc) break; } - spin_unlock_irqrestore(&host_set->lock, flags); + spin_unlock_irqrestore(ap->lock, flags); ata_eh_qc_complete(qc); @@ -592,9 +591,9 @@ void ata_eh_freeze_port(struct ata_port *ap) if (!ap->ops->error_handler) return; - spin_lock_irqsave(&ap->host_set->lock, flags); + spin_lock_irqsave(ap->lock, flags); __ata_port_freeze(ap); - spin_unlock_irqrestore(&ap->host_set->lock, flags); + spin_unlock_irqrestore(ap->lock, flags); } /** @@ -613,14 +612,14 @@ void ata_eh_thaw_port(struct ata_port *ap) if (!ap->ops->error_handler) return; - spin_lock_irqsave(&ap->host_set->lock, flags); + spin_lock_irqsave(ap->lock, flags); ap->flags &= ~ATA_FLAG_FROZEN; if (ap->ops->thaw) ap->ops->thaw(ap); - spin_unlock_irqrestore(&ap->host_set->lock, flags); + spin_unlock_irqrestore(ap->lock, flags); DPRINTK("ata%u port thawed\n", ap->id); } @@ -636,11 +635,11 @@ static void __ata_eh_qc_complete(struct ata_queued_cmd *qc) struct scsi_cmnd *scmd = qc->scsicmd; unsigned long flags; - spin_lock_irqsave(&ap->host_set->lock, flags); + spin_lock_irqsave(ap->lock, flags); qc->scsidone = ata_eh_scsidone; __ata_qc_complete(qc); WARN_ON(ata_tag_valid(qc->tag)); - spin_unlock_irqrestore(&ap->host_set->lock, flags); + spin_unlock_irqrestore(ap->lock, flags); scsi_eh_finish_cmd(scmd, &ap->eh_done_q); } @@ -694,7 +693,7 @@ static void ata_eh_detach_dev(struct ata_device *dev) ata_dev_disable(dev); - spin_lock_irqsave(&ap->host_set->lock, flags); + spin_lock_irqsave(ap->lock, flags); dev->flags &= ~ATA_DFLAG_DETACH; @@ -703,7 +702,7 @@ static void ata_eh_detach_dev(struct ata_device *dev) ap->flags |= ATA_FLAG_SCSI_HOTPLUG; } - spin_unlock_irqrestore(&ap->host_set->lock, flags); + spin_unlock_irqrestore(ap->lock, flags); } static void ata_eh_clear_action(struct ata_device *dev, @@ -749,10 +748,10 @@ static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev, { unsigned long flags; - spin_lock_irqsave(&ap->host_set->lock, flags); + spin_lock_irqsave(ap->lock, flags); ata_eh_clear_action(dev, &ap->eh_info, action); ap->flags |= ATA_FLAG_RECOVERED; - spin_unlock_irqrestore(&ap->host_set->lock, flags); + spin_unlock_irqrestore(ap->lock, flags); } /** @@ -1625,9 +1624,9 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, break; } - spin_lock_irqsave(&ap->host_set->lock, flags); + spin_lock_irqsave(ap->lock, flags); ap->flags |= ATA_FLAG_SCSI_HOTPLUG; - spin_unlock_irqrestore(&ap->host_set->lock, flags); + spin_unlock_irqrestore(ap->lock, flags); } } diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 9698949fa52a..d86abed62007 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -752,7 +752,7 @@ void ata_scsi_slave_destroy(struct scsi_device *sdev) if (!ap->ops->error_handler) return; - spin_lock_irqsave(&ap->host_set->lock, flags); + spin_lock_irqsave(ap->lock, flags); dev = __ata_scsi_find_dev(ap, sdev); if (dev && dev->sdev) { /* SCSI device already in CANCEL state, no need to offline it */ @@ -760,7 +760,7 @@ void ata_scsi_slave_destroy(struct scsi_device *sdev) dev->flags |= ATA_DFLAG_DETACH; ata_port_schedule_eh(ap); } - spin_unlock_irqrestore(&ap->host_set->lock, flags); + spin_unlock_irqrestore(ap->lock, flags); } /** @@ -2684,7 +2684,7 @@ int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) ap = ata_shost_to_port(shost); spin_unlock(shost->host_lock); - spin_lock(&ap->host_set->lock); + spin_lock(ap->lock); ata_scsi_dump_cdb(ap, cmd); @@ -2696,7 +2696,7 @@ int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) done(cmd); } - spin_unlock(&ap->host_set->lock); + spin_unlock(ap->lock); spin_lock(shost->host_lock); return rc; } @@ -2858,7 +2858,7 @@ static void ata_scsi_remove_dev(struct ata_device *dev) * increments reference counts regardless of device state. */ mutex_lock(&ap->host->scan_mutex); - spin_lock_irqsave(&ap->host_set->lock, flags); + spin_lock_irqsave(ap->lock, flags); /* clearing dev->sdev is protected by host_set lock */ sdev = dev->sdev; @@ -2882,7 +2882,7 @@ static void ata_scsi_remove_dev(struct ata_device *dev) } } - spin_unlock_irqrestore(&ap->host_set->lock, flags); + spin_unlock_irqrestore(ap->lock, flags); mutex_unlock(&ap->host->scan_mutex); if (sdev) { @@ -2926,9 +2926,9 @@ void ata_scsi_hotplug(void *data) if (!(dev->flags & ATA_DFLAG_DETACHED)) continue; - spin_lock_irqsave(&ap->host_set->lock, flags); + spin_lock_irqsave(ap->lock, flags); dev->flags &= ~ATA_DFLAG_DETACHED; - spin_unlock_irqrestore(&ap->host_set->lock, flags); + spin_unlock_irqrestore(ap->lock, flags); ata_scsi_remove_dev(dev); } @@ -2981,7 +2981,7 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, (lun != SCAN_WILD_CARD && lun != 0)) return -EINVAL; - spin_lock_irqsave(&ap->host_set->lock, flags); + spin_lock_irqsave(ap->lock, flags); if (id == SCAN_WILD_CARD) { ap->eh_info.probe_mask |= (1 << ATA_MAX_DEVICES) - 1; @@ -2999,7 +2999,7 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, if (rc == 0) ata_port_schedule_eh(ap); - spin_unlock_irqrestore(&ap->host_set->lock, flags); + spin_unlock_irqrestore(ap->lock, flags); return rc; } diff --git a/include/linux/libata.h b/include/linux/libata.h index 6b3c3af2c75f..20b1cf527c60 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -483,6 +483,7 @@ struct ata_eh_context { struct ata_port { struct Scsi_Host *host; /* our co-allocated scsi host */ const struct ata_port_operations *ops; + spinlock_t *lock; unsigned long flags; /* ATA_FLAG_xxx */ unsigned int id; /* unique id req'd by scsi midlyr */ unsigned int port_no; /* unique port #; from zero */ -- cgit v1.2.3 From 5b057c6b1a25d57edf2b4d1e956e50936480a9ff Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 23 Jun 2006 02:06:41 -0700 Subject: [NET]: Avoid allocating skb in skb_pad First of all it is unnecessary to allocate a new skb in skb_pad since the existing one is not shared. More importantly, our hard_start_xmit interface does not allow a new skb to be allocated since that breaks requeueing. This patch uses pskb_expand_head to expand the existing skb and linearize it if needed. Actually, someone should sift through every instance of skb_pad on a non-linear skb as they do not fit the reasons why this was originally created. Incidentally, this fixes a minor bug when the skb is cloned (tcpdump, TCP, etc.). As it is skb_pad will simply write over a cloned skb. Because of the position of the write it is unlikely to cause problems but still it's best if we don't do it. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- drivers/net/3c527.c | 3 +-- drivers/net/82596.c | 3 +-- drivers/net/a2065.c | 3 +-- drivers/net/ariadne.c | 3 +-- drivers/net/arm/ether1.c | 3 +-- drivers/net/arm/ether3.c | 3 +-- drivers/net/atarilance.c | 3 +-- drivers/net/cassini.c | 3 +-- drivers/net/declance.c | 3 +-- drivers/net/depca.c | 7 ++----- drivers/net/eepro.c | 3 +-- drivers/net/eexpress.c | 3 +-- drivers/net/epic100.c | 7 ++----- drivers/net/eth16i.c | 3 +-- drivers/net/hp100.c | 7 ++----- drivers/net/lance.c | 3 +-- drivers/net/lasi_82596.c | 3 +-- drivers/net/lp486e.c | 3 +-- drivers/net/myri10ge/myri10ge.c | 3 +-- drivers/net/pcmcia/fmvj18x_cs.c | 3 +-- drivers/net/pcmcia/xirc2ps_cs.c | 3 +-- drivers/net/r8169.c | 3 +-- drivers/net/seeq8005.c | 3 +-- drivers/net/sis190.c | 3 +-- drivers/net/sk98lin/skge.c | 2 +- drivers/net/skge.c | 3 +-- drivers/net/smc9194.c | 3 +-- drivers/net/sonic.c | 3 +-- drivers/net/starfire.c | 3 +-- drivers/net/via-rhine.c | 7 ++----- drivers/net/wireless/ray_cs.c | 3 +-- drivers/net/wireless/wavelan_cs.c | 7 ++----- drivers/net/yellowfin.c | 12 +++++------- drivers/net/znet.c | 3 +-- include/linux/skbuff.h | 11 +++++------ net/core/skbuff.c | 36 ++++++++++++++++++++++++++---------- 36 files changed, 74 insertions(+), 103 deletions(-) (limited to 'include') diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c index 1b1cb0026072..157eda573925 100644 --- a/drivers/net/3c527.c +++ b/drivers/net/3c527.c @@ -1031,8 +1031,7 @@ static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev) return 1; } - skb = skb_padto(skb, ETH_ZLEN); - if (skb == NULL) { + if (skb_padto(skb, ETH_ZLEN)) { netif_wake_queue(dev); return 0; } diff --git a/drivers/net/82596.c b/drivers/net/82596.c index da0c878dcba8..8a9f7d61b9b1 100644 --- a/drivers/net/82596.c +++ b/drivers/net/82596.c @@ -1070,8 +1070,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev) skb->len, (unsigned int)skb->data)); if (skb->len < ETH_ZLEN) { - skb = skb_padto(skb, ETH_ZLEN); - if (skb == NULL) + if (skb_padto(skb, ETH_ZLEN)) return 0; length = ETH_ZLEN; } diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c index 79bb56b8dcef..71165ac0257a 100644 --- a/drivers/net/a2065.c +++ b/drivers/net/a2065.c @@ -573,8 +573,7 @@ static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev) if (len < ETH_ZLEN) { len = ETH_ZLEN; - skb = skb_padto(skb, ETH_ZLEN); - if (skb == NULL) + if (skb_padto(skb, ETH_ZLEN)) return 0; } diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c index d1b6b1f794e2..a9bb7a4aff98 100644 --- a/drivers/net/ariadne.c +++ b/drivers/net/ariadne.c @@ -607,8 +607,7 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev) /* FIXME: is the 79C960 new enough to do its own padding right ? */ if (skb->len < ETH_ZLEN) { - skb = skb_padto(skb, ETH_ZLEN); - if (skb == NULL) + if (skb_padto(skb, ETH_ZLEN)) return 0; len = ETH_ZLEN; } diff --git a/drivers/net/arm/ether1.c b/drivers/net/arm/ether1.c index 36475eb2727f..312955d07b28 100644 --- a/drivers/net/arm/ether1.c +++ b/drivers/net/arm/ether1.c @@ -700,8 +700,7 @@ ether1_sendpacket (struct sk_buff *skb, struct net_device *dev) } if (skb->len < ETH_ZLEN) { - skb = skb_padto(skb, ETH_ZLEN); - if (skb == NULL) + if (skb_padto(skb, ETH_ZLEN)) goto out; } diff --git a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c index f1d5b1027ff7..081074180e62 100644 --- a/drivers/net/arm/ether3.c +++ b/drivers/net/arm/ether3.c @@ -518,8 +518,7 @@ ether3_sendpacket(struct sk_buff *skb, struct net_device *dev) length = (length + 1) & ~1; if (length != skb->len) { - skb = skb_padto(skb, length); - if (skb == NULL) + if (skb_padto(skb, length)) goto out; } diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c index 442b2cbeb58a..91783a8008be 100644 --- a/drivers/net/atarilance.c +++ b/drivers/net/atarilance.c @@ -804,8 +804,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) ++len; if (len > skb->len) { - skb = skb_padto(skb, len); - if (skb == NULL) + if (skb_padto(skb, len)) return 0; } diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index 39f36aa05aa8..565a54f1d06a 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c @@ -2915,8 +2915,7 @@ static int cas_start_xmit(struct sk_buff *skb, struct net_device *dev) */ static int ring; - skb = skb_padto(skb, cp->min_frame_size); - if (!skb) + if (skb_padto(skb, cp->min_frame_size)) return 0; /* XXX: we need some higher-level QoS hooks to steer packets to diff --git a/drivers/net/declance.c b/drivers/net/declance.c index f130bdab3fd3..d3d958e7ac56 100644 --- a/drivers/net/declance.c +++ b/drivers/net/declance.c @@ -885,8 +885,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) len = skblen; if (len < ETH_ZLEN) { - skb = skb_padto(skb, ETH_ZLEN); - if (skb == NULL) + if (skb_padto(skb, ETH_ZLEN)) return 0; len = ETH_ZLEN; } diff --git a/drivers/net/depca.c b/drivers/net/depca.c index 0941d40f046f..e946c43d3b10 100644 --- a/drivers/net/depca.c +++ b/drivers/net/depca.c @@ -938,11 +938,8 @@ static int depca_start_xmit(struct sk_buff *skb, struct net_device *dev) if (skb->len < 1) goto out; - if (skb->len < ETH_ZLEN) { - skb = skb_padto(skb, ETH_ZLEN); - if (skb == NULL) - goto out; - } + if (skb_padto(skb, ETH_ZLEN)) + goto out; netif_stop_queue(dev); diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c index a806dfe54d23..e70f172699db 100644 --- a/drivers/net/eepro.c +++ b/drivers/net/eepro.c @@ -1154,8 +1154,7 @@ static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev) printk(KERN_DEBUG "%s: entering eepro_send_packet routine.\n", dev->name); if (length < ETH_ZLEN) { - skb = skb_padto(skb, ETH_ZLEN); - if (skb == NULL) + if (skb_padto(skb, ETH_ZLEN)) return 0; length = ETH_ZLEN; } diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c index 82bd356e4f3a..a74b20715755 100644 --- a/drivers/net/eexpress.c +++ b/drivers/net/eexpress.c @@ -677,8 +677,7 @@ static int eexp_xmit(struct sk_buff *buf, struct net_device *dev) #endif if (buf->len < ETH_ZLEN) { - buf = skb_padto(buf, ETH_ZLEN); - if (buf == NULL) + if (skb_padto(buf, ETH_ZLEN)) return 0; length = ETH_ZLEN; } diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index 8d680ce600d7..724d7dc35fa3 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -1027,11 +1027,8 @@ static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev) u32 ctrl_word; unsigned long flags; - if (skb->len < ETH_ZLEN) { - skb = skb_padto(skb, ETH_ZLEN); - if (skb == NULL) - return 0; - } + if (skb_padto(skb, ETH_ZLEN)) + return 0; /* Caution: the write order is important here, set the field with the "ownership" bit last. */ diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c index b67545be2caa..4bf76f86d8e9 100644 --- a/drivers/net/eth16i.c +++ b/drivers/net/eth16i.c @@ -1064,8 +1064,7 @@ static int eth16i_tx(struct sk_buff *skb, struct net_device *dev) unsigned long flags; if (length < ETH_ZLEN) { - skb = skb_padto(skb, ETH_ZLEN); - if (skb == NULL) + if (skb_padto(skb, ETH_ZLEN)) return 0; length = ETH_ZLEN; } diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c index 247c8ca86033..dd1dc32dc98d 100644 --- a/drivers/net/hp100.c +++ b/drivers/net/hp100.c @@ -1487,11 +1487,8 @@ static int hp100_start_xmit_bm(struct sk_buff *skb, struct net_device *dev) if (skb->len <= 0) return 0; - if (skb->len < ETH_ZLEN && lp->chip == HP100_CHIPID_SHASTA) { - skb = skb_padto(skb, ETH_ZLEN); - if (skb == NULL) - return 0; - } + if (lp->chip == HP100_CHIPID_SHASTA && skb_padto(skb, ETH_ZLEN)) + return 0; /* Get Tx ring tail pointer */ if (lp->txrtail->next == lp->txrhead) { diff --git a/drivers/net/lance.c b/drivers/net/lance.c index bb5ad479210b..c1c3452c90ca 100644 --- a/drivers/net/lance.c +++ b/drivers/net/lance.c @@ -968,8 +968,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) /* The old LANCE chips doesn't automatically pad buffers to min. size. */ if (chip_table[lp->chip_version].flags & LANCE_MUST_PAD) { if (skb->len < ETH_ZLEN) { - skb = skb_padto(skb, ETH_ZLEN); - if (skb == NULL) + if (skb_padto(skb, ETH_ZLEN)) goto out; lp->tx_ring[entry].length = -ETH_ZLEN; } diff --git a/drivers/net/lasi_82596.c b/drivers/net/lasi_82596.c index 957888de3d7e..1ab09447baa5 100644 --- a/drivers/net/lasi_82596.c +++ b/drivers/net/lasi_82596.c @@ -1083,8 +1083,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev) skb->len, skb->data)); if (length < ETH_ZLEN) { - skb = skb_padto(skb, ETH_ZLEN); - if (skb == NULL) + if (skb_padto(skb, ETH_ZLEN)) return 0; length = ETH_ZLEN; } diff --git a/drivers/net/lp486e.c b/drivers/net/lp486e.c index 94d5ea1ce8bd..bf3f343ae715 100644 --- a/drivers/net/lp486e.c +++ b/drivers/net/lp486e.c @@ -877,8 +877,7 @@ static int i596_start_xmit (struct sk_buff *skb, struct net_device *dev) { length = skb->len; if (length < ETH_ZLEN) { - skb = skb_padto(skb, ETH_ZLEN); - if (skb == NULL) + if (skb_padto(skb, ETH_ZLEN)) return 0; length = ETH_ZLEN; } diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 5a74f63618bc..b983e1e04348 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -1939,8 +1939,7 @@ again: /* pad frames to at least ETH_ZLEN bytes */ if (unlikely(skb->len < ETH_ZLEN)) { - skb = skb_padto(skb, ETH_ZLEN); - if (skb == NULL) { + if (skb_padto(skb, ETH_ZLEN)) { /* The packet is gone, so we must * return 0 */ mgp->stats.tx_dropped += 1; diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index 09b11761cdfa..ea93b8f18605 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -831,8 +831,7 @@ static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev) if (length < ETH_ZLEN) { - skb = skb_padto(skb, ETH_ZLEN); - if (skb == NULL) + if (skb_padto(skb, ETH_ZLEN)) return 0; length = ETH_ZLEN; } diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index e80d1e3aec68..9bae77ce1314 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -1374,8 +1374,7 @@ do_start_xmit(struct sk_buff *skb, struct net_device *dev) */ if (pktlen < ETH_ZLEN) { - skb = skb_padto(skb, ETH_ZLEN); - if (skb == NULL) + if (skb_padto(skb, ETH_ZLEN)) return 0; pktlen = ETH_ZLEN; } diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 9945cc6b8d90..985afe0e6273 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -2222,8 +2222,7 @@ static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev) len = skb->len; if (unlikely(len < ETH_ZLEN)) { - skb = skb_padto(skb, ETH_ZLEN); - if (!skb) + if (skb_padto(skb, ETH_ZLEN)) goto err_update_stats; len = ETH_ZLEN; } diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c index bcef03feb2fc..efd0f235020f 100644 --- a/drivers/net/seeq8005.c +++ b/drivers/net/seeq8005.c @@ -396,8 +396,7 @@ static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev) unsigned char *buf; if (length < ETH_ZLEN) { - skb = skb_padto(skb, ETH_ZLEN); - if (skb == NULL) + if (skb_padto(skb, ETH_ZLEN)) return 0; length = ETH_ZLEN; } diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index 31dd3f036fa8..df39f3447655 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -1156,8 +1156,7 @@ static int sis190_start_xmit(struct sk_buff *skb, struct net_device *dev) dma_addr_t mapping; if (unlikely(skb->len < ETH_ZLEN)) { - skb = skb_padto(skb, ETH_ZLEN); - if (!skb) { + if (skb_padto(skb, ETH_ZLEN)) { tp->stats.tx_dropped++; goto out; } diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c index 38a26df4095f..f3efbd177ae7 100644 --- a/drivers/net/sk98lin/skge.c +++ b/drivers/net/sk98lin/skge.c @@ -1525,7 +1525,7 @@ struct sk_buff *pMessage) /* pointer to send-message */ ** This is to resolve faulty padding by the HW with 0xaa bytes. */ if (BytesSend < C_LEN_ETHERNET_MINSIZE) { - if ((pMessage = skb_padto(pMessage, C_LEN_ETHERNET_MINSIZE)) == NULL) { + if (skb_padto(pMessage, C_LEN_ETHERNET_MINSIZE)) { spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags); return 0; } diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 536dd1cf7f79..19a4a16055dc 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -2310,8 +2310,7 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev) u64 map; unsigned long flags; - skb = skb_padto(skb, ETH_ZLEN); - if (!skb) + if (skb_padto(skb, ETH_ZLEN)) return NETDEV_TX_OK; if (!spin_trylock_irqsave(&skge->tx_lock, flags)) diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c index 6cf16f322ad5..8b0321f1976c 100644 --- a/drivers/net/smc9194.c +++ b/drivers/net/smc9194.c @@ -523,8 +523,7 @@ static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * de length = skb->len; if (length < ETH_ZLEN) { - skb = skb_padto(skb, ETH_ZLEN); - if (skb == NULL) { + if (skb_padto(skb, ETH_ZLEN)) { netif_wake_queue(dev); return 0; } diff --git a/drivers/net/sonic.c b/drivers/net/sonic.c index 90b818a8de6e..cab0dd958492 100644 --- a/drivers/net/sonic.c +++ b/drivers/net/sonic.c @@ -231,8 +231,7 @@ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev) length = skb->len; if (length < ETH_ZLEN) { - skb = skb_padto(skb, ETH_ZLEN); - if (skb == NULL) + if (skb_padto(skb, ETH_ZLEN)) return 0; length = ETH_ZLEN; } diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index 9b7805be21da..c158eedc7813 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -1349,8 +1349,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) #if defined(ZEROCOPY) && defined(HAS_BROKEN_FIRMWARE) if (skb->ip_summed == CHECKSUM_HW) { - skb = skb_padto(skb, (skb->len + PADDING_MASK) & ~PADDING_MASK); - if (skb == NULL) + if (skb_padto(skb, (skb->len + PADDING_MASK) & ~PADDING_MASK)) return NETDEV_TX_OK; } #endif /* ZEROCOPY && HAS_BROKEN_FIRMWARE */ diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index fdc21037f6dc..c80a4f1d5f7a 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -1284,11 +1284,8 @@ static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev) /* Calculate the next Tx descriptor entry. */ entry = rp->cur_tx % TX_RING_SIZE; - if (skb->len < ETH_ZLEN) { - skb = skb_padto(skb, ETH_ZLEN); - if (skb == NULL) - return 0; - } + if (skb_padto(skb, ETH_ZLEN)) + return 0; rp->tx_skbuff[entry] = skb; diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 879eb427607c..a915fe6c6aa5 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -924,8 +924,7 @@ static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev) if (length < ETH_ZLEN) { - skb = skb_padto(skb, ETH_ZLEN); - if (skb == NULL) + if (skb_padto(skb, ETH_ZLEN)) return 0; length = ETH_ZLEN; } diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index f7724eb2fa7e..561250f73fd3 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c @@ -3194,11 +3194,8 @@ wavelan_packet_xmit(struct sk_buff * skb, * and we don't have the Ethernet specific requirement of beeing * able to detect collisions, therefore in theory we don't really * need to pad. Jean II */ - if (skb->len < ETH_ZLEN) { - skb = skb_padto(skb, ETH_ZLEN); - if (skb == NULL) - return 0; - } + if (skb_padto(skb, ETH_ZLEN)) + return 0; wv_packet_write(dev, skb->data, skb->len); diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index fd0f43b7db5b..ecec8e5db786 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -862,13 +862,11 @@ static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Fix GX chipset errata. */ if (cacheline_end > 24 || cacheline_end == 0) { len = skb->len + 32 - cacheline_end + 1; - if (len != skb->len) - skb = skb_padto(skb, len); - } - if (skb == NULL) { - yp->tx_skbuff[entry] = NULL; - netif_wake_queue(dev); - return 0; + if (skb_padto(skb, len)) { + yp->tx_skbuff[entry] = NULL; + netif_wake_queue(dev); + return 0; + } } } yp->tx_skbuff[entry] = skb; diff --git a/drivers/net/znet.c b/drivers/net/znet.c index 3ac047bc727d..a7c089df66e6 100644 --- a/drivers/net/znet.c +++ b/drivers/net/znet.c @@ -544,8 +544,7 @@ static int znet_send_packet(struct sk_buff *skb, struct net_device *dev) printk(KERN_DEBUG "%s: ZNet_send_packet.\n", dev->name); if (length < ETH_ZLEN) { - skb = skb_padto(skb, ETH_ZLEN); - if (skb == NULL) + if (skb_padto(skb, ETH_ZLEN)) return 0; length = ETH_ZLEN; } diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 66f8819f9568..f8c7eb79a27f 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -345,7 +345,7 @@ extern struct sk_buff *skb_realloc_headroom(struct sk_buff *skb, extern struct sk_buff *skb_copy_expand(const struct sk_buff *skb, int newheadroom, int newtailroom, gfp_t priority); -extern struct sk_buff * skb_pad(struct sk_buff *skb, int pad); +extern int skb_pad(struct sk_buff *skb, int pad); #define dev_kfree_skb(a) kfree_skb(a) extern void skb_over_panic(struct sk_buff *skb, int len, void *here); @@ -1122,16 +1122,15 @@ static inline int skb_cow(struct sk_buff *skb, unsigned int headroom) * * Pads up a buffer to ensure the trailing bytes exist and are * blanked. If the buffer already contains sufficient data it - * is untouched. Returns the buffer, which may be a replacement - * for the original, or NULL for out of memory - in which case - * the original buffer is still freed. + * is untouched. Otherwise it is extended. Returns zero on + * success. The skb is freed on error. */ -static inline struct sk_buff *skb_padto(struct sk_buff *skb, unsigned int len) +static inline int skb_padto(struct sk_buff *skb, unsigned int len) { unsigned int size = skb->len; if (likely(size >= len)) - return skb; + return 0; return skb_pad(skb, len-size); } diff --git a/net/core/skbuff.c b/net/core/skbuff.c index bb7210f4005e..fe63d4efbd4d 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -781,24 +781,40 @@ struct sk_buff *skb_copy_expand(const struct sk_buff *skb, * filled. Used by network drivers which may DMA or transfer data * beyond the buffer end onto the wire. * - * May return NULL in out of memory cases. + * May return error in out of memory cases. The skb is freed on error. */ -struct sk_buff *skb_pad(struct sk_buff *skb, int pad) +int skb_pad(struct sk_buff *skb, int pad) { - struct sk_buff *nskb; + int err; + int ntail; /* If the skbuff is non linear tailroom is always zero.. */ - if (skb_tailroom(skb) >= pad) { + if (!skb_cloned(skb) && skb_tailroom(skb) >= pad) { memset(skb->data+skb->len, 0, pad); - return skb; + return 0; } - - nskb = skb_copy_expand(skb, skb_headroom(skb), skb_tailroom(skb) + pad, GFP_ATOMIC); + + ntail = skb->data_len + pad - (skb->end - skb->tail); + if (likely(skb_cloned(skb) || ntail > 0)) { + err = pskb_expand_head(skb, 0, ntail, GFP_ATOMIC); + if (unlikely(err)) + goto free_skb; + } + + /* FIXME: The use of this function with non-linear skb's really needs + * to be audited. + */ + err = skb_linearize(skb); + if (unlikely(err)) + goto free_skb; + + memset(skb->data + skb->len, 0, pad); + return 0; + +free_skb: kfree_skb(skb); - if (nskb) - memset(nskb->data+nskb->len, 0, pad); - return nskb; + return err; } /* Trims skb to length len. It can change skb pointers. -- cgit v1.2.3 From 7967168cefdbc63bf332d6b1548eca7cd65ebbcc Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 22 Jun 2006 02:40:14 -0700 Subject: [NET]: Merge TSO/UFO fields in sk_buff Having separate fields in sk_buff for TSO/UFO (tso_size/ufo_size) is not going to scale if we add any more segmentation methods (e.g., DCCP). So let's merge them. They were used to tell the protocol of a packet. This function has been subsumed by the new gso_type field. This is essentially a set of netdev feature bits (shifted by 16 bits) that are required to process a specific skb. As such it's easy to tell whether a given device can process a GSO skb: you just have to and the gso_type field and the netdev's features field. I've made gso_type a conjunction. The idea is that you have a base type (e.g., SKB_GSO_TCPV4) that can be modified further to support new features. For example, if we add a hardware TSO type that supports ECN, they would declare NETIF_F_TSO | NETIF_F_TSO_ECN. All TSO packets with CWR set would have a gso_type of SKB_GSO_TCPV4 | SKB_GSO_TCPV4_ECN while all other TSO packets would be SKB_GSO_TCPV4. This means that only the CWR packets need to be emulated in software. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- drivers/net/8139cp.c | 2 +- drivers/net/bnx2.c | 4 ++-- drivers/net/chelsio/sge.c | 4 ++-- drivers/net/e1000/e1000_main.c | 10 ++++----- drivers/net/forcedeth.c | 4 ++-- drivers/net/ixgb/ixgb_main.c | 4 ++-- drivers/net/loopback.c | 4 ++-- drivers/net/myri10ge/myri10ge.c | 4 ++-- drivers/net/r8169.c | 2 +- drivers/net/s2io.c | 16 +++++++------- drivers/net/sky2.c | 4 ++-- drivers/net/tg3.c | 4 ++-- drivers/net/typhoon.c | 2 +- drivers/s390/net/qeth_eddp.c | 12 +++++------ drivers/s390/net/qeth_main.c | 4 ++-- drivers/s390/net/qeth_tso.h | 2 +- include/linux/netdevice.h | 14 ++++++++++-- include/linux/skbuff.h | 12 ++++++++--- include/net/tcp.h | 4 ++-- net/bridge/br_forward.c | 4 ++-- net/bridge/br_netfilter.c | 2 +- net/core/skbuff.c | 16 ++++++++------ net/ipv4/ip_output.c | 16 ++++++++------ net/ipv4/tcp.c | 4 ++-- net/ipv4/tcp_input.c | 2 +- net/ipv4/tcp_output.c | 47 ++++++++++++++++++++++++----------------- net/ipv6/ip6_output.c | 7 +++--- 27 files changed, 120 insertions(+), 90 deletions(-) (limited to 'include') diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index a26077a175ad..0cdc830449d8 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -797,7 +797,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) entry = cp->tx_head; eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0; if (dev->features & NETIF_F_TSO) - mss = skb_shinfo(skb)->tso_size; + mss = skb_shinfo(skb)->gso_size; if (skb_shinfo(skb)->nr_frags == 0) { struct cp_desc *txd = &cp->tx_ring[entry]; diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 702d546567ad..7635736cc791 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -1640,7 +1640,7 @@ bnx2_tx_int(struct bnx2 *bp) skb = tx_buf->skb; #ifdef BCM_TSO /* partial BD completions possible with TSO packets */ - if (skb_shinfo(skb)->tso_size) { + if (skb_shinfo(skb)->gso_size) { u16 last_idx, last_ring_idx; last_idx = sw_cons + @@ -4428,7 +4428,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) (TX_BD_FLAGS_VLAN_TAG | (vlan_tx_tag_get(skb) << 16)); } #ifdef BCM_TSO - if ((mss = skb_shinfo(skb)->tso_size) && + if ((mss = skb_shinfo(skb)->gso_size) && (skb->len > (bp->dev->mtu + ETH_HLEN))) { u32 tcp_opt_len, ip_tcp_len; diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c index 4391bf4bf573..53efff6da784 100644 --- a/drivers/net/chelsio/sge.c +++ b/drivers/net/chelsio/sge.c @@ -1418,7 +1418,7 @@ int t1_start_xmit(struct sk_buff *skb, struct net_device *dev) struct cpl_tx_pkt *cpl; #ifdef NETIF_F_TSO - if (skb_shinfo(skb)->tso_size) { + if (skb_shinfo(skb)->gso_size) { int eth_type; struct cpl_tx_pkt_lso *hdr; @@ -1433,7 +1433,7 @@ int t1_start_xmit(struct sk_buff *skb, struct net_device *dev) hdr->ip_hdr_words = skb->nh.iph->ihl; hdr->tcp_hdr_words = skb->h.th->doff; hdr->eth_type_mss = htons(MK_ETH_TYPE_MSS(eth_type, - skb_shinfo(skb)->tso_size)); + skb_shinfo(skb)->gso_size)); hdr->len = htonl(skb->len - sizeof(*hdr)); cpl = (struct cpl_tx_pkt *)hdr; sge->stats.tx_lso_pkts++; diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index a373ccb308d8..32b7d444b374 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -2394,7 +2394,7 @@ e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, uint8_t ipcss, ipcso, tucss, tucso, hdr_len; int err; - if (skb_shinfo(skb)->tso_size) { + if (skb_shinfo(skb)->gso_size) { if (skb_header_cloned(skb)) { err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC); if (err) @@ -2402,7 +2402,7 @@ e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, } hdr_len = ((skb->h.raw - skb->data) + (skb->h.th->doff << 2)); - mss = skb_shinfo(skb)->tso_size; + mss = skb_shinfo(skb)->gso_size; if (skb->protocol == htons(ETH_P_IP)) { skb->nh.iph->tot_len = 0; skb->nh.iph->check = 0; @@ -2519,7 +2519,7 @@ e1000_tx_map(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, * tso gets written back prematurely before the data is fully * DMA'd to the controller */ if (!skb->data_len && tx_ring->last_tx_tso && - !skb_shinfo(skb)->tso_size) { + !skb_shinfo(skb)->gso_size) { tx_ring->last_tx_tso = 0; size -= 4; } @@ -2757,7 +2757,7 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) } #ifdef NETIF_F_TSO - mss = skb_shinfo(skb)->tso_size; + mss = skb_shinfo(skb)->gso_size; /* The controller does a simple calculation to * make sure there is enough room in the FIFO before * initiating the DMA for each buffer. The calc is: @@ -2807,7 +2807,7 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) #ifdef NETIF_F_TSO /* Controller Erratum workaround */ if (!skb->data_len && tx_ring->last_tx_tso && - !skb_shinfo(skb)->tso_size) + !skb_shinfo(skb)->gso_size) count++; #endif diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 191383d461d7..21be4fa071b5 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -1495,8 +1495,8 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) np->tx_skbuff[nr] = skb; #ifdef NETIF_F_TSO - if (skb_shinfo(skb)->tso_size) - tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->tso_size << NV_TX2_TSO_SHIFT); + if (skb_shinfo(skb)->gso_size) + tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->gso_size << NV_TX2_TSO_SHIFT); else #endif tx_flags_extra = (skb->ip_summed == CHECKSUM_HW ? (NV_TX2_CHECKSUM_L3|NV_TX2_CHECKSUM_L4) : 0); diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index 57006fb8840e..8bb32f946993 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -1173,7 +1173,7 @@ ixgb_tso(struct ixgb_adapter *adapter, struct sk_buff *skb) uint16_t ipcse, tucse, mss; int err; - if(likely(skb_shinfo(skb)->tso_size)) { + if(likely(skb_shinfo(skb)->gso_size)) { if (skb_header_cloned(skb)) { err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC); if (err) @@ -1181,7 +1181,7 @@ ixgb_tso(struct ixgb_adapter *adapter, struct sk_buff *skb) } hdr_len = ((skb->h.raw - skb->data) + (skb->h.th->doff << 2)); - mss = skb_shinfo(skb)->tso_size; + mss = skb_shinfo(skb)->gso_size; skb->nh.iph->tot_len = 0; skb->nh.iph->check = 0; skb->h.th->check = ~csum_tcpudp_magic(skb->nh.iph->saddr, diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index b79d6e8d3045..43fef7de8cb9 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -74,7 +74,7 @@ static void emulate_large_send_offload(struct sk_buff *skb) struct iphdr *iph = skb->nh.iph; struct tcphdr *th = (struct tcphdr*)(skb->nh.raw + (iph->ihl * 4)); unsigned int doffset = (iph->ihl + th->doff) * 4; - unsigned int mtu = skb_shinfo(skb)->tso_size + doffset; + unsigned int mtu = skb_shinfo(skb)->gso_size + doffset; unsigned int offset = 0; u32 seq = ntohl(th->seq); u16 id = ntohs(iph->id); @@ -139,7 +139,7 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) #endif #ifdef LOOPBACK_TSO - if (skb_shinfo(skb)->tso_size) { + if (skb_shinfo(skb)->gso_size) { BUG_ON(skb->protocol != htons(ETH_P_IP)); BUG_ON(skb->nh.iph->protocol != IPPROTO_TCP); diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index b983e1e04348..dbdf189436fa 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -1879,7 +1879,7 @@ again: #ifdef NETIF_F_TSO if (skb->len > (dev->mtu + ETH_HLEN)) { - mss = skb_shinfo(skb)->tso_size; + mss = skb_shinfo(skb)->gso_size; if (mss != 0) max_segments = MYRI10GE_MAX_SEND_DESC_TSO; } @@ -2112,7 +2112,7 @@ abort_linearize: } idx = (idx + 1) & tx->mask; } while (idx != last_idx); - if (skb_shinfo(skb)->tso_size) { + if (skb_shinfo(skb)->gso_size) { printk(KERN_ERR "myri10ge: %s: TSO but wanted to linearize?!?!?\n", mgp->dev->name); diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 985afe0e6273..12d1cb289bb0 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -2172,7 +2172,7 @@ static int rtl8169_xmit_frags(struct rtl8169_private *tp, struct sk_buff *skb, static inline u32 rtl8169_tso_csum(struct sk_buff *skb, struct net_device *dev) { if (dev->features & NETIF_F_TSO) { - u32 mss = skb_shinfo(skb)->tso_size; + u32 mss = skb_shinfo(skb)->gso_size; if (mss) return LargeSend | ((mss & MSSMask) << MSSShift); diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 11daed495b97..3defe5d4f7d3 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -3959,8 +3959,8 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) txdp->Control_1 = 0; txdp->Control_2 = 0; #ifdef NETIF_F_TSO - mss = skb_shinfo(skb)->tso_size; - if (mss) { + mss = skb_shinfo(skb)->gso_size; + if (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV4) { txdp->Control_1 |= TXD_TCP_LSO_EN; txdp->Control_1 |= TXD_TCP_LSO_MSS(mss); } @@ -3980,10 +3980,10 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) } frg_len = skb->len - skb->data_len; - if (skb_shinfo(skb)->ufo_size) { + if (skb_shinfo(skb)->gso_type == SKB_GSO_UDPV4) { int ufo_size; - ufo_size = skb_shinfo(skb)->ufo_size; + ufo_size = skb_shinfo(skb)->gso_size; ufo_size &= ~7; txdp->Control_1 |= TXD_UFO_EN; txdp->Control_1 |= TXD_UFO_MSS(ufo_size); @@ -4009,7 +4009,7 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) txdp->Host_Control = (unsigned long) skb; txdp->Control_1 |= TXD_BUFFER0_SIZE(frg_len); - if (skb_shinfo(skb)->ufo_size) + if (skb_shinfo(skb)->gso_type == SKB_GSO_UDPV4) txdp->Control_1 |= TXD_UFO_EN; frg_cnt = skb_shinfo(skb)->nr_frags; @@ -4024,12 +4024,12 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) (sp->pdev, frag->page, frag->page_offset, frag->size, PCI_DMA_TODEVICE); txdp->Control_1 = TXD_BUFFER0_SIZE(frag->size); - if (skb_shinfo(skb)->ufo_size) + if (skb_shinfo(skb)->gso_type == SKB_GSO_UDPV4) txdp->Control_1 |= TXD_UFO_EN; } txdp->Control_1 |= TXD_GATHER_CODE_LAST; - if (skb_shinfo(skb)->ufo_size) + if (skb_shinfo(skb)->gso_type == SKB_GSO_UDPV4) frg_cnt++; /* as Txd0 was used for inband header */ tx_fifo = mac_control->tx_FIFO_start[queue]; @@ -4043,7 +4043,7 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) if (mss) val64 |= TX_FIFO_SPECIAL_FUNC; #endif - if (skb_shinfo(skb)->ufo_size) + if (skb_shinfo(skb)->gso_type == SKB_GSO_UDPV4) val64 |= TX_FIFO_SPECIAL_FUNC; writeq(val64, &tx_fifo->List_Control); diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index fba1e4d4d83d..d3577871be28 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1160,7 +1160,7 @@ static unsigned tx_le_req(const struct sk_buff *skb) count = sizeof(dma_addr_t) / sizeof(u32); count += skb_shinfo(skb)->nr_frags * count; - if (skb_shinfo(skb)->tso_size) + if (skb_shinfo(skb)->gso_size) ++count; if (skb->ip_summed == CHECKSUM_HW) @@ -1232,7 +1232,7 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) } /* Check for TCP Segmentation Offload */ - mss = skb_shinfo(skb)->tso_size; + mss = skb_shinfo(skb)->gso_size; if (mss != 0) { /* just drop the packet if non-linear expansion fails */ if (skb_header_cloned(skb) && diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index b2ddd4522a87..e3e380f90f86 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -3780,7 +3780,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) #if TG3_TSO_SUPPORT != 0 mss = 0; if (skb->len > (tp->dev->mtu + ETH_HLEN) && - (mss = skb_shinfo(skb)->tso_size) != 0) { + (mss = skb_shinfo(skb)->gso_size) != 0) { int tcp_opt_len, ip_tcp_len; if (skb_header_cloned(skb) && @@ -3905,7 +3905,7 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) #if TG3_TSO_SUPPORT != 0 mss = 0; if (skb->len > (tp->dev->mtu + ETH_HLEN) && - (mss = skb_shinfo(skb)->tso_size) != 0) { + (mss = skb_shinfo(skb)->gso_size) != 0) { int tcp_opt_len, ip_tcp_len; if (skb_header_cloned(skb) && diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index d9258d42090c..e49e8b520c28 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -340,7 +340,7 @@ enum state_values { #endif #if defined(NETIF_F_TSO) -#define skb_tso_size(x) (skb_shinfo(x)->tso_size) +#define skb_tso_size(x) (skb_shinfo(x)->gso_size) #define TSO_NUM_DESCRIPTORS 2 #define TSO_OFFLOAD_ON TYPHOON_OFFLOAD_TCP_SEGMENT #else diff --git a/drivers/s390/net/qeth_eddp.c b/drivers/s390/net/qeth_eddp.c index 0bab60a20309..38aad8321456 100644 --- a/drivers/s390/net/qeth_eddp.c +++ b/drivers/s390/net/qeth_eddp.c @@ -420,7 +420,7 @@ __qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx, } tcph = eddp->skb->h.th; while (eddp->skb_offset < eddp->skb->len) { - data_len = min((int)skb_shinfo(eddp->skb)->tso_size, + data_len = min((int)skb_shinfo(eddp->skb)->gso_size, (int)(eddp->skb->len - eddp->skb_offset)); /* prepare qdio hdr */ if (eddp->qh.hdr.l2.id == QETH_HEADER_TYPE_LAYER2){ @@ -515,20 +515,20 @@ qeth_eddp_calc_num_pages(struct qeth_eddp_context *ctx, struct sk_buff *skb, QETH_DBF_TEXT(trace, 5, "eddpcanp"); /* can we put multiple skbs in one page? */ - skbs_per_page = PAGE_SIZE / (skb_shinfo(skb)->tso_size + hdr_len); + skbs_per_page = PAGE_SIZE / (skb_shinfo(skb)->gso_size + hdr_len); if (skbs_per_page > 1){ - ctx->num_pages = (skb_shinfo(skb)->tso_segs + 1) / + ctx->num_pages = (skb_shinfo(skb)->gso_segs + 1) / skbs_per_page + 1; ctx->elements_per_skb = 1; } else { /* no -> how many elements per skb? */ - ctx->elements_per_skb = (skb_shinfo(skb)->tso_size + hdr_len + + ctx->elements_per_skb = (skb_shinfo(skb)->gso_size + hdr_len + PAGE_SIZE) >> PAGE_SHIFT; ctx->num_pages = ctx->elements_per_skb * - (skb_shinfo(skb)->tso_segs + 1); + (skb_shinfo(skb)->gso_segs + 1); } ctx->num_elements = ctx->elements_per_skb * - (skb_shinfo(skb)->tso_segs + 1); + (skb_shinfo(skb)->gso_segs + 1); } static inline struct qeth_eddp_context * diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index 9e671a48cd2f..56009d768326 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -4417,7 +4417,7 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb) struct qeth_eddp_context *ctx = NULL; int tx_bytes = skb->len; unsigned short nr_frags = skb_shinfo(skb)->nr_frags; - unsigned short tso_size = skb_shinfo(skb)->tso_size; + unsigned short tso_size = skb_shinfo(skb)->gso_size; int rc; QETH_DBF_TEXT(trace, 6, "sendpkt"); @@ -4453,7 +4453,7 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb) queue = card->qdio.out_qs [qeth_get_priority_queue(card, skb, ipv, cast_type)]; - if (skb_shinfo(skb)->tso_size) + if (skb_shinfo(skb)->gso_size) large_send = card->options.large_send; /*are we able to do TSO ? If so ,prepare and send it from here */ diff --git a/drivers/s390/net/qeth_tso.h b/drivers/s390/net/qeth_tso.h index 24ef40ca9562..593f298142c1 100644 --- a/drivers/s390/net/qeth_tso.h +++ b/drivers/s390/net/qeth_tso.h @@ -51,7 +51,7 @@ qeth_tso_fill_header(struct qeth_card *card, struct sk_buff *skb) hdr->ext.hdr_version = 1; hdr->ext.hdr_len = 28; /*insert non-fix values */ - hdr->ext.mss = skb_shinfo(skb)->tso_size; + hdr->ext.mss = skb_shinfo(skb)->gso_size; hdr->ext.dg_hdr_len = (__u16)(iph->ihl*4 + tcph->doff*4); hdr->ext.payload_len = (__u16)(skb->len - hdr->ext.dg_hdr_len - sizeof(struct qeth_hdr_tso)); diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index cead6be467ed..fa5671307b90 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -308,9 +308,12 @@ struct net_device #define NETIF_F_HW_VLAN_RX 256 /* Receive VLAN hw acceleration */ #define NETIF_F_HW_VLAN_FILTER 512 /* Receive filtering on VLAN */ #define NETIF_F_VLAN_CHALLENGED 1024 /* Device cannot handle VLAN packets */ -#define NETIF_F_TSO 2048 /* Can offload TCP/IP segmentation */ #define NETIF_F_LLTX 4096 /* LockLess TX */ -#define NETIF_F_UFO 8192 /* Can offload UDP Large Send*/ + + /* Segmentation offload features */ +#define NETIF_F_GSO_SHIFT 16 +#define NETIF_F_TSO (SKB_GSO_TCPV4 << NETIF_F_GSO_SHIFT) +#define NETIF_F_UFO (SKB_GSO_UDPV4 << NETIF_F_GSO_SHIFT) #define NETIF_F_GEN_CSUM (NETIF_F_NO_CSUM | NETIF_F_HW_CSUM) #define NETIF_F_ALL_CSUM (NETIF_F_IP_CSUM | NETIF_F_GEN_CSUM) @@ -979,6 +982,13 @@ extern void dev_seq_stop(struct seq_file *seq, void *v); extern void linkwatch_run_queue(void); +static inline int netif_needs_gso(struct net_device *dev, struct sk_buff *skb) +{ + int feature = skb_shinfo(skb)->gso_type << NETIF_F_GSO_SHIFT; + return skb_shinfo(skb)->gso_size && + (dev->features & feature) != feature; +} + #endif /* __KERNEL__ */ #endif /* _LINUX_DEV_H */ diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index f8c7eb79a27f..97b0d2d1a6b0 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -134,9 +134,10 @@ struct skb_frag_struct { struct skb_shared_info { atomic_t dataref; unsigned short nr_frags; - unsigned short tso_size; - unsigned short tso_segs; - unsigned short ufo_size; + unsigned short gso_size; + /* Warning: this field is not always filled in (UFO)! */ + unsigned short gso_segs; + unsigned short gso_type; unsigned int ip6_frag_id; struct sk_buff *frag_list; skb_frag_t frags[MAX_SKB_FRAGS]; @@ -168,6 +169,11 @@ enum { SKB_FCLONE_CLONE, }; +enum { + SKB_GSO_TCPV4 = 1 << 0, + SKB_GSO_UDPV4 = 1 << 1, +}; + /** * struct sk_buff - socket buffer * @next: Next buffer in list diff --git a/include/net/tcp.h b/include/net/tcp.h index 5f4eb5c79689..b197a9e615c1 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -569,13 +569,13 @@ struct tcp_skb_cb { */ static inline int tcp_skb_pcount(const struct sk_buff *skb) { - return skb_shinfo(skb)->tso_segs; + return skb_shinfo(skb)->gso_segs; } /* This is valid iff tcp_skb_pcount() > 1. */ static inline int tcp_skb_mss(const struct sk_buff *skb) { - return skb_shinfo(skb)->tso_size; + return skb_shinfo(skb)->gso_size; } static inline void tcp_dec_pcount_approx(__u32 *count, diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c index 0dca027ceb80..8be9f2123e54 100644 --- a/net/bridge/br_forward.c +++ b/net/bridge/br_forward.c @@ -34,8 +34,8 @@ static inline unsigned packet_length(const struct sk_buff *skb) int br_dev_queue_push_xmit(struct sk_buff *skb) { - /* drop mtu oversized packets except tso */ - if (packet_length(skb) > skb->dev->mtu && !skb_shinfo(skb)->tso_size) + /* drop mtu oversized packets except gso */ + if (packet_length(skb) > skb->dev->mtu && !skb_shinfo(skb)->gso_size) kfree_skb(skb); else { #ifdef CONFIG_BRIDGE_NETFILTER diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 3e41f9d6d51c..8298a5179aef 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -761,7 +761,7 @@ static int br_nf_dev_queue_xmit(struct sk_buff *skb) { if (skb->protocol == htons(ETH_P_IP) && skb->len > skb->dev->mtu && - !(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size)) + !skb_shinfo(skb)->gso_size) return ip_fragment(skb, br_dev_queue_push_xmit); else return br_dev_queue_push_xmit(skb); diff --git a/net/core/skbuff.c b/net/core/skbuff.c index fe63d4efbd4d..368d98578c14 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -172,9 +172,9 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask, shinfo = skb_shinfo(skb); atomic_set(&shinfo->dataref, 1); shinfo->nr_frags = 0; - shinfo->tso_size = 0; - shinfo->tso_segs = 0; - shinfo->ufo_size = 0; + shinfo->gso_size = 0; + shinfo->gso_segs = 0; + shinfo->gso_type = 0; shinfo->ip6_frag_id = 0; shinfo->frag_list = NULL; @@ -238,8 +238,9 @@ struct sk_buff *alloc_skb_from_cache(kmem_cache_t *cp, atomic_set(&(skb_shinfo(skb)->dataref), 1); skb_shinfo(skb)->nr_frags = 0; - skb_shinfo(skb)->tso_size = 0; - skb_shinfo(skb)->tso_segs = 0; + skb_shinfo(skb)->gso_size = 0; + skb_shinfo(skb)->gso_segs = 0; + skb_shinfo(skb)->gso_type = 0; skb_shinfo(skb)->frag_list = NULL; out: return skb; @@ -528,8 +529,9 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old) #endif skb_copy_secmark(new, old); atomic_set(&new->users, 1); - skb_shinfo(new)->tso_size = skb_shinfo(old)->tso_size; - skb_shinfo(new)->tso_segs = skb_shinfo(old)->tso_segs; + skb_shinfo(new)->gso_size = skb_shinfo(old)->gso_size; + skb_shinfo(new)->gso_segs = skb_shinfo(old)->gso_segs; + skb_shinfo(new)->gso_type = skb_shinfo(old)->gso_type; } /** diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 8538aac3d148..7624fd1d8f9f 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -210,8 +210,7 @@ static inline int ip_finish_output(struct sk_buff *skb) return dst_output(skb); } #endif - if (skb->len > dst_mtu(skb->dst) && - !(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size)) + if (skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->gso_size) return ip_fragment(skb, ip_finish_output2); else return ip_finish_output2(skb); @@ -362,7 +361,7 @@ packet_routed: } ip_select_ident_more(iph, &rt->u.dst, sk, - (skb_shinfo(skb)->tso_segs ?: 1) - 1); + (skb_shinfo(skb)->gso_segs ?: 1) - 1); /* Add an IP checksum. */ ip_send_check(iph); @@ -744,7 +743,8 @@ static inline int ip_ufo_append_data(struct sock *sk, (length - transhdrlen)); if (!err) { /* specify the length of each IP datagram fragment*/ - skb_shinfo(skb)->ufo_size = (mtu - fragheaderlen); + skb_shinfo(skb)->gso_size = mtu - fragheaderlen; + skb_shinfo(skb)->gso_type = SKB_GSO_UDPV4; __skb_queue_tail(&sk->sk_write_queue, skb); return 0; @@ -1087,14 +1087,16 @@ ssize_t ip_append_page(struct sock *sk, struct page *page, inet->cork.length += size; if ((sk->sk_protocol == IPPROTO_UDP) && - (rt->u.dst.dev->features & NETIF_F_UFO)) - skb_shinfo(skb)->ufo_size = (mtu - fragheaderlen); + (rt->u.dst.dev->features & NETIF_F_UFO)) { + skb_shinfo(skb)->gso_size = mtu - fragheaderlen; + skb_shinfo(skb)->gso_type = SKB_GSO_UDPV4; + } while (size > 0) { int i; - if (skb_shinfo(skb)->ufo_size) + if (skb_shinfo(skb)->gso_size) len = size; else { diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 74998f250071..062dd1a0d8a8 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -571,7 +571,7 @@ new_segment: skb->ip_summed = CHECKSUM_HW; tp->write_seq += copy; TCP_SKB_CB(skb)->end_seq += copy; - skb_shinfo(skb)->tso_segs = 0; + skb_shinfo(skb)->gso_segs = 0; if (!copied) TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_PSH; @@ -818,7 +818,7 @@ new_segment: tp->write_seq += copy; TCP_SKB_CB(skb)->end_seq += copy; - skb_shinfo(skb)->tso_segs = 0; + skb_shinfo(skb)->gso_segs = 0; from += copy; copied += copy; diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index e08245bdda3a..94fe5b1f9dcb 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1073,7 +1073,7 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ else pkt_len = (end_seq - TCP_SKB_CB(skb)->seq); - if (tcp_fragment(sk, skb, pkt_len, skb_shinfo(skb)->tso_size)) + if (tcp_fragment(sk, skb, pkt_len, skb_shinfo(skb)->gso_size)) break; pcount = tcp_skb_pcount(skb); } diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 07bb5a2b375e..bdd71db8bf90 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -515,15 +515,17 @@ static void tcp_set_skb_tso_segs(struct sock *sk, struct sk_buff *skb, unsigned /* Avoid the costly divide in the normal * non-TSO case. */ - skb_shinfo(skb)->tso_segs = 1; - skb_shinfo(skb)->tso_size = 0; + skb_shinfo(skb)->gso_segs = 1; + skb_shinfo(skb)->gso_size = 0; + skb_shinfo(skb)->gso_type = 0; } else { unsigned int factor; factor = skb->len + (mss_now - 1); factor /= mss_now; - skb_shinfo(skb)->tso_segs = factor; - skb_shinfo(skb)->tso_size = mss_now; + skb_shinfo(skb)->gso_segs = factor; + skb_shinfo(skb)->gso_size = mss_now; + skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4; } } @@ -914,7 +916,7 @@ static int tcp_init_tso_segs(struct sock *sk, struct sk_buff *skb, unsigned int if (!tso_segs || (tso_segs > 1 && - skb_shinfo(skb)->tso_size != mss_now)) { + tcp_skb_mss(skb) != mss_now)) { tcp_set_skb_tso_segs(sk, skb, mss_now); tso_segs = tcp_skb_pcount(skb); } @@ -1724,8 +1726,9 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb) tp->snd_una == (TCP_SKB_CB(skb)->end_seq - 1)) { if (!pskb_trim(skb, 0)) { TCP_SKB_CB(skb)->seq = TCP_SKB_CB(skb)->end_seq - 1; - skb_shinfo(skb)->tso_segs = 1; - skb_shinfo(skb)->tso_size = 0; + skb_shinfo(skb)->gso_segs = 1; + skb_shinfo(skb)->gso_size = 0; + skb_shinfo(skb)->gso_type = 0; skb->ip_summed = CHECKSUM_NONE; skb->csum = 0; } @@ -1930,8 +1933,9 @@ void tcp_send_fin(struct sock *sk) skb->csum = 0; TCP_SKB_CB(skb)->flags = (TCPCB_FLAG_ACK | TCPCB_FLAG_FIN); TCP_SKB_CB(skb)->sacked = 0; - skb_shinfo(skb)->tso_segs = 1; - skb_shinfo(skb)->tso_size = 0; + skb_shinfo(skb)->gso_segs = 1; + skb_shinfo(skb)->gso_size = 0; + skb_shinfo(skb)->gso_type = 0; /* FIN eats a sequence byte, write_seq advanced by tcp_queue_skb(). */ TCP_SKB_CB(skb)->seq = tp->write_seq; @@ -1963,8 +1967,9 @@ void tcp_send_active_reset(struct sock *sk, gfp_t priority) skb->csum = 0; TCP_SKB_CB(skb)->flags = (TCPCB_FLAG_ACK | TCPCB_FLAG_RST); TCP_SKB_CB(skb)->sacked = 0; - skb_shinfo(skb)->tso_segs = 1; - skb_shinfo(skb)->tso_size = 0; + skb_shinfo(skb)->gso_segs = 1; + skb_shinfo(skb)->gso_size = 0; + skb_shinfo(skb)->gso_type = 0; /* Send it off. */ TCP_SKB_CB(skb)->seq = tcp_acceptable_seq(sk, tp); @@ -2047,8 +2052,9 @@ struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst, TCP_SKB_CB(skb)->seq = tcp_rsk(req)->snt_isn; TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq + 1; TCP_SKB_CB(skb)->sacked = 0; - skb_shinfo(skb)->tso_segs = 1; - skb_shinfo(skb)->tso_size = 0; + skb_shinfo(skb)->gso_segs = 1; + skb_shinfo(skb)->gso_size = 0; + skb_shinfo(skb)->gso_type = 0; th->seq = htonl(TCP_SKB_CB(skb)->seq); th->ack_seq = htonl(tcp_rsk(req)->rcv_isn + 1); if (req->rcv_wnd == 0) { /* ignored for retransmitted syns */ @@ -2152,8 +2158,9 @@ int tcp_connect(struct sock *sk) TCP_SKB_CB(buff)->flags = TCPCB_FLAG_SYN; TCP_ECN_send_syn(sk, tp, buff); TCP_SKB_CB(buff)->sacked = 0; - skb_shinfo(buff)->tso_segs = 1; - skb_shinfo(buff)->tso_size = 0; + skb_shinfo(buff)->gso_segs = 1; + skb_shinfo(buff)->gso_size = 0; + skb_shinfo(buff)->gso_type = 0; buff->csum = 0; TCP_SKB_CB(buff)->seq = tp->write_seq++; TCP_SKB_CB(buff)->end_seq = tp->write_seq; @@ -2257,8 +2264,9 @@ void tcp_send_ack(struct sock *sk) buff->csum = 0; TCP_SKB_CB(buff)->flags = TCPCB_FLAG_ACK; TCP_SKB_CB(buff)->sacked = 0; - skb_shinfo(buff)->tso_segs = 1; - skb_shinfo(buff)->tso_size = 0; + skb_shinfo(buff)->gso_segs = 1; + skb_shinfo(buff)->gso_size = 0; + skb_shinfo(buff)->gso_type = 0; /* Send it off, this clears delayed acks for us. */ TCP_SKB_CB(buff)->seq = TCP_SKB_CB(buff)->end_seq = tcp_acceptable_seq(sk, tp); @@ -2293,8 +2301,9 @@ static int tcp_xmit_probe_skb(struct sock *sk, int urgent) skb->csum = 0; TCP_SKB_CB(skb)->flags = TCPCB_FLAG_ACK; TCP_SKB_CB(skb)->sacked = urgent; - skb_shinfo(skb)->tso_segs = 1; - skb_shinfo(skb)->tso_size = 0; + skb_shinfo(skb)->gso_segs = 1; + skb_shinfo(skb)->gso_size = 0; + skb_shinfo(skb)->gso_type = 0; /* Use a previous sequence. This should cause the other * end to send an ack. Don't queue or clone SKB, just diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index d29620f4910e..abb94de33768 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -148,7 +148,7 @@ static int ip6_output2(struct sk_buff *skb) int ip6_output(struct sk_buff *skb) { - if ((skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->ufo_size) || + if ((skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->gso_size) || dst_allfrag(skb->dst)) return ip6_fragment(skb, ip6_output2); else @@ -833,8 +833,9 @@ static inline int ip6_ufo_append_data(struct sock *sk, struct frag_hdr fhdr; /* specify the length of each IP datagram fragment*/ - skb_shinfo(skb)->ufo_size = (mtu - fragheaderlen) - - sizeof(struct frag_hdr); + skb_shinfo(skb)->gso_size = mtu - fragheaderlen - + sizeof(struct frag_hdr); + skb_shinfo(skb)->gso_type = SKB_GSO_UDPV4; ipv6_select_ident(skb, &fhdr); skb_shinfo(skb)->ip6_frag_id = fhdr.identification; __skb_queue_tail(&sk->sk_write_queue, skb); -- cgit v1.2.3 From f6a78bfcb141f963187464bac838d46a81c3882a Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 22 Jun 2006 02:57:17 -0700 Subject: [NET]: Add generic segmentation offload This patch adds the infrastructure for generic segmentation offload. The idea is to tap into the potential savings of TSO without hardware support by postponing the allocation of segmented skb's until just before the entry point into the NIC driver. The same structure can be used to support software IPv6 TSO, as well as UFO and segmentation offload for other relevant protocols, e.g., DCCP. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- include/linux/netdevice.h | 8 ++- net/core/dev.c | 127 ++++++++++++++++++++++++++++++++++++++++++++-- net/sched/sch_generic.c | 19 +++++-- 3 files changed, 143 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index fa5671307b90..b4eae18390cc 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -405,6 +405,9 @@ struct net_device struct list_head qdisc_list; unsigned long tx_queue_len; /* Max frames per queue allowed */ + /* Partially transmitted GSO packet. */ + struct sk_buff *gso_skb; + /* ingress path synchronizer */ spinlock_t ingress_lock; struct Qdisc *qdisc_ingress; @@ -539,6 +542,7 @@ struct packet_type { struct net_device *, struct packet_type *, struct net_device *); + struct sk_buff *(*gso_segment)(struct sk_buff *skb, int sg); void *af_packet_priv; struct list_head list; }; @@ -689,7 +693,8 @@ extern int dev_change_name(struct net_device *, char *); extern int dev_set_mtu(struct net_device *, int); extern int dev_set_mac_address(struct net_device *, struct sockaddr *); -extern void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev); +extern int dev_hard_start_xmit(struct sk_buff *skb, + struct net_device *dev); extern void dev_init(void); @@ -963,6 +968,7 @@ extern int netdev_max_backlog; extern int weight_p; extern int netdev_set_master(struct net_device *dev, struct net_device *master); extern int skb_checksum_help(struct sk_buff *skb, int inward); +extern struct sk_buff *skb_gso_segment(struct sk_buff *skb, int sg); #ifdef CONFIG_BUG extern void netdev_rx_csum_fault(struct net_device *dev); #else diff --git a/net/core/dev.c b/net/core/dev.c index 29e3888102bc..d293e0f90a0c 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -116,6 +116,7 @@ #include #include #include +#include /* * The list of packet types we will receive (as opposed to discard) @@ -1048,7 +1049,7 @@ static inline void net_timestamp(struct sk_buff *skb) * taps currently in use. */ -void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev) +static void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev) { struct packet_type *ptype; @@ -1186,6 +1187,40 @@ out: return ret; } +/** + * skb_gso_segment - Perform segmentation on skb. + * @skb: buffer to segment + * @sg: whether scatter-gather is supported on the target. + * + * This function segments the given skb and returns a list of segments. + */ +struct sk_buff *skb_gso_segment(struct sk_buff *skb, int sg) +{ + struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT); + struct packet_type *ptype; + int type = skb->protocol; + + BUG_ON(skb_shinfo(skb)->frag_list); + BUG_ON(skb->ip_summed != CHECKSUM_HW); + + skb->mac.raw = skb->data; + skb->mac_len = skb->nh.raw - skb->data; + __skb_pull(skb, skb->mac_len); + + rcu_read_lock(); + list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type) & 15], list) { + if (ptype->type == type && !ptype->dev && ptype->gso_segment) { + segs = ptype->gso_segment(skb, sg); + break; + } + } + rcu_read_unlock(); + + return segs; +} + +EXPORT_SYMBOL(skb_gso_segment); + /* Take action when hardware reception checksum errors are detected. */ #ifdef CONFIG_BUG void netdev_rx_csum_fault(struct net_device *dev) @@ -1222,6 +1257,86 @@ static inline int illegal_highdma(struct net_device *dev, struct sk_buff *skb) #define illegal_highdma(dev, skb) (0) #endif +struct dev_gso_cb { + void (*destructor)(struct sk_buff *skb); +}; + +#define DEV_GSO_CB(skb) ((struct dev_gso_cb *)(skb)->cb) + +static void dev_gso_skb_destructor(struct sk_buff *skb) +{ + struct dev_gso_cb *cb; + + do { + struct sk_buff *nskb = skb->next; + + skb->next = nskb->next; + nskb->next = NULL; + kfree_skb(nskb); + } while (skb->next); + + cb = DEV_GSO_CB(skb); + if (cb->destructor) + cb->destructor(skb); +} + +/** + * dev_gso_segment - Perform emulated hardware segmentation on skb. + * @skb: buffer to segment + * + * This function segments the given skb and stores the list of segments + * in skb->next. + */ +static int dev_gso_segment(struct sk_buff *skb) +{ + struct net_device *dev = skb->dev; + struct sk_buff *segs; + + segs = skb_gso_segment(skb, dev->features & NETIF_F_SG && + !illegal_highdma(dev, skb)); + if (unlikely(IS_ERR(segs))) + return PTR_ERR(segs); + + skb->next = segs; + DEV_GSO_CB(skb)->destructor = skb->destructor; + skb->destructor = dev_gso_skb_destructor; + + return 0; +} + +int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + if (likely(!skb->next)) { + if (netdev_nit) + dev_queue_xmit_nit(skb, dev); + + if (!netif_needs_gso(dev, skb)) + return dev->hard_start_xmit(skb, dev); + + if (unlikely(dev_gso_segment(skb))) + goto out_kfree_skb; + } + + do { + struct sk_buff *nskb = skb->next; + int rc; + + skb->next = nskb->next; + nskb->next = NULL; + rc = dev->hard_start_xmit(nskb, dev); + if (unlikely(rc)) { + skb->next = nskb; + return rc; + } + } while (skb->next); + + skb->destructor = DEV_GSO_CB(skb)->destructor; + +out_kfree_skb: + kfree_skb(skb); + return 0; +} + #define HARD_TX_LOCK(dev, cpu) { \ if ((dev->features & NETIF_F_LLTX) == 0) { \ netif_tx_lock(dev); \ @@ -1266,6 +1381,10 @@ int dev_queue_xmit(struct sk_buff *skb) struct Qdisc *q; int rc = -ENOMEM; + /* GSO will handle the following emulations directly. */ + if (netif_needs_gso(dev, skb)) + goto gso; + if (skb_shinfo(skb)->frag_list && !(dev->features & NETIF_F_FRAGLIST) && __skb_linearize(skb)) @@ -1290,6 +1409,7 @@ int dev_queue_xmit(struct sk_buff *skb) if (skb_checksum_help(skb, 0)) goto out_kfree_skb; +gso: spin_lock_prefetch(&dev->queue_lock); /* Disable soft irqs for various locks below. Also @@ -1346,11 +1466,8 @@ int dev_queue_xmit(struct sk_buff *skb) HARD_TX_LOCK(dev, cpu); if (!netif_queue_stopped(dev)) { - if (netdev_nit) - dev_queue_xmit_nit(skb, dev); - rc = 0; - if (!dev->hard_start_xmit(skb, dev)) { + if (!dev_hard_start_xmit(skb, dev)) { HARD_TX_UNLOCK(dev); goto out; } diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 7aad0121232c..74d4a1dceeec 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -96,8 +96,11 @@ static inline int qdisc_restart(struct net_device *dev) struct sk_buff *skb; /* Dequeue packet */ - if ((skb = q->dequeue(q)) != NULL) { + if (((skb = dev->gso_skb)) || ((skb = q->dequeue(q)))) { unsigned nolock = (dev->features & NETIF_F_LLTX); + + dev->gso_skb = NULL; + /* * When the driver has LLTX set it does its own locking * in start_xmit. No need to add additional overhead by @@ -134,10 +137,8 @@ static inline int qdisc_restart(struct net_device *dev) if (!netif_queue_stopped(dev)) { int ret; - if (netdev_nit) - dev_queue_xmit_nit(skb, dev); - ret = dev->hard_start_xmit(skb, dev); + ret = dev_hard_start_xmit(skb, dev); if (ret == NETDEV_TX_OK) { if (!nolock) { netif_tx_unlock(dev); @@ -171,7 +172,10 @@ static inline int qdisc_restart(struct net_device *dev) */ requeue: - q->ops->requeue(skb, q); + if (skb->next) + dev->gso_skb = skb; + else + q->ops->requeue(skb, q); netif_schedule(dev); return 1; } @@ -593,6 +597,11 @@ void dev_deactivate(struct net_device *dev) /* Wait for outstanding qdisc_run calls. */ while (test_bit(__LINK_STATE_QDISC_RUNNING, &dev->state)) yield(); + + if (dev->gso_skb) { + kfree_skb(dev->gso_skb); + dev->gso_skb = NULL; + } } void dev_init_scheduler(struct net_device *dev) -- cgit v1.2.3 From f4c50d990dcf11a296679dc05de3873783236711 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 22 Jun 2006 03:02:40 -0700 Subject: [NET]: Add software TSOv4 This patch adds the GSO implementation for IPv4 TCP. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- include/linux/skbuff.h | 1 + include/net/protocol.h | 1 + include/net/tcp.h | 2 + net/core/skbuff.c | 126 +++++++++++++++++++++++++++++++++++++++++++++++++ net/ipv4/af_inet.c | 51 ++++++++++++++++++++ net/ipv4/tcp.c | 62 ++++++++++++++++++++++++ 6 files changed, 243 insertions(+) (limited to 'include') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 97b0d2d1a6b0..a45bba9b8cbd 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1297,6 +1297,7 @@ extern void skb_split(struct sk_buff *skb, struct sk_buff *skb1, const u32 len); extern void skb_release_data(struct sk_buff *skb); +extern struct sk_buff *skb_segment(struct sk_buff *skb, int sg); static inline void *skb_header_pointer(const struct sk_buff *skb, int offset, int len, void *buffer) diff --git a/include/net/protocol.h b/include/net/protocol.h index bcaee39bd2ff..3b6dc15c68a5 100644 --- a/include/net/protocol.h +++ b/include/net/protocol.h @@ -36,6 +36,7 @@ struct net_protocol { int (*handler)(struct sk_buff *skb); void (*err_handler)(struct sk_buff *skb, u32 info); + struct sk_buff *(*gso_segment)(struct sk_buff *skb, int sg); int no_policy; }; diff --git a/include/net/tcp.h b/include/net/tcp.h index b197a9e615c1..ca3d38dfc00b 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1086,6 +1086,8 @@ extern struct request_sock_ops tcp_request_sock_ops; extern int tcp_v4_destroy_sock(struct sock *sk); +extern struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int sg); + #ifdef CONFIG_PROC_FS extern int tcp4_proc_init(void); extern void tcp4_proc_exit(void); diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 368d98578c14..8e5044ba3ab6 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -1842,6 +1842,132 @@ unsigned char *skb_pull_rcsum(struct sk_buff *skb, unsigned int len) EXPORT_SYMBOL_GPL(skb_pull_rcsum); +/** + * skb_segment - Perform protocol segmentation on skb. + * @skb: buffer to segment + * @sg: whether scatter-gather can be used for generated segments + * + * This function performs segmentation on the given skb. It returns + * the segment at the given position. It returns NULL if there are + * no more segments to generate, or when an error is encountered. + */ +struct sk_buff *skb_segment(struct sk_buff *skb, int sg) +{ + struct sk_buff *segs = NULL; + struct sk_buff *tail = NULL; + unsigned int mss = skb_shinfo(skb)->gso_size; + unsigned int doffset = skb->data - skb->mac.raw; + unsigned int offset = doffset; + unsigned int headroom; + unsigned int len; + int nfrags = skb_shinfo(skb)->nr_frags; + int err = -ENOMEM; + int i = 0; + int pos; + + __skb_push(skb, doffset); + headroom = skb_headroom(skb); + pos = skb_headlen(skb); + + do { + struct sk_buff *nskb; + skb_frag_t *frag; + int hsize, nsize; + int k; + int size; + + len = skb->len - offset; + if (len > mss) + len = mss; + + hsize = skb_headlen(skb) - offset; + if (hsize < 0) + hsize = 0; + nsize = hsize + doffset; + if (nsize > len + doffset || !sg) + nsize = len + doffset; + + nskb = alloc_skb(nsize + headroom, GFP_ATOMIC); + if (unlikely(!nskb)) + goto err; + + if (segs) + tail->next = nskb; + else + segs = nskb; + tail = nskb; + + nskb->dev = skb->dev; + nskb->priority = skb->priority; + nskb->protocol = skb->protocol; + nskb->dst = dst_clone(skb->dst); + memcpy(nskb->cb, skb->cb, sizeof(skb->cb)); + nskb->pkt_type = skb->pkt_type; + nskb->mac_len = skb->mac_len; + + skb_reserve(nskb, headroom); + nskb->mac.raw = nskb->data; + nskb->nh.raw = nskb->data + skb->mac_len; + nskb->h.raw = nskb->nh.raw + (skb->h.raw - skb->nh.raw); + memcpy(skb_put(nskb, doffset), skb->data, doffset); + + if (!sg) { + nskb->csum = skb_copy_and_csum_bits(skb, offset, + skb_put(nskb, len), + len, 0); + continue; + } + + frag = skb_shinfo(nskb)->frags; + k = 0; + + nskb->ip_summed = CHECKSUM_HW; + nskb->csum = skb->csum; + memcpy(skb_put(nskb, hsize), skb->data + offset, hsize); + + while (pos < offset + len) { + BUG_ON(i >= nfrags); + + *frag = skb_shinfo(skb)->frags[i]; + get_page(frag->page); + size = frag->size; + + if (pos < offset) { + frag->page_offset += offset - pos; + frag->size -= offset - pos; + } + + k++; + + if (pos + size <= offset + len) { + i++; + pos += size; + } else { + frag->size -= pos + size - (offset + len); + break; + } + + frag++; + } + + skb_shinfo(nskb)->nr_frags = k; + nskb->data_len = len - hsize; + nskb->len += nskb->data_len; + nskb->truesize += nskb->data_len; + } while ((offset += len) < skb->len); + + return segs; + +err: + while ((skb = segs)) { + segs = skb->next; + kfree(skb); + } + return ERR_PTR(err); +} + +EXPORT_SYMBOL_GPL(skb_segment); + void __init skb_init(void) { skbuff_head_cache = kmem_cache_create("skbuff_head_cache", diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 0a277453526b..461216b47948 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -68,6 +68,7 @@ */ #include +#include #include #include #include @@ -1096,6 +1097,54 @@ int inet_sk_rebuild_header(struct sock *sk) EXPORT_SYMBOL(inet_sk_rebuild_header); +static struct sk_buff *inet_gso_segment(struct sk_buff *skb, int sg) +{ + struct sk_buff *segs = ERR_PTR(-EINVAL); + struct iphdr *iph; + struct net_protocol *ops; + int proto; + int ihl; + int id; + + if (!pskb_may_pull(skb, sizeof(*iph))) + goto out; + + iph = skb->nh.iph; + ihl = iph->ihl * 4; + if (ihl < sizeof(*iph)) + goto out; + + if (!pskb_may_pull(skb, ihl)) + goto out; + + skb->h.raw = __skb_pull(skb, ihl); + iph = skb->nh.iph; + id = ntohs(iph->id); + proto = iph->protocol & (MAX_INET_PROTOS - 1); + segs = ERR_PTR(-EPROTONOSUPPORT); + + rcu_read_lock(); + ops = rcu_dereference(inet_protos[proto]); + if (ops && ops->gso_segment) + segs = ops->gso_segment(skb, sg); + rcu_read_unlock(); + + if (IS_ERR(segs)) + goto out; + + skb = segs; + do { + iph = skb->nh.iph; + iph->id = htons(id++); + iph->tot_len = htons(skb->len - skb->mac_len); + iph->check = 0; + iph->check = ip_fast_csum(skb->nh.raw, iph->ihl); + } while ((skb = skb->next)); + +out: + return segs; +} + #ifdef CONFIG_IP_MULTICAST static struct net_protocol igmp_protocol = { .handler = igmp_rcv, @@ -1105,6 +1154,7 @@ static struct net_protocol igmp_protocol = { static struct net_protocol tcp_protocol = { .handler = tcp_v4_rcv, .err_handler = tcp_v4_err, + .gso_segment = tcp_tso_segment, .no_policy = 1, }; @@ -1150,6 +1200,7 @@ static int ipv4_proc_init(void); static struct packet_type ip_packet_type = { .type = __constant_htons(ETH_P_IP), .func = ip_rcv, + .gso_segment = inet_gso_segment, }; static int __init inet_init(void) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 062dd1a0d8a8..0e029c4e2903 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -258,6 +258,7 @@ #include #include #include +#include #include #include @@ -2144,6 +2145,67 @@ int compat_tcp_getsockopt(struct sock *sk, int level, int optname, EXPORT_SYMBOL(compat_tcp_getsockopt); #endif +struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int sg) +{ + struct sk_buff *segs = ERR_PTR(-EINVAL); + struct tcphdr *th; + unsigned thlen; + unsigned int seq; + unsigned int delta; + unsigned int oldlen; + unsigned int len; + + if (!pskb_may_pull(skb, sizeof(*th))) + goto out; + + th = skb->h.th; + thlen = th->doff * 4; + if (thlen < sizeof(*th)) + goto out; + + if (!pskb_may_pull(skb, thlen)) + goto out; + + oldlen = ~htonl(skb->len); + __skb_pull(skb, thlen); + + segs = skb_segment(skb, sg); + if (IS_ERR(segs)) + goto out; + + len = skb_shinfo(skb)->gso_size; + delta = csum_add(oldlen, htonl(thlen + len)); + + skb = segs; + th = skb->h.th; + seq = ntohl(th->seq); + + do { + th->fin = th->psh = 0; + + if (skb->ip_summed == CHECKSUM_NONE) { + th->check = csum_fold(csum_partial( + skb->h.raw, thlen, csum_add(skb->csum, delta))); + } + + seq += len; + skb = skb->next; + th = skb->h.th; + + th->seq = htonl(seq); + th->cwr = 0; + } while (skb->next); + + if (skb->ip_summed == CHECKSUM_NONE) { + delta = csum_add(oldlen, htonl(skb->tail - skb->h.raw)); + th->check = csum_fold(csum_partial( + skb->h.raw, thlen, csum_add(skb->csum, delta))); + } + +out: + return segs; +} + extern void __skb_cb_too_small_for_tcp(int, int); extern struct tcp_congestion_ops tcp_reno; -- cgit v1.2.3 From 37c3185a02d4b85fbe134bf5204535405dd2c957 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 22 Jun 2006 03:07:29 -0700 Subject: [NET]: Added GSO toggle This patch adds a generic segmentation offload toggle that can be turned on/off for each net device. For now it only supports in TCPv4. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- include/linux/ethtool.h | 2 ++ include/linux/netdevice.h | 1 + include/net/sock.h | 4 ++++ net/bridge/br_if.c | 17 +++++++++++------ net/core/ethtool.c | 29 +++++++++++++++++++++++++++++ 5 files changed, 47 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index cf2abeca92a0..c6310aef5ab0 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -411,6 +411,8 @@ struct ethtool_ops { #define ETHTOOL_GPERMADDR 0x00000020 /* Get permanent hardware address */ #define ETHTOOL_GUFO 0x00000021 /* Get UFO enable (ethtool_value) */ #define ETHTOOL_SUFO 0x00000022 /* Set UFO enable (ethtool_value) */ +#define ETHTOOL_GGSO 0x00000023 /* Get GSO enable (ethtool_value) */ +#define ETHTOOL_SGSO 0x00000024 /* Set GSO enable (ethtool_value) */ /* compatibility with older code */ #define SPARC_ETH_GSET ETHTOOL_GSET diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index b4eae18390cc..bc747e5d7138 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -308,6 +308,7 @@ struct net_device #define NETIF_F_HW_VLAN_RX 256 /* Receive VLAN hw acceleration */ #define NETIF_F_HW_VLAN_FILTER 512 /* Receive filtering on VLAN */ #define NETIF_F_VLAN_CHALLENGED 1024 /* Device cannot handle VLAN packets */ +#define NETIF_F_GSO 2048 /* Enable software GSO. */ #define NETIF_F_LLTX 4096 /* LockLess TX */ /* Segmentation offload features */ diff --git a/include/net/sock.h b/include/net/sock.h index d10dfecb6cbd..a897f05de3b5 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1030,9 +1030,13 @@ static inline void sk_setup_caps(struct sock *sk, struct dst_entry *dst) { __sk_dst_set(sk, dst); sk->sk_route_caps = dst->dev->features; + if (sk->sk_route_caps & NETIF_F_GSO) + sk->sk_route_caps |= NETIF_F_TSO; if (sk->sk_route_caps & NETIF_F_TSO) { if (sock_flag(sk, SOCK_NO_LARGESEND) || dst->header_len) sk->sk_route_caps &= ~NETIF_F_TSO; + else + sk->sk_route_caps |= NETIF_F_SG | NETIF_F_HW_CSUM; } } diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index fdec773f5b52..07956ecf545e 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -376,15 +376,20 @@ void br_features_recompute(struct net_bridge *br) features = br->feature_mask & ~NETIF_F_ALL_CSUM; list_for_each_entry(p, &br->port_list, list) { - if (checksum & NETIF_F_NO_CSUM && - !(p->dev->features & NETIF_F_NO_CSUM)) + unsigned long feature = p->dev->features; + + if (checksum & NETIF_F_NO_CSUM && !(feature & NETIF_F_NO_CSUM)) checksum ^= NETIF_F_NO_CSUM | NETIF_F_HW_CSUM; - if (checksum & NETIF_F_HW_CSUM && - !(p->dev->features & NETIF_F_HW_CSUM)) + if (checksum & NETIF_F_HW_CSUM && !(feature & NETIF_F_HW_CSUM)) checksum ^= NETIF_F_HW_CSUM | NETIF_F_IP_CSUM; - if (!(p->dev->features & NETIF_F_IP_CSUM)) + if (!(feature & NETIF_F_IP_CSUM)) checksum = 0; - features &= p->dev->features; + + if (feature & NETIF_F_GSO) + feature |= NETIF_F_TSO; + feature |= NETIF_F_GSO; + + features &= feature; } br->dev->features = features | checksum | NETIF_F_LLTX; diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 33ce7ed6afc6..27ce1683caf5 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -614,6 +614,29 @@ static int ethtool_set_ufo(struct net_device *dev, char __user *useraddr) return dev->ethtool_ops->set_ufo(dev, edata.data); } +static int ethtool_get_gso(struct net_device *dev, char __user *useraddr) +{ + struct ethtool_value edata = { ETHTOOL_GGSO }; + + edata.data = dev->features & NETIF_F_GSO; + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; +} + +static int ethtool_set_gso(struct net_device *dev, char __user *useraddr) +{ + struct ethtool_value edata; + + if (copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + if (edata.data) + dev->features |= NETIF_F_GSO; + else + dev->features &= ~NETIF_F_GSO; + return 0; +} + static int ethtool_self_test(struct net_device *dev, char __user *useraddr) { struct ethtool_test test; @@ -905,6 +928,12 @@ int dev_ethtool(struct ifreq *ifr) case ETHTOOL_SUFO: rc = ethtool_set_ufo(dev, useraddr); break; + case ETHTOOL_GGSO: + rc = ethtool_get_gso(dev, useraddr); + break; + case ETHTOOL_SGSO: + rc = ethtool_set_gso(dev, useraddr); + break; default: rc = -EOPNOTSUPP; } -- cgit v1.2.3 From c8a553ad7f0bf943047943a758cf07017819cb3c Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Thu, 22 Jun 2006 14:28:09 -0700 Subject: [TCP]: Move inclusion of to correct place in The new header shouldn't be included from the !__KERNEL__ portion of tcp.h Signed-off-by: David Woodhouse Signed-off-by: David S. Miller --- include/linux/tcp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 420a689c3fb4..8ebf497907f8 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -18,7 +18,6 @@ #define _LINUX_TCP_H #include -#include #include struct tcphdr { @@ -161,6 +160,7 @@ struct tcp_info #ifdef __KERNEL__ #include +#include #include #include #include -- cgit v1.2.3 From f4b8ea7849544114e9d3d682df4d400180854677 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 22 Jun 2006 16:00:11 -0700 Subject: [NET]: fix net-core kernel-doc Warning(/var/linsrc/linux-2617-g4//include/linux/skbuff.h:304): No description found for parameter 'dma_cookie' Warning(/var/linsrc/linux-2617-g4//include/net/sock.h:1274): No description found for parameter 'copied_early' Warning(/var/linsrc/linux-2617-g4//net/core/dev.c:3309): No description found for parameter 'chan' Warning(/var/linsrc/linux-2617-g4//net/core/dev.c:3309): No description found for parameter 'event' Signed-off-by: Randy Dunlap Signed-off-by: David S. Miller --- include/linux/skbuff.h | 2 ++ include/net/sock.h | 1 + net/core/dev.c | 4 ++-- 3 files changed, 5 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index a45bba9b8cbd..16eef03ce0eb 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -215,6 +215,8 @@ enum { * @nf_bridge: Saved data about a bridged frame - see br_netfilter.c * @tc_index: Traffic control index * @tc_verd: traffic control verdict + * @dma_cookie: a cookie to one of several possible DMA operations + * done by skb DMA functions * @secmark: security marking */ diff --git a/include/net/sock.h b/include/net/sock.h index a897f05de3b5..2d8d6adf1616 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1269,6 +1269,7 @@ sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb) * sk_eat_skb - Release a skb if it is no longer needed * @sk: socket to eat this skb from * @skb: socket buffer to eat + * @copied_early: flag indicating whether DMA operations copied this data early * * This routine must be called with interrupts disabled or with the socket * locked so that the sk_buff queue operation is ok. diff --git a/net/core/dev.c b/net/core/dev.c index d293e0f90a0c..9b8f0f22c81d 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3418,8 +3418,8 @@ static void net_dma_rebalance(void) /** * netdev_dma_event - event callback for the net_dma_client * @client: should always be net_dma_client - * @chan: - * @event: + * @chan: DMA channel for the event + * @event: event type */ static void netdev_dma_event(struct dma_client *client, struct dma_chan *chan, enum dma_event event) -- cgit v1.2.3 From 454e2398be9b9fa30433fccc548db34d19aa9958 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 23 Jun 2006 02:02:57 -0700 Subject: [PATCH] VFS: Permit filesystem to override root dentry on mount Extend the get_sb() filesystem operation to take an extra argument that permits the VFS to pass in the target vfsmount that defines the mountpoint. The filesystem is then required to manually set the superblock and root dentry pointers. For most filesystems, this should be done with simple_set_mnt() which will set the superblock pointer and then set the root dentry to the superblock's s_root (as per the old default behaviour). The get_sb() op now returns an integer as there's now no need to return the superblock pointer. This patch permits a superblock to be implicitly shared amongst several mount points, such as can be done with NFS to avoid potential inode aliasing. In such a case, simple_set_mnt() would not be called, and instead the mnt_root and mnt_sb would be set directly. The patch also makes the following changes: (*) the get_sb_*() convenience functions in the core kernel now take a vfsmount pointer argument and return an integer, so most filesystems have to change very little. (*) If one of the convenience function is not used, then get_sb() should normally call simple_set_mnt() to instantiate the vfsmount. This will always return 0, and so can be tail-called from get_sb(). (*) generic_shutdown_super() now calls shrink_dcache_sb() to clean up the dcache upon superblock destruction rather than shrink_dcache_anon(). This is required because the superblock may now have multiple trees that aren't actually bound to s_root, but that still need to be cleaned up. The currently called functions assume that the whole tree is rooted at s_root, and that anonymous dentries are not the roots of trees which results in dentries being left unculled. However, with the way NFS superblock sharing are currently set to be implemented, these assumptions are violated: the root of the filesystem is simply a dummy dentry and inode (the real inode for '/' may well be inaccessible), and all the vfsmounts are rooted on anonymous[*] dentries with child trees. [*] Anonymous until discovered from another tree. (*) The documentation has been adjusted, including the additional bit of changing ext2_* into foo_* in the documentation. [akpm@osdl.org: convert ipath_fs, do other stuff] Signed-off-by: David Howells Acked-by: Al Viro Cc: Nathan Scott Cc: Roland Dreier Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/filesystems/Locking | 7 +- Documentation/filesystems/porting | 7 +- Documentation/filesystems/vfs.txt | 4 +- arch/ia64/kernel/perfmon.c | 7 +- arch/powerpc/platforms/cell/spufs/inode.c | 6 +- drivers/infiniband/core/uverbs_main.c | 7 +- drivers/infiniband/hw/ipath/ipath_fs.c | 13 ++-- drivers/isdn/capi/capifs.c | 6 +- drivers/misc/ibmasm/ibmasmfs.c | 7 +- drivers/oprofile/oprofilefs.c | 6 +- drivers/usb/core/inode.c | 6 +- drivers/usb/gadget/inode.c | 6 +- fs/9p/vfs_super.c | 21 +++--- fs/adfs/super.c | 7 +- fs/affs/super.c | 7 +- fs/afs/super.c | 24 ++++--- fs/autofs/init.c | 6 +- fs/autofs4/init.c | 6 +- fs/befs/linuxvfs.c | 7 +- fs/bfs/inode.c | 6 +- fs/binfmt_misc.c | 6 +- fs/block_dev.c | 6 +- fs/cifs/cifsfs.c | 10 +-- fs/coda/inode.c | 6 +- fs/configfs/mount.c | 6 +- fs/cramfs/inode.c | 7 +- fs/dcache.c | 40 ----------- fs/debugfs/inode.c | 8 +-- fs/devfs/base.c | 8 +-- fs/devpts/inode.c | 6 +- fs/efs/super.c | 6 +- fs/eventpoll.c | 13 ++-- fs/ext2/super.c | 6 +- fs/ext3/super.c | 6 +- fs/freevxfs/vxfs_super.c | 7 +- fs/fuse/inode.c | 8 +-- fs/hfs/super.c | 7 +- fs/hfsplus/super.c | 8 ++- fs/hostfs/hostfs_kern.c | 8 +-- fs/hpfs/super.c | 7 +- fs/hppfs/hppfs_kern.c | 8 +-- fs/hugetlbfs/inode.c | 6 +- fs/inotify_user.c | 6 +- fs/isofs/inode.c | 7 +- fs/jffs/inode-v23.c | 7 +- fs/jffs2/super.c | 49 ++++++++------ fs/jfs/super.c | 7 +- fs/libfs.c | 12 ++-- fs/minix/inode.c | 7 +- fs/msdos/namei.c | 9 +-- fs/namespace.c | 9 +++ fs/ncpfs/inode.c | 6 +- fs/nfs/inode.c | 96 +++++++++++++++----------- fs/nfsd/nfsctl.c | 6 +- fs/ntfs/super.c | 7 +- fs/ocfs2/dlm/dlmfs.c | 6 +- fs/ocfs2/super.c | 12 ++-- fs/openpromfs/inode.c | 6 +- fs/pipe.c | 9 ++- fs/proc/root.c | 6 +- fs/qnx4/inode.c | 7 +- fs/ramfs/inode.c | 13 ++-- fs/reiserfs/super.c | 9 +-- fs/romfs/inode.c | 7 +- fs/smbfs/inode.c | 6 +- fs/super.c | 109 +++++++++++++++++------------- fs/sysfs/mount.c | 6 +- fs/sysv/super.c | 13 ++-- fs/udf/super.c | 6 +- fs/ufs/super.c | 6 +- fs/vfat/namei.c | 9 +-- fs/xfs/linux-2.6/xfs_super.c | 8 ++- include/linux/dcache.h | 1 - include/linux/fs.h | 25 ++++--- include/linux/ramfs.h | 4 +- ipc/mqueue.c | 8 +-- kernel/cpuset.c | 8 +-- kernel/futex.c | 8 +-- mm/shmem.c | 6 +- net/socket.c | 7 +- net/sunrpc/rpc_pipe.c | 6 +- security/inode.c | 8 +-- security/selinux/selinuxfs.c | 7 +- 83 files changed, 482 insertions(+), 431 deletions(-) (limited to 'include') diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking index 1045da582b9b..3abf08f1b14a 100644 --- a/Documentation/filesystems/Locking +++ b/Documentation/filesystems/Locking @@ -142,15 +142,16 @@ see also dquot_operations section. --------------------------- file_system_type --------------------------- prototypes: - struct super_block *(*get_sb) (struct file_system_type *, int, - const char *, void *); + struct int (*get_sb) (struct file_system_type *, int, + const char *, void *, struct vfsmount *); void (*kill_sb) (struct super_block *); locking rules: may block BKL get_sb yes yes kill_sb yes yes -->get_sb() returns error or a locked superblock (exclusive on ->s_umount). +->get_sb() returns error or 0 with locked superblock attached to the vfsmount +(exclusive on ->s_umount). ->kill_sb() takes a write-locked superblock, does all shutdown work on it, unlocks and drops the reference. diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting index 2f388460cbe7..5531694059ab 100644 --- a/Documentation/filesystems/porting +++ b/Documentation/filesystems/porting @@ -50,10 +50,11 @@ Turn your foo_read_super() into a function that would return 0 in case of success and negative number in case of error (-EINVAL unless you have more informative error value to report). Call it foo_fill_super(). Now declare -struct super_block foo_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +int foo_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_bdev(fs_type, flags, dev_name, data, ext2_fill_super); + return get_sb_bdev(fs_type, flags, dev_name, data, foo_fill_super, + mnt); } (or similar with s/bdev/nodev/ or s/bdev/single/, depending on the kind of diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt index 3a2e5520c1e3..dd7d0dcedc87 100644 --- a/Documentation/filesystems/vfs.txt +++ b/Documentation/filesystems/vfs.txt @@ -113,8 +113,8 @@ members are defined: struct file_system_type { const char *name; int fs_flags; - struct super_block *(*get_sb) (struct file_system_type *, int, - const char *, void *); + struct int (*get_sb) (struct file_system_type *, int, + const char *, void *, struct vfsmount *); void (*kill_sb) (struct super_block *); struct module *owner; struct file_system_type * next; diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c index 077f21216b65..2359e2809f50 100644 --- a/arch/ia64/kernel/perfmon.c +++ b/arch/ia64/kernel/perfmon.c @@ -595,10 +595,11 @@ pfm_get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, } -static struct super_block * -pfmfs_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) +static int +pfmfs_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, + struct vfsmount *mnt) { - return get_sb_pseudo(fs_type, "pfm:", NULL, PFMFS_MAGIC); + return get_sb_pseudo(fs_type, "pfm:", NULL, PFMFS_MAGIC, mnt); } static struct file_system_type pfm_fs_type = { diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index 1987697b23a0..7b4572805db9 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -436,11 +436,11 @@ spufs_fill_super(struct super_block *sb, void *data, int silent) return spufs_create_root(sb, data); } -static struct super_block * +static int spufs_get_sb(struct file_system_type *fstype, int flags, - const char *name, void *data) + const char *name, void *data, struct vfsmount *mnt) { - return get_sb_single(fstype, flags, data, spufs_fill_super); + return get_sb_single(fstype, flags, data, spufs_fill_super, mnt); } static struct file_system_type spufs_type = { diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 5ec2d49e9bb6..e57d3c50f75f 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -821,11 +821,12 @@ static void ib_uverbs_remove_one(struct ib_device *device) kref_put(&uverbs_dev->ref, ib_uverbs_release_dev); } -static struct super_block *uverbs_event_get_sb(struct file_system_type *fs_type, int flags, - const char *dev_name, void *data) +static int uverbs_event_get_sb(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data, + struct vfsmount *mnt) { return get_sb_pseudo(fs_type, "infinibandevent:", NULL, - INFINIBANDEVENTFS_MAGIC); + INFINIBANDEVENTFS_MAGIC, mnt); } static struct file_system_type uverbs_event_fs = { diff --git a/drivers/infiniband/hw/ipath/ipath_fs.c b/drivers/infiniband/hw/ipath/ipath_fs.c index e274120567e1..63de3046aff3 100644 --- a/drivers/infiniband/hw/ipath/ipath_fs.c +++ b/drivers/infiniband/hw/ipath/ipath_fs.c @@ -542,13 +542,14 @@ bail: return ret; } -static struct super_block *ipathfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, - void *data) +static int ipathfs_get_sb(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data, struct vfsmount *mnt) { - ipath_super = get_sb_single(fs_type, flags, data, - ipathfs_fill_super); - return ipath_super; + int ret = get_sb_single(fs_type, flags, data, + ipathfs_fill_super, mnt); + if (ret >= 0) + ipath_super = mnt->mnt_sb; + return ret; } static void ipathfs_kill_super(struct super_block *s) diff --git a/drivers/isdn/capi/capifs.c b/drivers/isdn/capi/capifs.c index 0a37aded4b54..9ea6bd0ddc35 100644 --- a/drivers/isdn/capi/capifs.c +++ b/drivers/isdn/capi/capifs.c @@ -121,10 +121,10 @@ fail: return -ENOMEM; } -static struct super_block *capifs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int capifs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_single(fs_type, flags, data, capifs_fill_super); + return get_sb_single(fs_type, flags, data, capifs_fill_super, mnt); } static struct file_system_type capifs_fs_type = { diff --git a/drivers/misc/ibmasm/ibmasmfs.c b/drivers/misc/ibmasm/ibmasmfs.c index 26a230b6ff80..4a35caff5d02 100644 --- a/drivers/misc/ibmasm/ibmasmfs.c +++ b/drivers/misc/ibmasm/ibmasmfs.c @@ -90,10 +90,11 @@ static void ibmasmfs_create_files (struct super_block *sb, struct dentry *root); static int ibmasmfs_fill_super (struct super_block *sb, void *data, int silent); -static struct super_block *ibmasmfs_get_super(struct file_system_type *fst, - int flags, const char *name, void *data) +static int ibmasmfs_get_super(struct file_system_type *fst, + int flags, const char *name, void *data, + struct vfsmount *mnt) { - return get_sb_single(fst, flags, data, ibmasmfs_fill_super); + return get_sb_single(fst, flags, data, ibmasmfs_fill_super, mnt); } static struct super_operations ibmasmfs_s_ops = { diff --git a/drivers/oprofile/oprofilefs.c b/drivers/oprofile/oprofilefs.c index b62da9b0cbf0..71c2da277d6e 100644 --- a/drivers/oprofile/oprofilefs.c +++ b/drivers/oprofile/oprofilefs.c @@ -272,10 +272,10 @@ static int oprofilefs_fill_super(struct super_block * sb, void * data, int silen } -static struct super_block *oprofilefs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int oprofilefs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_single(fs_type, flags, data, oprofilefs_fill_super); + return get_sb_single(fs_type, flags, data, oprofilefs_fill_super, mnt); } diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index 3cf945cc5b9a..95f5ad923b0f 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c @@ -543,10 +543,10 @@ static void fs_remove_file (struct dentry *dentry) /* --------------------------------------------------------------------- */ -static struct super_block *usb_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int usb_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_single(fs_type, flags, data, usbfs_fill_super); + return get_sb_single(fs_type, flags, data, usbfs_fill_super, mnt); } static struct file_system_type usb_fs_type = { diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index aef0722b8f17..3bdc5e3ba234 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -2070,11 +2070,11 @@ enomem0: } /* "mount -t gadgetfs path /dev/gadget" ends up here */ -static struct super_block * +static int gadgetfs_get_sb (struct file_system_type *t, int flags, - const char *path, void *opts) + const char *path, void *opts, struct vfsmount *mnt) { - return get_sb_single (t, flags, opts, gadgetfs_fill_super); + return get_sb_single (t, flags, opts, gadgetfs_fill_super, mnt); } static void diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c index 61c599b4a1e3..872943004e59 100644 --- a/fs/9p/vfs_super.c +++ b/fs/9p/vfs_super.c @@ -99,12 +99,13 @@ v9fs_fill_super(struct super_block *sb, struct v9fs_session_info *v9ses, * @flags: mount flags * @dev_name: device name that was mounted * @data: mount options + * @mnt: mountpoint record to be instantiated * */ -static struct super_block *v9fs_get_sb(struct file_system_type - *fs_type, int flags, - const char *dev_name, void *data) +static int v9fs_get_sb(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data, + struct vfsmount *mnt) { struct super_block *sb = NULL; struct v9fs_fcall *fcall = NULL; @@ -123,17 +124,19 @@ static struct super_block *v9fs_get_sb(struct file_system_type v9ses = kzalloc(sizeof(struct v9fs_session_info), GFP_KERNEL); if (!v9ses) - return ERR_PTR(-ENOMEM); + return -ENOMEM; if ((newfid = v9fs_session_init(v9ses, dev_name, data)) < 0) { dprintk(DEBUG_ERROR, "problem initiating session\n"); - sb = ERR_PTR(newfid); + retval = newfid; goto out_free_session; } sb = sget(fs_type, NULL, v9fs_set_super, v9ses); - if (IS_ERR(sb)) + if (IS_ERR(sb)) { + retval = PTR_ERR(sb); goto out_close_session; + } v9fs_fill_super(sb, v9ses, flags); inode = v9fs_get_inode(sb, S_IFDIR | mode); @@ -184,19 +187,19 @@ static struct super_block *v9fs_get_sb(struct file_system_type goto put_back_sb; } - return sb; + return simple_set_mnt(mnt, sb); out_close_session: v9fs_session_close(v9ses); out_free_session: kfree(v9ses); - return sb; + return retval; put_back_sb: /* deactivate_super calls v9fs_kill_super which will frees the rest */ up_write(&sb->s_umount); deactivate_super(sb); - return ERR_PTR(retval); + return retval; } /** diff --git a/fs/adfs/super.c b/fs/adfs/super.c index 252abda0d200..1b58a9b7f6aa 100644 --- a/fs/adfs/super.c +++ b/fs/adfs/super.c @@ -470,10 +470,11 @@ error: return -EINVAL; } -static struct super_block *adfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int adfs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_bdev(fs_type, flags, dev_name, data, adfs_fill_super); + return get_sb_bdev(fs_type, flags, dev_name, data, adfs_fill_super, + mnt); } static struct file_system_type adfs_fs_type = { diff --git a/fs/affs/super.c b/fs/affs/super.c index 4d7e5b19e5cd..6a52e7875403 100644 --- a/fs/affs/super.c +++ b/fs/affs/super.c @@ -524,10 +524,11 @@ affs_statfs(struct super_block *sb, struct kstatfs *buf) return 0; } -static struct super_block *affs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int affs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_bdev(fs_type, flags, dev_name, data, affs_fill_super); + return get_sb_bdev(fs_type, flags, dev_name, data, affs_fill_super, + mnt); } static struct file_system_type affs_fs_type = { diff --git a/fs/afs/super.c b/fs/afs/super.c index 53c56e7231ab..82468df0ba54 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c @@ -38,9 +38,9 @@ struct afs_mount_params { static void afs_i_init_once(void *foo, kmem_cache_t *cachep, unsigned long flags); -static struct super_block *afs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, - void *data); +static int afs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *data, struct vfsmount *mnt); static struct inode *afs_alloc_inode(struct super_block *sb); @@ -294,10 +294,11 @@ static int afs_fill_super(struct super_block *sb, void *data, int silent) * get an AFS superblock * - TODO: don't use get_sb_nodev(), but rather call sget() directly */ -static struct super_block *afs_get_sb(struct file_system_type *fs_type, - int flags, - const char *dev_name, - void *options) +static int afs_get_sb(struct file_system_type *fs_type, + int flags, + const char *dev_name, + void *options, + struct vfsmount *mnt) { struct afs_mount_params params; struct super_block *sb; @@ -311,7 +312,7 @@ static struct super_block *afs_get_sb(struct file_system_type *fs_type, ret = afscm_start(); if (ret < 0) { _leave(" = %d", ret); - return ERR_PTR(ret); + return ret; } /* parse the options */ @@ -348,18 +349,19 @@ static struct super_block *afs_get_sb(struct file_system_type *fs_type, goto error; } sb->s_flags |= MS_ACTIVE; + simple_set_mnt(mnt, sb); afs_put_volume(params.volume); afs_put_cell(params.default_cell); - _leave(" = %p", sb); - return sb; + _leave(" = 0 [%p]", 0, sb); + return 0; error: afs_put_volume(params.volume); afs_put_cell(params.default_cell); afscm_stop(); _leave(" = %d", ret); - return ERR_PTR(ret); + return ret; } /* end afs_get_sb() */ /*****************************************************************************/ diff --git a/fs/autofs/init.c b/fs/autofs/init.c index b977ece69f0c..aca123752406 100644 --- a/fs/autofs/init.c +++ b/fs/autofs/init.c @@ -14,10 +14,10 @@ #include #include "autofs_i.h" -static struct super_block *autofs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int autofs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_nodev(fs_type, flags, data, autofs_fill_super); + return get_sb_nodev(fs_type, flags, data, autofs_fill_super, mnt); } static struct file_system_type autofs_fs_type = { diff --git a/fs/autofs4/init.c b/fs/autofs4/init.c index acecec8578ce..5d9193332bef 100644 --- a/fs/autofs4/init.c +++ b/fs/autofs4/init.c @@ -14,10 +14,10 @@ #include #include "autofs_i.h" -static struct super_block *autofs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int autofs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_nodev(fs_type, flags, data, autofs4_fill_super); + return get_sb_nodev(fs_type, flags, data, autofs4_fill_super, mnt); } static struct file_system_type autofs_fs_type = { diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index 68ebd10f345d..6ed07a5f10c6 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -899,11 +899,12 @@ befs_statfs(struct super_block *sb, struct kstatfs *buf) return 0; } -static struct super_block * +static int befs_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, - void *data) + void *data, struct vfsmount *mnt) { - return get_sb_bdev(fs_type, flags, dev_name, data, befs_fill_super); + return get_sb_bdev(fs_type, flags, dev_name, data, befs_fill_super, + mnt); } static struct file_system_type befs_fs_type = { diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c index 55a7a78332f8..e7da03f63a5a 100644 --- a/fs/bfs/inode.c +++ b/fs/bfs/inode.c @@ -410,10 +410,10 @@ out: return -EINVAL; } -static struct super_block *bfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int bfs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_bdev(fs_type, flags, dev_name, data, bfs_fill_super); + return get_sb_bdev(fs_type, flags, dev_name, data, bfs_fill_super, mnt); } static struct file_system_type bfs_fs_type = { diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index 599f36fd0f67..07a4996cca3f 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c @@ -739,10 +739,10 @@ static int bm_fill_super(struct super_block * sb, void * data, int silent) return err; } -static struct super_block *bm_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int bm_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_single(fs_type, flags, data, bm_fill_super); + return get_sb_single(fs_type, flags, data, bm_fill_super, mnt); } static struct linux_binfmt misc_format = { diff --git a/fs/block_dev.c b/fs/block_dev.c index 44aaba202f78..028d9fb9c2d5 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -300,10 +300,10 @@ static struct super_operations bdev_sops = { .clear_inode = bdev_clear_inode, }; -static struct super_block *bd_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int bd_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_pseudo(fs_type, "bdev:", &bdev_sops, 0x62646576); + return get_sb_pseudo(fs_type, "bdev:", &bdev_sops, 0x62646576, mnt); } static struct file_system_type bd_type = { diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index c262d8874ce9..08b35801dfed 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -460,9 +460,9 @@ struct super_operations cifs_super_ops = { .remount_fs = cifs_remount, }; -static struct super_block * +static int cifs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { int rc; struct super_block *sb = sget(fs_type, NULL, set_anon_super, NULL); @@ -470,7 +470,7 @@ cifs_get_sb(struct file_system_type *fs_type, cFYI(1, ("Devname: %s flags: %d ", dev_name, flags)); if (IS_ERR(sb)) - return sb; + return PTR_ERR(sb); sb->s_flags = flags; @@ -478,10 +478,10 @@ cifs_get_sb(struct file_system_type *fs_type, if (rc) { up_write(&sb->s_umount); deactivate_super(sb); - return ERR_PTR(rc); + return rc; } sb->s_flags |= MS_ACTIVE; - return sb; + return simple_set_mnt(mnt, sb); } static ssize_t cifs_file_writev(struct file *file, const struct iovec *iov, diff --git a/fs/coda/inode.c b/fs/coda/inode.c index ada1a81df6bd..cba70201567d 100644 --- a/fs/coda/inode.c +++ b/fs/coda/inode.c @@ -307,10 +307,10 @@ static int coda_statfs(struct super_block *sb, struct kstatfs *buf) /* init_coda: used by filesystems.c to register coda */ -static struct super_block *coda_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int coda_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_nodev(fs_type, flags, data, coda_fill_super); + return get_sb_nodev(fs_type, flags, data, coda_fill_super, mnt); } struct file_system_type coda_fs_type = { diff --git a/fs/configfs/mount.c b/fs/configfs/mount.c index f920d30478e5..94dab7bdd851 100644 --- a/fs/configfs/mount.c +++ b/fs/configfs/mount.c @@ -103,10 +103,10 @@ static int configfs_fill_super(struct super_block *sb, void *data, int silent) return 0; } -static struct super_block *configfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int configfs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_single(fs_type, flags, data, configfs_fill_super); + return get_sb_single(fs_type, flags, data, configfs_fill_super, mnt); } static struct file_system_type configfs_fs_type = { diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c index 9efcc3a164e8..37a91a153aa5 100644 --- a/fs/cramfs/inode.c +++ b/fs/cramfs/inode.c @@ -528,10 +528,11 @@ static struct super_operations cramfs_ops = { .statfs = cramfs_statfs, }; -static struct super_block *cramfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int cramfs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_bdev(fs_type, flags, dev_name, data, cramfs_fill_super); + return get_sb_bdev(fs_type, flags, dev_name, data, cramfs_fill_super, + mnt); } static struct file_system_type cramfs_fs_type = { diff --git a/fs/dcache.c b/fs/dcache.c index 59dbc92c2079..313b54b2b8f2 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -687,46 +687,6 @@ void shrink_dcache_parent(struct dentry * parent) prune_dcache(found, parent->d_sb); } -/** - * shrink_dcache_anon - further prune the cache - * @head: head of d_hash list of dentries to prune - * - * Prune the dentries that are anonymous - * - * parsing d_hash list does not hlist_for_each_entry_rcu() as it - * done under dcache_lock. - * - */ -void shrink_dcache_anon(struct super_block *sb) -{ - struct hlist_node *lp; - struct hlist_head *head = &sb->s_anon; - int found; - do { - found = 0; - spin_lock(&dcache_lock); - hlist_for_each(lp, head) { - struct dentry *this = hlist_entry(lp, struct dentry, d_hash); - if (!list_empty(&this->d_lru)) { - dentry_stat.nr_unused--; - list_del_init(&this->d_lru); - } - - /* - * move only zero ref count dentries to the end - * of the unused list for prune_dcache - */ - if (!atomic_read(&this->d_count)) { - list_add_tail(&this->d_lru, &dentry_unused); - dentry_stat.nr_unused++; - found++; - } - } - spin_unlock(&dcache_lock); - prune_dcache(found, sb); - } while(found); -} - /* * Scan `nr' dentries and return the number which remain. * diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index b55b4ea9a676..440128ebef3b 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -111,11 +111,11 @@ static int debug_fill_super(struct super_block *sb, void *data, int silent) return simple_fill_super(sb, DEBUGFS_MAGIC, debug_files); } -static struct super_block *debug_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, - void *data) +static int debug_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *data, struct vfsmount *mnt) { - return get_sb_single(fs_type, flags, data, debug_fill_super); + return get_sb_single(fs_type, flags, data, debug_fill_super, mnt); } static struct file_system_type debug_fs_type = { diff --git a/fs/devfs/base.c b/fs/devfs/base.c index 52f5059c4f31..51a97f132745 100644 --- a/fs/devfs/base.c +++ b/fs/devfs/base.c @@ -2549,11 +2549,11 @@ static int devfs_fill_super(struct super_block *sb, void *data, int silent) return -EINVAL; } /* End Function devfs_fill_super */ -static struct super_block *devfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, - void *data) +static int devfs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *data, struct vfsmount *mnt) { - return get_sb_single(fs_type, flags, data, devfs_fill_super); + return get_sb_single(fs_type, flags, data, devfs_fill_super, mnt); } static struct file_system_type devfs_fs_type = { diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c index 14c5620b5cab..f7aef5bb584a 100644 --- a/fs/devpts/inode.c +++ b/fs/devpts/inode.c @@ -130,10 +130,10 @@ fail: return -ENOMEM; } -static struct super_block *devpts_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int devpts_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_single(fs_type, flags, data, devpts_fill_super); + return get_sb_single(fs_type, flags, data, devpts_fill_super, mnt); } static struct file_system_type devpts_fs_type = { diff --git a/fs/efs/super.c b/fs/efs/super.c index dff623e3ddbf..1ba5e14f879f 100644 --- a/fs/efs/super.c +++ b/fs/efs/super.c @@ -18,10 +18,10 @@ static int efs_statfs(struct super_block *s, struct kstatfs *buf); static int efs_fill_super(struct super_block *s, void *d, int silent); -static struct super_block *efs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int efs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_bdev(fs_type, flags, dev_name, data, efs_fill_super); + return get_sb_bdev(fs_type, flags, dev_name, data, efs_fill_super, mnt); } static struct file_system_type efs_fs_type = { diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 2695337d4d64..08e7e6a555ca 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -268,9 +268,9 @@ static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events, int maxevents, long timeout); static int eventpollfs_delete_dentry(struct dentry *dentry); static struct inode *ep_eventpoll_inode(void); -static struct super_block *eventpollfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, - void *data); +static int eventpollfs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *data, struct vfsmount *mnt); /* * This semaphore is used to serialize ep_free() and eventpoll_release_file(). @@ -1595,11 +1595,12 @@ eexit_1: } -static struct super_block * +static int eventpollfs_get_sb(struct file_system_type *fs_type, int flags, - const char *dev_name, void *data) + const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_pseudo(fs_type, "eventpoll:", NULL, EVENTPOLLFS_MAGIC); + return get_sb_pseudo(fs_type, "eventpoll:", NULL, EVENTPOLLFS_MAGIC, + mnt); } diff --git a/fs/ext2/super.c b/fs/ext2/super.c index 7e30bae174ed..a4dfffac5967 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -1087,10 +1087,10 @@ static int ext2_statfs (struct super_block * sb, struct kstatfs * buf) return 0; } -static struct super_block *ext2_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int ext2_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_bdev(fs_type, flags, dev_name, data, ext2_fill_super); + return get_sb_bdev(fs_type, flags, dev_name, data, ext2_fill_super, mnt); } #ifdef CONFIG_QUOTA diff --git a/fs/ext3/super.c b/fs/ext3/super.c index f8a5266ea1ff..657f8e73b62f 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -2646,10 +2646,10 @@ out: #endif -static struct super_block *ext3_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int ext3_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_bdev(fs_type, flags, dev_name, data, ext3_fill_super); + return get_sb_bdev(fs_type, flags, dev_name, data, ext3_fill_super, mnt); } static struct file_system_type ext3_fs_type = { diff --git a/fs/freevxfs/vxfs_super.c b/fs/freevxfs/vxfs_super.c index b44c916d24a1..d76eeaafbde2 100644 --- a/fs/freevxfs/vxfs_super.c +++ b/fs/freevxfs/vxfs_super.c @@ -241,10 +241,11 @@ out: /* * The usual module blurb. */ -static struct super_block *vxfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int vxfs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_bdev(fs_type, flags, dev_name, data, vxfs_fill_super); + return get_sb_bdev(fs_type, flags, dev_name, data, vxfs_fill_super, + mnt); } static struct file_system_type vxfs_fs_type = { diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 7627022446b2..c91f0a50aadb 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -569,11 +569,11 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) return err; } -static struct super_block *fuse_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, - void *raw_data) +static int fuse_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *raw_data, struct vfsmount *mnt) { - return get_sb_nodev(fs_type, flags, raw_data, fuse_fill_super); + return get_sb_nodev(fs_type, flags, raw_data, fuse_fill_super, mnt); } static struct file_system_type fuse_fs_type = { diff --git a/fs/hfs/super.c b/fs/hfs/super.c index 1181d116117d..ee5b80a409e8 100644 --- a/fs/hfs/super.c +++ b/fs/hfs/super.c @@ -413,10 +413,11 @@ bail: return res; } -static struct super_block *hfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int hfs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, + struct vfsmount *mnt) { - return get_sb_bdev(fs_type, flags, dev_name, data, hfs_fill_super); + return get_sb_bdev(fs_type, flags, dev_name, data, hfs_fill_super, mnt); } static struct file_system_type hfs_fs_type = { diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c index 7843f792a4b7..0ed8b7e8e87f 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c @@ -450,10 +450,12 @@ static void hfsplus_destroy_inode(struct inode *inode) #define HFSPLUS_INODE_SIZE sizeof(struct hfsplus_inode_info) -static struct super_block *hfsplus_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int hfsplus_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, + struct vfsmount *mnt) { - return get_sb_bdev(fs_type, flags, dev_name, data, hfsplus_fill_super); + return get_sb_bdev(fs_type, flags, dev_name, data, hfsplus_fill_super, + mnt); } static struct file_system_type hfsplus_fs_type = { diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index bf0f8e16e433..04035e08f5c1 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c @@ -993,11 +993,11 @@ static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent) return(err); } -static struct super_block *hostfs_read_sb(struct file_system_type *type, - int flags, const char *dev_name, - void *data) +static int hostfs_read_sb(struct file_system_type *type, + int flags, const char *dev_name, + void *data, struct vfsmount *mnt) { - return(get_sb_nodev(type, flags, data, hostfs_fill_sb_common)); + return get_sb_nodev(type, flags, data, hostfs_fill_sb_common, mnt); } static struct file_system_type hostfs_type = { diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c index d72d8c87c996..3b25cf3e2e65 100644 --- a/fs/hpfs/super.c +++ b/fs/hpfs/super.c @@ -662,10 +662,11 @@ bail0: return -EINVAL; } -static struct super_block *hpfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int hpfs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_bdev(fs_type, flags, dev_name, data, hpfs_fill_super); + return get_sb_bdev(fs_type, flags, dev_name, data, hpfs_fill_super, + mnt); } static struct file_system_type hpfs_fs_type = { diff --git a/fs/hppfs/hppfs_kern.c b/fs/hppfs/hppfs_kern.c index 5e6363be246f..ec43c22bc9c0 100644 --- a/fs/hppfs/hppfs_kern.c +++ b/fs/hppfs/hppfs_kern.c @@ -769,11 +769,11 @@ static int hppfs_fill_super(struct super_block *sb, void *d, int silent) return(err); } -static struct super_block *hppfs_read_super(struct file_system_type *type, - int flags, const char *dev_name, - void *data) +static int hppfs_read_super(struct file_system_type *type, + int flags, const char *dev_name, + void *data, struct vfsmount *mnt) { - return(get_sb_nodev(type, flags, data, hppfs_fill_super)); + return get_sb_nodev(type, flags, data, hppfs_fill_super, mnt); } static struct file_system_type hppfs_type = { diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 3a5b4e923455..4665c26171f7 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -723,10 +723,10 @@ void hugetlb_put_quota(struct address_space *mapping) } } -static struct super_block *hugetlbfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int hugetlbfs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_nodev(fs_type, flags, data, hugetlbfs_fill_super); + return get_sb_nodev(fs_type, flags, data, hugetlbfs_fill_super, mnt); } static struct file_system_type hugetlbfs_fs_type = { diff --git a/fs/inotify_user.c b/fs/inotify_user.c index 9e9931e2badd..f2386442adee 100644 --- a/fs/inotify_user.c +++ b/fs/inotify_user.c @@ -672,11 +672,11 @@ out: return ret; } -static struct super_block * +static int inotify_get_sb(struct file_system_type *fs_type, int flags, - const char *dev_name, void *data) + const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_pseudo(fs_type, "inotify", NULL, 0xBAD1DEA); + return get_sb_pseudo(fs_type, "inotify", NULL, 0xBAD1DEA, mnt); } static struct file_system_type inotify_fs_type = { diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index 70adbb98bad1..17268da63a49 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -1399,10 +1399,11 @@ struct inode *isofs_iget(struct super_block *sb, return inode; } -static struct super_block *isofs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int isofs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_bdev(fs_type, flags, dev_name, data, isofs_fill_super); + return get_sb_bdev(fs_type, flags, dev_name, data, isofs_fill_super, + mnt); } static struct file_system_type iso9660_fs_type = { diff --git a/fs/jffs/inode-v23.c b/fs/jffs/inode-v23.c index 020cc097c539..dd93a091ad67 100644 --- a/fs/jffs/inode-v23.c +++ b/fs/jffs/inode-v23.c @@ -1785,10 +1785,11 @@ static struct super_operations jffs_ops = .remount_fs = jffs_remount, }; -static struct super_block *jffs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int jffs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_bdev(fs_type, flags, dev_name, data, jffs_fill_super); + return get_sb_bdev(fs_type, flags, dev_name, data, jffs_fill_super, + mnt); } static struct file_system_type jffs_fs_type = { diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index 9d0521451f59..2378a662c256 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c @@ -111,9 +111,10 @@ static int jffs2_sb_set(struct super_block *sb, void *data) return 0; } -static struct super_block *jffs2_get_sb_mtd(struct file_system_type *fs_type, - int flags, const char *dev_name, - void *data, struct mtd_info *mtd) +static int jffs2_get_sb_mtd(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *data, struct mtd_info *mtd, + struct vfsmount *mnt) { struct super_block *sb; struct jffs2_sb_info *c; @@ -121,19 +122,20 @@ static struct super_block *jffs2_get_sb_mtd(struct file_system_type *fs_type, c = kmalloc(sizeof(*c), GFP_KERNEL); if (!c) - return ERR_PTR(-ENOMEM); + return -ENOMEM; memset(c, 0, sizeof(*c)); c->mtd = mtd; sb = sget(fs_type, jffs2_sb_compare, jffs2_sb_set, c); if (IS_ERR(sb)) - goto out_put; + goto out_error; if (sb->s_root) { /* New mountpoint for JFFS2 which is already mounted */ D1(printk(KERN_DEBUG "jffs2_get_sb_mtd(): Device %d (\"%s\") is already mounted\n", mtd->index, mtd->name)); + ret = simple_set_mnt(mnt, sb); goto out_put; } @@ -161,44 +163,47 @@ static struct super_block *jffs2_get_sb_mtd(struct file_system_type *fs_type, /* Failure case... */ up_write(&sb->s_umount); deactivate_super(sb); - return ERR_PTR(ret); + return ret; } sb->s_flags |= MS_ACTIVE; - return sb; + return simple_set_mnt(mnt, sb); +out_error: + ret = PTR_ERR(sb); out_put: kfree(c); put_mtd_device(mtd); - return sb; + return ret; } -static struct super_block *jffs2_get_sb_mtdnr(struct file_system_type *fs_type, - int flags, const char *dev_name, - void *data, int mtdnr) +static int jffs2_get_sb_mtdnr(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *data, int mtdnr, + struct vfsmount *mnt) { struct mtd_info *mtd; mtd = get_mtd_device(NULL, mtdnr); if (!mtd) { D1(printk(KERN_DEBUG "jffs2: MTD device #%u doesn't appear to exist\n", mtdnr)); - return ERR_PTR(-EINVAL); + return -EINVAL; } - return jffs2_get_sb_mtd(fs_type, flags, dev_name, data, mtd); + return jffs2_get_sb_mtd(fs_type, flags, dev_name, data, mtd, mnt); } -static struct super_block *jffs2_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, - void *data) +static int jffs2_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *data, struct vfsmount *mnt) { int err; struct nameidata nd; int mtdnr; if (!dev_name) - return ERR_PTR(-EINVAL); + return -EINVAL; D1(printk(KERN_DEBUG "jffs2_get_sb(): dev_name \"%s\"\n", dev_name)); @@ -220,7 +225,7 @@ static struct super_block *jffs2_get_sb(struct file_system_type *fs_type, mtd = get_mtd_device(NULL, mtdnr); if (mtd) { if (!strcmp(mtd->name, dev_name+4)) - return jffs2_get_sb_mtd(fs_type, flags, dev_name, data, mtd); + return jffs2_get_sb_mtd(fs_type, flags, dev_name, data, mtd, mnt); put_mtd_device(mtd); } } @@ -233,7 +238,7 @@ static struct super_block *jffs2_get_sb(struct file_system_type *fs_type, if (!*endptr) { /* It was a valid number */ D1(printk(KERN_DEBUG "jffs2_get_sb(): mtd%%d, mtdnr %d\n", mtdnr)); - return jffs2_get_sb_mtdnr(fs_type, flags, dev_name, data, mtdnr); + return jffs2_get_sb_mtdnr(fs_type, flags, dev_name, data, mtdnr, mnt); } } } @@ -247,7 +252,7 @@ static struct super_block *jffs2_get_sb(struct file_system_type *fs_type, err, nd.dentry->d_inode)); if (err) - return ERR_PTR(err); + return err; err = -EINVAL; @@ -269,11 +274,11 @@ static struct super_block *jffs2_get_sb(struct file_system_type *fs_type, mtdnr = iminor(nd.dentry->d_inode); path_release(&nd); - return jffs2_get_sb_mtdnr(fs_type, flags, dev_name, data, mtdnr); + return jffs2_get_sb_mtdnr(fs_type, flags, dev_name, data, mtdnr, mnt); out: path_release(&nd); - return ERR_PTR(err); + return err; } static void jffs2_put_super (struct super_block *sb) diff --git a/fs/jfs/super.c b/fs/jfs/super.c index db6f41d6dd60..18a28137b90e 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c @@ -565,10 +565,11 @@ static void jfs_unlockfs(struct super_block *sb) } } -static struct super_block *jfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int jfs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_bdev(fs_type, flags, dev_name, data, jfs_fill_super); + return get_sb_bdev(fs_type, flags, dev_name, data, jfs_fill_super, + mnt); } static int jfs_sync_fs(struct super_block *sb, int wait) diff --git a/fs/libfs.c b/fs/libfs.c index 7145ba7a48d0..7d70efa46da9 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -196,9 +196,9 @@ struct inode_operations simple_dir_inode_operations = { * Common helper for pseudo-filesystems (sockfs, pipefs, bdev - stuff that * will never be mountable) */ -struct super_block * -get_sb_pseudo(struct file_system_type *fs_type, char *name, - struct super_operations *ops, unsigned long magic) +int get_sb_pseudo(struct file_system_type *fs_type, char *name, + struct super_operations *ops, unsigned long magic, + struct vfsmount *mnt) { struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL); static struct super_operations default_ops = {.statfs = simple_statfs}; @@ -207,7 +207,7 @@ get_sb_pseudo(struct file_system_type *fs_type, char *name, struct qstr d_name = {.name = name, .len = strlen(name)}; if (IS_ERR(s)) - return s; + return PTR_ERR(s); s->s_flags = MS_NOUSER; s->s_maxbytes = ~0ULL; @@ -232,12 +232,12 @@ get_sb_pseudo(struct file_system_type *fs_type, char *name, d_instantiate(dentry, root); s->s_root = dentry; s->s_flags |= MS_ACTIVE; - return s; + return simple_set_mnt(mnt, s); Enomem: up_write(&s->s_umount); deactivate_super(s); - return ERR_PTR(-ENOMEM); + return -ENOMEM; } int simple_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) diff --git a/fs/minix/inode.c b/fs/minix/inode.c index 2dcccf1d1b7f..14f24dfbfe30 100644 --- a/fs/minix/inode.c +++ b/fs/minix/inode.c @@ -559,10 +559,11 @@ void minix_truncate(struct inode * inode) V2_minix_truncate(inode); } -static struct super_block *minix_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int minix_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_bdev(fs_type, flags, dev_name, data, minix_fill_super); + return get_sb_bdev(fs_type, flags, dev_name, data, minix_fill_super, + mnt); } static struct file_system_type minix_fs_type = { diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c index 5b76ccd19e3f..9e44158a7540 100644 --- a/fs/msdos/namei.c +++ b/fs/msdos/namei.c @@ -661,11 +661,12 @@ static int msdos_fill_super(struct super_block *sb, void *data, int silent) return 0; } -static struct super_block *msdos_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, - void *data) +static int msdos_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *data, struct vfsmount *mnt) { - return get_sb_bdev(fs_type, flags, dev_name, data, msdos_fill_super); + return get_sb_bdev(fs_type, flags, dev_name, data, msdos_fill_super, + mnt); } static struct file_system_type msdos_fs_type = { diff --git a/fs/namespace.c b/fs/namespace.c index bf478addb852..c13072a5f1ee 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -86,6 +86,15 @@ struct vfsmount *alloc_vfsmnt(const char *name) return mnt; } +int simple_set_mnt(struct vfsmount *mnt, struct super_block *sb) +{ + mnt->mnt_sb = sb; + mnt->mnt_root = dget(sb->s_root); + return 0; +} + +EXPORT_SYMBOL(simple_set_mnt); + void free_vfsmnt(struct vfsmount *mnt) { kfree(mnt->mnt_devname); diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index a1f3e972c6ef..8db033fab3fd 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -957,10 +957,10 @@ out: return result; } -static struct super_block *ncp_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int ncp_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_nodev(fs_type, flags, data, ncp_fill_super); + return get_sb_nodev(fs_type, flags, data, ncp_fill_super, mnt); } static struct file_system_type ncp_fs_type = { diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index d0b991a92327..ff645a961bc8 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -1690,8 +1690,8 @@ static int nfs_compare_super(struct super_block *sb, void *data) return !nfs_compare_fh(&old->fh, &server->fh); } -static struct super_block *nfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *raw_data) +static int nfs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) { int error; struct nfs_server *server = NULL; @@ -1699,14 +1699,14 @@ static struct super_block *nfs_get_sb(struct file_system_type *fs_type, struct nfs_fh *root; struct nfs_mount_data *data = raw_data; - s = ERR_PTR(-EINVAL); + error = -EINVAL; if (data == NULL) { dprintk("%s: missing data argument\n", __FUNCTION__); - goto out_err; + goto out_err_noserver; } if (data->version <= 0 || data->version > NFS_MOUNT_VERSION) { dprintk("%s: bad mount version\n", __FUNCTION__); - goto out_err; + goto out_err_noserver; } switch (data->version) { case 1: @@ -1718,7 +1718,7 @@ static struct super_block *nfs_get_sb(struct file_system_type *fs_type, dprintk("%s: mount structure version %d does not support NFSv3\n", __FUNCTION__, data->version); - goto out_err; + goto out_err_noserver; } data->root.size = NFS2_FHSIZE; memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE); @@ -1727,24 +1727,24 @@ static struct super_block *nfs_get_sb(struct file_system_type *fs_type, dprintk("%s: mount structure version %d does not support strong security\n", __FUNCTION__, data->version); - goto out_err; + goto out_err_noserver; } case 5: memset(data->context, 0, sizeof(data->context)); } #ifndef CONFIG_NFS_V3 /* If NFSv3 is not compiled in, return -EPROTONOSUPPORT */ - s = ERR_PTR(-EPROTONOSUPPORT); + error = -EPROTONOSUPPORT; if (data->flags & NFS_MOUNT_VER3) { dprintk("%s: NFSv3 not compiled into kernel\n", __FUNCTION__); - goto out_err; + goto out_err_noserver; } #endif /* CONFIG_NFS_V3 */ - s = ERR_PTR(-ENOMEM); + error = -ENOMEM; server = kzalloc(sizeof(struct nfs_server), GFP_KERNEL); if (!server) - goto out_err; + goto out_err_noserver; /* Zero out the NFS state stuff */ init_nfsv4_state(server); server->client = server->client_sys = server->client_acl = ERR_PTR(-EINVAL); @@ -1754,7 +1754,7 @@ static struct super_block *nfs_get_sb(struct file_system_type *fs_type, root->size = data->root.size; else root->size = NFS2_FHSIZE; - s = ERR_PTR(-EINVAL); + error = -EINVAL; if (root->size > sizeof(root->data)) { dprintk("%s: invalid root filehandle\n", __FUNCTION__); goto out_err; @@ -1770,15 +1770,20 @@ static struct super_block *nfs_get_sb(struct file_system_type *fs_type, } /* Fire up rpciod if not yet running */ - s = ERR_PTR(rpciod_up()); - if (IS_ERR(s)) { - dprintk("%s: couldn't start rpciod! Error = %ld\n", - __FUNCTION__, PTR_ERR(s)); + error = rpciod_up(); + if (error < 0) { + dprintk("%s: couldn't start rpciod! Error = %d\n", + __FUNCTION__, error); goto out_err; } s = sget(fs_type, nfs_compare_super, nfs_set_super, server); - if (IS_ERR(s) || s->s_root) + if (IS_ERR(s)) { + error = PTR_ERR(s); + goto out_err_rpciod; + } + + if (s->s_root) goto out_rpciod_down; s->s_flags = flags; @@ -1787,15 +1792,22 @@ static struct super_block *nfs_get_sb(struct file_system_type *fs_type, if (error) { up_write(&s->s_umount); deactivate_super(s); - return ERR_PTR(error); + return error; } s->s_flags |= MS_ACTIVE; - return s; + return simple_set_mnt(mnt, s); + out_rpciod_down: rpciod_down(); + kfree(server); + return simple_set_mnt(mnt, s); + +out_err_rpciod: + rpciod_down(); out_err: kfree(server); - return s; +out_err_noserver: + return error; } static void nfs_kill_super(struct super_block *s) @@ -2032,8 +2044,8 @@ nfs_copy_user_string(char *dst, struct nfs_string *src, int maxlen) return dst; } -static struct super_block *nfs4_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *raw_data) +static int nfs4_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) { int error; struct nfs_server *server; @@ -2043,16 +2055,16 @@ static struct super_block *nfs4_get_sb(struct file_system_type *fs_type, if (data == NULL) { dprintk("%s: missing data argument\n", __FUNCTION__); - return ERR_PTR(-EINVAL); + return -EINVAL; } if (data->version <= 0 || data->version > NFS4_MOUNT_VERSION) { dprintk("%s: bad mount version\n", __FUNCTION__); - return ERR_PTR(-EINVAL); + return -EINVAL; } server = kzalloc(sizeof(struct nfs_server), GFP_KERNEL); if (!server) - return ERR_PTR(-ENOMEM); + return -ENOMEM; /* Zero out the NFS state stuff */ init_nfsv4_state(server); server->client = server->client_sys = server->client_acl = ERR_PTR(-EINVAL); @@ -2074,33 +2086,41 @@ static struct super_block *nfs4_get_sb(struct file_system_type *fs_type, /* We now require that the mount process passes the remote address */ if (data->host_addrlen != sizeof(server->addr)) { - s = ERR_PTR(-EINVAL); + error = -EINVAL; goto out_free; } if (copy_from_user(&server->addr, data->host_addr, sizeof(server->addr))) { - s = ERR_PTR(-EFAULT); + error = -EFAULT; goto out_free; } if (server->addr.sin_family != AF_INET || server->addr.sin_addr.s_addr == INADDR_ANY) { dprintk("%s: mount program didn't pass remote IP address!\n", __FUNCTION__); - s = ERR_PTR(-EINVAL); + error = -EINVAL; goto out_free; } /* Fire up rpciod if not yet running */ - s = ERR_PTR(rpciod_up()); - if (IS_ERR(s)) { - dprintk("%s: couldn't start rpciod! Error = %ld\n", - __FUNCTION__, PTR_ERR(s)); + error = rpciod_up(); + if (error < 0) { + dprintk("%s: couldn't start rpciod! Error = %d\n", + __FUNCTION__, error); goto out_free; } s = sget(fs_type, nfs4_compare_super, nfs_set_super, server); - - if (IS_ERR(s) || s->s_root) + if (IS_ERR(s)) { + error = PTR_ERR(s); goto out_free; + } + + if (s->s_root) { + kfree(server->mnt_path); + kfree(server->hostname); + kfree(server); + return simple_set_mnt(mnt, s); + } s->s_flags = flags; @@ -2108,17 +2128,17 @@ static struct super_block *nfs4_get_sb(struct file_system_type *fs_type, if (error) { up_write(&s->s_umount); deactivate_super(s); - return ERR_PTR(error); + return error; } s->s_flags |= MS_ACTIVE; - return s; + return simple_set_mnt(mnt, s); out_err: - s = (struct super_block *)p; + error = PTR_ERR(p); out_free: kfree(server->mnt_path); kfree(server->hostname); kfree(server); - return s; + return error; } static void nfs4_kill_super(struct super_block *sb) diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 3ef017b3b5bd..a1810e6a93e5 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -494,10 +494,10 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent) return simple_fill_super(sb, 0x6e667364, nfsd_files); } -static struct super_block *nfsd_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int nfsd_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_single(fs_type, flags, data, nfsd_fill_super); + return get_sb_single(fs_type, flags, data, nfsd_fill_super, mnt); } static struct file_system_type nfsd_fs_type = { diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index 27833f6df49f..d5d5e969294f 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c @@ -3093,10 +3093,11 @@ struct kmem_cache *ntfs_index_ctx_cache; /* Driver wide mutex. */ DEFINE_MUTEX(ntfs_lock); -static struct super_block *ntfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int ntfs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_bdev(fs_type, flags, dev_name, data, ntfs_fill_super); + return get_sb_bdev(fs_type, flags, dev_name, data, ntfs_fill_super, + mnt); } static struct file_system_type ntfs_fs_type = { diff --git a/fs/ocfs2/dlm/dlmfs.c b/fs/ocfs2/dlm/dlmfs.c index 7e88e24b3471..7273d9fa6bab 100644 --- a/fs/ocfs2/dlm/dlmfs.c +++ b/fs/ocfs2/dlm/dlmfs.c @@ -574,10 +574,10 @@ static struct inode_operations dlmfs_file_inode_operations = { .getattr = simple_getattr, }; -static struct super_block *dlmfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int dlmfs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_nodev(fs_type, flags, data, dlmfs_fill_super); + return get_sb_nodev(fs_type, flags, data, dlmfs_fill_super, mnt); } static struct file_system_type dlmfs_fs_type = { diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index 949b3dac30f1..788b8b50dc4c 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c @@ -672,12 +672,14 @@ read_super_error: return status; } -static struct super_block *ocfs2_get_sb(struct file_system_type *fs_type, - int flags, - const char *dev_name, - void *data) +static int ocfs2_get_sb(struct file_system_type *fs_type, + int flags, + const char *dev_name, + void *data, + struct vfsmount *mnt) { - return get_sb_bdev(fs_type, flags, dev_name, data, ocfs2_fill_super); + return get_sb_bdev(fs_type, flags, dev_name, data, ocfs2_fill_super, + mnt); } static struct file_system_type ocfs2_fs_type = { diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c index 0f14276a2e51..464e2bce0203 100644 --- a/fs/openpromfs/inode.c +++ b/fs/openpromfs/inode.c @@ -1054,10 +1054,10 @@ out_no_root: return -ENOMEM; } -static struct super_block *openprom_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int openprom_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_single(fs_type, flags, data, openprom_fill_super); + return get_sb_single(fs_type, flags, data, openprom_fill_super, mnt); } static struct file_system_type openprom_fs_type = { diff --git a/fs/pipe.c b/fs/pipe.c index 5acd8954aaa0..20352573e025 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -979,12 +979,11 @@ no_files: * any operations on the root directory. However, we need a non-trivial * d_name - pipe: will go nicely and kill the special-casing in procfs. */ - -static struct super_block * -pipefs_get_sb(struct file_system_type *fs_type, int flags, - const char *dev_name, void *data) +static int pipefs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, + struct vfsmount *mnt) { - return get_sb_pseudo(fs_type, "pipe:", NULL, PIPEFS_MAGIC); + return get_sb_pseudo(fs_type, "pipe:", NULL, PIPEFS_MAGIC, mnt); } static struct file_system_type pipe_fs_type = { diff --git a/fs/proc/root.c b/fs/proc/root.c index c3fd3611112f..9995356ce73e 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -26,10 +26,10 @@ struct proc_dir_entry *proc_net, *proc_net_stat, *proc_bus, *proc_root_fs, *proc struct proc_dir_entry *proc_sys_root; #endif -static struct super_block *proc_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int proc_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_single(fs_type, flags, data, proc_fill_super); + return get_sb_single(fs_type, flags, data, proc_fill_super, mnt); } static struct file_system_type proc_fs_type = { diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c index 2ecd46f85e9f..e6cca5cd4b44 100644 --- a/fs/qnx4/inode.c +++ b/fs/qnx4/inode.c @@ -561,10 +561,11 @@ static void destroy_inodecache(void) "qnx4_inode_cache: not all structures were freed\n"); } -static struct super_block *qnx4_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int qnx4_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_bdev(fs_type, flags, dev_name, data, qnx4_fill_super); + return get_sb_bdev(fs_type, flags, dev_name, data, qnx4_fill_super, + mnt); } static struct file_system_type qnx4_fs_type = { diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c index 14bd2246fb6d..b9677335cc8d 100644 --- a/fs/ramfs/inode.c +++ b/fs/ramfs/inode.c @@ -185,16 +185,17 @@ static int ramfs_fill_super(struct super_block * sb, void * data, int silent) return 0; } -struct super_block *ramfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +int ramfs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_nodev(fs_type, flags, data, ramfs_fill_super); + return get_sb_nodev(fs_type, flags, data, ramfs_fill_super, mnt); } -static struct super_block *rootfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int rootfs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_nodev(fs_type, flags|MS_NOUSER, data, ramfs_fill_super); + return get_sb_nodev(fs_type, flags|MS_NOUSER, data, ramfs_fill_super, + mnt); } static struct file_system_type ramfs_fs_type = { diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index cae2abbc0c71..f3ff41d33989 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -2249,11 +2249,12 @@ static ssize_t reiserfs_quota_write(struct super_block *sb, int type, #endif -static struct super_block *get_super_block(struct file_system_type *fs_type, - int flags, const char *dev_name, - void *data) +static int get_super_block(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *data, struct vfsmount *mnt) { - return get_sb_bdev(fs_type, flags, dev_name, data, reiserfs_fill_super); + return get_sb_bdev(fs_type, flags, dev_name, data, reiserfs_fill_super, + mnt); } static int __init init_reiserfs_fs(void) diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c index 9b9eda7b335c..4d6cd6621062 100644 --- a/fs/romfs/inode.c +++ b/fs/romfs/inode.c @@ -607,10 +607,11 @@ static struct super_operations romfs_ops = { .remount_fs = romfs_remount, }; -static struct super_block *romfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int romfs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_bdev(fs_type, flags, dev_name, data, romfs_fill_super); + return get_sb_bdev(fs_type, flags, dev_name, data, romfs_fill_super, + mnt); } static struct file_system_type romfs_fs_type = { diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c index fdeabc0a34f7..4a37c2bbfa3f 100644 --- a/fs/smbfs/inode.c +++ b/fs/smbfs/inode.c @@ -782,10 +782,10 @@ out: return error; } -static struct super_block *smb_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int smb_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_nodev(fs_type, flags, data, smb_fill_super); + return get_sb_nodev(fs_type, flags, data, smb_fill_super, mnt); } static struct file_system_type smb_fs_type = { diff --git a/fs/super.c b/fs/super.c index 9d5c2add7228..324c2d232f54 100644 --- a/fs/super.c +++ b/fs/super.c @@ -231,7 +231,7 @@ void generic_shutdown_super(struct super_block *sb) if (root) { sb->s_root = NULL; shrink_dcache_parent(root); - shrink_dcache_anon(sb); + shrink_dcache_sb(sb); dput(root); fsync_super(sb); lock_super(sb); @@ -676,9 +676,10 @@ static void bdev_uevent(struct block_device *bdev, enum kobject_action action) } } -struct super_block *get_sb_bdev(struct file_system_type *fs_type, +int get_sb_bdev(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, - int (*fill_super)(struct super_block *, void *, int)) + int (*fill_super)(struct super_block *, void *, int), + struct vfsmount *mnt) { struct block_device *bdev; struct super_block *s; @@ -686,7 +687,7 @@ struct super_block *get_sb_bdev(struct file_system_type *fs_type, bdev = open_bdev_excl(dev_name, flags, fs_type); if (IS_ERR(bdev)) - return (struct super_block *)bdev; + return PTR_ERR(bdev); /* * once the super is inserted into the list by sget, s_umount @@ -697,15 +698,17 @@ struct super_block *get_sb_bdev(struct file_system_type *fs_type, s = sget(fs_type, test_bdev_super, set_bdev_super, bdev); mutex_unlock(&bdev->bd_mount_mutex); if (IS_ERR(s)) - goto out; + goto error_s; if (s->s_root) { if ((flags ^ s->s_flags) & MS_RDONLY) { up_write(&s->s_umount); deactivate_super(s); - s = ERR_PTR(-EBUSY); + error = -EBUSY; + goto error_bdev; } - goto out; + + close_bdev_excl(bdev); } else { char b[BDEVNAME_SIZE]; @@ -716,18 +719,21 @@ struct super_block *get_sb_bdev(struct file_system_type *fs_type, if (error) { up_write(&s->s_umount); deactivate_super(s); - s = ERR_PTR(error); - } else { - s->s_flags |= MS_ACTIVE; - bdev_uevent(bdev, KOBJ_MOUNT); + goto error; } + + s->s_flags |= MS_ACTIVE; + bdev_uevent(bdev, KOBJ_MOUNT); } - return s; + return simple_set_mnt(mnt, s); -out: +error_s: + error = PTR_ERR(s); +error_bdev: close_bdev_excl(bdev); - return s; +error: + return error; } EXPORT_SYMBOL(get_sb_bdev); @@ -744,15 +750,16 @@ void kill_block_super(struct super_block *sb) EXPORT_SYMBOL(kill_block_super); -struct super_block *get_sb_nodev(struct file_system_type *fs_type, +int get_sb_nodev(struct file_system_type *fs_type, int flags, void *data, - int (*fill_super)(struct super_block *, void *, int)) + int (*fill_super)(struct super_block *, void *, int), + struct vfsmount *mnt) { int error; struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL); if (IS_ERR(s)) - return s; + return PTR_ERR(s); s->s_flags = flags; @@ -760,10 +767,10 @@ struct super_block *get_sb_nodev(struct file_system_type *fs_type, if (error) { up_write(&s->s_umount); deactivate_super(s); - return ERR_PTR(error); + return error; } s->s_flags |= MS_ACTIVE; - return s; + return simple_set_mnt(mnt, s); } EXPORT_SYMBOL(get_sb_nodev); @@ -773,94 +780,102 @@ static int compare_single(struct super_block *s, void *p) return 1; } -struct super_block *get_sb_single(struct file_system_type *fs_type, +int get_sb_single(struct file_system_type *fs_type, int flags, void *data, - int (*fill_super)(struct super_block *, void *, int)) + int (*fill_super)(struct super_block *, void *, int), + struct vfsmount *mnt) { struct super_block *s; int error; s = sget(fs_type, compare_single, set_anon_super, NULL); if (IS_ERR(s)) - return s; + return PTR_ERR(s); if (!s->s_root) { s->s_flags = flags; error = fill_super(s, data, flags & MS_SILENT ? 1 : 0); if (error) { up_write(&s->s_umount); deactivate_super(s); - return ERR_PTR(error); + return error; } s->s_flags |= MS_ACTIVE; } do_remount_sb(s, flags, data, 0); - return s; + return simple_set_mnt(mnt, s); } EXPORT_SYMBOL(get_sb_single); struct vfsmount * -do_kern_mount(const char *fstype, int flags, const char *name, void *data) +vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data) { - struct file_system_type *type = get_fs_type(fstype); - struct super_block *sb = ERR_PTR(-ENOMEM); struct vfsmount *mnt; - int error; char *secdata = NULL; + int error; if (!type) return ERR_PTR(-ENODEV); + error = -ENOMEM; mnt = alloc_vfsmnt(name); if (!mnt) goto out; if (data) { secdata = alloc_secdata(); - if (!secdata) { - sb = ERR_PTR(-ENOMEM); + if (!secdata) goto out_mnt; - } error = security_sb_copy_data(type, data, secdata); - if (error) { - sb = ERR_PTR(error); + if (error) goto out_free_secdata; - } } - sb = type->get_sb(type, flags, name, data); - if (IS_ERR(sb)) + error = type->get_sb(type, flags, name, data, mnt); + if (error < 0) goto out_free_secdata; - error = security_sb_kern_mount(sb, secdata); + + error = security_sb_kern_mount(mnt->mnt_sb, secdata); if (error) goto out_sb; - mnt->mnt_sb = sb; - mnt->mnt_root = dget(sb->s_root); - mnt->mnt_mountpoint = sb->s_root; + + mnt->mnt_mountpoint = mnt->mnt_root; mnt->mnt_parent = mnt; - up_write(&sb->s_umount); + up_write(&mnt->mnt_sb->s_umount); free_secdata(secdata); - put_filesystem(type); return mnt; out_sb: - up_write(&sb->s_umount); - deactivate_super(sb); - sb = ERR_PTR(error); + dput(mnt->mnt_root); + up_write(&mnt->mnt_sb->s_umount); + deactivate_super(mnt->mnt_sb); out_free_secdata: free_secdata(secdata); out_mnt: free_vfsmnt(mnt); out: + return ERR_PTR(error); +} + +EXPORT_SYMBOL_GPL(vfs_kern_mount); + +struct vfsmount * +do_kern_mount(const char *fstype, int flags, const char *name, void *data) +{ + struct file_system_type *type = get_fs_type(fstype); + struct vfsmount *mnt; + if (!type) + return ERR_PTR(-ENODEV); + mnt = vfs_kern_mount(type, flags, name, data); put_filesystem(type); - return (struct vfsmount *)sb; + return mnt; } EXPORT_SYMBOL_GPL(do_kern_mount); struct vfsmount *kern_mount(struct file_system_type *type) { - return do_kern_mount(type->name, 0, type->name, NULL); + return vfs_kern_mount(type, 0, type->name, NULL); } EXPORT_SYMBOL(kern_mount); diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index f1117e885bd6..40190c489271 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -66,10 +66,10 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent) return 0; } -static struct super_block *sysfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int sysfs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_single(fs_type, flags, data, sysfs_fill_super); + return get_sb_single(fs_type, flags, data, sysfs_fill_super, mnt); } static struct file_system_type sysfs_fs_type = { diff --git a/fs/sysv/super.c b/fs/sysv/super.c index e92b991e6dda..876639b93321 100644 --- a/fs/sysv/super.c +++ b/fs/sysv/super.c @@ -506,16 +506,17 @@ failed: /* Every kernel module contains stuff like this. */ -static struct super_block *sysv_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int sysv_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_bdev(fs_type, flags, dev_name, data, sysv_fill_super); + return get_sb_bdev(fs_type, flags, dev_name, data, sysv_fill_super, + mnt); } -static struct super_block *v7_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int v7_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_bdev(fs_type, flags, dev_name, data, v7_fill_super); + return get_sb_bdev(fs_type, flags, dev_name, data, v7_fill_super, mnt); } static struct file_system_type sysv_fs_type = { diff --git a/fs/udf/super.c b/fs/udf/super.c index e45789fe38e8..2250774a831d 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -94,10 +94,10 @@ static unsigned int udf_count_free(struct super_block *); static int udf_statfs(struct super_block *, struct kstatfs *); /* UDF filesystem type */ -static struct super_block *udf_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int udf_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_bdev(fs_type, flags, dev_name, data, udf_fill_super); + return get_sb_bdev(fs_type, flags, dev_name, data, udf_fill_super, mnt); } static struct file_system_type udf_fstype = { diff --git a/fs/ufs/super.c b/fs/ufs/super.c index db98a4c71e63..768fb8d9e67a 100644 --- a/fs/ufs/super.c +++ b/fs/ufs/super.c @@ -1311,10 +1311,10 @@ out: #endif -static struct super_block *ufs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int ufs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_bdev(fs_type, flags, dev_name, data, ufs_fill_super); + return get_sb_bdev(fs_type, flags, dev_name, data, ufs_fill_super, mnt); } static struct file_system_type ufs_fs_type = { diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c index a56cec3be5f0..9a8f48bae956 100644 --- a/fs/vfat/namei.c +++ b/fs/vfat/namei.c @@ -1023,11 +1023,12 @@ static int vfat_fill_super(struct super_block *sb, void *data, int silent) return 0; } -static struct super_block *vfat_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, - void *data) +static int vfat_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *data, struct vfsmount *mnt) { - return get_sb_bdev(fs_type, flags, dev_name, data, vfat_fill_super); + return get_sb_bdev(fs_type, flags, dev_name, data, vfat_fill_super, + mnt); } static struct file_system_type vfat_fs_type = { diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index f2a0778536f4..d03c89a36655 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c @@ -853,14 +853,16 @@ fail_vfsop: return -error; } -STATIC struct super_block * +STATIC int xfs_fs_get_sb( struct file_system_type *fs_type, int flags, const char *dev_name, - void *data) + void *data, + struct vfsmount *mnt) { - return get_sb_bdev(fs_type, flags, dev_name, data, xfs_fs_fill_super); + return get_sb_bdev(fs_type, flags, dev_name, data, xfs_fs_fill_super, + mnt); } STATIC struct super_operations xfs_super_operations = { diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 46d0e079735d..0dd1610a94a9 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -217,7 +217,6 @@ extern struct dentry * d_alloc_anon(struct inode *); extern struct dentry * d_splice_alias(struct inode *, struct dentry *); extern void shrink_dcache_sb(struct super_block *); extern void shrink_dcache_parent(struct dentry *); -extern void shrink_dcache_anon(struct super_block *); extern int d_invalidate(struct dentry *); /* only used at mount-time */ diff --git a/include/linux/fs.h b/include/linux/fs.h index 73c7d6f04b31..3e50dd24af87 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1269,23 +1269,26 @@ find_exported_dentry(struct super_block *sb, void *obj, void *parent, struct file_system_type { const char *name; int fs_flags; - struct super_block *(*get_sb) (struct file_system_type *, int, - const char *, void *); + int (*get_sb) (struct file_system_type *, int, + const char *, void *, struct vfsmount *); void (*kill_sb) (struct super_block *); struct module *owner; struct file_system_type * next; struct list_head fs_supers; }; -struct super_block *get_sb_bdev(struct file_system_type *fs_type, +extern int get_sb_bdev(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, - int (*fill_super)(struct super_block *, void *, int)); -struct super_block *get_sb_single(struct file_system_type *fs_type, + int (*fill_super)(struct super_block *, void *, int), + struct vfsmount *mnt); +extern int get_sb_single(struct file_system_type *fs_type, int flags, void *data, - int (*fill_super)(struct super_block *, void *, int)); -struct super_block *get_sb_nodev(struct file_system_type *fs_type, + int (*fill_super)(struct super_block *, void *, int), + struct vfsmount *mnt); +extern int get_sb_nodev(struct file_system_type *fs_type, int flags, void *data, - int (*fill_super)(struct super_block *, void *, int)); + int (*fill_super)(struct super_block *, void *, int), + struct vfsmount *mnt); void generic_shutdown_super(struct super_block *sb); void kill_block_super(struct super_block *sb); void kill_anon_super(struct super_block *sb); @@ -1296,8 +1299,10 @@ struct super_block *sget(struct file_system_type *type, int (*test)(struct super_block *,void *), int (*set)(struct super_block *,void *), void *data); -struct super_block *get_sb_pseudo(struct file_system_type *, char *, - struct super_operations *ops, unsigned long); +extern int get_sb_pseudo(struct file_system_type *, char *, + struct super_operations *ops, unsigned long, + struct vfsmount *mnt); +extern int simple_set_mnt(struct vfsmount *mnt, struct super_block *sb); int __put_super(struct super_block *sb); int __put_super_and_need_restart(struct super_block *sb); void unnamed_dev_init(void); diff --git a/include/linux/ramfs.h b/include/linux/ramfs.h index 78ecfa28b1c2..00b340ba6612 100644 --- a/include/linux/ramfs.h +++ b/include/linux/ramfs.h @@ -2,8 +2,8 @@ #define _LINUX_RAMFS_H struct inode *ramfs_get_inode(struct super_block *sb, int mode, dev_t dev); -struct super_block *ramfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data); +extern int ramfs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt); #ifndef CONFIG_MMU extern unsigned long ramfs_nommu_get_unmapped_area(struct file *file, diff --git a/ipc/mqueue.c b/ipc/mqueue.c index 1511714a9585..0a2a24b6ebe4 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -205,11 +205,11 @@ static int mqueue_fill_super(struct super_block *sb, void *data, int silent) return 0; } -static struct super_block *mqueue_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, - void *data) +static int mqueue_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *data, struct vfsmount *mnt) { - return get_sb_single(fs_type, flags, data, mqueue_fill_super); + return get_sb_single(fs_type, flags, data, mqueue_fill_super, mnt); } static void init_once(void *foo, kmem_cache_t * cachep, unsigned long flags) diff --git a/kernel/cpuset.c b/kernel/cpuset.c index ab81fdd4572b..77f45ffd5ea1 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -392,11 +392,11 @@ static int cpuset_fill_super(struct super_block *sb, void *unused_data, return 0; } -static struct super_block *cpuset_get_sb(struct file_system_type *fs_type, - int flags, const char *unused_dev_name, - void *data) +static int cpuset_get_sb(struct file_system_type *fs_type, + int flags, const char *unused_dev_name, + void *data, struct vfsmount *mnt) { - return get_sb_single(fs_type, flags, data, cpuset_fill_super); + return get_sb_single(fs_type, flags, data, cpuset_fill_super, mnt); } static struct file_system_type cpuset_fs_type = { diff --git a/kernel/futex.c b/kernel/futex.c index 5699c512057b..e1a380c77a5a 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -1056,11 +1056,11 @@ asmlinkage long sys_futex(u32 __user *uaddr, int op, int val, (unsigned long)uaddr2, val2, val3); } -static struct super_block * -futexfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int futexfs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, + struct vfsmount *mnt) { - return get_sb_pseudo(fs_type, "futex", NULL, 0xBAD1DEA); + return get_sb_pseudo(fs_type, "futex", NULL, 0xBAD1DEA, mnt); } static struct file_system_type futex_fs_type = { diff --git a/mm/shmem.c b/mm/shmem.c index 1e43c8a865ba..7617bb1c6bf7 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -2233,10 +2233,10 @@ static struct vm_operations_struct shmem_vm_ops = { }; -static struct super_block *shmem_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int shmem_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_nodev(fs_type, flags, data, shmem_fill_super); + return get_sb_nodev(fs_type, flags, data, shmem_fill_super, mnt); } static struct file_system_type tmpfs_fs_type = { diff --git a/net/socket.c b/net/socket.c index 02948b622bd2..565f5e8d1191 100644 --- a/net/socket.c +++ b/net/socket.c @@ -335,10 +335,11 @@ static struct super_operations sockfs_ops = { .statfs = simple_statfs, }; -static struct super_block *sockfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int sockfs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_pseudo(fs_type, "socket:", &sockfs_ops, SOCKFS_MAGIC); + return get_sb_pseudo(fs_type, "socket:", &sockfs_ops, SOCKFS_MAGIC, + mnt); } static struct vfsmount *sock_mnt __read_mostly; diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index cc673dd8433f..8241fa726803 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -815,11 +815,11 @@ out: return -ENOMEM; } -static struct super_block * +static int rpc_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_single(fs_type, flags, data, rpc_fill_super); + return get_sb_single(fs_type, flags, data, rpc_fill_super, mnt); } static struct file_system_type rpc_pipe_fs_type = { diff --git a/security/inode.c b/security/inode.c index 0f77b0223662..e6fc29ac8564 100644 --- a/security/inode.c +++ b/security/inode.c @@ -135,11 +135,11 @@ static int fill_super(struct super_block *sb, void *data, int silent) return simple_fill_super(sb, SECURITYFS_MAGIC, files); } -static struct super_block *get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, - void *data) +static int get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *data, struct vfsmount *mnt) { - return get_sb_single(fs_type, flags, data, fill_super); + return get_sb_single(fs_type, flags, data, fill_super, mnt); } static struct file_system_type fs_type = { diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 2e73d3279f2d..7029bbc9bef8 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -1345,10 +1345,11 @@ err: goto out; } -static struct super_block *sel_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int sel_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, + struct vfsmount *mnt) { - return get_sb_single(fs_type, flags, data, sel_fill_super); + return get_sb_single(fs_type, flags, data, sel_fill_super, mnt); } static struct file_system_type sel_fs_type = { -- cgit v1.2.3 From 726c334223180e3c0197cc980a432681370d4baf Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 23 Jun 2006 02:02:58 -0700 Subject: [PATCH] VFS: Permit filesystem to perform statfs with a known root dentry Give the statfs superblock operation a dentry pointer rather than a superblock pointer. This complements the get_sb() patch. That reduced the significance of sb->s_root, allowing NFS to place a fake root there. However, NFS does require a dentry to use as a target for the statfs operation. This permits the root in the vfsmount to be used instead. linux/mount.h has been added where necessary to make allyesconfig build successfully. Interest has also been expressed for use with the FUSE and XFS filesystems. Signed-off-by: David Howells Acked-by: Al Viro Cc: Nathan Scott Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/filesystems/Locking | 2 +- Documentation/filesystems/vfs.txt | 2 +- arch/alpha/kernel/osf_sys.c | 2 +- arch/mips/kernel/sysirix.c | 12 ++++++------ arch/parisc/hpux/sys_hpux.c | 10 +++++----- arch/sparc64/solaris/fs.c | 4 ++-- fs/adfs/super.c | 8 ++++---- fs/affs/super.c | 5 +++-- fs/befs/linuxvfs.c | 5 +++-- fs/bfs/inode.c | 3 ++- fs/cifs/cifsfs.c | 3 ++- fs/coda/inode.c | 6 +++--- fs/coda/upcall.c | 4 ++-- fs/compat.c | 8 ++++---- fs/cramfs/inode.c | 4 +++- fs/efs/super.c | 6 +++--- fs/ext2/super.c | 5 +++-- fs/ext3/super.c | 5 +++-- fs/fat/inode.c | 8 ++++---- fs/freevxfs/vxfs_super.c | 13 +++++++------ fs/fuse/inode.c | 3 ++- fs/hfs/super.c | 4 +++- fs/hfsplus/super.c | 4 +++- fs/hostfs/hostfs_kern.c | 4 ++-- fs/hpfs/super.c | 3 ++- fs/hppfs/hppfs_kern.c | 2 +- fs/hugetlbfs/inode.c | 4 ++-- fs/isofs/inode.c | 6 ++++-- fs/jffs/inode-v23.c | 4 ++-- fs/jffs2/fs.c | 4 ++-- fs/jffs2/os-linux.h | 2 +- fs/jfs/super.c | 4 ++-- fs/libfs.c | 4 ++-- fs/minix/inode.c | 10 +++++----- fs/ncpfs/inode.c | 5 +++-- fs/nfs/inode.c | 5 +++-- fs/nfsd/nfs4xdr.c | 2 +- fs/nfsd/vfs.c | 2 +- fs/ntfs/super.c | 7 ++++--- fs/ocfs2/super.c | 10 +++++----- fs/open.c | 26 +++++++++++++------------- fs/qnx4/inode.c | 6 ++++-- fs/reiserfs/super.c | 8 ++++---- fs/romfs/inode.c | 4 ++-- fs/smbfs/inode.c | 6 +++--- fs/smbfs/proc.c | 4 ++-- fs/smbfs/proto.h | 2 +- fs/super.c | 2 +- fs/sysv/inode.c | 3 ++- fs/udf/super.c | 6 ++++-- fs/ufs/super.c | 3 ++- fs/xfs/linux-2.6/xfs_super.c | 4 ++-- include/linux/coda_psdev.h | 2 +- include/linux/fs.h | 6 +++--- include/linux/mount.h | 5 +++++ include/linux/security.h | 14 +++++++------- kernel/acct.c | 2 +- mm/shmem.c | 4 ++-- security/dummy.c | 2 +- security/selinux/hooks.c | 6 +++--- 60 files changed, 175 insertions(+), 144 deletions(-) (limited to 'include') diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking index 3abf08f1b14a..d31efbbdfe50 100644 --- a/Documentation/filesystems/Locking +++ b/Documentation/filesystems/Locking @@ -99,7 +99,7 @@ prototypes: int (*sync_fs)(struct super_block *sb, int wait); void (*write_super_lockfs) (struct super_block *); void (*unlockfs) (struct super_block *); - int (*statfs) (struct super_block *, struct kstatfs *); + int (*statfs) (struct dentry *, struct kstatfs *); int (*remount_fs) (struct super_block *, int *, char *); void (*clear_inode) (struct inode *); void (*umount_begin) (struct super_block *); diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt index dd7d0dcedc87..9d3aed628bc1 100644 --- a/Documentation/filesystems/vfs.txt +++ b/Documentation/filesystems/vfs.txt @@ -211,7 +211,7 @@ struct super_operations { int (*sync_fs)(struct super_block *sb, int wait); void (*write_super_lockfs) (struct super_block *); void (*unlockfs) (struct super_block *); - int (*statfs) (struct super_block *, struct kstatfs *); + int (*statfs) (struct dentry *, struct kstatfs *); int (*remount_fs) (struct super_block *, int *, char *); void (*clear_inode) (struct inode *); void (*umount_begin) (struct super_block *); diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index 31afe3d91ac6..e15dcf4f3dcd 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -244,7 +244,7 @@ do_osf_statfs(struct dentry * dentry, struct osf_statfs __user *buffer, unsigned long bufsiz) { struct kstatfs linux_stat; - int error = vfs_statfs(dentry->d_inode->i_sb, &linux_stat); + int error = vfs_statfs(dentry, &linux_stat); if (!error) error = linux_to_osf_statfs(&linux_stat, buffer, bufsiz); return error; diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c index 5407b784cd01..19e1ef43eb4b 100644 --- a/arch/mips/kernel/sysirix.c +++ b/arch/mips/kernel/sysirix.c @@ -694,7 +694,7 @@ asmlinkage int irix_statfs(const char __user *path, if (error) goto out; - error = vfs_statfs(nd.dentry->d_inode->i_sb, &kbuf); + error = vfs_statfs(nd.dentry, &kbuf); if (error) goto dput_and_out; @@ -732,7 +732,7 @@ asmlinkage int irix_fstatfs(unsigned int fd, struct irix_statfs __user *buf) goto out; } - error = vfs_statfs(file->f_dentry->d_inode->i_sb, &kbuf); + error = vfs_statfs(file->f_dentry, &kbuf); if (error) goto out_f; @@ -1360,7 +1360,7 @@ asmlinkage int irix_statvfs(char __user *fname, struct irix_statvfs __user *buf) error = user_path_walk(fname, &nd); if (error) goto out; - error = vfs_statfs(nd.dentry->d_inode->i_sb, &kbuf); + error = vfs_statfs(nd.dentry, &kbuf); if (error) goto dput_and_out; @@ -1406,7 +1406,7 @@ asmlinkage int irix_fstatvfs(int fd, struct irix_statvfs __user *buf) error = -EBADF; goto out; } - error = vfs_statfs(file->f_dentry->d_inode->i_sb, &kbuf); + error = vfs_statfs(file->f_dentry, &kbuf); if (error) goto out_f; @@ -1611,7 +1611,7 @@ asmlinkage int irix_statvfs64(char __user *fname, struct irix_statvfs64 __user * error = user_path_walk(fname, &nd); if (error) goto out; - error = vfs_statfs(nd.dentry->d_inode->i_sb, &kbuf); + error = vfs_statfs(nd.dentry, &kbuf); if (error) goto dput_and_out; @@ -1658,7 +1658,7 @@ asmlinkage int irix_fstatvfs64(int fd, struct irix_statvfs __user *buf) error = -EBADF; goto out; } - error = vfs_statfs(file->f_dentry->d_inode->i_sb, &kbuf); + error = vfs_statfs(file->f_dentry, &kbuf); if (error) goto out_f; diff --git a/arch/parisc/hpux/sys_hpux.c b/arch/parisc/hpux/sys_hpux.c index 05273ccced0e..cb69727027ae 100644 --- a/arch/parisc/hpux/sys_hpux.c +++ b/arch/parisc/hpux/sys_hpux.c @@ -145,7 +145,7 @@ static int hpux_ustat(dev_t dev, struct hpux_ustat __user *ubuf) s = user_get_super(dev); if (s == NULL) goto out; - err = vfs_statfs(s, &sbuf); + err = vfs_statfs(s->s_root, &sbuf); drop_super(s); if (err) goto out; @@ -186,12 +186,12 @@ struct hpux_statfs { int16_t f_pad; }; -static int vfs_statfs_hpux(struct super_block *sb, struct hpux_statfs *buf) +static int vfs_statfs_hpux(struct dentry *dentry, struct hpux_statfs *buf) { struct kstatfs st; int retval; - retval = vfs_statfs(sb, &st); + retval = vfs_statfs(dentry, &st); if (retval) return retval; @@ -219,7 +219,7 @@ asmlinkage long hpux_statfs(const char __user *path, error = user_path_walk(path, &nd); if (!error) { struct hpux_statfs tmp; - error = vfs_statfs_hpux(nd.dentry->d_inode->i_sb, &tmp); + error = vfs_statfs_hpux(nd.dentry, &tmp); if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) error = -EFAULT; path_release(&nd); @@ -237,7 +237,7 @@ asmlinkage long hpux_fstatfs(unsigned int fd, struct hpux_statfs __user * buf) file = fget(fd); if (!file) goto out; - error = vfs_statfs_hpux(file->f_dentry->d_inode->i_sb, &tmp); + error = vfs_statfs_hpux(file->f_dentry, &tmp); if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) error = -EFAULT; fput(file); diff --git a/arch/sparc64/solaris/fs.c b/arch/sparc64/solaris/fs.c index 4885ca6cbc77..0f0eb6aa1c40 100644 --- a/arch/sparc64/solaris/fs.c +++ b/arch/sparc64/solaris/fs.c @@ -356,7 +356,7 @@ static int report_statvfs(struct vfsmount *mnt, struct inode *inode, u32 buf) int error; struct sol_statvfs __user *ss = A(buf); - error = vfs_statfs(mnt->mnt_sb, &s); + error = vfs_statfs(mnt->mnt_root, &s); if (!error) { const char *p = mnt->mnt_sb->s_type->name; int i = 0; @@ -392,7 +392,7 @@ static int report_statvfs64(struct vfsmount *mnt, struct inode *inode, u32 buf) int error; struct sol_statvfs64 __user *ss = A(buf); - error = vfs_statfs(mnt->mnt_sb, &s); + error = vfs_statfs(mnt->mnt_root, &s); if (!error) { const char *p = mnt->mnt_sb->s_type->name; int i = 0; diff --git a/fs/adfs/super.c b/fs/adfs/super.c index 1b58a9b7f6aa..ba1c88af49fe 100644 --- a/fs/adfs/super.c +++ b/fs/adfs/super.c @@ -196,17 +196,17 @@ static int adfs_remount(struct super_block *sb, int *flags, char *data) return parse_options(sb, data); } -static int adfs_statfs(struct super_block *sb, struct kstatfs *buf) +static int adfs_statfs(struct dentry *dentry, struct kstatfs *buf) { - struct adfs_sb_info *asb = ADFS_SB(sb); + struct adfs_sb_info *asb = ADFS_SB(dentry->d_sb); buf->f_type = ADFS_SUPER_MAGIC; buf->f_namelen = asb->s_namelen; - buf->f_bsize = sb->s_blocksize; + buf->f_bsize = dentry->d_sb->s_blocksize; buf->f_blocks = asb->s_size; buf->f_files = asb->s_ids_per_zone * asb->s_map_size; buf->f_bavail = - buf->f_bfree = adfs_map_free(sb); + buf->f_bfree = adfs_map_free(dentry->d_sb); buf->f_ffree = (long)(buf->f_bfree * buf->f_files) / (long)buf->f_blocks; return 0; diff --git a/fs/affs/super.c b/fs/affs/super.c index 6a52e7875403..8765cba35bb9 100644 --- a/fs/affs/super.c +++ b/fs/affs/super.c @@ -18,7 +18,7 @@ extern struct timezone sys_tz; -static int affs_statfs(struct super_block *sb, struct kstatfs *buf); +static int affs_statfs(struct dentry *dentry, struct kstatfs *buf); static int affs_remount (struct super_block *sb, int *flags, char *data); static void @@ -508,8 +508,9 @@ affs_remount(struct super_block *sb, int *flags, char *data) } static int -affs_statfs(struct super_block *sb, struct kstatfs *buf) +affs_statfs(struct dentry *dentry, struct kstatfs *buf) { + struct super_block *sb = dentry->d_sb; int free; pr_debug("AFFS: statfs() partsize=%d, reserved=%d\n",AFFS_SB(sb)->s_partition_size, diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index 6ed07a5f10c6..08201fab26cd 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -49,7 +49,7 @@ static int befs_nls2utf(struct super_block *sb, const char *in, int in_len, char **out, int *out_len); static void befs_put_super(struct super_block *); static int befs_remount(struct super_block *, int *, char *); -static int befs_statfs(struct super_block *, struct kstatfs *); +static int befs_statfs(struct dentry *, struct kstatfs *); static int parse_options(char *, befs_mount_options *); static const struct super_operations befs_sops = { @@ -880,8 +880,9 @@ befs_remount(struct super_block *sb, int *flags, char *data) } static int -befs_statfs(struct super_block *sb, struct kstatfs *buf) +befs_statfs(struct dentry *dentry, struct kstatfs *buf) { + struct super_block *sb = dentry->d_sb; befs_debug(sb, "---> befs_statfs()"); diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c index e7da03f63a5a..cf74f3d4d966 100644 --- a/fs/bfs/inode.c +++ b/fs/bfs/inode.c @@ -203,8 +203,9 @@ static void bfs_put_super(struct super_block *s) s->s_fs_info = NULL; } -static int bfs_statfs(struct super_block *s, struct kstatfs *buf) +static int bfs_statfs(struct dentry *dentry, struct kstatfs *buf) { + struct super_block *s = dentry->d_sb; struct bfs_sb_info *info = BFS_SB(s); u64 id = huge_encode_dev(s->s_bdev->bd_dev); buf->f_type = BFS_MAGIC; diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 08b35801dfed..7520f4687158 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -166,8 +166,9 @@ cifs_put_super(struct super_block *sb) } static int -cifs_statfs(struct super_block *sb, struct kstatfs *buf) +cifs_statfs(struct dentry *dentry, struct kstatfs *buf) { + struct super_block *sb = dentry->d_sb; int xid; int rc = -EOPNOTSUPP; struct cifs_sb_info *cifs_sb; diff --git a/fs/coda/inode.c b/fs/coda/inode.c index cba70201567d..87f1dc8aa24b 100644 --- a/fs/coda/inode.c +++ b/fs/coda/inode.c @@ -36,7 +36,7 @@ /* VFS super_block ops */ static void coda_clear_inode(struct inode *); static void coda_put_super(struct super_block *); -static int coda_statfs(struct super_block *sb, struct kstatfs *buf); +static int coda_statfs(struct dentry *dentry, struct kstatfs *buf); static kmem_cache_t * coda_inode_cachep; @@ -278,13 +278,13 @@ struct inode_operations coda_file_inode_operations = { .setattr = coda_setattr, }; -static int coda_statfs(struct super_block *sb, struct kstatfs *buf) +static int coda_statfs(struct dentry *dentry, struct kstatfs *buf) { int error; lock_kernel(); - error = venus_statfs(sb, buf); + error = venus_statfs(dentry, buf); unlock_kernel(); diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c index 1bae99650a91..b040eba13a7d 100644 --- a/fs/coda/upcall.c +++ b/fs/coda/upcall.c @@ -611,7 +611,7 @@ int venus_pioctl(struct super_block *sb, struct CodaFid *fid, return error; } -int venus_statfs(struct super_block *sb, struct kstatfs *sfs) +int venus_statfs(struct dentry *dentry, struct kstatfs *sfs) { union inputArgs *inp; union outputArgs *outp; @@ -620,7 +620,7 @@ int venus_statfs(struct super_block *sb, struct kstatfs *sfs) insize = max_t(unsigned int, INSIZE(statfs), OUTSIZE(statfs)); UPARG(CODA_STATFS); - error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); + error = coda_upcall(coda_sbp(dentry->d_sb), insize, &outsize, inp); if (!error) { sfs->f_blocks = outp->coda_statfs.stat.f_blocks; diff --git a/fs/compat.c b/fs/compat.c index b1f64786a613..7e7e5bc4f3cf 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -197,7 +197,7 @@ asmlinkage long compat_sys_statfs(const char __user *path, struct compat_statfs error = user_path_walk(path, &nd); if (!error) { struct kstatfs tmp; - error = vfs_statfs(nd.dentry->d_inode->i_sb, &tmp); + error = vfs_statfs(nd.dentry, &tmp); if (!error) error = put_compat_statfs(buf, &tmp); path_release(&nd); @@ -215,7 +215,7 @@ asmlinkage long compat_sys_fstatfs(unsigned int fd, struct compat_statfs __user file = fget(fd); if (!file) goto out; - error = vfs_statfs(file->f_dentry->d_inode->i_sb, &tmp); + error = vfs_statfs(file->f_dentry, &tmp); if (!error) error = put_compat_statfs(buf, &tmp); fput(file); @@ -265,7 +265,7 @@ asmlinkage long compat_sys_statfs64(const char __user *path, compat_size_t sz, s error = user_path_walk(path, &nd); if (!error) { struct kstatfs tmp; - error = vfs_statfs(nd.dentry->d_inode->i_sb, &tmp); + error = vfs_statfs(nd.dentry, &tmp); if (!error) error = put_compat_statfs64(buf, &tmp); path_release(&nd); @@ -286,7 +286,7 @@ asmlinkage long compat_sys_fstatfs64(unsigned int fd, compat_size_t sz, struct c file = fget(fd); if (!file) goto out; - error = vfs_statfs(file->f_dentry->d_inode->i_sb, &tmp); + error = vfs_statfs(file->f_dentry, &tmp); if (!error) error = put_compat_statfs64(buf, &tmp); fput(file); diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c index 37a91a153aa5..8a9d5d3b3262 100644 --- a/fs/cramfs/inode.c +++ b/fs/cramfs/inode.c @@ -322,8 +322,10 @@ out: return -EINVAL; } -static int cramfs_statfs(struct super_block *sb, struct kstatfs *buf) +static int cramfs_statfs(struct dentry *dentry, struct kstatfs *buf) { + struct super_block *sb = dentry->d_sb; + buf->f_type = CRAMFS_MAGIC; buf->f_bsize = PAGE_CACHE_SIZE; buf->f_blocks = CRAMFS_SB(sb)->blocks; diff --git a/fs/efs/super.c b/fs/efs/super.c index 1ba5e14f879f..8ac2462ae5dd 100644 --- a/fs/efs/super.c +++ b/fs/efs/super.c @@ -15,7 +15,7 @@ #include #include -static int efs_statfs(struct super_block *s, struct kstatfs *buf); +static int efs_statfs(struct dentry *dentry, struct kstatfs *buf); static int efs_fill_super(struct super_block *s, void *d, int silent); static int efs_get_sb(struct file_system_type *fs_type, @@ -322,8 +322,8 @@ out_no_fs: return -EINVAL; } -static int efs_statfs(struct super_block *s, struct kstatfs *buf) { - struct efs_sb_info *sb = SUPER_INFO(s); +static int efs_statfs(struct dentry *dentry, struct kstatfs *buf) { + struct efs_sb_info *sb = SUPER_INFO(dentry->d_sb); buf->f_type = EFS_SUPER_MAGIC; /* efs magic number */ buf->f_bsize = EFS_BLOCKSIZE; /* blocksize */ diff --git a/fs/ext2/super.c b/fs/ext2/super.c index a4dfffac5967..a6c4d6e02324 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -39,7 +39,7 @@ static void ext2_sync_super(struct super_block *sb, struct ext2_super_block *es); static int ext2_remount (struct super_block * sb, int * flags, char * data); -static int ext2_statfs (struct super_block * sb, struct kstatfs * buf); +static int ext2_statfs (struct dentry * dentry, struct kstatfs * buf); void ext2_error (struct super_block * sb, const char * function, const char * fmt, ...) @@ -1038,8 +1038,9 @@ restore_opts: return err; } -static int ext2_statfs (struct super_block * sb, struct kstatfs * buf) +static int ext2_statfs (struct dentry * dentry, struct kstatfs * buf) { + struct super_block *sb = dentry->d_sb; struct ext2_sb_info *sbi = EXT2_SB(sb); unsigned long overhead; int i; diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 657f8e73b62f..e08b6439617c 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -58,7 +58,7 @@ static int ext3_sync_fs(struct super_block *sb, int wait); static const char *ext3_decode_error(struct super_block * sb, int errno, char nbuf[16]); static int ext3_remount (struct super_block * sb, int * flags, char * data); -static int ext3_statfs (struct super_block * sb, struct kstatfs * buf); +static int ext3_statfs (struct dentry * dentry, struct kstatfs * buf); static void ext3_unlockfs(struct super_block *sb); static void ext3_write_super (struct super_block * sb); static void ext3_write_super_lockfs(struct super_block *sb); @@ -2318,8 +2318,9 @@ restore_opts: return err; } -static int ext3_statfs (struct super_block * sb, struct kstatfs * buf) +static int ext3_statfs (struct dentry * dentry, struct kstatfs * buf) { + struct super_block *sb = dentry->d_sb; struct ext3_sb_info *sbi = EXT3_SB(sb); struct ext3_super_block *es = sbi->s_es; unsigned long overhead; diff --git a/fs/fat/inode.c b/fs/fat/inode.c index c1ce284f8a94..7c35d582ec10 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -539,18 +539,18 @@ static int fat_remount(struct super_block *sb, int *flags, char *data) return 0; } -static int fat_statfs(struct super_block *sb, struct kstatfs *buf) +static int fat_statfs(struct dentry *dentry, struct kstatfs *buf) { - struct msdos_sb_info *sbi = MSDOS_SB(sb); + struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb); /* If the count of free cluster is still unknown, counts it here. */ if (sbi->free_clusters == -1) { - int err = fat_count_free_clusters(sb); + int err = fat_count_free_clusters(dentry->d_sb); if (err) return err; } - buf->f_type = sb->s_magic; + buf->f_type = dentry->d_sb->s_magic; buf->f_bsize = sbi->cluster_size; buf->f_blocks = sbi->max_cluster - FAT_START_ENT; buf->f_bfree = sbi->free_clusters; diff --git a/fs/freevxfs/vxfs_super.c b/fs/freevxfs/vxfs_super.c index d76eeaafbde2..b74b791fc23b 100644 --- a/fs/freevxfs/vxfs_super.c +++ b/fs/freevxfs/vxfs_super.c @@ -40,6 +40,7 @@ #include #include #include +#include #include "vxfs.h" #include "vxfs_extern.h" @@ -55,7 +56,7 @@ MODULE_ALIAS("vxfs"); /* makes mount -t vxfs autoload the module */ static void vxfs_put_super(struct super_block *); -static int vxfs_statfs(struct super_block *, struct kstatfs *); +static int vxfs_statfs(struct dentry *, struct kstatfs *); static int vxfs_remount(struct super_block *, int *, char *); static struct super_operations vxfs_super_ops = { @@ -90,12 +91,12 @@ vxfs_put_super(struct super_block *sbp) /** * vxfs_statfs - get filesystem information - * @sbp: VFS superblock + * @dentry: VFS dentry to locate superblock * @bufp: output buffer * * Description: * vxfs_statfs fills the statfs buffer @bufp with information - * about the filesystem described by @sbp. + * about the filesystem described by @dentry. * * Returns: * Zero. @@ -107,12 +108,12 @@ vxfs_put_super(struct super_block *sbp) * This is everything but complete... */ static int -vxfs_statfs(struct super_block *sbp, struct kstatfs *bufp) +vxfs_statfs(struct dentry *dentry, struct kstatfs *bufp) { - struct vxfs_sb_info *infp = VXFS_SBI(sbp); + struct vxfs_sb_info *infp = VXFS_SBI(dentry->d_sb); bufp->f_type = VXFS_SUPER_MAGIC; - bufp->f_bsize = sbp->s_blocksize; + bufp->f_bsize = dentry->d_sb->s_blocksize; bufp->f_blocks = infp->vsi_raw->vs_dsize; bufp->f_bfree = infp->vsi_raw->vs_free; bufp->f_bavail = 0; diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index c91f0a50aadb..a13c0f529058 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -236,8 +236,9 @@ static void convert_fuse_statfs(struct kstatfs *stbuf, struct fuse_kstatfs *attr /* fsid is left zero */ } -static int fuse_statfs(struct super_block *sb, struct kstatfs *buf) +static int fuse_statfs(struct dentry *dentry, struct kstatfs *buf) { + struct super_block *sb = dentry->d_sb; struct fuse_conn *fc = get_fuse_conn_super(sb); struct fuse_req *req; struct fuse_statfs_out outarg; diff --git a/fs/hfs/super.c b/fs/hfs/super.c index ee5b80a409e8..d9227bf14e86 100644 --- a/fs/hfs/super.c +++ b/fs/hfs/super.c @@ -80,8 +80,10 @@ static void hfs_put_super(struct super_block *sb) * * changed f_files/f_ffree to reflect the fs_ablock/free_ablocks. */ -static int hfs_statfs(struct super_block *sb, struct kstatfs *buf) +static int hfs_statfs(struct dentry *dentry, struct kstatfs *buf) { + struct super_block *sb = dentry->d_sb; + buf->f_type = HFS_SUPER_MAGIC; buf->f_bsize = sb->s_blocksize; buf->f_blocks = (u32)HFS_SB(sb)->fs_ablocks * HFS_SB(sb)->fs_div; diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c index 0ed8b7e8e87f..0a92fa2336a2 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c @@ -212,8 +212,10 @@ static void hfsplus_put_super(struct super_block *sb) sb->s_fs_info = NULL; } -static int hfsplus_statfs(struct super_block *sb, struct kstatfs *buf) +static int hfsplus_statfs(struct dentry *dentry, struct kstatfs *buf) { + struct super_block *sb = dentry->d_sb; + buf->f_type = HFSPLUS_SUPER_MAGIC; buf->f_bsize = sb->s_blocksize; buf->f_blocks = HFSPLUS_SB(sb).total_blocks << HFSPLUS_SB(sb).fs_shift; diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index 04035e08f5c1..8e0d37743e7c 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c @@ -239,7 +239,7 @@ static int read_inode(struct inode *ino) return(err); } -int hostfs_statfs(struct super_block *sb, struct kstatfs *sf) +int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf) { /* do_statfs uses struct statfs64 internally, but the linux kernel * struct statfs still has 32-bit versions for most of these fields, @@ -252,7 +252,7 @@ int hostfs_statfs(struct super_block *sb, struct kstatfs *sf) long long f_files; long long f_ffree; - err = do_statfs(HOSTFS_I(sb->s_root->d_inode)->host_filename, + err = do_statfs(HOSTFS_I(dentry->d_sb->s_root->d_inode)->host_filename, &sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files, &f_ffree, &sf->f_fsid, sizeof(sf->f_fsid), &sf->f_namelen, sf->f_spare); diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c index 3b25cf3e2e65..f798480a363f 100644 --- a/fs/hpfs/super.c +++ b/fs/hpfs/super.c @@ -135,8 +135,9 @@ static unsigned count_bitmaps(struct super_block *s) return count; } -static int hpfs_statfs(struct super_block *s, struct kstatfs *buf) +static int hpfs_statfs(struct dentry *dentry, struct kstatfs *buf) { + struct super_block *s = dentry->d_sb; struct hpfs_sb_info *sbi = hpfs_sb(s); lock_kernel(); diff --git a/fs/hppfs/hppfs_kern.c b/fs/hppfs/hppfs_kern.c index ec43c22bc9c0..3a9bdf58166f 100644 --- a/fs/hppfs/hppfs_kern.c +++ b/fs/hppfs/hppfs_kern.c @@ -616,7 +616,7 @@ static const struct file_operations hppfs_dir_fops = { .fsync = hppfs_fsync, }; -static int hppfs_statfs(struct super_block *sb, struct kstatfs *sf) +static int hppfs_statfs(struct dentry *dentry, struct kstatfs *sf) { sf->f_blocks = 0; sf->f_bfree = 0; diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 4665c26171f7..678fc72c3646 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -467,9 +467,9 @@ static int hugetlbfs_set_page_dirty(struct page *page) return 0; } -static int hugetlbfs_statfs(struct super_block *sb, struct kstatfs *buf) +static int hugetlbfs_statfs(struct dentry *dentry, struct kstatfs *buf) { - struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(sb); + struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(dentry->d_sb); buf->f_type = HUGETLBFS_MAGIC; buf->f_bsize = HPAGE_SIZE; diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index 17268da63a49..3f9c8ba1fa1f 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -56,7 +56,7 @@ static void isofs_put_super(struct super_block *sb) } static void isofs_read_inode(struct inode *); -static int isofs_statfs (struct super_block *, struct kstatfs *); +static int isofs_statfs (struct dentry *, struct kstatfs *); static kmem_cache_t *isofs_inode_cachep; @@ -901,8 +901,10 @@ out_freesbi: return -EINVAL; } -static int isofs_statfs (struct super_block *sb, struct kstatfs *buf) +static int isofs_statfs (struct dentry *dentry, struct kstatfs *buf) { + struct super_block *sb = dentry->d_sb; + buf->f_type = ISOFS_SUPER_MAGIC; buf->f_bsize = sb->s_blocksize; buf->f_blocks = (ISOFS_SB(sb)->s_nzones diff --git a/fs/jffs/inode-v23.c b/fs/jffs/inode-v23.c index dd93a091ad67..9e46ea6da752 100644 --- a/fs/jffs/inode-v23.c +++ b/fs/jffs/inode-v23.c @@ -377,9 +377,9 @@ jffs_new_inode(const struct inode * dir, struct jffs_raw_inode *raw_inode, /* Get statistics of the file system. */ static int -jffs_statfs(struct super_block *sb, struct kstatfs *buf) +jffs_statfs(struct dentry *dentry, struct kstatfs *buf) { - struct jffs_control *c = (struct jffs_control *) sb->s_fs_info; + struct jffs_control *c = (struct jffs_control *) dentry->d_sb->s_fs_info; struct jffs_fmcontrol *fmc; lock_kernel(); diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index 7b6c24b14f85..2900ec3ec3af 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c @@ -192,9 +192,9 @@ int jffs2_setattr(struct dentry *dentry, struct iattr *iattr) return rc; } -int jffs2_statfs(struct super_block *sb, struct kstatfs *buf) +int jffs2_statfs(struct dentry *dentry, struct kstatfs *buf) { - struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); + struct jffs2_sb_info *c = JFFS2_SB_INFO(dentry->d_sb); unsigned long avail; buf->f_type = JFFS2_SUPER_MAGIC; diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h index cd4021bcb944..6b5223565405 100644 --- a/fs/jffs2/os-linux.h +++ b/fs/jffs2/os-linux.h @@ -175,7 +175,7 @@ void jffs2_clear_inode (struct inode *); void jffs2_dirty_inode(struct inode *inode); struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_inode *ri); -int jffs2_statfs (struct super_block *, struct kstatfs *); +int jffs2_statfs (struct dentry *, struct kstatfs *); void jffs2_write_super (struct super_block *); int jffs2_remount_fs (struct super_block *, int *, char *); int jffs2_do_fill_super(struct super_block *sb, void *data, int silent); diff --git a/fs/jfs/super.c b/fs/jfs/super.c index 18a28137b90e..73d2aba084c6 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c @@ -139,9 +139,9 @@ static void jfs_destroy_inode(struct inode *inode) kmem_cache_free(jfs_inode_cachep, ji); } -static int jfs_statfs(struct super_block *sb, struct kstatfs *buf) +static int jfs_statfs(struct dentry *dentry, struct kstatfs *buf) { - struct jfs_sb_info *sbi = JFS_SBI(sb); + struct jfs_sb_info *sbi = JFS_SBI(dentry->d_sb); s64 maxinodes; struct inomap *imap = JFS_IP(sbi->ipimap)->i_imap; diff --git a/fs/libfs.c b/fs/libfs.c index 7d70efa46da9..1b1156381787 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -20,9 +20,9 @@ int simple_getattr(struct vfsmount *mnt, struct dentry *dentry, return 0; } -int simple_statfs(struct super_block *sb, struct kstatfs *buf) +int simple_statfs(struct dentry *dentry, struct kstatfs *buf) { - buf->f_type = sb->s_magic; + buf->f_type = dentry->d_sb->s_magic; buf->f_bsize = PAGE_CACHE_SIZE; buf->f_namelen = NAME_MAX; return 0; diff --git a/fs/minix/inode.c b/fs/minix/inode.c index 14f24dfbfe30..a6fb509b7341 100644 --- a/fs/minix/inode.c +++ b/fs/minix/inode.c @@ -19,7 +19,7 @@ static void minix_read_inode(struct inode * inode); static int minix_write_inode(struct inode * inode, int wait); -static int minix_statfs(struct super_block *sb, struct kstatfs *buf); +static int minix_statfs(struct dentry *dentry, struct kstatfs *buf); static int minix_remount (struct super_block * sb, int * flags, char * data); static void minix_delete_inode(struct inode *inode) @@ -296,11 +296,11 @@ out_bad_sb: return -EINVAL; } -static int minix_statfs(struct super_block *sb, struct kstatfs *buf) +static int minix_statfs(struct dentry *dentry, struct kstatfs *buf) { - struct minix_sb_info *sbi = minix_sb(sb); - buf->f_type = sb->s_magic; - buf->f_bsize = sb->s_blocksize; + struct minix_sb_info *sbi = minix_sb(dentry->d_sb); + buf->f_type = dentry->d_sb->s_magic; + buf->f_bsize = dentry->d_sb->s_blocksize; buf->f_blocks = (sbi->s_nzones - sbi->s_firstdatazone) << sbi->s_log_zone_size; buf->f_bfree = minix_count_free_blocks(sbi); buf->f_bavail = buf->f_bfree; diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index 8db033fab3fd..90d2ea28f333 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -39,7 +39,7 @@ static void ncp_delete_inode(struct inode *); static void ncp_put_super(struct super_block *); -static int ncp_statfs(struct super_block *, struct kstatfs *); +static int ncp_statfs(struct dentry *, struct kstatfs *); static kmem_cache_t * ncp_inode_cachep; @@ -724,13 +724,14 @@ static void ncp_put_super(struct super_block *sb) kfree(server); } -static int ncp_statfs(struct super_block *sb, struct kstatfs *buf) +static int ncp_statfs(struct dentry *dentry, struct kstatfs *buf) { struct dentry* d; struct inode* i; struct ncp_inode_info* ni; struct ncp_server* s; struct ncp_volume_info vi; + struct super_block *sb = dentry->d_sb; int err; __u8 dh; diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index ff645a961bc8..937fbfc381bb 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -65,7 +65,7 @@ static int nfs_write_inode(struct inode *,int); static void nfs_delete_inode(struct inode *); static void nfs_clear_inode(struct inode *); static void nfs_umount_begin(struct super_block *); -static int nfs_statfs(struct super_block *, struct kstatfs *); +static int nfs_statfs(struct dentry *, struct kstatfs *); static int nfs_show_options(struct seq_file *, struct vfsmount *); static int nfs_show_stats(struct seq_file *, struct vfsmount *); static void nfs_zap_acl_cache(struct inode *); @@ -534,8 +534,9 @@ nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data, int silent) } static int -nfs_statfs(struct super_block *sb, struct kstatfs *buf) +nfs_statfs(struct dentry *dentry, struct kstatfs *buf) { + struct super_block *sb = dentry->d_sb; struct nfs_server *server = NFS_SB(sb); unsigned char blockbits; unsigned long blockres; diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index de3998f15f10..5446a0861d1d 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -1310,7 +1310,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, if ((bmval0 & (FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL)) || (bmval1 & (FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE | FATTR4_WORD1_SPACE_TOTAL))) { - status = vfs_statfs(dentry->d_inode->i_sb, &statfs); + status = vfs_statfs(dentry, &statfs); if (status) goto out_nfserr; } diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 1d65f13f458c..245eaa1fb59b 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -1737,7 +1737,7 @@ int nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat) { int err = fh_verify(rqstp, fhp, 0, MAY_NOP); - if (!err && vfs_statfs(fhp->fh_dentry->d_inode->i_sb,stat)) + if (!err && vfs_statfs(fhp->fh_dentry,stat)) err = nfserr_io; return err; } diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index d5d5e969294f..0e14acea3f8b 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c @@ -2601,10 +2601,10 @@ static unsigned long __get_nr_free_mft_records(ntfs_volume *vol, /** * ntfs_statfs - return information about mounted NTFS volume - * @sb: super block of mounted volume + * @dentry: dentry from mounted volume * @sfs: statfs structure in which to return the information * - * Return information about the mounted NTFS volume @sb in the statfs structure + * Return information about the mounted NTFS volume @dentry in the statfs structure * pointed to by @sfs (this is initialized with zeros before ntfs_statfs is * called). We interpret the values to be correct of the moment in time at * which we are called. Most values are variable otherwise and this isn't just @@ -2617,8 +2617,9 @@ static unsigned long __get_nr_free_mft_records(ntfs_volume *vol, * * Return 0 on success or -errno on error. */ -static int ntfs_statfs(struct super_block *sb, struct kstatfs *sfs) +static int ntfs_statfs(struct dentry *dentry, struct kstatfs *sfs) { + struct super_block *sb = dentry->d_sb; s64 size; ntfs_volume *vol = NTFS_SB(sb); ntfs_inode *mft_ni = NTFS_I(vol->mft_ino); diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index 788b8b50dc4c..cdf73393f094 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c @@ -100,7 +100,7 @@ static int ocfs2_initialize_mem_caches(void); static void ocfs2_free_mem_caches(void); static void ocfs2_delete_osb(struct ocfs2_super *osb); -static int ocfs2_statfs(struct super_block *sb, struct kstatfs *buf); +static int ocfs2_statfs(struct dentry *dentry, struct kstatfs *buf); static int ocfs2_sync_fs(struct super_block *sb, int wait); @@ -857,7 +857,7 @@ static void ocfs2_put_super(struct super_block *sb) mlog_exit_void(); } -static int ocfs2_statfs(struct super_block *sb, struct kstatfs *buf) +static int ocfs2_statfs(struct dentry *dentry, struct kstatfs *buf) { struct ocfs2_super *osb; u32 numbits, freebits; @@ -866,9 +866,9 @@ static int ocfs2_statfs(struct super_block *sb, struct kstatfs *buf) struct buffer_head *bh = NULL; struct inode *inode = NULL; - mlog_entry("(%p, %p)\n", sb, buf); + mlog_entry("(%p, %p)\n", dentry->d_sb, buf); - osb = OCFS2_SB(sb); + osb = OCFS2_SB(dentry->d_sb); inode = ocfs2_get_system_file_inode(osb, GLOBAL_BITMAP_SYSTEM_INODE, @@ -891,7 +891,7 @@ static int ocfs2_statfs(struct super_block *sb, struct kstatfs *buf) freebits = numbits - le32_to_cpu(bm_lock->id1.bitmap1.i_used); buf->f_type = OCFS2_SUPER_MAGIC; - buf->f_bsize = sb->s_blocksize; + buf->f_bsize = dentry->d_sb->s_blocksize; buf->f_namelen = OCFS2_MAX_FILENAME_LEN; buf->f_blocks = ((sector_t) numbits) * (osb->s_clustersize >> osb->sb->s_blocksize_bits); diff --git a/fs/open.c b/fs/open.c index 4f178acd4c09..a37ff861108f 100644 --- a/fs/open.c +++ b/fs/open.c @@ -31,18 +31,18 @@ #include -int vfs_statfs(struct super_block *sb, struct kstatfs *buf) +int vfs_statfs(struct dentry *dentry, struct kstatfs *buf) { int retval = -ENODEV; - if (sb) { + if (dentry) { retval = -ENOSYS; - if (sb->s_op->statfs) { + if (dentry->d_sb->s_op->statfs) { memset(buf, 0, sizeof(*buf)); - retval = security_sb_statfs(sb); + retval = security_sb_statfs(dentry); if (retval) return retval; - retval = sb->s_op->statfs(sb, buf); + retval = dentry->d_sb->s_op->statfs(dentry, buf); if (retval == 0 && buf->f_frsize == 0) buf->f_frsize = buf->f_bsize; } @@ -52,12 +52,12 @@ int vfs_statfs(struct super_block *sb, struct kstatfs *buf) EXPORT_SYMBOL(vfs_statfs); -static int vfs_statfs_native(struct super_block *sb, struct statfs *buf) +static int vfs_statfs_native(struct dentry *dentry, struct statfs *buf) { struct kstatfs st; int retval; - retval = vfs_statfs(sb, &st); + retval = vfs_statfs(dentry, &st); if (retval) return retval; @@ -95,12 +95,12 @@ static int vfs_statfs_native(struct super_block *sb, struct statfs *buf) return 0; } -static int vfs_statfs64(struct super_block *sb, struct statfs64 *buf) +static int vfs_statfs64(struct dentry *dentry, struct statfs64 *buf) { struct kstatfs st; int retval; - retval = vfs_statfs(sb, &st); + retval = vfs_statfs(dentry, &st); if (retval) return retval; @@ -130,7 +130,7 @@ asmlinkage long sys_statfs(const char __user * path, struct statfs __user * buf) error = user_path_walk(path, &nd); if (!error) { struct statfs tmp; - error = vfs_statfs_native(nd.dentry->d_inode->i_sb, &tmp); + error = vfs_statfs_native(nd.dentry, &tmp); if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) error = -EFAULT; path_release(&nd); @@ -149,7 +149,7 @@ asmlinkage long sys_statfs64(const char __user *path, size_t sz, struct statfs64 error = user_path_walk(path, &nd); if (!error) { struct statfs64 tmp; - error = vfs_statfs64(nd.dentry->d_inode->i_sb, &tmp); + error = vfs_statfs64(nd.dentry, &tmp); if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) error = -EFAULT; path_release(&nd); @@ -168,7 +168,7 @@ asmlinkage long sys_fstatfs(unsigned int fd, struct statfs __user * buf) file = fget(fd); if (!file) goto out; - error = vfs_statfs_native(file->f_dentry->d_inode->i_sb, &tmp); + error = vfs_statfs_native(file->f_dentry, &tmp); if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) error = -EFAULT; fput(file); @@ -189,7 +189,7 @@ asmlinkage long sys_fstatfs64(unsigned int fd, size_t sz, struct statfs64 __user file = fget(fd); if (!file) goto out; - error = vfs_statfs64(file->f_dentry->d_inode->i_sb, &tmp); + error = vfs_statfs64(file->f_dentry, &tmp); if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) error = -EFAULT; fput(file); diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c index e6cca5cd4b44..2f24c46f72a1 100644 --- a/fs/qnx4/inode.c +++ b/fs/qnx4/inode.c @@ -128,7 +128,7 @@ static struct inode *qnx4_alloc_inode(struct super_block *sb); static void qnx4_destroy_inode(struct inode *inode); static void qnx4_read_inode(struct inode *); static int qnx4_remount(struct super_block *sb, int *flags, char *data); -static int qnx4_statfs(struct super_block *, struct kstatfs *); +static int qnx4_statfs(struct dentry *, struct kstatfs *); static struct super_operations qnx4_sops = { @@ -282,8 +282,10 @@ unsigned long qnx4_block_map( struct inode *inode, long iblock ) return block; } -static int qnx4_statfs(struct super_block *sb, struct kstatfs *buf) +static int qnx4_statfs(struct dentry *dentry, struct kstatfs *buf) { + struct super_block *sb = dentry->d_sb; + lock_kernel(); buf->f_type = sb->s_magic; diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index f3ff41d33989..00f1321e9209 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -60,7 +60,7 @@ static int is_any_reiserfs_magic_string(struct reiserfs_super_block *rs) } static int reiserfs_remount(struct super_block *s, int *flags, char *data); -static int reiserfs_statfs(struct super_block *s, struct kstatfs *buf); +static int reiserfs_statfs(struct dentry *dentry, struct kstatfs *buf); static int reiserfs_sync_fs(struct super_block *s, int wait) { @@ -1938,15 +1938,15 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) return errval; } -static int reiserfs_statfs(struct super_block *s, struct kstatfs *buf) +static int reiserfs_statfs(struct dentry *dentry, struct kstatfs *buf) { - struct reiserfs_super_block *rs = SB_DISK_SUPER_BLOCK(s); + struct reiserfs_super_block *rs = SB_DISK_SUPER_BLOCK(dentry->d_sb); buf->f_namelen = (REISERFS_MAX_NAME(s->s_blocksize)); buf->f_bfree = sb_free_blocks(rs); buf->f_bavail = buf->f_bfree; buf->f_blocks = sb_block_count(rs) - sb_bmap_nr(rs) - 1; - buf->f_bsize = s->s_blocksize; + buf->f_bsize = dentry->d_sb->s_blocksize; /* changed to accommodate gcc folks. */ buf->f_type = REISERFS_SUPER_MAGIC; return 0; diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c index 4d6cd6621062..283fbc6b8eea 100644 --- a/fs/romfs/inode.c +++ b/fs/romfs/inode.c @@ -179,12 +179,12 @@ outnobh: /* That's simple too. */ static int -romfs_statfs(struct super_block *sb, struct kstatfs *buf) +romfs_statfs(struct dentry *dentry, struct kstatfs *buf) { buf->f_type = ROMFS_MAGIC; buf->f_bsize = ROMBSIZE; buf->f_bfree = buf->f_bavail = buf->f_ffree; - buf->f_blocks = (romfs_maxsize(sb)+ROMBSIZE-1)>>ROMBSBITS; + buf->f_blocks = (romfs_maxsize(dentry->d_sb)+ROMBSIZE-1)>>ROMBSBITS; buf->f_namelen = ROMFS_MAXFN; return 0; } diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c index 4a37c2bbfa3f..506ff87c1d4b 100644 --- a/fs/smbfs/inode.c +++ b/fs/smbfs/inode.c @@ -48,7 +48,7 @@ static void smb_delete_inode(struct inode *); static void smb_put_super(struct super_block *); -static int smb_statfs(struct super_block *, struct kstatfs *); +static int smb_statfs(struct dentry *, struct kstatfs *); static int smb_show_options(struct seq_file *, struct vfsmount *); static kmem_cache_t *smb_inode_cachep; @@ -641,13 +641,13 @@ out_no_server: } static int -smb_statfs(struct super_block *sb, struct kstatfs *buf) +smb_statfs(struct dentry *dentry, struct kstatfs *buf) { int result; lock_kernel(); - result = smb_proc_dskattr(sb, buf); + result = smb_proc_dskattr(dentry, buf); unlock_kernel(); diff --git a/fs/smbfs/proc.c b/fs/smbfs/proc.c index b1b878b81730..c3495059889d 100644 --- a/fs/smbfs/proc.c +++ b/fs/smbfs/proc.c @@ -3226,9 +3226,9 @@ smb_proc_settime(struct dentry *dentry, struct smb_fattr *fattr) } int -smb_proc_dskattr(struct super_block *sb, struct kstatfs *attr) +smb_proc_dskattr(struct dentry *dentry, struct kstatfs *attr) { - struct smb_sb_info *server = SMB_SB(sb); + struct smb_sb_info *server = SMB_SB(dentry->d_sb); int result; char *p; long unit; diff --git a/fs/smbfs/proto.h b/fs/smbfs/proto.h index 47664597e6b1..972ed7dad388 100644 --- a/fs/smbfs/proto.h +++ b/fs/smbfs/proto.h @@ -29,7 +29,7 @@ extern int smb_proc_getattr(struct dentry *dir, struct smb_fattr *fattr); extern int smb_proc_setattr(struct dentry *dir, struct smb_fattr *fattr); extern int smb_proc_setattr_unix(struct dentry *d, struct iattr *attr, unsigned int major, unsigned int minor); extern int smb_proc_settime(struct dentry *dentry, struct smb_fattr *fattr); -extern int smb_proc_dskattr(struct super_block *sb, struct kstatfs *attr); +extern int smb_proc_dskattr(struct dentry *dentry, struct kstatfs *attr); extern int smb_proc_read_link(struct smb_sb_info *server, struct dentry *d, char *buffer, int len); extern int smb_proc_symlink(struct smb_sb_info *server, struct dentry *d, const char *oldpath); extern int smb_proc_link(struct smb_sb_info *server, struct dentry *dentry, struct dentry *new_dentry); diff --git a/fs/super.c b/fs/super.c index 324c2d232f54..057b5325b7ef 100644 --- a/fs/super.c +++ b/fs/super.c @@ -486,7 +486,7 @@ asmlinkage long sys_ustat(unsigned dev, struct ustat __user * ubuf) s = user_get_super(new_decode_dev(dev)); if (s == NULL) goto out; - err = vfs_statfs(s, &sbuf); + err = vfs_statfs(s->s_root, &sbuf); drop_super(s); if (err) goto out; diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c index 3ff89cc5833a..58b2d22142ba 100644 --- a/fs/sysv/inode.c +++ b/fs/sysv/inode.c @@ -85,8 +85,9 @@ static void sysv_put_super(struct super_block *sb) kfree(sbi); } -static int sysv_statfs(struct super_block *sb, struct kstatfs *buf) +static int sysv_statfs(struct dentry *dentry, struct kstatfs *buf) { + struct super_block *sb = dentry->d_sb; struct sysv_sb_info *sbi = SYSV_SB(sb); buf->f_type = sb->s_magic; diff --git a/fs/udf/super.c b/fs/udf/super.c index 2250774a831d..44fe2cb0bbb2 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -91,7 +91,7 @@ static void udf_load_partdesc(struct super_block *, struct buffer_head *); static void udf_open_lvid(struct super_block *); static void udf_close_lvid(struct super_block *); static unsigned int udf_count_free(struct super_block *); -static int udf_statfs(struct super_block *, struct kstatfs *); +static int udf_statfs(struct dentry *, struct kstatfs *); /* UDF filesystem type */ static int udf_get_sb(struct file_system_type *fs_type, @@ -1779,8 +1779,10 @@ udf_put_super(struct super_block *sb) * Written, tested, and released. */ static int -udf_statfs(struct super_block *sb, struct kstatfs *buf) +udf_statfs(struct dentry *dentry, struct kstatfs *buf) { + struct super_block *sb = dentry->d_sb; + buf->f_type = UDF_SUPER_MAGIC; buf->f_bsize = sb->s_blocksize; buf->f_blocks = UDF_SB_PARTLEN(sb, UDF_SB_PARTITION(sb)); diff --git a/fs/ufs/super.c b/fs/ufs/super.c index 768fb8d9e67a..fe5ab2aa2899 100644 --- a/fs/ufs/super.c +++ b/fs/ufs/super.c @@ -1113,8 +1113,9 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data) return 0; } -static int ufs_statfs (struct super_block *sb, struct kstatfs *buf) +static int ufs_statfs (struct dentry *dentry, struct kstatfs *buf) { + struct super_block *sb = dentry->d_sb; struct ufs_sb_private_info * uspi; struct ufs_super_block_first * usb1; struct ufs_super_block * usb; diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index d03c89a36655..4fb0fc65af34 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c @@ -684,10 +684,10 @@ xfs_fs_sync_super( STATIC int xfs_fs_statfs( - struct super_block *sb, + struct dentry *dentry, struct kstatfs *statp) { - return -bhv_vfs_statvfs(vfs_from_sb(sb), statp, NULL); + return -bhv_vfs_statvfs(vfs_from_sb(dentry->d_sb), statp, NULL); } STATIC int diff --git a/include/linux/coda_psdev.h b/include/linux/coda_psdev.h index d539262a8f89..98f6c52c152b 100644 --- a/include/linux/coda_psdev.h +++ b/include/linux/coda_psdev.h @@ -70,7 +70,7 @@ int venus_pioctl(struct super_block *sb, struct CodaFid *fid, unsigned int cmd, struct PioctlData *data); int coda_downcall(int opcode, union outputArgs *out, struct super_block *sb); int venus_fsync(struct super_block *sb, struct CodaFid *fid); -int venus_statfs(struct super_block *sb, struct kstatfs *sfs); +int venus_statfs(struct dentry *dentry, struct kstatfs *sfs); /* messages between coda filesystem in kernel and Venus */ diff --git a/include/linux/fs.h b/include/linux/fs.h index 3e50dd24af87..c823a3815e24 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1096,7 +1096,7 @@ struct super_operations { int (*sync_fs)(struct super_block *sb, int wait); void (*write_super_lockfs) (struct super_block *); void (*unlockfs) (struct super_block *); - int (*statfs) (struct super_block *, struct kstatfs *); + int (*statfs) (struct dentry *, struct kstatfs *); int (*remount_fs) (struct super_block *, int *, char *); void (*clear_inode) (struct inode *); void (*umount_begin) (struct super_block *); @@ -1325,7 +1325,7 @@ extern struct vfsmount *copy_tree(struct vfsmount *, struct dentry *, int); extern void mnt_set_mountpoint(struct vfsmount *, struct dentry *, struct vfsmount *); -extern int vfs_statfs(struct super_block *, struct kstatfs *); +extern int vfs_statfs(struct dentry *, struct kstatfs *); /* /sys/fs */ extern struct subsystem fs_subsys; @@ -1746,7 +1746,7 @@ extern int dcache_dir_close(struct inode *, struct file *); extern loff_t dcache_dir_lseek(struct file *, loff_t, int); extern int dcache_readdir(struct file *, void *, filldir_t); extern int simple_getattr(struct vfsmount *, struct dentry *, struct kstat *); -extern int simple_statfs(struct super_block *, struct kstatfs *); +extern int simple_statfs(struct dentry *, struct kstatfs *); extern int simple_link(struct dentry *, struct inode *, struct dentry *); extern int simple_unlink(struct inode *, struct dentry *); extern int simple_rmdir(struct inode *, struct dentry *); diff --git a/include/linux/mount.h b/include/linux/mount.h index b7472ae91fa4..60718f12caa9 100644 --- a/include/linux/mount.h +++ b/include/linux/mount.h @@ -17,6 +17,11 @@ #include #include +struct super_block; +struct vfsmount; +struct dentry; +struct namespace; + #define MNT_NOSUID 0x01 #define MNT_NODEV 0x02 #define MNT_NOEXEC 0x04 diff --git a/include/linux/security.h b/include/linux/security.h index 47722d355532..383c320fc834 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -171,9 +171,9 @@ struct swap_info_struct; * Deallocate and clear the sb->s_security field. * @sb contains the super_block structure to be modified. * @sb_statfs: - * Check permission before obtaining filesystem statistics for the @sb - * filesystem. - * @sb contains the super_block structure for the filesystem. + * Check permission before obtaining filesystem statistics for the @mnt + * mountpoint. + * @dentry is a handle on the superblock for the filesystem. * Return 0 if permission is granted. * @sb_mount: * Check permission before an object specified by @dev_name is mounted on @@ -1127,7 +1127,7 @@ struct security_operations { int (*sb_copy_data)(struct file_system_type *type, void *orig, void *copy); int (*sb_kern_mount) (struct super_block *sb, void *data); - int (*sb_statfs) (struct super_block * sb); + int (*sb_statfs) (struct dentry *dentry); int (*sb_mount) (char *dev_name, struct nameidata * nd, char *type, unsigned long flags, void *data); int (*sb_check_sb) (struct vfsmount * mnt, struct nameidata * nd); @@ -1450,9 +1450,9 @@ static inline int security_sb_kern_mount (struct super_block *sb, void *data) return security_ops->sb_kern_mount (sb, data); } -static inline int security_sb_statfs (struct super_block *sb) +static inline int security_sb_statfs (struct dentry *dentry) { - return security_ops->sb_statfs (sb); + return security_ops->sb_statfs (dentry); } static inline int security_sb_mount (char *dev_name, struct nameidata *nd, @@ -2162,7 +2162,7 @@ static inline int security_sb_kern_mount (struct super_block *sb, void *data) return 0; } -static inline int security_sb_statfs (struct super_block *sb) +static inline int security_sb_statfs (struct dentry *dentry) { return 0; } diff --git a/kernel/acct.c b/kernel/acct.c index b327f4d20104..6802020e0ceb 100644 --- a/kernel/acct.c +++ b/kernel/acct.c @@ -118,7 +118,7 @@ static int check_free_space(struct file *file) spin_unlock(&acct_globals.lock); /* May block */ - if (vfs_statfs(file->f_dentry->d_inode->i_sb, &sbuf)) + if (vfs_statfs(file->f_dentry, &sbuf)) return res; suspend = sbuf.f_blocks * SUSPEND; resume = sbuf.f_blocks * RESUME; diff --git a/mm/shmem.c b/mm/shmem.c index 7617bb1c6bf7..10020d8b4073 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -1654,9 +1654,9 @@ static ssize_t shmem_file_sendfile(struct file *in_file, loff_t *ppos, return desc.error; } -static int shmem_statfs(struct super_block *sb, struct kstatfs *buf) +static int shmem_statfs(struct dentry *dentry, struct kstatfs *buf) { - struct shmem_sb_info *sbinfo = SHMEM_SB(sb); + struct shmem_sb_info *sbinfo = SHMEM_SB(dentry->d_sb); buf->f_type = TMPFS_MAGIC; buf->f_bsize = PAGE_CACHE_SIZE; diff --git a/security/dummy.c b/security/dummy.c index 6de4a4a5eb13..c98d553984ec 100644 --- a/security/dummy.c +++ b/security/dummy.c @@ -191,7 +191,7 @@ static int dummy_sb_kern_mount (struct super_block *sb, void *data) return 0; } -static int dummy_sb_statfs (struct super_block *sb) +static int dummy_sb_statfs (struct dentry *dentry) { return 0; } diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 524915dfda64..093efba4d9b6 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1903,13 +1903,13 @@ static int selinux_sb_kern_mount(struct super_block *sb, void *data) return superblock_has_perm(current, sb, FILESYSTEM__MOUNT, &ad); } -static int selinux_sb_statfs(struct super_block *sb) +static int selinux_sb_statfs(struct dentry *dentry) { struct avc_audit_data ad; AVC_AUDIT_DATA_INIT(&ad,FS); - ad.u.fs.dentry = sb->s_root; - return superblock_has_perm(current, sb, FILESYSTEM__GETATTR, &ad); + ad.u.fs.dentry = dentry->d_sb->s_root; + return superblock_has_perm(current, dentry->d_sb, FILESYSTEM__GETATTR, &ad); } static int selinux_mount(char * dev_name, -- cgit v1.2.3 From cb2b95e1c6b56e3d2369d3a5f4bc97f4fa180683 Mon Sep 17 00:00:00 2001 From: Andy Whitcroft Date: Fri, 23 Jun 2006 02:03:01 -0700 Subject: [PATCH] zone handle unaligned zone boundaries The buddy allocator has a requirement that boundaries between contigious zones occur aligned with the the MAX_ORDER ranges. Where they do not we will incorrectly merge pages cross zone boundaries. This can lead to pages from the wrong zone being handed out. Originally the buddy allocator would check that buddies were in the same zone by referencing the zone start and end page frame numbers. This was removed as it became very expensive and the buddy allocator already made the assumption that zones boundaries were aligned. It is clear that not all configurations and architectures are honouring this alignment requirement. Therefore it seems safest to reintroduce support for non-aligned zone boundaries. This patch introduces a new check when considering a page a buddy it compares the zone_table index for the two pages and refuses to merge the pages where they do not match. The zone_table index is unique for each node/zone combination when FLATMEM/DISCONTIGMEM is enabled and for each section/zone combination when SPARSEMEM is enabled (a SPARSEMEM section is at least a MAX_ORDER size). Signed-off-by: Andy Whitcroft Cc: Dave Hansen Cc: Mel Gorman Cc: Yasunori Goto Cc: KAMEZAWA Hiroyuki Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mm.h | 7 +++++-- mm/page_alloc.c | 17 +++++++++++------ 2 files changed, 16 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/include/linux/mm.h b/include/linux/mm.h index e2fa375e478e..697c6bf248c2 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -465,10 +465,13 @@ static inline unsigned long page_zonenum(struct page *page) struct zone; extern struct zone *zone_table[]; +static inline int page_zone_id(struct page *page) +{ + return (page->flags >> ZONETABLE_PGSHIFT) & ZONETABLE_MASK; +} static inline struct zone *page_zone(struct page *page) { - return zone_table[(page->flags >> ZONETABLE_PGSHIFT) & - ZONETABLE_MASK]; + return zone_table[page_zone_id(page)]; } static inline unsigned long page_to_nid(struct page *page) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 253a450c400d..fd631c2536a5 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -286,22 +286,27 @@ __find_combined_index(unsigned long page_idx, unsigned int order) * we can do coalesce a page and its buddy if * (a) the buddy is not in a hole && * (b) the buddy is in the buddy system && - * (c) a page and its buddy have the same order. + * (c) a page and its buddy have the same order && + * (d) a page and its buddy are in the same zone. * * For recording whether a page is in the buddy system, we use PG_buddy. * Setting, clearing, and testing PG_buddy is serialized by zone->lock. * * For recording page's order, we use page_private(page). */ -static inline int page_is_buddy(struct page *page, int order) +static inline int page_is_buddy(struct page *page, struct page *buddy, + int order) { #ifdef CONFIG_HOLES_IN_ZONE - if (!pfn_valid(page_to_pfn(page))) + if (!pfn_valid(page_to_pfn(buddy))) return 0; #endif - if (PageBuddy(page) && page_order(page) == order) { - BUG_ON(page_count(page) != 0); + if (page_zone_id(page) != page_zone_id(buddy)) + return 0; + + if (PageBuddy(buddy) && page_order(buddy) == order) { + BUG_ON(page_count(buddy) != 0); return 1; } return 0; @@ -352,7 +357,7 @@ static inline void __free_one_page(struct page *page, struct page *buddy; buddy = __page_find_buddy(page, page_idx, order); - if (!page_is_buddy(buddy, order)) + if (!page_is_buddy(page, buddy, order)) break; /* Move the buddy up one level. */ list_del(&buddy->lru); -- cgit v1.2.3 From f886ed443fedb109e2062988bf120a531f0ec80a Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Fri, 23 Jun 2006 02:03:06 -0700 Subject: [PATCH] PG_uncached is ia64 only As Nick points out, only ia64 uses PG_uncached. So we can push it up into the higher bits of the lower half of page->flags and make room for another flag on 32-bit machines. Cc: "Luck, Tony" Cc: Jesse Barnes Cc: Jes Sorensen Cc: Nick Piggin Cc: Andy Whitcroft Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/page-flags.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h index d276a4e2f825..0c076d58c676 100644 --- a/include/linux/page-flags.h +++ b/include/linux/page-flags.h @@ -7,6 +7,8 @@ #include #include +#include + #include /* @@ -88,7 +90,17 @@ #define PG_nosave_free 18 /* Free, should not be written */ #define PG_buddy 19 /* Page is free, on buddy lists */ -#define PG_uncached 20 /* Page has been mapped as uncached */ + +#if (BITS_PER_LONG > 32) +/* + * 64-bit-only flags build down from bit 31 + * + * 32 bit -------------------------------| FIELDS | FLAGS | + * 64 bit | FIELDS | ?????? FLAGS | + * 63 32 0 + */ +#define PG_uncached 31 /* Page has been mapped as uncached */ +#endif /* * Global page accounting. One instance per CPU. Only unsigned longs are -- cgit v1.2.3 From 02b694dea473ad3db1e2d1b14c1fef8fbd92e5e6 Mon Sep 17 00:00:00 2001 From: Yasunori Goto Date: Fri, 23 Jun 2006 02:03:08 -0700 Subject: [PATCH] wait_table and zonelist initializing for memory hotadd: change name of wait_table_size() This is just to rename from wait_table_size() to wait_table_hash_nr_entries(). Signed-off-by: Yasunori Goto Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mmzone.h | 4 ++-- mm/page_alloc.c | 12 +++++++----- 2 files changed, 9 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index 9742e3c16222..652673ea92f1 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -197,7 +197,7 @@ struct zone { /* * wait_table -- the array holding the hash table - * wait_table_size -- the size of the hash table array + * wait_table_hash_nr_entries -- the size of the hash table array * wait_table_bits -- wait_table_size == (1 << wait_table_bits) * * The purpose of all these is to keep track of the people @@ -220,7 +220,7 @@ struct zone { * free_area_init_core() performs the initialization of them. */ wait_queue_head_t * wait_table; - unsigned long wait_table_size; + unsigned long wait_table_hash_nr_entries; unsigned long wait_table_bits; /* diff --git a/mm/page_alloc.c b/mm/page_alloc.c index fd631c2536a5..27320a0542d3 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1727,7 +1727,7 @@ void __init build_all_zonelists(void) */ #define PAGES_PER_WAITQUEUE 256 -static inline unsigned long wait_table_size(unsigned long pages) +static inline unsigned long wait_table_hash_nr_entries(unsigned long pages) { unsigned long size = 1; @@ -2019,13 +2019,15 @@ void zone_wait_table_init(struct zone *zone, unsigned long zone_size_pages) * The per-page waitqueue mechanism uses hashed waitqueues * per zone. */ - zone->wait_table_size = wait_table_size(zone_size_pages); - zone->wait_table_bits = wait_table_bits(zone->wait_table_size); + zone->wait_table_hash_nr_entries = + wait_table_hash_nr_entries(zone_size_pages); + zone->wait_table_bits = + wait_table_bits(zone->wait_table_hash_nr_entries); zone->wait_table = (wait_queue_head_t *) - alloc_bootmem_node(pgdat, zone->wait_table_size + alloc_bootmem_node(pgdat, zone->wait_table_hash_nr_entries * sizeof(wait_queue_head_t)); - for(i = 0; i < zone->wait_table_size; ++i) + for(i = 0; i < zone->wait_table_hash_nr_entries; ++i) init_waitqueue_head(zone->wait_table + i); } -- cgit v1.2.3 From 86356ab147669bd3bcb2149fd9561d1280835c24 Mon Sep 17 00:00:00 2001 From: Yasunori Goto Date: Fri, 23 Jun 2006 02:03:09 -0700 Subject: [PATCH] wait_table and zonelist initializing for memory hotadd: change to meminit for build_zonelist Change definitions of some functions and data from __init to __meminit. These functions and data can be used after bootup by this patch to be used for hot-add codes. Signed-off-by: Yasunori Goto Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/bootmem.h | 4 ++-- mm/page_alloc.c | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/include/linux/bootmem.h b/include/linux/bootmem.h index da2d107fe2cf..22866fa2d960 100644 --- a/include/linux/bootmem.h +++ b/include/linux/bootmem.h @@ -91,8 +91,8 @@ static inline void *alloc_remap(int nid, unsigned long size) } #endif -extern unsigned long __initdata nr_kernel_pages; -extern unsigned long __initdata nr_all_pages; +extern unsigned long nr_kernel_pages; +extern unsigned long nr_all_pages; extern void *__init alloc_large_system_hash(const char *tablename, unsigned long bucketsize, diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 27320a0542d3..5ae75bead4df 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -83,8 +83,8 @@ EXPORT_SYMBOL(zone_table); static char *zone_names[MAX_NR_ZONES] = { "DMA", "DMA32", "Normal", "HighMem" }; int min_free_kbytes = 1024; -unsigned long __initdata nr_kernel_pages; -unsigned long __initdata nr_all_pages; +unsigned long __meminitdata nr_kernel_pages; +unsigned long __meminitdata nr_all_pages; #ifdef CONFIG_DEBUG_VM static int page_outside_zone_boundaries(struct zone *zone, struct page *page) @@ -1517,7 +1517,7 @@ void show_free_areas(void) * * Add all populated zones of a node to the zonelist. */ -static int __init build_zonelists_node(pg_data_t *pgdat, +static int __meminit build_zonelists_node(pg_data_t *pgdat, struct zonelist *zonelist, int nr_zones, int zone_type) { struct zone *zone; @@ -1553,7 +1553,7 @@ static inline int highest_zone(int zone_bits) #ifdef CONFIG_NUMA #define MAX_NODE_LOAD (num_online_nodes()) -static int __initdata node_load[MAX_NUMNODES]; +static int __meminitdata node_load[MAX_NUMNODES]; /** * find_next_best_node - find the next node that should appear in a given node's fallback list * @node: node whose fallback list we're appending @@ -1568,7 +1568,7 @@ static int __initdata node_load[MAX_NUMNODES]; * on them otherwise. * It returns -1 if no node is found. */ -static int __init find_next_best_node(int node, nodemask_t *used_node_mask) +static int __meminit find_next_best_node(int node, nodemask_t *used_node_mask) { int n, val; int min_val = INT_MAX; @@ -1614,7 +1614,7 @@ static int __init find_next_best_node(int node, nodemask_t *used_node_mask) return best_node; } -static void __init build_zonelists(pg_data_t *pgdat) +static void __meminit build_zonelists(pg_data_t *pgdat) { int i, j, k, node, local_node; int prev_node, load; @@ -1666,7 +1666,7 @@ static void __init build_zonelists(pg_data_t *pgdat) #else /* CONFIG_NUMA */ -static void __init build_zonelists(pg_data_t *pgdat) +static void __meminit build_zonelists(pg_data_t *pgdat) { int i, j, k, node, local_node; @@ -2071,7 +2071,7 @@ static __meminit void init_currently_empty_zone(struct zone *zone, * - mark all memory queues empty * - clear the memory bitmaps */ -static void __init free_area_init_core(struct pglist_data *pgdat, +static void __meminit free_area_init_core(struct pglist_data *pgdat, unsigned long *zones_size, unsigned long *zholes_size) { unsigned long j; @@ -2159,7 +2159,7 @@ static void __init alloc_node_mem_map(struct pglist_data *pgdat) #endif /* CONFIG_FLAT_NODE_MEM_MAP */ } -void __init free_area_init_node(int nid, struct pglist_data *pgdat, +void __meminit free_area_init_node(int nid, struct pglist_data *pgdat, unsigned long *zones_size, unsigned long node_start_pfn, unsigned long *zholes_size) { -- cgit v1.2.3 From 718127cc3170454f4aa274fdd2f1e01574fecd66 Mon Sep 17 00:00:00 2001 From: Yasunori Goto Date: Fri, 23 Jun 2006 02:03:10 -0700 Subject: [PATCH] wait_table and zonelist initializing for memory hotadd: add return code for init_current_empty_zone When add_zone() is called against empty zone (not populated zone), we have to initialize the zone which didn't initialize at boot time. But, init_currently_empty_zone() may fail due to allocation of wait table. So, this patch is to catch its error code. Changes against wait_table is in the next patch. Signed-off-by: KAMEZAWA Hiroyuki Signed-off-by: Yasunori Goto Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mmzone.h | 3 +++ mm/memory_hotplug.c | 15 +++++++++++++-- mm/page_alloc.c | 11 ++++++++--- 3 files changed, 24 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index 652673ea92f1..e82fc1a52cd0 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -333,6 +333,9 @@ void wakeup_kswapd(struct zone *zone, int order); int zone_watermark_ok(struct zone *z, int order, unsigned long mark, int classzone_idx, int alloc_flags); +extern int init_currently_empty_zone(struct zone *zone, unsigned long start_pfn, + unsigned long size); + #ifdef CONFIG_HAVE_MEMORY_PRESENT void memory_present(int nid, unsigned long start, unsigned long end); #else diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index 70df5c0d957e..71da5c98c9c1 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c @@ -26,7 +26,7 @@ extern void zonetable_add(struct zone *zone, int nid, int zid, unsigned long pfn, unsigned long size); -static void __add_zone(struct zone *zone, unsigned long phys_start_pfn) +static int __add_zone(struct zone *zone, unsigned long phys_start_pfn) { struct pglist_data *pgdat = zone->zone_pgdat; int nr_pages = PAGES_PER_SECTION; @@ -34,8 +34,15 @@ static void __add_zone(struct zone *zone, unsigned long phys_start_pfn) int zone_type; zone_type = zone - pgdat->node_zones; + if (!populated_zone(zone)) { + int ret = 0; + ret = init_currently_empty_zone(zone, phys_start_pfn, nr_pages); + if (ret < 0) + return ret; + } memmap_init_zone(nr_pages, nid, zone_type, phys_start_pfn); zonetable_add(zone, nid, zone_type, phys_start_pfn, nr_pages); + return 0; } extern int sparse_add_one_section(struct zone *zone, unsigned long start_pfn, @@ -50,7 +57,11 @@ static int __add_section(struct zone *zone, unsigned long phys_start_pfn) if (ret < 0) return ret; - __add_zone(zone, phys_start_pfn); + ret = __add_zone(zone, phys_start_pfn); + + if (ret < 0) + return ret; + return register_new_memory(__pfn_to_section(phys_start_pfn)); } diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 5ae75bead4df..4bc66f6b7718 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -2050,8 +2050,9 @@ static __meminit void zone_pcp_init(struct zone *zone) zone->name, zone->present_pages, batch); } -static __meminit void init_currently_empty_zone(struct zone *zone, - unsigned long zone_start_pfn, unsigned long size) +__meminit int init_currently_empty_zone(struct zone *zone, + unsigned long zone_start_pfn, + unsigned long size) { struct pglist_data *pgdat = zone->zone_pgdat; @@ -2063,6 +2064,8 @@ static __meminit void init_currently_empty_zone(struct zone *zone, memmap_init(size, pgdat->node_id, zone_idx(zone), zone_start_pfn); zone_init_free_lists(pgdat, zone, zone->spanned_pages); + + return 0; } /* @@ -2077,6 +2080,7 @@ static void __meminit free_area_init_core(struct pglist_data *pgdat, unsigned long j; int nid = pgdat->node_id; unsigned long zone_start_pfn = pgdat->node_start_pfn; + int ret; pgdat_resize_init(pgdat); pgdat->nr_zones = 0; @@ -2118,7 +2122,8 @@ static void __meminit free_area_init_core(struct pglist_data *pgdat, continue; zonetable_add(zone, nid, j, zone_start_pfn, size); - init_currently_empty_zone(zone, zone_start_pfn, size); + ret = init_currently_empty_zone(zone, zone_start_pfn, size); + BUG_ON(ret); zone_start_pfn += size; } } -- cgit v1.2.3 From 67de648211fa041fe08a0c25241a4980bbb90698 Mon Sep 17 00:00:00 2001 From: Andy Whitcroft Date: Fri, 23 Jun 2006 02:03:12 -0700 Subject: [PATCH] squash duplicate page_to_pfn and pfn_to_page We have architectures where the size of page_to_pfn and pfn_to_page are significant enough to overall image size that they wish to push them out of line. However, in the process we have grown a second copy of the implementation of each of these routines for each memory model. Share the implmentation exposing it either inline or out-of-line as required. Signed-off-by: Andy Whitcroft Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-generic/memory_model.h | 27 +++++++++++++++------------ mm/page_alloc.c | 32 ++------------------------------ 2 files changed, 17 insertions(+), 42 deletions(-) (limited to 'include') diff --git a/include/asm-generic/memory_model.h b/include/asm-generic/memory_model.h index 0cfb086dd373..8078cbd2c016 100644 --- a/include/asm-generic/memory_model.h +++ b/include/asm-generic/memory_model.h @@ -23,29 +23,23 @@ #endif /* CONFIG_DISCONTIGMEM */ -#ifdef CONFIG_OUT_OF_LINE_PFN_TO_PAGE -struct page; -/* this is useful when inlined pfn_to_page is too big */ -extern struct page *pfn_to_page(unsigned long pfn); -extern unsigned long page_to_pfn(struct page *page); -#else /* * supports 3 memory models. */ #if defined(CONFIG_FLATMEM) -#define pfn_to_page(pfn) (mem_map + ((pfn) - ARCH_PFN_OFFSET)) -#define page_to_pfn(page) ((unsigned long)((page) - mem_map) + \ +#define __pfn_to_page(pfn) (mem_map + ((pfn) - ARCH_PFN_OFFSET)) +#define __page_to_pfn(page) ((unsigned long)((page) - mem_map) + \ ARCH_PFN_OFFSET) #elif defined(CONFIG_DISCONTIGMEM) -#define pfn_to_page(pfn) \ +#define __pfn_to_page(pfn) \ ({ unsigned long __pfn = (pfn); \ unsigned long __nid = arch_pfn_to_nid(pfn); \ NODE_DATA(__nid)->node_mem_map + arch_local_page_offset(__pfn, __nid);\ }) -#define page_to_pfn(pg) \ +#define __page_to_pfn(pg) \ ({ struct page *__pg = (pg); \ struct pglist_data *__pgdat = NODE_DATA(page_to_nid(__pg)); \ (unsigned long)(__pg - __pgdat->node_mem_map) + \ @@ -57,18 +51,27 @@ extern unsigned long page_to_pfn(struct page *page); * Note: section's mem_map is encorded to reflect its start_pfn. * section[i].section_mem_map == mem_map's address - start_pfn; */ -#define page_to_pfn(pg) \ +#define __page_to_pfn(pg) \ ({ struct page *__pg = (pg); \ int __sec = page_to_section(__pg); \ __pg - __section_mem_map_addr(__nr_to_section(__sec)); \ }) -#define pfn_to_page(pfn) \ +#define __pfn_to_page(pfn) \ ({ unsigned long __pfn = (pfn); \ struct mem_section *__sec = __pfn_to_section(__pfn); \ __section_mem_map_addr(__sec) + __pfn; \ }) #endif /* CONFIG_FLATMEM/DISCONTIGMEM/SPARSEMEM */ + +#ifdef CONFIG_OUT_OF_LINE_PFN_TO_PAGE +struct page; +/* this is useful when inlined pfn_to_page is too big */ +extern struct page *pfn_to_page(unsigned long pfn); +extern unsigned long page_to_pfn(struct page *page); +#else +#define page_to_pfn __page_to_pfn +#define pfn_to_page __pfn_to_page #endif /* CONFIG_OUT_OF_LINE_PFN_TO_PAGE */ #endif /* __ASSEMBLY__ */ diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 9dfbe6b7d1c8..5af33186a25f 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -2879,42 +2879,14 @@ void *__init alloc_large_system_hash(const char *tablename, } #ifdef CONFIG_OUT_OF_LINE_PFN_TO_PAGE -/* - * pfn <-> page translation. out-of-line version. - * (see asm-generic/memory_model.h) - */ -#if defined(CONFIG_FLATMEM) -struct page *pfn_to_page(unsigned long pfn) -{ - return mem_map + (pfn - ARCH_PFN_OFFSET); -} -unsigned long page_to_pfn(struct page *page) -{ - return (page - mem_map) + ARCH_PFN_OFFSET; -} -#elif defined(CONFIG_DISCONTIGMEM) struct page *pfn_to_page(unsigned long pfn) { - int nid = arch_pfn_to_nid(pfn); - return NODE_DATA(nid)->node_mem_map + arch_local_page_offset(pfn,nid); + return __pfn_to_page(pfn); } unsigned long page_to_pfn(struct page *page) { - struct pglist_data *pgdat = NODE_DATA(page_to_nid(page)); - return (page - pgdat->node_mem_map) + pgdat->node_start_pfn; -} -#elif defined(CONFIG_SPARSEMEM) -struct page *pfn_to_page(unsigned long pfn) -{ - return __section_mem_map_addr(__pfn_to_section(pfn)) + pfn; -} - -unsigned long page_to_pfn(struct page *page) -{ - long section_id = page_to_section(page); - return page - __section_mem_map_addr(__nr_to_section(section_id)); + return __page_to_pfn(page); } -#endif /* CONFIG_FLATMEM/DISCONTIGMME/SPARSEMEM */ EXPORT_SYMBOL(pfn_to_page); EXPORT_SYMBOL(page_to_pfn); #endif /* CONFIG_OUT_OF_LINE_PFN_TO_PAGE */ -- cgit v1.2.3 From fadd8fbd153c12963f8fe3c9ef7f8967f286f98b Mon Sep 17 00:00:00 2001 From: KAMEZAWA Hiroyuki Date: Fri, 23 Jun 2006 02:03:13 -0700 Subject: [PATCH] support for panic at OOM This patch adds panic_on_oom sysctl under sys.vm. When sysctl vm.panic_on_oom = 1, the kernel panics intead of killing rogue processes. And if vm.panic_on_oom is 0 the kernel will do oom_kill() in the same way as it does today. Of course, the default value is 0 and only root can modifies it. In general, oom_killer works well and kill rogue processes. So the whole system can survive. But there are environments where panic is preferable rather than kill some processes. Signed-off-by: KAMEZAWA Hiroyuki Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/sysctl/vm.txt | 13 +++++++++++++ include/linux/sysctl.h | 1 + kernel/sysctl.c | 9 +++++++++ mm/oom_kill.c | 3 +++ 4 files changed, 26 insertions(+) (limited to 'include') diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt index a46c10fcddfc..2dc246af4885 100644 --- a/Documentation/sysctl/vm.txt +++ b/Documentation/sysctl/vm.txt @@ -29,6 +29,7 @@ Currently, these files are in /proc/sys/vm: - drop-caches - zone_reclaim_mode - zone_reclaim_interval +- panic_on_oom ============================================================== @@ -178,3 +179,15 @@ Time is set in seconds and set by default to 30 seconds. Reduce the interval if undesired off node allocations occur. However, too frequent scans will have a negative impact onoff node allocation performance. +============================================================= + +panic_on_oom + +This enables or disables panic on out-of-memory feature. If this is set to 1, +the kernel panics when out-of-memory happens. If this is set to 0, the kernel +will kill some rogue process, called oom_killer. Usually, oom_killer can kill +rogue processes and system will survive. If you want to panic the system +rather than killing rogue processes, set this to 1. + +The default value is 0. + diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index cee944dbdcd4..c7132029af0f 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -186,6 +186,7 @@ enum VM_PERCPU_PAGELIST_FRACTION=30,/* int: fraction of pages in each percpu_pagelist */ VM_ZONE_RECLAIM_MODE=31, /* reclaim local zone memory before going off node */ VM_ZONE_RECLAIM_INTERVAL=32, /* time period to wait after reclaim failure */ + VM_PANIC_ON_OOM=33, /* panic at out-of-memory */ }; diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 0d656e61621d..072ac446810a 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -59,6 +59,7 @@ extern int proc_nr_files(ctl_table *table, int write, struct file *filp, extern int C_A_D; extern int sysctl_overcommit_memory; extern int sysctl_overcommit_ratio; +extern int sysctl_panic_on_oom; extern int max_threads; extern int sysrq_enabled; extern int core_uses_pid; @@ -701,6 +702,14 @@ static ctl_table vm_table[] = { .mode = 0644, .proc_handler = &proc_dointvec, }, + { + .ctl_name = VM_PANIC_ON_OOM, + .procname = "panic_on_oom", + .data = &sysctl_panic_on_oom, + .maxlen = sizeof(sysctl_panic_on_oom), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, { .ctl_name = VM_OVERCOMMIT_RATIO, .procname = "overcommit_ratio", diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 042e6436c3ee..f9bb3cf32384 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -22,6 +22,7 @@ #include #include +int sysctl_panic_on_oom; /* #define DEBUG */ /** @@ -344,6 +345,8 @@ void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask, int order) break; case CONSTRAINT_NONE: + if (sysctl_panic_on_oom) + panic("out of memory. panic_on_oom is selected\n"); retry: /* * Rambo mode: Shoot down a process and hope it solves whatever -- cgit v1.2.3 From e8f03d02080b25f53cd6bba8dc3a297803f18c01 Mon Sep 17 00:00:00 2001 From: Andreas Dilger Date: Fri, 23 Jun 2006 02:03:14 -0700 Subject: [PATCH] reserve space for swap label Reserve space in the swap disk header for a LABEL and UUID to be specified. This has been possible with util-linux-2.12b (via e2fsprogs 1.36 libblkid), and is used by at least FC3 and later. The kernel doesn't really care about this, but the space shouldn't accidentally be used by something else either. Also make the on-disk structures be fixed-size types, instead of "int", though I don't know of any architecture in use where an "int" isn't the same size as a "__u32" (all current kernel arches have it as "unsigned int"). Signed-off-by: Andreas Dilger Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/swap.h | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/linux/swap.h b/include/linux/swap.h index aca9bfae208f..cd28ad206dae 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -48,12 +48,14 @@ union swap_header { char magic[10]; /* SWAP-SPACE or SWAPSPACE2 */ } magic; struct { - char bootbits[1024]; /* Space for disklabel etc. */ - unsigned int version; - unsigned int last_page; - unsigned int nr_badpages; - unsigned int padding[125]; - unsigned int badpages[1]; + char bootbits[1024]; /* Space for disklabel etc. */ + __u32 version; + __u32 last_page; + __u32 nr_badpages; + unsigned char sws_uuid[16]; + unsigned char sws_volume[16]; + __u32 padding[117]; + __u32 badpages[1]; } info; }; -- cgit v1.2.3 From a43a8c39bbb493c9e93f6764b350de2e33e18e92 Mon Sep 17 00:00:00 2001 From: "Chen, Kenneth W" Date: Fri, 23 Jun 2006 02:03:15 -0700 Subject: [PATCH] tightening hugetlb strict accounting Current hugetlb strict accounting for shared mapping always assume mapping starts at zero file offset and reserves pages between zero and size of the file. This assumption often reserves (or lock down) a lot more pages then necessary if application maps at none zero file offset. libhugetlbfs is one example that requires proper reservation on shared mapping starts at none zero offset. This patch extends the reservation and hugetlb strict accounting to support any arbitrary pair of (offset, len), resulting a much more robust and accurate scheme. More importantly, it won't lock down any hugetlb pages outside file mapping. Signed-off-by: Ken Chen Acked-by: Adam Litke Cc: David Gibson Cc: William Lee Irwin III Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/hugetlbfs/inode.c | 21 ++-- include/linux/hugetlb.h | 8 +- mm/hugetlb.c | 282 +++++++++++++++++++++++++++--------------------- 3 files changed, 173 insertions(+), 138 deletions(-) (limited to 'include') diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 678fc72c3646..e6410d8edd0e 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -59,7 +59,6 @@ static void huge_pagevec_release(struct pagevec *pvec) static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma) { struct inode *inode = file->f_dentry->d_inode; - struct hugetlbfs_inode_info *info = HUGETLBFS_I(inode); loff_t len, vma_len; int ret; @@ -87,9 +86,10 @@ static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma) if (!(vma->vm_flags & VM_WRITE) && len > inode->i_size) goto out; - if (vma->vm_flags & VM_MAYSHARE) - if (hugetlb_extend_reservation(info, len >> HPAGE_SHIFT) != 0) - goto out; + if (vma->vm_flags & VM_MAYSHARE && + hugetlb_reserve_pages(inode, vma->vm_pgoff >> (HPAGE_SHIFT-PAGE_SHIFT), + len >> HPAGE_SHIFT)) + goto out; ret = 0; hugetlb_prefault_arch_hook(vma->vm_mm); @@ -195,12 +195,8 @@ static void truncate_hugepages(struct inode *inode, loff_t lstart) const pgoff_t start = lstart >> HPAGE_SHIFT; struct pagevec pvec; pgoff_t next; - int i; + int i, freed = 0; - hugetlb_truncate_reservation(HUGETLBFS_I(inode), - lstart >> HPAGE_SHIFT); - if (!mapping->nrpages) - return; pagevec_init(&pvec, 0); next = start; while (1) { @@ -221,10 +217,12 @@ static void truncate_hugepages(struct inode *inode, loff_t lstart) truncate_huge_page(page); unlock_page(page); hugetlb_put_quota(mapping); + freed++; } huge_pagevec_release(&pvec); } BUG_ON(!lstart && mapping->nrpages); + hugetlb_unreserve_pages(inode, start, freed); } static void hugetlbfs_delete_inode(struct inode *inode) @@ -366,6 +364,7 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb, uid_t uid, inode->i_mapping->a_ops = &hugetlbfs_aops; inode->i_mapping->backing_dev_info =&hugetlbfs_backing_dev_info; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + INIT_LIST_HEAD(&inode->i_mapping->private_list); info = HUGETLBFS_I(inode); mpol_shared_policy_init(&info->policy, MPOL_DEFAULT, NULL); switch (mode & S_IFMT) { @@ -538,7 +537,6 @@ static struct inode *hugetlbfs_alloc_inode(struct super_block *sb) hugetlbfs_inc_free_inodes(sbinfo); return NULL; } - p->prereserved_hpages = 0; return &p->vfs_inode; } @@ -781,8 +779,7 @@ struct file *hugetlb_zero_setup(size_t size) goto out_file; error = -ENOMEM; - if (hugetlb_extend_reservation(HUGETLBFS_I(inode), - size >> HPAGE_SHIFT) != 0) + if (hugetlb_reserve_pages(inode, 0, size >> HPAGE_SHIFT)) goto out_inode; d_instantiate(dentry, inode); diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h index 4c5e610fe442..c25a38d8f600 100644 --- a/include/linux/hugetlb.h +++ b/include/linux/hugetlb.h @@ -23,6 +23,8 @@ int hugetlb_report_node_meminfo(int, char *); unsigned long hugetlb_total_pages(void); int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long address, int write_access); +int hugetlb_reserve_pages(struct inode *inode, long from, long to); +void hugetlb_unreserve_pages(struct inode *inode, long offset, long freed); extern unsigned long max_huge_pages; extern const unsigned long hugetlb_zero, hugetlb_infinity; @@ -139,8 +141,6 @@ struct hugetlbfs_sb_info { struct hugetlbfs_inode_info { struct shared_policy policy; - /* Protected by the (global) hugetlb_lock */ - unsigned long prereserved_hpages; struct inode vfs_inode; }; @@ -157,10 +157,6 @@ static inline struct hugetlbfs_sb_info *HUGETLBFS_SB(struct super_block *sb) extern const struct file_operations hugetlbfs_file_operations; extern struct vm_operations_struct hugetlb_vm_ops; struct file *hugetlb_zero_setup(size_t); -int hugetlb_extend_reservation(struct hugetlbfs_inode_info *info, - unsigned long atleast_hpages); -void hugetlb_truncate_reservation(struct hugetlbfs_inode_info *info, - unsigned long atmost_hpages); int hugetlb_get_quota(struct address_space *mapping); void hugetlb_put_quota(struct address_space *mapping); diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 832f676ca038..df499973255f 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -22,7 +22,7 @@ #include "internal.h" const unsigned long hugetlb_zero = 0, hugetlb_infinity = ~0UL; -static unsigned long nr_huge_pages, free_huge_pages, reserved_huge_pages; +static unsigned long nr_huge_pages, free_huge_pages, resv_huge_pages; unsigned long max_huge_pages; static struct list_head hugepage_freelists[MAX_NUMNODES]; static unsigned int nr_huge_pages_node[MAX_NUMNODES]; @@ -123,39 +123,13 @@ static int alloc_fresh_huge_page(void) static struct page *alloc_huge_page(struct vm_area_struct *vma, unsigned long addr) { - struct inode *inode = vma->vm_file->f_dentry->d_inode; struct page *page; - int use_reserve = 0; - unsigned long idx; spin_lock(&hugetlb_lock); - - if (vma->vm_flags & VM_MAYSHARE) { - - /* idx = radix tree index, i.e. offset into file in - * HPAGE_SIZE units */ - idx = ((addr - vma->vm_start) >> HPAGE_SHIFT) - + (vma->vm_pgoff >> (HPAGE_SHIFT - PAGE_SHIFT)); - - /* The hugetlbfs specific inode info stores the number - * of "guaranteed available" (huge) pages. That is, - * the first 'prereserved_hpages' pages of the inode - * are either already instantiated, or have been - * pre-reserved (by hugetlb_reserve_for_inode()). Here - * we're in the process of instantiating the page, so - * we use this to determine whether to draw from the - * pre-reserved pool or the truly free pool. */ - if (idx < HUGETLBFS_I(inode)->prereserved_hpages) - use_reserve = 1; - } - - if (!use_reserve) { - if (free_huge_pages <= reserved_huge_pages) - goto fail; - } else { - BUG_ON(reserved_huge_pages == 0); - reserved_huge_pages--; - } + if (vma->vm_flags & VM_MAYSHARE) + resv_huge_pages--; + else if (free_huge_pages <= resv_huge_pages) + goto fail; page = dequeue_huge_page(vma, addr); if (!page) @@ -165,96 +139,11 @@ static struct page *alloc_huge_page(struct vm_area_struct *vma, set_page_refcounted(page); return page; - fail: - WARN_ON(use_reserve); /* reserved allocations shouldn't fail */ +fail: spin_unlock(&hugetlb_lock); return NULL; } -/* hugetlb_extend_reservation() - * - * Ensure that at least 'atleast' hugepages are, and will remain, - * available to instantiate the first 'atleast' pages of the given - * inode. If the inode doesn't already have this many pages reserved - * or instantiated, set aside some hugepages in the reserved pool to - * satisfy later faults (or fail now if there aren't enough, rather - * than getting the SIGBUS later). - */ -int hugetlb_extend_reservation(struct hugetlbfs_inode_info *info, - unsigned long atleast) -{ - struct inode *inode = &info->vfs_inode; - unsigned long change_in_reserve = 0; - int ret = 0; - - spin_lock(&hugetlb_lock); - read_lock_irq(&inode->i_mapping->tree_lock); - - if (info->prereserved_hpages >= atleast) - goto out; - - /* Because we always call this on shared mappings, none of the - * pages beyond info->prereserved_hpages can have been - * instantiated, so we need to reserve all of them now. */ - change_in_reserve = atleast - info->prereserved_hpages; - - if ((reserved_huge_pages + change_in_reserve) > free_huge_pages) { - ret = -ENOMEM; - goto out; - } - - reserved_huge_pages += change_in_reserve; - info->prereserved_hpages = atleast; - - out: - read_unlock_irq(&inode->i_mapping->tree_lock); - spin_unlock(&hugetlb_lock); - - return ret; -} - -/* hugetlb_truncate_reservation() - * - * This returns pages reserved for the given inode to the general free - * hugepage pool. If the inode has any pages prereserved, but not - * instantiated, beyond offset (atmost << HPAGE_SIZE), then release - * them. - */ -void hugetlb_truncate_reservation(struct hugetlbfs_inode_info *info, - unsigned long atmost) -{ - struct inode *inode = &info->vfs_inode; - struct address_space *mapping = inode->i_mapping; - unsigned long idx; - unsigned long change_in_reserve = 0; - struct page *page; - - spin_lock(&hugetlb_lock); - read_lock_irq(&inode->i_mapping->tree_lock); - - if (info->prereserved_hpages <= atmost) - goto out; - - /* Count pages which were reserved, but not instantiated, and - * which we can now release. */ - for (idx = atmost; idx < info->prereserved_hpages; idx++) { - page = radix_tree_lookup(&mapping->page_tree, idx); - if (!page) - /* Pages which are already instantiated can't - * be unreserved (and in fact have already - * been removed from the reserved pool) */ - change_in_reserve++; - } - - BUG_ON(reserved_huge_pages < change_in_reserve); - reserved_huge_pages -= change_in_reserve; - info->prereserved_hpages = atmost; - - out: - read_unlock_irq(&inode->i_mapping->tree_lock); - spin_unlock(&hugetlb_lock); -} - static int __init hugetlb_init(void) { unsigned long i; @@ -334,7 +223,7 @@ static unsigned long set_max_huge_pages(unsigned long count) return nr_huge_pages; spin_lock(&hugetlb_lock); - count = max(count, reserved_huge_pages); + count = max(count, resv_huge_pages); try_to_free_low(count); while (count < nr_huge_pages) { struct page *page = dequeue_huge_page(NULL, 0); @@ -361,11 +250,11 @@ int hugetlb_report_meminfo(char *buf) return sprintf(buf, "HugePages_Total: %5lu\n" "HugePages_Free: %5lu\n" - "HugePages_Rsvd: %5lu\n" + "HugePages_Rsvd: %5lu\n" "Hugepagesize: %5lu kB\n", nr_huge_pages, free_huge_pages, - reserved_huge_pages, + resv_huge_pages, HPAGE_SIZE/1024); } @@ -754,3 +643,156 @@ void hugetlb_change_protection(struct vm_area_struct *vma, flush_tlb_range(vma, start, end); } +struct file_region { + struct list_head link; + long from; + long to; +}; + +static long region_add(struct list_head *head, long f, long t) +{ + struct file_region *rg, *nrg, *trg; + + /* Locate the region we are either in or before. */ + list_for_each_entry(rg, head, link) + if (f <= rg->to) + break; + + /* Round our left edge to the current segment if it encloses us. */ + if (f > rg->from) + f = rg->from; + + /* Check for and consume any regions we now overlap with. */ + nrg = rg; + list_for_each_entry_safe(rg, trg, rg->link.prev, link) { + if (&rg->link == head) + break; + if (rg->from > t) + break; + + /* If this area reaches higher then extend our area to + * include it completely. If this is not the first area + * which we intend to reuse, free it. */ + if (rg->to > t) + t = rg->to; + if (rg != nrg) { + list_del(&rg->link); + kfree(rg); + } + } + nrg->from = f; + nrg->to = t; + return 0; +} + +static long region_chg(struct list_head *head, long f, long t) +{ + struct file_region *rg, *nrg; + long chg = 0; + + /* Locate the region we are before or in. */ + list_for_each_entry(rg, head, link) + if (f <= rg->to) + break; + + /* If we are below the current region then a new region is required. + * Subtle, allocate a new region at the position but make it zero + * size such that we can guarentee to record the reservation. */ + if (&rg->link == head || t < rg->from) { + nrg = kmalloc(sizeof(*nrg), GFP_KERNEL); + if (nrg == 0) + return -ENOMEM; + nrg->from = f; + nrg->to = f; + INIT_LIST_HEAD(&nrg->link); + list_add(&nrg->link, rg->link.prev); + + return t - f; + } + + /* Round our left edge to the current segment if it encloses us. */ + if (f > rg->from) + f = rg->from; + chg = t - f; + + /* Check for and consume any regions we now overlap with. */ + list_for_each_entry(rg, rg->link.prev, link) { + if (&rg->link == head) + break; + if (rg->from > t) + return chg; + + /* We overlap with this area, if it extends futher than + * us then we must extend ourselves. Account for its + * existing reservation. */ + if (rg->to > t) { + chg += rg->to - t; + t = rg->to; + } + chg -= rg->to - rg->from; + } + return chg; +} + +static long region_truncate(struct list_head *head, long end) +{ + struct file_region *rg, *trg; + long chg = 0; + + /* Locate the region we are either in or before. */ + list_for_each_entry(rg, head, link) + if (end <= rg->to) + break; + if (&rg->link == head) + return 0; + + /* If we are in the middle of a region then adjust it. */ + if (end > rg->from) { + chg = rg->to - end; + rg->to = end; + rg = list_entry(rg->link.next, typeof(*rg), link); + } + + /* Drop any remaining regions. */ + list_for_each_entry_safe(rg, trg, rg->link.prev, link) { + if (&rg->link == head) + break; + chg += rg->to - rg->from; + list_del(&rg->link); + kfree(rg); + } + return chg; +} + +static int hugetlb_acct_memory(long delta) +{ + int ret = -ENOMEM; + + spin_lock(&hugetlb_lock); + if ((delta + resv_huge_pages) <= free_huge_pages) { + resv_huge_pages += delta; + ret = 0; + } + spin_unlock(&hugetlb_lock); + return ret; +} + +int hugetlb_reserve_pages(struct inode *inode, long from, long to) +{ + long ret, chg; + + chg = region_chg(&inode->i_mapping->private_list, from, to); + if (chg < 0) + return chg; + ret = hugetlb_acct_memory(chg); + if (ret < 0) + return ret; + region_add(&inode->i_mapping->private_list, from, to); + return 0; +} + +void hugetlb_unreserve_pages(struct inode *inode, long offset, long freed) +{ + long chg = region_truncate(&inode->i_mapping->private_list, offset); + hugetlb_acct_memory(freed - chg); +} -- cgit v1.2.3 From 762834e8bf46bf41ce9034d062a7c1f8563175f3 Mon Sep 17 00:00:00 2001 From: Yasunori Goto Date: Fri, 23 Jun 2006 02:03:19 -0700 Subject: [PATCH] Unify pxm_to_node() and node_to_pxm() Consolidate the various arch-specific implementations of pxm_to_node() and node_to_pxm() into a single generic version. Signed-off-by: Yasunori Goto Cc: "Luck, Tony" Cc: Andi Kleen Cc: Dave Hansen Cc: "Brown, Len" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/Kconfig | 6 ++++++ arch/i386/kernel/srat.c | 19 ++-------------- arch/ia64/hp/common/sba_iommu.c | 2 +- arch/ia64/kernel/acpi.c | 24 +++++++-------------- arch/ia64/pci/pci.c | 2 +- arch/ia64/sn/kernel/setup.c | 4 ++-- arch/x86_64/mm/srat.c | 33 +--------------------------- drivers/acpi/Kconfig | 2 +- drivers/acpi/numa.c | 48 +++++++++++++++++++++++++++++++++++++++++ include/acpi/acpi_numa.h | 23 ++++++++++++++++++++ include/asm-x86_64/numa.h | 1 - include/linux/acpi.h | 9 ++++++++ 12 files changed, 102 insertions(+), 71 deletions(-) create mode 100644 include/acpi/acpi_numa.h (limited to 'include') diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig index 8dfa3054f10f..15d23da2455f 100644 --- a/arch/i386/Kconfig +++ b/arch/i386/Kconfig @@ -173,6 +173,12 @@ config ACPI_SRAT bool default y depends on NUMA && (X86_SUMMIT || X86_GENERICARCH) + select ACPI_NUMA + +config HAVE_ARCH_PARSE_SRAT + bool + default y + depends on ACPI_SRAT config X86_SUMMIT_NUMA bool diff --git a/arch/i386/kernel/srat.c b/arch/i386/kernel/srat.c index 52b3ed5d2cb5..989c85255dbe 100644 --- a/arch/i386/kernel/srat.c +++ b/arch/i386/kernel/srat.c @@ -39,7 +39,6 @@ #define NODE_ARRAY_OFFSET(x) ((x) % 8) /* 8 bits/char */ #define BMAP_SET(bmap, bit) ((bmap)[NODE_ARRAY_INDEX(bit)] |= 1 << NODE_ARRAY_OFFSET(bit)) #define BMAP_TEST(bmap, bit) ((bmap)[NODE_ARRAY_INDEX(bit)] & (1 << NODE_ARRAY_OFFSET(bit))) -#define MAX_PXM_DOMAINS 256 /* 1 byte and no promises about values */ /* bitmap length; _PXM is at most 255 */ #define PXM_BITMAP_LEN (MAX_PXM_DOMAINS / 8) static u8 pxm_bitmap[PXM_BITMAP_LEN]; /* bitmap of proximity domains */ @@ -213,19 +212,11 @@ static __init void node_read_chunk(int nid, struct node_memory_chunk_s *memory_c node_end_pfn[nid] = memory_chunk->end_pfn; } -static u8 pxm_to_nid_map[MAX_PXM_DOMAINS];/* _PXM to logical node ID map */ - -int pxm_to_node(int pxm) -{ - return pxm_to_nid_map[pxm]; -} - /* Parse the ACPI Static Resource Affinity Table */ static int __init acpi20_parse_srat(struct acpi_table_srat *sratp) { u8 *start, *end, *p; int i, j, nid; - u8 nid_to_pxm_map[MAX_NUMNODES];/* logical node ID to _PXM map */ start = (u8 *)(&(sratp->reserved) + 1); /* skip header */ p = start; @@ -235,10 +226,6 @@ static int __init acpi20_parse_srat(struct acpi_table_srat *sratp) memset(node_memory_chunk, 0, sizeof(node_memory_chunk)); memset(zholes_size, 0, sizeof(zholes_size)); - /* -1 in these maps means not available */ - memset(pxm_to_nid_map, -1, sizeof(pxm_to_nid_map)); - memset(nid_to_pxm_map, -1, sizeof(nid_to_pxm_map)); - num_memory_chunks = 0; while (p < end) { switch (*p) { @@ -278,9 +265,7 @@ static int __init acpi20_parse_srat(struct acpi_table_srat *sratp) nodes_clear(node_online_map); for (i = 0; i < MAX_PXM_DOMAINS; i++) { if (BMAP_TEST(pxm_bitmap, i)) { - nid = num_online_nodes(); - pxm_to_nid_map[i] = nid; - nid_to_pxm_map[nid] = i; + int nid = acpi_map_pxm_to_node(i); node_set_online(nid); } } @@ -288,7 +273,7 @@ static int __init acpi20_parse_srat(struct acpi_table_srat *sratp) /* set cnode id in memory chunk structure */ for (i = 0; i < num_memory_chunks; i++) - node_memory_chunk[i].nid = pxm_to_nid_map[node_memory_chunk[i].pxm]; + node_memory_chunk[i].nid = pxm_to_node(node_memory_chunk[i].pxm); printk("pxm bitmap: "); for (i = 0; i < sizeof(pxm_bitmap); i++) { diff --git a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c index bdccd0b1eb60..3ce443e6c016 100644 --- a/arch/ia64/hp/common/sba_iommu.c +++ b/arch/ia64/hp/common/sba_iommu.c @@ -1958,7 +1958,7 @@ sba_map_ioc_to_node(struct ioc *ioc, acpi_handle handle) if (pxm < 0) return; - node = pxm_to_nid_map[pxm]; + node = pxm_to_node(pxm); if (node >= MAX_NUMNODES || !node_online(node)) return; diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c index 58c93a30348c..d1c52cf67882 100644 --- a/arch/ia64/kernel/acpi.c +++ b/arch/ia64/kernel/acpi.c @@ -415,9 +415,6 @@ static int __initdata srat_num_cpus; /* number of cpus */ static u32 __devinitdata pxm_flag[PXM_FLAG_LEN]; #define pxm_bit_set(bit) (set_bit(bit,(void *)pxm_flag)) #define pxm_bit_test(bit) (test_bit(bit,(void *)pxm_flag)) -/* maps to convert between proximity domain and logical node ID */ -int __devinitdata pxm_to_nid_map[MAX_PXM_DOMAINS]; -int __initdata nid_to_pxm_map[MAX_NUMNODES]; static struct acpi_table_slit __initdata *slit_table; static int get_processor_proximity_domain(struct acpi_table_processor_affinity *pa) @@ -533,22 +530,17 @@ void __init acpi_numa_arch_fixup(void) * MCD - This can probably be dropped now. No need for pxm ID to node ID * mapping with sparse node numbering iff MAX_PXM_DOMAINS <= MAX_NUMNODES. */ - /* calculate total number of nodes in system from PXM bitmap */ - memset(pxm_to_nid_map, -1, sizeof(pxm_to_nid_map)); - memset(nid_to_pxm_map, -1, sizeof(nid_to_pxm_map)); nodes_clear(node_online_map); for (i = 0; i < MAX_PXM_DOMAINS; i++) { if (pxm_bit_test(i)) { - int nid = num_online_nodes(); - pxm_to_nid_map[i] = nid; - nid_to_pxm_map[nid] = i; + int nid = acpi_map_pxm_to_node(i); node_set_online(nid); } } /* set logical node id in memory chunk structure */ for (i = 0; i < num_node_memblks; i++) - node_memblk[i].nid = pxm_to_nid_map[node_memblk[i].nid]; + node_memblk[i].nid = pxm_to_node(node_memblk[i].nid); /* assign memory bank numbers for each chunk on each node */ for_each_online_node(i) { @@ -562,7 +554,7 @@ void __init acpi_numa_arch_fixup(void) /* set logical node id in cpu structure */ for (i = 0; i < srat_num_cpus; i++) - node_cpuid[i].nid = pxm_to_nid_map[node_cpuid[i].nid]; + node_cpuid[i].nid = pxm_to_node(node_cpuid[i].nid); printk(KERN_INFO "Number of logical nodes in system = %d\n", num_online_nodes()); @@ -575,11 +567,11 @@ void __init acpi_numa_arch_fixup(void) for (i = 0; i < slit_table->localities; i++) { if (!pxm_bit_test(i)) continue; - node_from = pxm_to_nid_map[i]; + node_from = pxm_to_node(i); for (j = 0; j < slit_table->localities; j++) { if (!pxm_bit_test(j)) continue; - node_to = pxm_to_nid_map[j]; + node_to = pxm_to_node(j); node_distance(node_from, node_to) = slit_table->entry[i * slit_table->localities + j]; } @@ -785,9 +777,9 @@ int acpi_map_cpu2node(acpi_handle handle, int cpu, long physid) /* * Assuming that the container driver would have set the proximity - * domain and would have initialized pxm_to_nid_map[pxm_id] && pxm_flag + * domain and would have initialized pxm_to_node(pxm_id) && pxm_flag */ - node_cpuid[cpu].nid = (pxm_id < 0) ? 0 : pxm_to_nid_map[pxm_id]; + node_cpuid[cpu].nid = (pxm_id < 0) ? 0 : pxm_to_node(pxm_id); node_cpuid[cpu].phys_id = physid; #endif @@ -966,7 +958,7 @@ acpi_map_iosapic(acpi_handle handle, u32 depth, void *context, void **ret) if (pxm < 0) return AE_OK; - node = pxm_to_nid_map[pxm]; + node = pxm_to_node(pxm); if (node >= MAX_NUMNODES || !node_online(node) || cpus_empty(node_to_cpumask(node))) diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c index ab829a22f8a4..cf7751b99d1c 100644 --- a/arch/ia64/pci/pci.c +++ b/arch/ia64/pci/pci.c @@ -352,7 +352,7 @@ pci_acpi_scan_root(struct acpi_device *device, int domain, int bus) pxm = acpi_get_pxm(controller->acpi_handle); #ifdef CONFIG_NUMA if (pxm >= 0) - controller->node = pxm_to_nid_map[pxm]; + controller->node = pxm_to_node(pxm); #endif acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_window, diff --git a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c index 30988dfbddff..93577abae36d 100644 --- a/arch/ia64/sn/kernel/setup.c +++ b/arch/ia64/sn/kernel/setup.c @@ -139,7 +139,7 @@ static int __init pxm_to_nasid(int pxm) int i; int nid; - nid = pxm_to_nid_map[pxm]; + nid = pxm_to_node(pxm); for (i = 0; i < num_node_memblks; i++) { if (node_memblk[i].nid == nid) { return NASID_GET(node_memblk[i].start_paddr); @@ -704,7 +704,7 @@ void __init build_cnode_tables(void) * cnode == node for all C & M bricks. */ for_each_online_node(node) { - nasid = pxm_to_nasid(nid_to_pxm_map[node]); + nasid = pxm_to_nasid(node_to_pxm(node)); sn_cnodeid_to_nasid[node] = nasid; physical_node_map[nasid] = node; } diff --git a/arch/x86_64/mm/srat.c b/arch/x86_64/mm/srat.c index 474df22c6ed2..502fce65e96a 100644 --- a/arch/x86_64/mm/srat.c +++ b/arch/x86_64/mm/srat.c @@ -30,7 +30,6 @@ static struct acpi_table_slit *acpi_slit; static nodemask_t nodes_parsed __initdata; -static nodemask_t nodes_found __initdata; static struct bootnode nodes[MAX_NUMNODES] __initdata; static struct bootnode nodes_add[MAX_NUMNODES] __initdata; static int found_add_area __initdata; @@ -38,33 +37,14 @@ int hotadd_percent __initdata = 0; #ifndef RESERVE_HOTADD #define hotadd_percent 0 /* Ignore all settings */ #endif -static u8 pxm2node[256] = { [0 ... 255] = 0xff }; /* Too small nodes confuse the VM badly. Usually they result from BIOS bugs. */ #define NODE_MIN_SIZE (4*1024*1024) -static int node_to_pxm(int n); - -int pxm_to_node(int pxm) -{ - if ((unsigned)pxm >= 256) - return -1; - /* Extend 0xff to (int)-1 */ - return (signed char)pxm2node[pxm]; -} - static __init int setup_node(int pxm) { - unsigned node = pxm2node[pxm]; - if (node == 0xff) { - if (nodes_weight(nodes_found) >= MAX_NUMNODES) - return -1; - node = first_unset_node(nodes_found); - node_set(node, nodes_found); - pxm2node[pxm] = node; - } - return pxm2node[pxm]; + return acpi_map_pxm_to_node(pxm); } static __init int conflicting_nodes(unsigned long start, unsigned long end) @@ -440,17 +420,6 @@ int __init acpi_scan_nodes(unsigned long start, unsigned long end) return 0; } -static int node_to_pxm(int n) -{ - int i; - if (pxm2node[n] == n) - return n; - for (i = 0; i < 256; i++) - if (pxm2node[i] == n) - return i; - return 0; -} - void __init srat_reserve_add_area(int nodeid) { if (found_add_area && nodes_add[nodeid].end) { diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index c24652d31bf9..230c53852231 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -162,7 +162,7 @@ config ACPI_THERMAL config ACPI_NUMA bool "NUMA support" depends on NUMA - depends on (IA64 || X86_64) + depends on (X86 || IA64) default y if IA64_GENERIC || IA64_SGI_SN2 config ACPI_ASUS diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c index 64b98e82feb7..e2c1a16078c9 100644 --- a/drivers/acpi/numa.c +++ b/drivers/acpi/numa.c @@ -36,12 +36,60 @@ #define _COMPONENT ACPI_NUMA ACPI_MODULE_NAME("numa") +static nodemask_t nodes_found_map = NODE_MASK_NONE; +#define PXM_INVAL -1 +#define NID_INVAL -1 + +/* maps to convert between proximity domain and logical node ID */ +int __cpuinitdata pxm_to_node_map[MAX_PXM_DOMAINS] + = { [0 ... MAX_PXM_DOMAINS - 1] = NID_INVAL }; +int __cpuinitdata node_to_pxm_map[MAX_NUMNODES] + = { [0 ... MAX_NUMNODES - 1] = PXM_INVAL }; + extern int __init acpi_table_parse_madt_family(enum acpi_table_id id, unsigned long madt_size, int entry_id, acpi_madt_entry_handler handler, unsigned int max_entries); +int __cpuinit pxm_to_node(int pxm) +{ + if (pxm < 0) + return NID_INVAL; + return pxm_to_node_map[pxm]; +} + +int __cpuinit node_to_pxm(int node) +{ + if (node < 0) + return PXM_INVAL; + return node_to_pxm_map[node]; +} + +int __cpuinit acpi_map_pxm_to_node(int pxm) +{ + int node = pxm_to_node_map[pxm]; + + if (node < 0){ + if (nodes_weight(nodes_found_map) >= MAX_NUMNODES) + return NID_INVAL; + node = first_unset_node(nodes_found_map); + pxm_to_node_map[pxm] = node; + node_to_pxm_map[node] = pxm; + node_set(node, nodes_found_map); + } + + return node; +} + +void __cpuinit acpi_unmap_pxm_to_node(int node) +{ + int pxm = node_to_pxm_map[node]; + pxm_to_node_map[pxm] = NID_INVAL; + node_to_pxm_map[node] = PXM_INVAL; + node_clear(node, nodes_found_map); +} + void __init acpi_table_print_srat_entry(acpi_table_entry_header * header) { diff --git a/include/acpi/acpi_numa.h b/include/acpi/acpi_numa.h new file mode 100644 index 000000000000..1049f2a0a6db --- /dev/null +++ b/include/acpi/acpi_numa.h @@ -0,0 +1,23 @@ +#ifndef __ACPI_NUMA_H +#define __ACPI_NUMA_H + +#ifdef CONFIG_ACPI_NUMA +#include + +/* Proximity bitmap length */ +#if MAX_NUMNODES > 256 +#define MAX_PXM_DOMAINS MAX_NUMNODES +#else +#define MAX_PXM_DOMAINS (256) /* Old pxm spec is defined 8 bit */ +#endif + +extern int __cpuinitdata pxm_to_node_map[MAX_PXM_DOMAINS]; +extern int __cpuinitdata node_to_pxm_map[MAX_NUMNODES]; + +extern int __cpuinit pxm_to_node(int); +extern int __cpuinit node_to_pxm(int); +extern int __cpuinit acpi_map_pxm_to_node(int); +extern void __cpuinit acpi_unmap_pxm_to_node(int); + +#endif /* CONFIG_ACPI_NUMA */ +#endif /* __ACP_NUMA_H */ diff --git a/include/asm-x86_64/numa.h b/include/asm-x86_64/numa.h index 1cc92fe02503..933ff11ece15 100644 --- a/include/asm-x86_64/numa.h +++ b/include/asm-x86_64/numa.h @@ -8,7 +8,6 @@ struct bootnode { }; extern int compute_hash_shift(struct bootnode *nodes, int numnodes); -extern int pxm_to_node(int nid); #define ZONE_ALIGN (1UL << (MAX_ORDER+PAGE_SHIFT)) diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 1cf0b91d05bd..90d6df1551ed 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -37,6 +37,7 @@ #include #include #include +#include #include @@ -407,10 +408,18 @@ void acpi_table_print_madt_entry (acpi_table_entry_header *madt); void acpi_table_print_srat_entry (acpi_table_entry_header *srat); /* the following four functions are architecture-dependent */ +#ifdef CONFIG_HAVE_ARCH_PARSE_SRAT +#define NR_NODE_MEMBLKS MAX_NUMNODES +#define acpi_numa_slit_init(slit) do {} while (0) +#define acpi_numa_processor_affinity_init(pa) do {} while (0) +#define acpi_numa_memory_affinity_init(ma) do {} while (0) +#define acpi_numa_arch_fixup() do {} while (0) +#else void acpi_numa_slit_init (struct acpi_table_slit *slit); void acpi_numa_processor_affinity_init (struct acpi_table_processor_affinity *pa); void acpi_numa_memory_affinity_init (struct acpi_table_memory_affinity *ma); void acpi_numa_arch_fixup(void); +#endif #ifdef CONFIG_ACPI_HOTPLUG_CPU /* Arch dependent functions for cpu hotplug support */ -- cgit v1.2.3 From 833423143c3a7c6545e409d65febd0d92deb351b Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Fri, 23 Jun 2006 02:03:20 -0700 Subject: [PATCH] mm: introduce remap_vmalloc_range() Add remap_vmalloc_range, vmalloc_user, and vmalloc_32_user so that drivers can have a nice interface for remapping vmalloc memory. Signed-off-by: Nick Piggin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/vmalloc.h | 8 ++++ mm/vmalloc.c | 122 +++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 128 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h index 1d5577b2b752..f6024ab4eff0 100644 --- a/include/linux/vmalloc.h +++ b/include/linux/vmalloc.h @@ -4,10 +4,13 @@ #include #include /* pgprot_t */ +struct vm_area_struct; + /* bits in vm_struct->flags */ #define VM_IOREMAP 0x00000001 /* ioremap() and friends */ #define VM_ALLOC 0x00000002 /* vmalloc() */ #define VM_MAP 0x00000004 /* vmap()ed pages */ +#define VM_USERMAP 0x00000008 /* suitable for remap_vmalloc_range */ /* bits [20..32] reserved for arch specific ioremap internals */ /* @@ -32,9 +35,11 @@ struct vm_struct { * Highlevel APIs for driver use */ extern void *vmalloc(unsigned long size); +extern void *vmalloc_user(unsigned long size); extern void *vmalloc_node(unsigned long size, int node); extern void *vmalloc_exec(unsigned long size); extern void *vmalloc_32(unsigned long size); +extern void *vmalloc_32_user(unsigned long size); extern void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot); extern void *__vmalloc_area(struct vm_struct *area, gfp_t gfp_mask, pgprot_t prot); @@ -45,6 +50,9 @@ extern void vfree(void *addr); extern void *vmap(struct page **pages, unsigned int count, unsigned long flags, pgprot_t prot); extern void vunmap(void *addr); + +extern int remap_vmalloc_range(struct vm_area_struct *vma, void *addr, + unsigned long pgoff); /* * Lowlevel-APIs (not for driver use!) diff --git a/mm/vmalloc.c b/mm/vmalloc.c index c0504f1e34eb..35f8553f893a 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -256,6 +256,19 @@ struct vm_struct *get_vm_area_node(unsigned long size, unsigned long flags, int return __get_vm_area_node(size, flags, VMALLOC_START, VMALLOC_END, node); } +/* Caller must hold vmlist_lock */ +static struct vm_struct *__find_vm_area(void *addr) +{ + struct vm_struct *tmp; + + for (tmp = vmlist; tmp != NULL; tmp = tmp->next) { + if (tmp->addr == addr) + break; + } + + return tmp; +} + /* Caller must hold vmlist_lock */ struct vm_struct *__remove_vm_area(void *addr) { @@ -498,10 +511,32 @@ EXPORT_SYMBOL(__vmalloc); */ void *vmalloc(unsigned long size) { - return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL); + return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL); } EXPORT_SYMBOL(vmalloc); +/** + * vmalloc_user - allocate virtually contiguous memory which has + * been zeroed so it can be mapped to userspace without + * leaking data. + * + * @size: allocation size + */ +void *vmalloc_user(unsigned long size) +{ + struct vm_struct *area; + void *ret; + + ret = __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO, PAGE_KERNEL); + write_lock(&vmlist_lock); + area = __find_vm_area(ret); + area->flags |= VM_USERMAP; + write_unlock(&vmlist_lock); + + return ret; +} +EXPORT_SYMBOL(vmalloc_user); + /** * vmalloc_node - allocate memory on a specific node * @@ -516,7 +551,7 @@ EXPORT_SYMBOL(vmalloc); */ void *vmalloc_node(unsigned long size, int node) { - return __vmalloc_node(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL, node); + return __vmalloc_node(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL, node); } EXPORT_SYMBOL(vmalloc_node); @@ -556,6 +591,28 @@ void *vmalloc_32(unsigned long size) } EXPORT_SYMBOL(vmalloc_32); +/** + * vmalloc_32_user - allocate virtually contiguous memory (32bit + * addressable) which is zeroed so it can be + * mapped to userspace without leaking data. + * + * @size: allocation size + */ +void *vmalloc_32_user(unsigned long size) +{ + struct vm_struct *area; + void *ret; + + ret = __vmalloc(size, GFP_KERNEL | __GFP_ZERO, PAGE_KERNEL); + write_lock(&vmlist_lock); + area = __find_vm_area(ret); + area->flags |= VM_USERMAP; + write_unlock(&vmlist_lock); + + return ret; +} +EXPORT_SYMBOL(vmalloc_32_user); + long vread(char *buf, char *addr, unsigned long count) { struct vm_struct *tmp; @@ -630,3 +687,64 @@ finished: read_unlock(&vmlist_lock); return buf - buf_start; } + +/** + * remap_vmalloc_range - map vmalloc pages to userspace + * + * @vma: vma to cover (map full range of vma) + * @addr: vmalloc memory + * @pgoff: number of pages into addr before first page to map + * @returns: 0 for success, -Exxx on failure + * + * This function checks that addr is a valid vmalloc'ed area, and + * that it is big enough to cover the vma. Will return failure if + * that criteria isn't met. + * + * Similar to remap_pfn_range (see mm/memory.c) + */ +int remap_vmalloc_range(struct vm_area_struct *vma, void *addr, + unsigned long pgoff) +{ + struct vm_struct *area; + unsigned long uaddr = vma->vm_start; + unsigned long usize = vma->vm_end - vma->vm_start; + int ret; + + if ((PAGE_SIZE-1) & (unsigned long)addr) + return -EINVAL; + + read_lock(&vmlist_lock); + area = __find_vm_area(addr); + if (!area) + goto out_einval_locked; + + if (!(area->flags & VM_USERMAP)) + goto out_einval_locked; + + if (usize + (pgoff << PAGE_SHIFT) > area->size - PAGE_SIZE) + goto out_einval_locked; + read_unlock(&vmlist_lock); + + addr += pgoff << PAGE_SHIFT; + do { + struct page *page = vmalloc_to_page(addr); + ret = vm_insert_page(vma, uaddr, page); + if (ret) + return ret; + + uaddr += PAGE_SIZE; + addr += PAGE_SIZE; + usize -= PAGE_SIZE; + } while (usize > 0); + + /* Prevent "things" like memory migration? VM_flags need a cleanup... */ + vma->vm_flags |= VM_RESERVED; + + return ret; + +out_einval_locked: + read_unlock(&vmlist_lock); + return -EINVAL; +} +EXPORT_SYMBOL(remap_vmalloc_range); + -- cgit v1.2.3 From 929f97276bcf7f4a95272ed08a85339b98ba210d Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Fri, 23 Jun 2006 02:03:21 -0700 Subject: [PATCH] change gen_pool allocator to not touch managed memory Modify the gen_pool allocator (lib/genalloc.c) to utilize a bitmap scheme instead of the buddy scheme. The purpose of this change is to eliminate the touching of the actual memory being allocated. Since the change modifies the interface, a change to the uncached allocator (arch/ia64/kernel/uncached.c) is also required. Both Andrey Volkov and Jes Sorenson have expressed a desire that the gen_pool allocator not write to the memory being managed. See the following: http://marc.theaimsgroup.com/?l=linux-kernel&m=113518602713125&w=2 http://marc.theaimsgroup.com/?l=linux-kernel&m=113533568827916&w=2 Signed-off-by: Dean Nelson Cc: Andrey Volkov Acked-by: Jes Sorensen Cc: "Luck, Tony" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ia64/kernel/uncached.c | 200 +++++++++++++++--------------- arch/ia64/sn/kernel/sn2/cache.c | 15 ++- include/linux/genalloc.h | 35 +++--- lib/genalloc.c | 263 ++++++++++++++++++---------------------- 4 files changed, 252 insertions(+), 261 deletions(-) (limited to 'include') diff --git a/arch/ia64/kernel/uncached.c b/arch/ia64/kernel/uncached.c index fcd2bad0286f..5f03b9e524dd 100644 --- a/arch/ia64/kernel/uncached.c +++ b/arch/ia64/kernel/uncached.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001-2005 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2001-2006 Silicon Graphics, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License @@ -29,15 +29,8 @@ #include #include -#define DEBUG 0 -#if DEBUG -#define dprintk printk -#else -#define dprintk(x...) do { } while (0) -#endif - -void __init efi_memmap_walk_uc (efi_freemem_callback_t callback); +extern void __init efi_memmap_walk_uc(efi_freemem_callback_t, void *); #define MAX_UNCACHED_GRANULES 5 static int allocated_granules; @@ -60,6 +53,7 @@ static void uncached_ipi_visibility(void *data) static void uncached_ipi_mc_drain(void *data) { int status; + status = ia64_pal_mc_drain(); if (status) printk(KERN_WARNING "ia64_pal_mc_drain() failed with %i on " @@ -67,30 +61,35 @@ static void uncached_ipi_mc_drain(void *data) } -static unsigned long -uncached_get_new_chunk(struct gen_pool *poolp) +/* + * Add a new chunk of uncached memory pages to the specified pool. + * + * @pool: pool to add new chunk of uncached memory to + * @nid: node id of node to allocate memory from, or -1 + * + * This is accomplished by first allocating a granule of cached memory pages + * and then converting them to uncached memory pages. + */ +static int uncached_add_chunk(struct gen_pool *pool, int nid) { struct page *page; - void *tmp; int status, i; - unsigned long addr, node; + unsigned long c_addr, uc_addr; if (allocated_granules >= MAX_UNCACHED_GRANULES) - return 0; + return -1; + + /* attempt to allocate a granule's worth of cached memory pages */ - node = poolp->private; - page = alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, + page = alloc_pages_node(nid, GFP_KERNEL | __GFP_ZERO, IA64_GRANULE_SHIFT-PAGE_SHIFT); + if (!page) + return -1; - dprintk(KERN_INFO "get_new_chunk page %p, addr %lx\n", - page, (unsigned long)(page-vmem_map) << PAGE_SHIFT); + /* convert the memory pages from cached to uncached */ - /* - * Do magic if no mem on local node! XXX - */ - if (!page) - return 0; - tmp = page_address(page); + c_addr = (unsigned long)page_address(page); + uc_addr = c_addr - PAGE_OFFSET + __IA64_UNCACHED_OFFSET; /* * There's a small race here where it's possible for someone to @@ -100,76 +99,90 @@ uncached_get_new_chunk(struct gen_pool *poolp) for (i = 0; i < (IA64_GRANULE_SIZE / PAGE_SIZE); i++) SetPageUncached(&page[i]); - flush_tlb_kernel_range(tmp, tmp + IA64_GRANULE_SIZE); + flush_tlb_kernel_range(uc_addr, uc_adddr + IA64_GRANULE_SIZE); status = ia64_pal_prefetch_visibility(PAL_VISIBILITY_PHYSICAL); - - dprintk(KERN_INFO "pal_prefetch_visibility() returns %i on cpu %i\n", - status, raw_smp_processor_id()); - if (!status) { status = smp_call_function(uncached_ipi_visibility, NULL, 0, 1); if (status) - printk(KERN_WARNING "smp_call_function failed for " - "uncached_ipi_visibility! (%i)\n", status); + goto failed; } + preempt_disable(); + if (ia64_platform_is("sn2")) - sn_flush_all_caches((unsigned long)tmp, IA64_GRANULE_SIZE); + sn_flush_all_caches(uc_addr, IA64_GRANULE_SIZE); else - flush_icache_range((unsigned long)tmp, - (unsigned long)tmp+IA64_GRANULE_SIZE); + flush_icache_range(uc_addr, uc_addr + IA64_GRANULE_SIZE); + + /* flush the just introduced uncached translation from the TLB */ + local_flush_tlb_all(); + + preempt_enable(); ia64_pal_mc_drain(); status = smp_call_function(uncached_ipi_mc_drain, NULL, 0, 1); if (status) - printk(KERN_WARNING "smp_call_function failed for " - "uncached_ipi_mc_drain! (%i)\n", status); + goto failed; - addr = (unsigned long)tmp - PAGE_OFFSET + __IA64_UNCACHED_OFFSET; + /* + * The chunk of memory pages has been converted to uncached so now we + * can add it to the pool. + */ + status = gen_pool_add(pool, uc_addr, IA64_GRANULE_SIZE, nid); + if (status) + goto failed; allocated_granules++; - return addr; + return 0; + + /* failed to convert or add the chunk so give it back to the kernel */ +failed: + for (i = 0; i < (IA64_GRANULE_SIZE / PAGE_SIZE); i++) + ClearPageUncached(&page[i]); + + free_pages(c_addr, IA64_GRANULE_SHIFT-PAGE_SHIFT); + return -1; } /* * uncached_alloc_page * + * @starting_nid: node id of node to start with, or -1 + * * Allocate 1 uncached page. Allocates on the requested node. If no * uncached pages are available on the requested node, roundrobin starting - * with higher nodes. + * with the next higher node. */ -unsigned long -uncached_alloc_page(int nid) +unsigned long uncached_alloc_page(int starting_nid) { - unsigned long maddr; + unsigned long uc_addr; + struct gen_pool *pool; + int nid; - maddr = gen_pool_alloc(uncached_pool[nid], PAGE_SIZE); + if (unlikely(starting_nid >= MAX_NUMNODES)) + return 0; - dprintk(KERN_DEBUG "uncached_alloc_page returns %lx on node %i\n", - maddr, nid); + if (starting_nid < 0) + starting_nid = numa_node_id(); + nid = starting_nid; - /* - * If no memory is availble on our local node, try the - * remaining nodes in the system. - */ - if (!maddr) { - int i; - - for (i = MAX_NUMNODES - 1; i >= 0; i--) { - if (i == nid || !node_online(i)) - continue; - maddr = gen_pool_alloc(uncached_pool[i], PAGE_SIZE); - dprintk(KERN_DEBUG "uncached_alloc_page alternate search " - "returns %lx on node %i\n", maddr, i); - if (maddr) { - break; - } - } - } + do { + if (!node_online(nid)) + continue; + pool = uncached_pool[nid]; + if (pool == NULL) + continue; + do { + uc_addr = gen_pool_alloc(pool, PAGE_SIZE); + if (uc_addr != 0) + return uc_addr; + } while (uncached_add_chunk(pool, nid) == 0); + + } while ((nid = (nid + 1) % MAX_NUMNODES) != starting_nid); - return maddr; + return 0; } EXPORT_SYMBOL(uncached_alloc_page); @@ -177,21 +190,22 @@ EXPORT_SYMBOL(uncached_alloc_page); /* * uncached_free_page * + * @uc_addr: uncached address of page to free + * * Free a single uncached page. */ -void -uncached_free_page(unsigned long maddr) +void uncached_free_page(unsigned long uc_addr) { - int node; - - node = paddr_to_nid(maddr - __IA64_UNCACHED_OFFSET); + int nid = paddr_to_nid(uc_addr - __IA64_UNCACHED_OFFSET); + struct gen_pool *pool = uncached_pool[nid]; - dprintk(KERN_DEBUG "uncached_free_page(%lx) on node %i\n", maddr, node); + if (unlikely(pool == NULL)) + return; - if ((maddr & (0XFUL << 60)) != __IA64_UNCACHED_OFFSET) - panic("uncached_free_page invalid address %lx\n", maddr); + if ((uc_addr & (0XFUL << 60)) != __IA64_UNCACHED_OFFSET) + panic("uncached_free_page invalid address %lx\n", uc_addr); - gen_pool_free(uncached_pool[node], maddr, PAGE_SIZE); + gen_pool_free(pool, uc_addr, PAGE_SIZE); } EXPORT_SYMBOL(uncached_free_page); @@ -199,43 +213,39 @@ EXPORT_SYMBOL(uncached_free_page); /* * uncached_build_memmap, * + * @uc_start: uncached starting address of a chunk of uncached memory + * @uc_end: uncached ending address of a chunk of uncached memory + * @arg: ignored, (NULL argument passed in on call to efi_memmap_walk_uc()) + * * Called at boot time to build a map of pages that can be used for * memory special operations. */ -static int __init -uncached_build_memmap(unsigned long start, unsigned long end, void *arg) +static int __init uncached_build_memmap(unsigned long uc_start, + unsigned long uc_end, void *arg) { - long length = end - start; - int node; - - dprintk(KERN_ERR "uncached_build_memmap(%lx %lx)\n", start, end); + int nid = paddr_to_nid(uc_start - __IA64_UNCACHED_OFFSET); + struct gen_pool *pool = uncached_pool[nid]; + size_t size = uc_end - uc_start; touch_softlockup_watchdog(); - memset((char *)start, 0, length); - node = paddr_to_nid(start - __IA64_UNCACHED_OFFSET); - - for (; start < end ; start += PAGE_SIZE) { - dprintk(KERN_INFO "sticking %lx into the pool!\n", start); - gen_pool_free(uncached_pool[node], start, PAGE_SIZE); + if (pool != NULL) { + memset((char *)uc_start, 0, size); + (void) gen_pool_add(pool, uc_start, size, nid); } - return 0; } -static int __init uncached_init(void) { - int i; +static int __init uncached_init(void) +{ + int nid; - for (i = 0; i < MAX_NUMNODES; i++) { - if (!node_online(i)) - continue; - uncached_pool[i] = gen_pool_create(0, IA64_GRANULE_SHIFT, - &uncached_get_new_chunk, i); + for_each_online_node(nid) { + uncached_pool[nid] = gen_pool_create(PAGE_SHIFT, nid); } - efi_memmap_walk_uc(uncached_build_memmap); - + efi_memmap_walk_uc(uncached_build_memmap, NULL); return 0; } diff --git a/arch/ia64/sn/kernel/sn2/cache.c b/arch/ia64/sn/kernel/sn2/cache.c index bc3cfa17cd0f..2862cb33026d 100644 --- a/arch/ia64/sn/kernel/sn2/cache.c +++ b/arch/ia64/sn/kernel/sn2/cache.c @@ -3,11 +3,12 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2001-2003, 2006 Silicon Graphics, Inc. All rights reserved. * */ #include #include +#include /** * sn_flush_all_caches - flush a range of address from all caches (incl. L4) @@ -17,18 +18,24 @@ * Flush a range of addresses from all caches including L4. * All addresses fully or partially contained within * @flush_addr to @flush_addr + @bytes are flushed - * from the all caches. + * from all caches. */ void sn_flush_all_caches(long flush_addr, long bytes) { - flush_icache_range(flush_addr, flush_addr+bytes); + unsigned long addr = flush_addr; + + /* SHub1 requires a cached address */ + if (is_shub1() && (addr & RGN_BITS) == RGN_BASE(RGN_UNCACHED)) + addr = (addr - RGN_BASE(RGN_UNCACHED)) + RGN_BASE(RGN_KERNEL); + + flush_icache_range(addr, addr + bytes); /* * The last call may have returned before the caches * were actually flushed, so we call it again to make * sure. */ - flush_icache_range(flush_addr, flush_addr+bytes); + flush_icache_range(addr, addr + bytes); mb(); } EXPORT_SYMBOL(sn_flush_all_caches); diff --git a/include/linux/genalloc.h b/include/linux/genalloc.h index 7fd0576a4454..690c42803d2e 100644 --- a/include/linux/genalloc.h +++ b/include/linux/genalloc.h @@ -4,37 +4,32 @@ * Uses for this includes on-device special memory, uncached memory * etc. * - * This code is based on the buddy allocator found in the sym53c8xx_2 - * driver, adapted for general purpose use. - * * This source code is licensed under the GNU General Public License, * Version 2. See the file COPYING for more details. */ -#include -#define ALLOC_MIN_SHIFT 5 /* 32 bytes minimum */ /* - * Link between free memory chunks of a given size. + * General purpose special memory pool descriptor. */ -struct gen_pool_link { - struct gen_pool_link *next; +struct gen_pool { + rwlock_t lock; + struct list_head chunks; /* list of chunks in this pool */ + int min_alloc_order; /* minimum allocation order */ }; /* - * Memory pool descriptor. + * General purpose special memory pool chunk descriptor. */ -struct gen_pool { +struct gen_pool_chunk { spinlock_t lock; - unsigned long (*get_new_chunk)(struct gen_pool *); - struct gen_pool *next; - struct gen_pool_link *h; - unsigned long private; - int max_chunk_shift; + struct list_head next_chunk; /* next chunk in pool */ + unsigned long start_addr; /* starting address of memory chunk */ + unsigned long end_addr; /* ending address of memory chunk */ + unsigned long bits[0]; /* bitmap for allocating memory chunk */ }; -unsigned long gen_pool_alloc(struct gen_pool *poolp, int size); -void gen_pool_free(struct gen_pool *mp, unsigned long ptr, int size); -struct gen_pool *gen_pool_create(int nr_chunks, int max_chunk_shift, - unsigned long (*fp)(struct gen_pool *), - unsigned long data); +extern struct gen_pool *gen_pool_create(int, int); +extern int gen_pool_add(struct gen_pool *, unsigned long, size_t, int); +extern unsigned long gen_pool_alloc(struct gen_pool *, size_t); +extern void gen_pool_free(struct gen_pool *, unsigned long, size_t); diff --git a/lib/genalloc.c b/lib/genalloc.c index 9ce0a6a3b85a..71338b48e889 100644 --- a/lib/genalloc.c +++ b/lib/genalloc.c @@ -4,10 +4,6 @@ * Uses for this includes on-device special memory, uncached memory * etc. * - * This code is based on the buddy allocator found in the sym53c8xx_2 - * driver Copyright (C) 1999-2001 Gerard Roudier , - * and adapted for general purpose use. - * * Copyright 2005 (C) Jes Sorensen * * This source code is licensed under the GNU General Public License, @@ -15,172 +11,155 @@ */ #include -#include -#include -#include -#include -#include -#include -#include #include -#include - -struct gen_pool *gen_pool_create(int nr_chunks, int max_chunk_shift, - unsigned long (*fp)(struct gen_pool *), - unsigned long data) +/* + * Create a new special memory pool. + * + * @min_alloc_order: log base 2 of number of bytes each bitmap bit represents + * @nid: node id of the node the pool structure should be allocated on, or -1 + */ +struct gen_pool *gen_pool_create(int min_alloc_order, int nid) { - struct gen_pool *poolp; - unsigned long tmp; - int i; - - /* - * This is really an arbitrary limit, +10 is enough for - * IA64_GRANULE_SHIFT, aka 16MB. If anyone needs a large limit - * this can be increased without problems. - */ - if ((max_chunk_shift > (PAGE_SHIFT + 10)) || - ((max_chunk_shift < ALLOC_MIN_SHIFT) && max_chunk_shift)) - return NULL; - - if (!max_chunk_shift) - max_chunk_shift = PAGE_SHIFT; - - poolp = kmalloc(sizeof(struct gen_pool), GFP_KERNEL); - if (!poolp) - return NULL; - memset(poolp, 0, sizeof(struct gen_pool)); - poolp->h = kmalloc(sizeof(struct gen_pool_link) * - (max_chunk_shift - ALLOC_MIN_SHIFT + 1), - GFP_KERNEL); - if (!poolp->h) { - printk(KERN_WARNING "gen_pool_alloc() failed to allocate\n"); - kfree(poolp); - return NULL; - } - memset(poolp->h, 0, sizeof(struct gen_pool_link) * - (max_chunk_shift - ALLOC_MIN_SHIFT + 1)); - - spin_lock_init(&poolp->lock); - poolp->get_new_chunk = fp; - poolp->max_chunk_shift = max_chunk_shift; - poolp->private = data; - - for (i = 0; i < nr_chunks; i++) { - tmp = poolp->get_new_chunk(poolp); - printk(KERN_INFO "allocated %lx\n", tmp); - if (!tmp) - break; - gen_pool_free(poolp, tmp, (1 << poolp->max_chunk_shift)); - } + struct gen_pool *pool; - return poolp; + pool = kmalloc_node(sizeof(struct gen_pool), GFP_KERNEL, nid); + if (pool != NULL) { + rwlock_init(&pool->lock); + INIT_LIST_HEAD(&pool->chunks); + pool->min_alloc_order = min_alloc_order; + } + return pool; } EXPORT_SYMBOL(gen_pool_create); /* - * Simple power of two buddy-like generic allocator. - * Provides naturally aligned memory chunks. + * Add a new chunk of memory to the specified pool. + * + * @pool: pool to add new memory chunk to + * @addr: starting address of memory chunk to add to pool + * @size: size in bytes of the memory chunk to add to pool + * @nid: node id of the node the chunk structure and bitmap should be + * allocated on, or -1 */ -unsigned long gen_pool_alloc(struct gen_pool *poolp, int size) +int gen_pool_add(struct gen_pool *pool, unsigned long addr, size_t size, + int nid) { - int j, i, s, max_chunk_size; - unsigned long a, flags; - struct gen_pool_link *h = poolp->h; + struct gen_pool_chunk *chunk; + int nbits = size >> pool->min_alloc_order; + int nbytes = sizeof(struct gen_pool_chunk) + + (nbits + BITS_PER_BYTE - 1) / BITS_PER_BYTE; - max_chunk_size = 1 << poolp->max_chunk_shift; + chunk = kmalloc_node(nbytes, GFP_KERNEL, nid); + if (unlikely(chunk == NULL)) + return -1; - if (size > max_chunk_size) - return 0; + memset(chunk, 0, nbytes); + spin_lock_init(&chunk->lock); + chunk->start_addr = addr; + chunk->end_addr = addr + size; - size = max(size, 1 << ALLOC_MIN_SHIFT); - i = fls(size - 1); - s = 1 << i; - j = i -= ALLOC_MIN_SHIFT; - - spin_lock_irqsave(&poolp->lock, flags); - while (!h[j].next) { - if (s == max_chunk_size) { - struct gen_pool_link *ptr; - spin_unlock_irqrestore(&poolp->lock, flags); - ptr = (struct gen_pool_link *)poolp->get_new_chunk(poolp); - spin_lock_irqsave(&poolp->lock, flags); - h[j].next = ptr; - if (h[j].next) - h[j].next->next = NULL; - break; - } - j++; - s <<= 1; - } - a = (unsigned long) h[j].next; - if (a) { - h[j].next = h[j].next->next; - /* - * This should be split into a seperate function doing - * the chunk split in order to support custom - * handling memory not physically accessible by host - */ - while (j > i) { - j -= 1; - s >>= 1; - h[j].next = (struct gen_pool_link *) (a + s); - h[j].next->next = NULL; - } - } - spin_unlock_irqrestore(&poolp->lock, flags); - return a; + write_lock(&pool->lock); + list_add(&chunk->next_chunk, &pool->chunks); + write_unlock(&pool->lock); + + return 0; } -EXPORT_SYMBOL(gen_pool_alloc); +EXPORT_SYMBOL(gen_pool_add); /* - * Counter-part of the generic allocator. + * Allocate the requested number of bytes from the specified pool. + * Uses a first-fit algorithm. + * + * @pool: pool to allocate from + * @size: number of bytes to allocate from the pool */ -void gen_pool_free(struct gen_pool *poolp, unsigned long ptr, int size) +unsigned long gen_pool_alloc(struct gen_pool *pool, size_t size) { - struct gen_pool_link *q; - struct gen_pool_link *h = poolp->h; - unsigned long a, b, flags; - int i, s, max_chunk_size; - - max_chunk_size = 1 << poolp->max_chunk_shift; + struct list_head *_chunk; + struct gen_pool_chunk *chunk; + unsigned long addr, flags; + int order = pool->min_alloc_order; + int nbits, bit, start_bit, end_bit; - if (size > max_chunk_size) - return; - - size = max(size, 1 << ALLOC_MIN_SHIFT); - i = fls(size - 1); - s = 1 << i; - i -= ALLOC_MIN_SHIFT; - - a = ptr; + if (size == 0) + return 0; - spin_lock_irqsave(&poolp->lock, flags); - while (1) { - if (s == max_chunk_size) { - ((struct gen_pool_link *)a)->next = h[i].next; - h[i].next = (struct gen_pool_link *)a; - break; + nbits = (size + (1UL << order) - 1) >> order; + + read_lock(&pool->lock); + list_for_each(_chunk, &pool->chunks) { + chunk = list_entry(_chunk, struct gen_pool_chunk, next_chunk); + + end_bit = (chunk->end_addr - chunk->start_addr) >> order; + end_bit -= nbits + 1; + + spin_lock_irqsave(&chunk->lock, flags); + bit = -1; + while (bit + 1 < end_bit) { + bit = find_next_zero_bit(chunk->bits, end_bit, bit + 1); + if (bit >= end_bit) + break; + + start_bit = bit; + if (nbits > 1) { + bit = find_next_bit(chunk->bits, bit + nbits, + bit + 1); + if (bit - start_bit < nbits) + continue; + } + + addr = chunk->start_addr + + ((unsigned long)start_bit << order); + while (nbits--) + __set_bit(start_bit++, &chunk->bits); + spin_unlock_irqrestore(&chunk->lock, flags); + read_unlock(&pool->lock); + return addr; } - b = a ^ s; - q = &h[i]; + spin_unlock_irqrestore(&chunk->lock, flags); + } + read_unlock(&pool->lock); + return 0; +} +EXPORT_SYMBOL(gen_pool_alloc); - while (q->next && q->next != (struct gen_pool_link *)b) - q = q->next; - if (!q->next) { - ((struct gen_pool_link *)a)->next = h[i].next; - h[i].next = (struct gen_pool_link *)a; +/* + * Free the specified memory back to the specified pool. + * + * @pool: pool to free to + * @addr: starting address of memory to free back to pool + * @size: size in bytes of memory to free + */ +void gen_pool_free(struct gen_pool *pool, unsigned long addr, size_t size) +{ + struct list_head *_chunk; + struct gen_pool_chunk *chunk; + unsigned long flags; + int order = pool->min_alloc_order; + int bit, nbits; + + nbits = (size + (1UL << order) - 1) >> order; + + read_lock(&pool->lock); + list_for_each(_chunk, &pool->chunks) { + chunk = list_entry(_chunk, struct gen_pool_chunk, next_chunk); + + if (addr >= chunk->start_addr && addr < chunk->end_addr) { + BUG_ON(addr + size > chunk->end_addr); + spin_lock_irqsave(&chunk->lock, flags); + bit = (addr - chunk->start_addr) >> order; + while (nbits--) + __clear_bit(bit++, &chunk->bits); + spin_unlock_irqrestore(&chunk->lock, flags); break; } - q->next = q->next->next; - a = a & b; - s <<= 1; - i++; } - spin_unlock_irqrestore(&poolp->lock, flags); + BUG_ON(nbits > 0); + read_unlock(&pool->lock); } EXPORT_SYMBOL(gen_pool_free); -- cgit v1.2.3 From 612d6c19db2fd0dc97b0fa370613ecd4a305ffc3 Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Fri, 23 Jun 2006 02:03:22 -0700 Subject: [PATCH] radix-tree: direct data The ability to have height 0 radix trees (a direct pointer to the data item rather than going through a full node->slot) quietly disappeared with old-2.6-bkcvs commit ffee171812d51652f9ba284302d9e5c5cc14bdfd. On 64-bit machines this causes nearly 600 bytes to be used for every <= 4K file in pagecache. Re-introduce this feature, root tags stored in spare ->gfp_mask bits. Simplify radix_tree_delete's complex tag clearing arrangement (which would become even more complex) by just falling back to tag clearing functions (the pagecache radix-tree never uses this path anyway, so the icache savings will mean it's actually a speedup). On my 4GB G5, this saves 8MB RAM per kernel kernel source+object tree in pagecache. Pagecache lookup, insertion, and removal speed for small files will also be improved. This makes RCU radix tree harder, but it's worth it. Signed-off-by: Nick Piggin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/radix-tree.h | 5 +- lib/radix-tree.c | 192 ++++++++++++++++++++++++++------------------- 2 files changed, 114 insertions(+), 83 deletions(-) (limited to 'include') diff --git a/include/linux/radix-tree.h b/include/linux/radix-tree.h index dd83cca28001..9158a68140c9 100644 --- a/include/linux/radix-tree.h +++ b/include/linux/radix-tree.h @@ -23,6 +23,9 @@ #include #include +#define RADIX_TREE_MAX_TAGS 2 + +/* root tags are stored in gfp_mask, shifted by __GFP_BITS_SHIFT */ struct radix_tree_root { unsigned int height; gfp_t gfp_mask; @@ -45,8 +48,6 @@ do { \ (root)->rnode = NULL; \ } while (0) -#define RADIX_TREE_MAX_TAGS 2 - int radix_tree_insert(struct radix_tree_root *, unsigned long, void *); void *radix_tree_lookup(struct radix_tree_root *, unsigned long); void **radix_tree_lookup_slot(struct radix_tree_root *, unsigned long); diff --git a/lib/radix-tree.c b/lib/radix-tree.c index 7097bb239e40..35a2d93b3528 100644 --- a/lib/radix-tree.c +++ b/lib/radix-tree.c @@ -74,6 +74,11 @@ struct radix_tree_preload { }; DEFINE_PER_CPU(struct radix_tree_preload, radix_tree_preloads) = { 0, }; +static inline gfp_t root_gfp_mask(struct radix_tree_root *root) +{ + return root->gfp_mask & __GFP_BITS_MASK; +} + /* * This assumes that the caller has performed appropriate preallocation, and * that the caller has pinned this thread of control to the current CPU. @@ -82,9 +87,10 @@ static struct radix_tree_node * radix_tree_node_alloc(struct radix_tree_root *root) { struct radix_tree_node *ret; + gfp_t gfp_mask = root_gfp_mask(root); - ret = kmem_cache_alloc(radix_tree_node_cachep, root->gfp_mask); - if (ret == NULL && !(root->gfp_mask & __GFP_WAIT)) { + ret = kmem_cache_alloc(radix_tree_node_cachep, gfp_mask); + if (ret == NULL && !(gfp_mask & __GFP_WAIT)) { struct radix_tree_preload *rtp; rtp = &__get_cpu_var(radix_tree_preloads); @@ -152,6 +158,27 @@ static inline int tag_get(struct radix_tree_node *node, unsigned int tag, return test_bit(offset, node->tags[tag]); } +static inline void root_tag_set(struct radix_tree_root *root, unsigned int tag) +{ + root->gfp_mask |= (1 << (tag + __GFP_BITS_SHIFT)); +} + + +static inline void root_tag_clear(struct radix_tree_root *root, unsigned int tag) +{ + root->gfp_mask &= ~(1 << (tag + __GFP_BITS_SHIFT)); +} + +static inline void root_tag_clear_all(struct radix_tree_root *root) +{ + root->gfp_mask &= __GFP_BITS_MASK; +} + +static inline int root_tag_get(struct radix_tree_root *root, unsigned int tag) +{ + return root->gfp_mask & (1 << (tag + __GFP_BITS_SHIFT)); +} + /* * Returns 1 if any slot in the node has this tag set. * Otherwise returns 0. @@ -182,7 +209,6 @@ static int radix_tree_extend(struct radix_tree_root *root, unsigned long index) { struct radix_tree_node *node; unsigned int height; - char tags[RADIX_TREE_MAX_TAGS]; int tag; /* Figure out what the height should be. */ @@ -195,16 +221,6 @@ static int radix_tree_extend(struct radix_tree_root *root, unsigned long index) goto out; } - /* - * Prepare the tag status of the top-level node for propagation - * into the newly-pushed top-level node(s) - */ - for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) { - tags[tag] = 0; - if (any_tag_set(root->rnode, tag)) - tags[tag] = 1; - } - do { if (!(node = radix_tree_node_alloc(root))) return -ENOMEM; @@ -214,7 +230,7 @@ static int radix_tree_extend(struct radix_tree_root *root, unsigned long index) /* Propagate the aggregated tag info into the new root */ for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) { - if (tags[tag]) + if (root_tag_get(root, tag)) tag_set(node, tag, 0); } @@ -243,8 +259,7 @@ int radix_tree_insert(struct radix_tree_root *root, int error; /* Make sure the tree is high enough. */ - if ((!index && !root->rnode) || - index > radix_tree_maxindex(root->height)) { + if (index > radix_tree_maxindex(root->height)) { error = radix_tree_extend(root, index); if (error) return error; @@ -255,7 +270,7 @@ int radix_tree_insert(struct radix_tree_root *root, shift = (height-1) * RADIX_TREE_MAP_SHIFT; offset = 0; /* uninitialised var warning */ - do { + while (height > 0) { if (slot == NULL) { /* Have to add a child node. */ if (!(slot = radix_tree_node_alloc(root))) @@ -273,16 +288,21 @@ int radix_tree_insert(struct radix_tree_root *root, slot = node->slots[offset]; shift -= RADIX_TREE_MAP_SHIFT; height--; - } while (height > 0); + } if (slot != NULL) return -EEXIST; - BUG_ON(!node); - node->count++; - node->slots[offset] = item; - BUG_ON(tag_get(node, 0, offset)); - BUG_ON(tag_get(node, 1, offset)); + if (node) { + node->count++; + node->slots[offset] = item; + BUG_ON(tag_get(node, 0, offset)); + BUG_ON(tag_get(node, 1, offset)); + } else { + root->rnode = item; + BUG_ON(root_tag_get(root, 0)); + BUG_ON(root_tag_get(root, 1)); + } return 0; } @@ -295,9 +315,13 @@ static inline void **__lookup_slot(struct radix_tree_root *root, struct radix_tree_node **slot; height = root->height; + if (index > radix_tree_maxindex(height)) return NULL; + if (height == 0 && root->rnode) + return (void **)&root->rnode; + shift = (height-1) * RADIX_TREE_MAP_SHIFT; slot = &root->rnode; @@ -368,8 +392,8 @@ void *radix_tree_tag_set(struct radix_tree_root *root, if (index > radix_tree_maxindex(height)) return NULL; - shift = (height - 1) * RADIX_TREE_MAP_SHIFT; slot = root->rnode; + shift = (height - 1) * RADIX_TREE_MAP_SHIFT; while (height > 0) { int offset; @@ -383,6 +407,10 @@ void *radix_tree_tag_set(struct radix_tree_root *root, height--; } + /* set the root's tag bit */ + if (slot && !root_tag_get(root, tag)) + root_tag_set(root, tag); + return slot; } EXPORT_SYMBOL(radix_tree_tag_set); @@ -405,9 +433,8 @@ void *radix_tree_tag_clear(struct radix_tree_root *root, unsigned long index, unsigned int tag) { struct radix_tree_path path[RADIX_TREE_MAX_PATH], *pathp = path; - struct radix_tree_node *slot; + struct radix_tree_node *slot = NULL; unsigned int height, shift; - void *ret = NULL; height = root->height; if (index > radix_tree_maxindex(height)) @@ -432,20 +459,24 @@ void *radix_tree_tag_clear(struct radix_tree_root *root, height--; } - ret = slot; - if (ret == NULL) + if (slot == NULL) goto out; - do { + while (pathp->node) { if (!tag_get(pathp->node, tag, pathp->offset)) goto out; tag_clear(pathp->node, tag, pathp->offset); if (any_tag_set(pathp->node, tag)) goto out; pathp--; - } while (pathp->node); + } + + /* clear the root's tag bit */ + if (root_tag_get(root, tag)) + root_tag_clear(root, tag); + out: - return ret; + return slot; } EXPORT_SYMBOL(radix_tree_tag_clear); @@ -458,9 +489,8 @@ EXPORT_SYMBOL(radix_tree_tag_clear); * * Return values: * - * 0: tag not present - * 1: tag present, set - * -1: tag present, unset + * 0: tag not present or not set + * 1: tag set */ int radix_tree_tag_get(struct radix_tree_root *root, unsigned long index, unsigned int tag) @@ -473,6 +503,13 @@ int radix_tree_tag_get(struct radix_tree_root *root, if (index > radix_tree_maxindex(height)) return 0; + /* check the root's tag bit */ + if (!root_tag_get(root, tag)) + return 0; + + if (height == 0) + return 1; + shift = (height - 1) * RADIX_TREE_MAP_SHIFT; slot = root->rnode; @@ -494,7 +531,7 @@ int radix_tree_tag_get(struct radix_tree_root *root, int ret = tag_get(slot, tag, offset); BUG_ON(ret && saw_unset_tag); - return ret ? 1 : -1; + return ret; } slot = slot->slots[offset]; shift -= RADIX_TREE_MAP_SHIFT; @@ -514,8 +551,11 @@ __lookup(struct radix_tree_root *root, void **results, unsigned long index, unsigned long i; height = root->height; - if (height == 0) + if (height == 0) { + if (root->rnode && index == 0) + results[nr_found++] = root->rnode; goto out; + } shift = (height-1) * RADIX_TREE_MAP_SHIFT; slot = root->rnode; @@ -603,10 +643,16 @@ __lookup_tag(struct radix_tree_root *root, void **results, unsigned long index, unsigned int height = root->height; struct radix_tree_node *slot; + if (height == 0) { + if (root->rnode && index == 0) + results[nr_found++] = root->rnode; + goto out; + } + shift = (height - 1) * RADIX_TREE_MAP_SHIFT; slot = root->rnode; - while (height > 0) { + do { unsigned long i = (index >> shift) & RADIX_TREE_MAP_MASK; for ( ; i < RADIX_TREE_MAP_SIZE; i++) { @@ -637,7 +683,7 @@ __lookup_tag(struct radix_tree_root *root, void **results, unsigned long index, } shift -= RADIX_TREE_MAP_SHIFT; slot = slot->slots[i]; - } + } while (height > 0); out: *next_index = index; return nr_found; @@ -665,6 +711,10 @@ radix_tree_gang_lookup_tag(struct radix_tree_root *root, void **results, unsigned long cur_index = first_index; unsigned int ret = 0; + /* check the root's tag bit */ + if (!root_tag_get(root, tag)) + return 0; + while (ret < max_items) { unsigned int nr_found; unsigned long next_index; /* Index of next search */ @@ -689,7 +739,7 @@ EXPORT_SYMBOL(radix_tree_gang_lookup_tag); static inline void radix_tree_shrink(struct radix_tree_root *root) { /* try to shrink tree height */ - while (root->height > 1 && + while (root->height > 0 && root->rnode->count == 1 && root->rnode->slots[0]) { struct radix_tree_node *to_free = root->rnode; @@ -717,12 +767,8 @@ static inline void radix_tree_shrink(struct radix_tree_root *root) void *radix_tree_delete(struct radix_tree_root *root, unsigned long index) { struct radix_tree_path path[RADIX_TREE_MAX_PATH], *pathp = path; - struct radix_tree_path *orig_pathp; - struct radix_tree_node *slot; + struct radix_tree_node *slot = NULL; unsigned int height, shift; - void *ret = NULL; - char tags[RADIX_TREE_MAX_TAGS]; - int nr_cleared_tags; int tag; int offset; @@ -730,11 +776,17 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index) if (index > radix_tree_maxindex(height)) goto out; + slot = root->rnode; + if (height == 0 && root->rnode) { + root_tag_clear_all(root); + root->rnode = NULL; + goto out; + } + shift = (height - 1) * RADIX_TREE_MAP_SHIFT; pathp->node = NULL; - slot = root->rnode; - for ( ; height > 0; height--) { + do { if (slot == NULL) goto out; @@ -744,44 +796,22 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index) pathp->node = slot; slot = slot->slots[offset]; shift -= RADIX_TREE_MAP_SHIFT; - } + height--; + } while (height > 0); - ret = slot; - if (ret == NULL) + if (slot == NULL) goto out; - orig_pathp = pathp; - /* * Clear all tags associated with the just-deleted item */ - nr_cleared_tags = 0; for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) { - tags[tag] = 1; - if (tag_get(pathp->node, tag, pathp->offset)) { - tag_clear(pathp->node, tag, pathp->offset); - if (!any_tag_set(pathp->node, tag)) { - tags[tag] = 0; - nr_cleared_tags++; - } - } - } - - for (pathp--; nr_cleared_tags && pathp->node; pathp--) { - for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) { - if (tags[tag]) - continue; - - tag_clear(pathp->node, tag, pathp->offset); - if (any_tag_set(pathp->node, tag)) { - tags[tag] = 1; - nr_cleared_tags--; - } - } + if (tag_get(pathp->node, tag, pathp->offset)) + radix_tree_tag_clear(root, index, tag); } /* Now free the nodes we do not need anymore */ - for (pathp = orig_pathp; pathp->node; pathp--) { + while (pathp->node) { pathp->node->slots[pathp->offset] = NULL; pathp->node->count--; @@ -793,11 +823,15 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index) /* Node with zero slots in use so free it */ radix_tree_node_free(pathp->node); + + pathp--; } - root->rnode = NULL; + root_tag_clear_all(root); root->height = 0; + root->rnode = NULL; + out: - return ret; + return slot; } EXPORT_SYMBOL(radix_tree_delete); @@ -808,11 +842,7 @@ EXPORT_SYMBOL(radix_tree_delete); */ int radix_tree_tagged(struct radix_tree_root *root, unsigned int tag) { - struct radix_tree_node *rnode; - rnode = root->rnode; - if (!rnode) - return 0; - return any_tag_set(rnode, tag); + return root_tag_get(root, tag); } EXPORT_SYMBOL(radix_tree_tagged); -- cgit v1.2.3 From 111ebb6e6f7bd7de6d722c5848e95621f43700d9 Mon Sep 17 00:00:00 2001 From: OGAWA Hirofumi Date: Fri, 23 Jun 2006 02:03:26 -0700 Subject: [PATCH] writeback: fix range handling When a writeback_control's `start' and `end' fields are used to indicate a one-byte-range starting at file offset zero, the required values of .start=0,.end=0 mean that the ->writepages() implementation has no way of telling that it is being asked to perform a range request. Because we're currently overloading (start == 0 && end == 0) to mean "this is not a write-a-range request". To make all this sane, the patch changes range of writeback_control. So caller does: If it is calling ->writepages() to write pages, it sets range (range_start/end or range_cyclic) always. And if range_cyclic is true, ->writepages() thinks the range is cyclic, otherwise it just uses range_start and range_end. This patch does, - Add LLONG_MAX, LLONG_MIN, ULLONG_MAX to include/linux/kernel.h -1 is usually ok for range_end (type is long long). But, if someone did, range_end += val; range_end is "val - 1" u64val = range_end >> bits; u64val is "~(0ULL)" or something, they are wrong. So, this adds LLONG_MAX to avoid nasty things, and uses LLONG_MAX for range_end. - All callers of ->writepages() sets range_start/end or range_cyclic. - Fix updates of ->writeback_index. It seems already bit strange. If it starts at 0 and ended by check of nr_to_write, this last index may reduce chance to scan end of file. So, this updates ->writeback_index only if range_cyclic is true or whole-file is scanned. Signed-off-by: OGAWA Hirofumi Cc: Nathan Scott Cc: Anton Altaparmakov Cc: Steven French Cc: "Vladimir V. Saveliev" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/cifs/file.c | 24 +++++++++++------------- fs/fs-writeback.c | 4 ++++ fs/mpage.c | 22 ++++++++++------------ fs/sync.c | 2 +- include/linux/kernel.h | 3 +++ include/linux/writeback.h | 5 +++-- mm/filemap.c | 6 +++--- mm/page-writeback.c | 3 +++ mm/vmscan.c | 2 ++ 9 files changed, 40 insertions(+), 31 deletions(-) (limited to 'include') diff --git a/fs/cifs/file.c b/fs/cifs/file.c index e2b4ce1dad66..487ea8b3baaa 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -1079,9 +1079,9 @@ static int cifs_writepages(struct address_space *mapping, unsigned int bytes_written; struct cifs_sb_info *cifs_sb; int done = 0; - pgoff_t end = -1; + pgoff_t end; pgoff_t index; - int is_range = 0; + int range_whole = 0; struct kvec iov[32]; int len; int n_iov = 0; @@ -1122,16 +1122,14 @@ static int cifs_writepages(struct address_space *mapping, xid = GetXid(); pagevec_init(&pvec, 0); - if (wbc->sync_mode == WB_SYNC_NONE) + if (wbc->range_cyclic) { index = mapping->writeback_index; /* Start from prev offset */ - else { - index = 0; - scanned = 1; - } - if (wbc->start || wbc->end) { - index = wbc->start >> PAGE_CACHE_SHIFT; - end = wbc->end >> PAGE_CACHE_SHIFT; - is_range = 1; + end = -1; + } else { + index = wbc->range_start >> PAGE_CACHE_SHIFT; + end = wbc->range_end >> PAGE_CACHE_SHIFT; + if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX) + range_whole = 1; scanned = 1; } retry: @@ -1167,7 +1165,7 @@ retry: break; } - if (unlikely(is_range) && (page->index > end)) { + if (!wbc->range_cyclic && page->index > end) { done = 1; unlock_page(page); break; @@ -1271,7 +1269,7 @@ retry: index = 0; goto retry; } - if (!is_range) + if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0)) mapping->writeback_index = index; FreeXid(xid); diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index f3fbe2d030f4..6db95cf3aaa2 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -461,6 +461,8 @@ void sync_inodes_sb(struct super_block *sb, int wait) { struct writeback_control wbc = { .sync_mode = wait ? WB_SYNC_ALL : WB_SYNC_HOLD, + .range_start = 0, + .range_end = LLONG_MAX, }; unsigned long nr_dirty = read_page_state(nr_dirty); unsigned long nr_unstable = read_page_state(nr_unstable); @@ -559,6 +561,8 @@ int write_inode_now(struct inode *inode, int sync) struct writeback_control wbc = { .nr_to_write = LONG_MAX, .sync_mode = WB_SYNC_ALL, + .range_start = 0, + .range_end = LLONG_MAX, }; if (!mapping_cap_writeback_dirty(inode->i_mapping)) diff --git a/fs/mpage.c b/fs/mpage.c index 9bf2eb30e6f4..1e4598247d0b 100644 --- a/fs/mpage.c +++ b/fs/mpage.c @@ -707,9 +707,9 @@ mpage_writepages(struct address_space *mapping, struct pagevec pvec; int nr_pages; pgoff_t index; - pgoff_t end = -1; /* Inclusive */ + pgoff_t end; /* Inclusive */ int scanned = 0; - int is_range = 0; + int range_whole = 0; if (wbc->nonblocking && bdi_write_congested(bdi)) { wbc->encountered_congestion = 1; @@ -721,16 +721,14 @@ mpage_writepages(struct address_space *mapping, writepage = mapping->a_ops->writepage; pagevec_init(&pvec, 0); - if (wbc->sync_mode == WB_SYNC_NONE) { + if (wbc->range_cyclic) { index = mapping->writeback_index; /* Start from prev offset */ + end = -1; } else { - index = 0; /* whole-file sweep */ - scanned = 1; - } - if (wbc->start || wbc->end) { - index = wbc->start >> PAGE_CACHE_SHIFT; - end = wbc->end >> PAGE_CACHE_SHIFT; - is_range = 1; + index = wbc->range_start >> PAGE_CACHE_SHIFT; + end = wbc->range_end >> PAGE_CACHE_SHIFT; + if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX) + range_whole = 1; scanned = 1; } retry: @@ -759,7 +757,7 @@ retry: continue; } - if (unlikely(is_range) && page->index > end) { + if (!wbc->range_cyclic && page->index > end) { done = 1; unlock_page(page); continue; @@ -810,7 +808,7 @@ retry: index = 0; goto retry; } - if (!is_range) + if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0)) mapping->writeback_index = index; if (bio) mpage_bio_submit(WRITE, bio); diff --git a/fs/sync.c b/fs/sync.c index aab5ffe77e9f..955aef04da28 100644 --- a/fs/sync.c +++ b/fs/sync.c @@ -100,7 +100,7 @@ asmlinkage long sys_sync_file_range(int fd, loff_t offset, loff_t nbytes, } if (nbytes == 0) - endbyte = -1; + endbyte = LLONG_MAX; else endbyte--; /* inclusive */ diff --git a/include/linux/kernel.h b/include/linux/kernel.h index f4fc576ed4c4..25fccd859fbf 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -24,6 +24,9 @@ extern const char linux_banner[]; #define LONG_MAX ((long)(~0UL>>1)) #define LONG_MIN (-LONG_MAX - 1) #define ULONG_MAX (~0UL) +#define LLONG_MAX ((long long)(~0ULL>>1)) +#define LLONG_MIN (-LLONG_MAX - 1) +#define ULLONG_MAX (~0ULL) #define STACK_MAGIC 0xdeadbeef diff --git a/include/linux/writeback.h b/include/linux/writeback.h index 56f92fcbe94a..9e38b566d0e7 100644 --- a/include/linux/writeback.h +++ b/include/linux/writeback.h @@ -50,14 +50,15 @@ struct writeback_control { * a hint that the filesystem need only write out the pages inside that * byterange. The byte at `end' is included in the writeout request. */ - loff_t start; - loff_t end; + loff_t range_start; + loff_t range_end; unsigned nonblocking:1; /* Don't get stuck on request queues */ unsigned encountered_congestion:1; /* An output: a queue is full */ unsigned for_kupdate:1; /* A kupdate writeback */ unsigned for_reclaim:1; /* Invoked from the page allocator */ unsigned for_writepages:1; /* This is a writepages() call */ + unsigned range_cyclic:1; /* range_start is cyclic */ }; /* diff --git a/mm/filemap.c b/mm/filemap.c index fd57442186cb..3342067ca436 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -190,8 +190,8 @@ int __filemap_fdatawrite_range(struct address_space *mapping, loff_t start, struct writeback_control wbc = { .sync_mode = sync_mode, .nr_to_write = mapping->nrpages * 2, - .start = start, - .end = end, + .range_start = start, + .range_end = end, }; if (!mapping_cap_writeback_dirty(mapping)) @@ -204,7 +204,7 @@ int __filemap_fdatawrite_range(struct address_space *mapping, loff_t start, static inline int __filemap_fdatawrite(struct address_space *mapping, int sync_mode) { - return __filemap_fdatawrite_range(mapping, 0, 0, sync_mode); + return __filemap_fdatawrite_range(mapping, 0, LLONG_MAX, sync_mode); } int filemap_fdatawrite(struct address_space *mapping) diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 75d7f48b79bb..8ccf6f1b1473 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -204,6 +204,7 @@ static void balance_dirty_pages(struct address_space *mapping) .sync_mode = WB_SYNC_NONE, .older_than_this = NULL, .nr_to_write = write_chunk, + .range_cyclic = 1, }; get_dirty_limits(&wbs, &background_thresh, @@ -331,6 +332,7 @@ static void background_writeout(unsigned long _min_pages) .older_than_this = NULL, .nr_to_write = 0, .nonblocking = 1, + .range_cyclic = 1, }; for ( ; ; ) { @@ -407,6 +409,7 @@ static void wb_kupdate(unsigned long arg) .nr_to_write = 0, .nonblocking = 1, .for_kupdate = 1, + .range_cyclic = 1, }; sync_supers(); diff --git a/mm/vmscan.c b/mm/vmscan.c index 46be8a02280e..bc5d4f43036c 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -339,6 +339,8 @@ pageout_t pageout(struct page *page, struct address_space *mapping) struct writeback_control wbc = { .sync_mode = WB_SYNC_NONE, .nr_to_write = SWAP_CLUSTER_MAX, + .range_start = 0, + .range_end = LLONG_MAX, .nonblocking = 1, .for_reclaim = 1, }; -- cgit v1.2.3 From e7340f73307abed9283d0a07570d06e228c205dd Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Fri, 23 Jun 2006 02:03:29 -0700 Subject: [PATCH] page migration cleanup: remove useless definitions Remove the export for migrate_page_remove_references() and migrate_page_copy() that are unlikely to be used directly by filesystems implementing migration. The export was useful when buffer_migrate_page() lived in fs/buffer.c but it has now been moved to migrate.c in the migration reorg. Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/migrate.h | 2 -- mm/migrate.c | 6 ++---- 2 files changed, 2 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/linux/migrate.h b/include/linux/migrate.h index 6789c4940c9c..e8d3b08cc354 100644 --- a/include/linux/migrate.h +++ b/include/linux/migrate.h @@ -7,8 +7,6 @@ extern int isolate_lru_page(struct page *p, struct list_head *pagelist); extern int putback_lru_pages(struct list_head *l); extern int migrate_page(struct page *, struct page *); -extern void migrate_page_copy(struct page *, struct page *); -extern int migrate_page_remove_references(struct page *, struct page *, int); extern int migrate_pages(struct list_head *l, struct list_head *t, struct list_head *moved, struct list_head *failed); extern int migrate_pages_to(struct list_head *pagelist, diff --git a/mm/migrate.c b/mm/migrate.c index 49e71ddb6792..be3f141e53a4 100644 --- a/mm/migrate.c +++ b/mm/migrate.c @@ -169,7 +169,7 @@ retry: * Remove references for a page and establish the new page with the correct * basic settings to be able to stop accesses to the page. */ -int migrate_page_remove_references(struct page *newpage, +static int migrate_page_remove_references(struct page *newpage, struct page *page, int nr_refs) { struct address_space *mapping = page_mapping(page); @@ -246,12 +246,11 @@ int migrate_page_remove_references(struct page *newpage, return 0; } -EXPORT_SYMBOL(migrate_page_remove_references); /* * Copy the page to its new location */ -void migrate_page_copy(struct page *newpage, struct page *page) +static void migrate_page_copy(struct page *newpage, struct page *page) { copy_highpage(newpage, page); @@ -286,7 +285,6 @@ void migrate_page_copy(struct page *newpage, struct page *page) if (PageWriteback(newpage)) end_page_writeback(newpage); } -EXPORT_SYMBOL(migrate_page_copy); /************************************************************ * Migration functions -- cgit v1.2.3 From 2d1db3b1170db4e8bf0531dd636742269c2cf579 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Fri, 23 Jun 2006 02:03:33 -0700 Subject: [PATCH] page migration cleanup: pass "mapping" to migration functions Change handling of address spaces. Pass a pointer to the address space in which the page is migrated to all migration function. This avoids repeatedly having to retrieve the address space pointer from the page and checking it for validity. The old page mapping will change once migration has gone to a certain step, so it is less confusing to have the pointer always available. Move the setting of the mapping and index for the new page into migrate_pages(). Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/fs.h | 6 +++-- include/linux/migrate.h | 6 +++-- mm/migrate.c | 70 ++++++++++++++++++++++++------------------------- 3 files changed, 42 insertions(+), 40 deletions(-) (limited to 'include') diff --git a/include/linux/fs.h b/include/linux/fs.h index c823a3815e24..e917403f4d58 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -376,7 +376,8 @@ struct address_space_operations { struct page* (*get_xip_page)(struct address_space *, sector_t, int); /* migrate the contents of a page to the specified target */ - int (*migratepage) (struct page *, struct page *); + int (*migratepage) (struct address_space *, + struct page *, struct page *); }; struct backing_dev_info; @@ -1772,7 +1773,8 @@ extern void simple_release_fs(struct vfsmount **mount, int *count); extern ssize_t simple_read_from_buffer(void __user *, size_t, loff_t *, const void *, size_t); #ifdef CONFIG_MIGRATION -extern int buffer_migrate_page(struct page *, struct page *); +extern int buffer_migrate_page(struct address_space *, + struct page *, struct page *); #else #define buffer_migrate_page NULL #endif diff --git a/include/linux/migrate.h b/include/linux/migrate.h index e8d3b08cc354..287c47b5e5df 100644 --- a/include/linux/migrate.h +++ b/include/linux/migrate.h @@ -6,12 +6,14 @@ #ifdef CONFIG_MIGRATION extern int isolate_lru_page(struct page *p, struct list_head *pagelist); extern int putback_lru_pages(struct list_head *l); -extern int migrate_page(struct page *, struct page *); +extern int migrate_page(struct address_space *, + struct page *, struct page *); extern int migrate_pages(struct list_head *l, struct list_head *t, struct list_head *moved, struct list_head *failed); extern int migrate_pages_to(struct list_head *pagelist, struct vm_area_struct *vma, int dest); -extern int fail_migrate_page(struct page *, struct page *); +extern int fail_migrate_page(struct address_space *, + struct page *, struct page *); extern int migrate_prep(void); diff --git a/mm/migrate.c b/mm/migrate.c index 8095c607a494..f65e69d94527 100644 --- a/mm/migrate.c +++ b/mm/migrate.c @@ -173,15 +173,11 @@ retry: * 2 for pages with a mapping * 3 for pages with a mapping and PagePrivate set. */ -static int migrate_page_move_mapping(struct page *newpage, - struct page *page) +static int migrate_page_move_mapping(struct address_space *mapping, + struct page *newpage, struct page *page) { - struct address_space *mapping = page_mapping(page); struct page **radix_pointer; - if (!mapping) - return -EAGAIN; - write_lock_irq(&mapping->tree_lock); radix_pointer = (struct page **)radix_tree_lookup_slot( @@ -197,15 +193,8 @@ static int migrate_page_move_mapping(struct page *newpage, /* * Now we know that no one else is looking at the page. - * - * Certain minimal information about a page must be available - * in order for other subsystems to properly handle the page if they - * find it through the radix tree update before we are finished - * copying the page. */ get_page(newpage); - newpage->index = page->index; - newpage->mapping = page->mapping; if (PageSwapCache(page)) { SetPageSwapCache(newpage); set_page_private(newpage, page_private(page)); @@ -262,7 +251,8 @@ static void migrate_page_copy(struct page *newpage, struct page *page) ***********************************************************/ /* Always fail migration. Used for mappings that are not movable */ -int fail_migrate_page(struct page *newpage, struct page *page) +int fail_migrate_page(struct address_space *mapping, + struct page *newpage, struct page *page) { return -EIO; } @@ -274,13 +264,14 @@ EXPORT_SYMBOL(fail_migrate_page); * * Pages are locked upon entry and exit. */ -int migrate_page(struct page *newpage, struct page *page) +int migrate_page(struct address_space *mapping, + struct page *newpage, struct page *page) { int rc; BUG_ON(PageWriteback(page)); /* Writeback must be complete */ - rc = migrate_page_move_mapping(newpage, page); + rc = migrate_page_move_mapping(mapping, newpage, page); if (rc) return rc; @@ -305,21 +296,18 @@ EXPORT_SYMBOL(migrate_page); * if the underlying filesystem guarantees that no other references to "page" * exist. */ -int buffer_migrate_page(struct page *newpage, struct page *page) +int buffer_migrate_page(struct address_space *mapping, + struct page *newpage, struct page *page) { - struct address_space *mapping = page->mapping; struct buffer_head *bh, *head; int rc; - if (!mapping) - return -EAGAIN; - if (!page_has_buffers(page)) - return migrate_page(newpage, page); + return migrate_page(mapping, newpage, page); head = page_buffers(page); - rc = migrate_page_move_mapping(newpage, page); + rc = migrate_page_move_mapping(mapping, newpage, page); if (rc) return rc; @@ -448,9 +436,6 @@ redo: goto next; } - newpage = lru_to_page(to); - lock_page(newpage); - /* * Establish swap ptes for anonymous pages or destroy pte * maps for files. @@ -473,11 +458,18 @@ redo: rc = -EPERM; if (try_to_unmap(page, 1) == SWAP_FAIL) /* A vma has VM_LOCKED set -> permanent failure */ - goto unlock_both; + goto unlock_page; rc = -EAGAIN; if (page_mapped(page)) - goto unlock_both; + goto unlock_page; + + newpage = lru_to_page(to); + lock_page(newpage); + /* Prepare mapping for the new page.*/ + newpage->index = page->index; + newpage->mapping = page->mapping; + /* * Pages are properly locked and writeback is complete. * Try to migrate the page. @@ -494,7 +486,8 @@ redo: * own migration function. This is the most common * path for page migration. */ - rc = mapping->a_ops->migratepage(newpage, page); + rc = mapping->a_ops->migratepage(mapping, + newpage, page); goto unlock_both; } @@ -524,7 +517,7 @@ redo: */ if (!page_has_buffers(page) || try_to_release_page(page, GFP_KERNEL)) { - rc = migrate_page(newpage, page); + rc = migrate_page(mapping, newpage, page); goto unlock_both; } @@ -553,12 +546,17 @@ unlock_page: unlock_page(page); next: - if (rc == -EAGAIN) { - retry++; - } else if (rc) { - /* Permanent failure */ - list_move(&page->lru, failed); - nr_failed++; + if (rc) { + if (newpage) + newpage->mapping = NULL; + + if (rc == -EAGAIN) + retry++; + else { + /* Permanent failure */ + list_move(&page->lru, failed); + nr_failed++; + } } else { if (newpage) { /* Successful migration. Return page to LRU */ -- cgit v1.2.3 From 0697212a411c1dae03c27845f2de2f3adb32c331 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Fri, 23 Jun 2006 02:03:35 -0700 Subject: [PATCH] Swapless page migration: add R/W migration entries Implement read/write migration ptes We take the upper two swapfiles for the two types of migration ptes and define a series of macros in swapops.h. The VM is modified to handle the migration entries. migration entries can only be encountered when the page they are pointing to is locked. This limits the number of places one has to fix. We also check in copy_pte_range and in mprotect_pte_range() for migration ptes. We check for migration ptes in do_swap_cache and call a function that will then wait on the page lock. This allows us to effectively stop all accesses to apge. Migration entries are created by try_to_unmap if called for migration and removed by local functions in migrate.c From: Hugh Dickins Several times while testing swapless page migration (I've no NUMA, just hacking it up to migrate recklessly while running load), I've hit the BUG_ON(!PageLocked(p)) in migration_entry_to_page. This comes from an orphaned migration entry, unrelated to the current correctly locked migration, but hit by remove_anon_migration_ptes as it checks an address in each vma of the anon_vma list. Such an orphan may be left behind if an earlier migration raced with fork: copy_one_pte can duplicate a migration entry from parent to child, after remove_anon_migration_ptes has checked the child vma, but before it has removed it from the parent vma. (If the process were later to fault on this orphaned entry, it would hit the same BUG from migration_entry_wait.) This could be fixed by locking anon_vma in copy_one_pte, but we'd rather not. There's no such problem with file pages, because vma_prio_tree_add adds child vma after parent vma, and the page table locking at each end is enough to serialize. Follow that example with anon_vma: add new vmas to the tail instead of the head. (There's no corresponding problem when inserting migration entries, because a missed pte will leave the page count and mapcount high, which is allowed for. And there's no corresponding problem when migrating via swap, because a leftover swap entry will be correctly faulted. But the swapless method has no refcounting of its entries.) From: Ingo Molnar pte_unmap_unlock() takes the pte pointer as an argument. From: Hugh Dickins Several times while testing swapless page migration, gcc has tried to exec a pointer instead of a string: smells like COW mappings are not being properly write-protected on fork. The protection in copy_one_pte looks very convincing, until at last you realize that the second arg to make_migration_entry is a boolean "write", and SWP_MIGRATION_READ is 30. Anyway, it's better done like in change_pte_range, using is_write_migration_entry and make_migration_entry_read. From: Hugh Dickins Remove unnecessary obfuscation from sys_swapon's range check on swap type, which blew up causing memory corruption once swapless migration made MAX_SWAPFILES no longer 2 ^ MAX_SWAPFILES_SHIFT. Signed-off-by: Hugh Dickins Acked-by: Martin Schwidefsky Signed-off-by: Hugh Dickins Signed-off-by: Christoph Lameter Signed-off-by: Ingo Molnar From: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/swap.h | 7 +++ include/linux/swapops.h | 53 ++++++++++++++++++++ mm/memory.c | 18 ++++++- mm/migrate.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++- mm/mprotect.c | 23 +++++++-- mm/rmap.c | 38 ++++++++------ mm/swapfile.c | 20 +++----- 7 files changed, 255 insertions(+), 32 deletions(-) (limited to 'include') diff --git a/include/linux/swap.h b/include/linux/swap.h index cd28ad206dae..7cee73ef4f15 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -28,7 +28,14 @@ static inline int current_is_kswapd(void) * the type/offset into the pte as 5/27 as well. */ #define MAX_SWAPFILES_SHIFT 5 +#ifndef CONFIG_MIGRATION #define MAX_SWAPFILES (1 << MAX_SWAPFILES_SHIFT) +#else +/* Use last two entries for page migration swap entries */ +#define MAX_SWAPFILES ((1 << MAX_SWAPFILES_SHIFT)-2) +#define SWP_MIGRATION_READ MAX_SWAPFILES +#define SWP_MIGRATION_WRITE (MAX_SWAPFILES + 1) +#endif /* * Magic header for a swap area. The first part of the union is diff --git a/include/linux/swapops.h b/include/linux/swapops.h index 87b9d14c710d..ec639aa3a1d3 100644 --- a/include/linux/swapops.h +++ b/include/linux/swapops.h @@ -67,3 +67,56 @@ static inline pte_t swp_entry_to_pte(swp_entry_t entry) BUG_ON(pte_file(__swp_entry_to_pte(arch_entry))); return __swp_entry_to_pte(arch_entry); } + +#ifdef CONFIG_MIGRATION +static inline swp_entry_t make_migration_entry(struct page *page, int write) +{ + BUG_ON(!PageLocked(page)); + return swp_entry(write ? SWP_MIGRATION_WRITE : SWP_MIGRATION_READ, + page_to_pfn(page)); +} + +static inline int is_migration_entry(swp_entry_t entry) +{ + return unlikely(swp_type(entry) == SWP_MIGRATION_READ || + swp_type(entry) == SWP_MIGRATION_WRITE); +} + +static inline int is_write_migration_entry(swp_entry_t entry) +{ + return unlikely(swp_type(entry) == SWP_MIGRATION_WRITE); +} + +static inline struct page *migration_entry_to_page(swp_entry_t entry) +{ + struct page *p = pfn_to_page(swp_offset(entry)); + /* + * Any use of migration entries may only occur while the + * corresponding page is locked + */ + BUG_ON(!PageLocked(p)); + return p; +} + +static inline void make_migration_entry_read(swp_entry_t *entry) +{ + *entry = swp_entry(SWP_MIGRATION_READ, swp_offset(*entry)); +} + +extern void migration_entry_wait(struct mm_struct *mm, pmd_t *pmd, + unsigned long address); +#else + +#define make_migration_entry(page, write) swp_entry(0, 0) +#define is_migration_entry(swp) 0 +#define migration_entry_to_page(swp) NULL +static inline void make_migration_entry_read(swp_entry_t *entryp) { } +static inline void migration_entry_wait(struct mm_struct *mm, pmd_t *pmd, + unsigned long address) { } +static inline int is_write_migration_entry(swp_entry_t entry) +{ + return 0; +} + +#endif + diff --git a/mm/memory.c b/mm/memory.c index 7e3683fd4f3c..11673c5d2c20 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -434,7 +434,9 @@ copy_one_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm, /* pte contains position in swap or file, so copy. */ if (unlikely(!pte_present(pte))) { if (!pte_file(pte)) { - swap_duplicate(pte_to_swp_entry(pte)); + swp_entry_t entry = pte_to_swp_entry(pte); + + swap_duplicate(entry); /* make sure dst_mm is on swapoff's mmlist. */ if (unlikely(list_empty(&dst_mm->mmlist))) { spin_lock(&mmlist_lock); @@ -443,6 +445,16 @@ copy_one_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm, &src_mm->mmlist); spin_unlock(&mmlist_lock); } + if (is_write_migration_entry(entry) && + is_cow_mapping(vm_flags)) { + /* + * COW mappings require pages in both parent + * and child to be set to read. + */ + make_migration_entry_read(&entry); + pte = swp_entry_to_pte(entry); + set_pte_at(src_mm, addr, src_pte, pte); + } } goto out_set_pte; } @@ -1879,6 +1891,10 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma, goto out; entry = pte_to_swp_entry(orig_pte); + if (is_migration_entry(entry)) { + migration_entry_wait(mm, pmd, address); + goto out; + } page = lookup_swap_cache(entry); if (!page) { swapin_readahead(entry, address, vma); diff --git a/mm/migrate.c b/mm/migrate.c index 5a340f4ca212..0a011e421bb4 100644 --- a/mm/migrate.c +++ b/mm/migrate.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -23,7 +24,6 @@ #include #include #include -#include #include "internal.h" @@ -119,6 +119,132 @@ int putback_lru_pages(struct list_head *l) return count; } +static inline int is_swap_pte(pte_t pte) +{ + return !pte_none(pte) && !pte_present(pte) && !pte_file(pte); +} + +/* + * Restore a potential migration pte to a working pte entry + */ +static void remove_migration_pte(struct vm_area_struct *vma, unsigned long addr, + struct page *old, struct page *new) +{ + struct mm_struct *mm = vma->vm_mm; + swp_entry_t entry; + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + pte_t *ptep, pte; + spinlock_t *ptl; + + pgd = pgd_offset(mm, addr); + if (!pgd_present(*pgd)) + return; + + pud = pud_offset(pgd, addr); + if (!pud_present(*pud)) + return; + + pmd = pmd_offset(pud, addr); + if (!pmd_present(*pmd)) + return; + + ptep = pte_offset_map(pmd, addr); + + if (!is_swap_pte(*ptep)) { + pte_unmap(ptep); + return; + } + + ptl = pte_lockptr(mm, pmd); + spin_lock(ptl); + pte = *ptep; + if (!is_swap_pte(pte)) + goto out; + + entry = pte_to_swp_entry(pte); + + if (!is_migration_entry(entry) || migration_entry_to_page(entry) != old) + goto out; + + inc_mm_counter(mm, anon_rss); + get_page(new); + pte = pte_mkold(mk_pte(new, vma->vm_page_prot)); + if (is_write_migration_entry(entry)) + pte = pte_mkwrite(pte); + set_pte_at(mm, addr, ptep, pte); + page_add_anon_rmap(new, vma, addr); +out: + pte_unmap_unlock(ptep, ptl); +} + +/* + * Get rid of all migration entries and replace them by + * references to the indicated page. + * + * Must hold mmap_sem lock on at least one of the vmas containing + * the page so that the anon_vma cannot vanish. + */ +static void remove_migration_ptes(struct page *old, struct page *new) +{ + struct anon_vma *anon_vma; + struct vm_area_struct *vma; + unsigned long mapping; + + mapping = (unsigned long)new->mapping; + + if (!mapping || (mapping & PAGE_MAPPING_ANON) == 0) + return; + + /* + * We hold the mmap_sem lock. So no need to call page_lock_anon_vma. + */ + anon_vma = (struct anon_vma *) (mapping - PAGE_MAPPING_ANON); + spin_lock(&anon_vma->lock); + + list_for_each_entry(vma, &anon_vma->head, anon_vma_node) + remove_migration_pte(vma, page_address_in_vma(new, vma), + old, new); + + spin_unlock(&anon_vma->lock); +} + +/* + * Something used the pte of a page under migration. We need to + * get to the page and wait until migration is finished. + * When we return from this function the fault will be retried. + * + * This function is called from do_swap_page(). + */ +void migration_entry_wait(struct mm_struct *mm, pmd_t *pmd, + unsigned long address) +{ + pte_t *ptep, pte; + spinlock_t *ptl; + swp_entry_t entry; + struct page *page; + + ptep = pte_offset_map_lock(mm, pmd, address, &ptl); + pte = *ptep; + if (!is_swap_pte(pte)) + goto out; + + entry = pte_to_swp_entry(pte); + if (!is_migration_entry(entry)) + goto out; + + page = migration_entry_to_page(entry); + + get_page(page); + pte_unmap_unlock(ptep, ptl); + wait_on_page_locked(page); + put_page(page); + return; +out: + pte_unmap_unlock(ptep, ptl); +} + /* * swapout a single page * page is locked upon entry, unlocked on exit diff --git a/mm/mprotect.c b/mm/mprotect.c index 5faf01ad3ef8..14f93e62270f 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c @@ -19,7 +19,8 @@ #include #include #include - +#include +#include #include #include #include @@ -28,12 +29,13 @@ static void change_pte_range(struct mm_struct *mm, pmd_t *pmd, unsigned long addr, unsigned long end, pgprot_t newprot) { - pte_t *pte; + pte_t *pte, oldpte; spinlock_t *ptl; pte = pte_offset_map_lock(mm, pmd, addr, &ptl); do { - if (pte_present(*pte)) { + oldpte = *pte; + if (pte_present(oldpte)) { pte_t ptent; /* Avoid an SMP race with hardware updated dirty/clean @@ -43,7 +45,22 @@ static void change_pte_range(struct mm_struct *mm, pmd_t *pmd, ptent = pte_modify(ptep_get_and_clear(mm, addr, pte), newprot); set_pte_at(mm, addr, pte, ptent); lazy_mmu_prot_update(ptent); +#ifdef CONFIG_MIGRATION + } else if (!pte_file(oldpte)) { + swp_entry_t entry = pte_to_swp_entry(oldpte); + + if (is_write_migration_entry(entry)) { + /* + * A protection check is difficult so + * just be safe and disable write + */ + make_migration_entry_read(&entry); + set_pte_at(mm, addr, pte, + swp_entry_to_pte(entry)); + } +#endif } + } while (pte++, addr += PAGE_SIZE, addr != end); pte_unmap_unlock(pte - 1, ptl); } diff --git a/mm/rmap.c b/mm/rmap.c index 10806b7af40c..3b8ce86daa3a 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -103,7 +103,7 @@ int anon_vma_prepare(struct vm_area_struct *vma) spin_lock(&mm->page_table_lock); if (likely(!vma->anon_vma)) { vma->anon_vma = anon_vma; - list_add(&vma->anon_vma_node, &anon_vma->head); + list_add_tail(&vma->anon_vma_node, &anon_vma->head); allocated = NULL; } spin_unlock(&mm->page_table_lock); @@ -127,7 +127,7 @@ void __anon_vma_link(struct vm_area_struct *vma) struct anon_vma *anon_vma = vma->anon_vma; if (anon_vma) { - list_add(&vma->anon_vma_node, &anon_vma->head); + list_add_tail(&vma->anon_vma_node, &anon_vma->head); validate_anon_vma(vma); } } @@ -138,7 +138,7 @@ void anon_vma_link(struct vm_area_struct *vma) if (anon_vma) { spin_lock(&anon_vma->lock); - list_add(&vma->anon_vma_node, &anon_vma->head); + list_add_tail(&vma->anon_vma_node, &anon_vma->head); validate_anon_vma(vma); spin_unlock(&anon_vma->lock); } @@ -620,17 +620,27 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma, if (PageAnon(page)) { swp_entry_t entry = { .val = page_private(page) }; - /* - * Store the swap location in the pte. - * See handle_pte_fault() ... - */ - BUG_ON(!PageSwapCache(page)); - swap_duplicate(entry); - if (list_empty(&mm->mmlist)) { - spin_lock(&mmlist_lock); - if (list_empty(&mm->mmlist)) - list_add(&mm->mmlist, &init_mm.mmlist); - spin_unlock(&mmlist_lock); + + if (PageSwapCache(page)) { + /* + * Store the swap location in the pte. + * See handle_pte_fault() ... + */ + swap_duplicate(entry); + if (list_empty(&mm->mmlist)) { + spin_lock(&mmlist_lock); + if (list_empty(&mm->mmlist)) + list_add(&mm->mmlist, &init_mm.mmlist); + spin_unlock(&mmlist_lock); + } + } else { + /* + * Store the pfn of the page in a special migration + * pte. do_swap_page() will wait until the migration + * pte is removed and then restart fault handling. + */ + BUG_ON(!migration); + entry = make_migration_entry(page, pte_write(pteval)); } set_pte_at(mm, address, pte, swp_entry_to_pte(entry)); BUG_ON(pte_file(*pte)); diff --git a/mm/swapfile.c b/mm/swapfile.c index 47a6812f5f8c..e3b1362372c2 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -395,6 +395,9 @@ void free_swap_and_cache(swp_entry_t entry) struct swap_info_struct * p; struct page *page = NULL; + if (is_migration_entry(entry)) + return; + p = swap_info_get(entry); if (p) { if (swap_entry_free(p, swp_offset(entry)) == 1) { @@ -1400,19 +1403,7 @@ asmlinkage long sys_swapon(const char __user * specialfile, int swap_flags) if (!(p->flags & SWP_USED)) break; error = -EPERM; - /* - * Test if adding another swap device is possible. There are - * two limiting factors: 1) the number of bits for the swap - * type swp_entry_t definition and 2) the number of bits for - * the swap type in the swap ptes as defined by the different - * architectures. To honor both limitations a swap entry - * with swap offset 0 and swap type ~0UL is created, encoded - * to a swap pte, decoded to a swp_entry_t again and finally - * the swap type part is extracted. This will mask all bits - * from the initial ~0UL that can't be encoded in either the - * swp_entry_t or the architecture definition of a swap pte. - */ - if (type > swp_type(pte_to_swp_entry(swp_entry_to_pte(swp_entry(~0UL,0))))) { + if (type >= MAX_SWAPFILES) { spin_unlock(&swap_lock); goto out; } @@ -1702,6 +1693,9 @@ int swap_duplicate(swp_entry_t entry) unsigned long offset, type; int result = 0; + if (is_migration_entry(entry)) + return 1; + type = swp_type(entry); if (type >= nr_swapfiles) goto bad_file; -- cgit v1.2.3 From d75a0fcda2cfc71b50e16dc89e0c32c57d427e85 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Fri, 23 Jun 2006 02:03:36 -0700 Subject: [PATCH] Swapless page migration: rip out swap based logic Rip the page migration logic out. Remove all code that has to do with swapping during page migration. This also guts the ability to migrate pages to swap. No one used that so lets let it go for good. Page migration should be a bit broken after this patch. Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/rmap.h | 1 - mm/migrate.c | 75 +++------------------------------------------------- mm/rmap.c | 38 -------------------------- mm/swapfile.c | 9 ------- 4 files changed, 3 insertions(+), 120 deletions(-) (limited to 'include') diff --git a/include/linux/rmap.h b/include/linux/rmap.h index 2d4c81a220db..bf97b0900014 100644 --- a/include/linux/rmap.h +++ b/include/linux/rmap.h @@ -91,7 +91,6 @@ static inline void page_dup_rmap(struct page *page) */ int page_referenced(struct page *, int is_locked); int try_to_unmap(struct page *, int ignore_refs); -void remove_from_swap(struct page *page); /* * Called from mm/filemap_xip.c to unmap empty zero page diff --git a/mm/migrate.c b/mm/migrate.c index 0a011e421bb4..81721a061d50 100644 --- a/mm/migrate.c +++ b/mm/migrate.c @@ -70,10 +70,6 @@ int isolate_lru_page(struct page *page, struct list_head *pagelist) */ int migrate_prep(void) { - /* Must have swap device for migration */ - if (nr_swap_pages <= 0) - return -ENODEV; - /* * Clear the LRU lists so pages can be isolated. * Note that pages may be moved off the LRU after we have @@ -245,52 +241,6 @@ out: pte_unmap_unlock(ptep, ptl); } -/* - * swapout a single page - * page is locked upon entry, unlocked on exit - */ -static int swap_page(struct page *page) -{ - struct address_space *mapping = page_mapping(page); - - if (page_mapped(page) && mapping) - if (try_to_unmap(page, 1) != SWAP_SUCCESS) - goto unlock_retry; - - if (PageDirty(page)) { - /* Page is dirty, try to write it out here */ - switch(pageout(page, mapping)) { - case PAGE_KEEP: - case PAGE_ACTIVATE: - goto unlock_retry; - - case PAGE_SUCCESS: - goto retry; - - case PAGE_CLEAN: - ; /* try to free the page below */ - } - } - - if (PagePrivate(page)) { - if (!try_to_release_page(page, GFP_KERNEL) || - (!mapping && page_count(page) == 1)) - goto unlock_retry; - } - - if (remove_mapping(mapping, page)) { - /* Success */ - unlock_page(page); - return 0; - } - -unlock_retry: - unlock_page(page); - -retry: - return -EAGAIN; -} - /* * Replace the page in the mapping. * @@ -517,8 +467,7 @@ static int fallback_migrate_page(struct address_space *mapping, * Two lists are passed to this function. The first list * contains the pages isolated from the LRU to be migrated. * The second list contains new pages that the pages isolated - * can be moved to. If the second list is NULL then all - * pages are swapped out. + * can be moved to. * * The function returns after 10 attempts or if no pages * are movable anymore because to has become empty @@ -574,29 +523,11 @@ redo: * Only wait on writeback if we have already done a pass where * we we may have triggered writeouts for lots of pages. */ - if (pass > 0) { + if (pass > 0) wait_on_page_writeback(page); - } else { + else if (PageWriteback(page)) goto unlock_page; - } - - /* - * Anonymous pages must have swap cache references otherwise - * the information contained in the page maps cannot be - * preserved. - */ - if (PageAnon(page) && !PageSwapCache(page)) { - if (!add_to_swap(page, GFP_KERNEL)) { - rc = -ENOMEM; - goto unlock_page; - } - } - - if (!to) { - rc = swap_page(page); - goto next; - } /* * Establish swap ptes for anonymous pages or destroy pte diff --git a/mm/rmap.c b/mm/rmap.c index 3b8ce86daa3a..a53a10b93ecf 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -205,44 +205,6 @@ out: return anon_vma; } -#ifdef CONFIG_MIGRATION -/* - * Remove an anonymous page from swap replacing the swap pte's - * through real pte's pointing to valid pages and then releasing - * the page from the swap cache. - * - * Must hold page lock on page and mmap_sem of one vma that contains - * the page. - */ -void remove_from_swap(struct page *page) -{ - struct anon_vma *anon_vma; - struct vm_area_struct *vma; - unsigned long mapping; - - if (!PageSwapCache(page)) - return; - - mapping = (unsigned long)page->mapping; - - if (!mapping || (mapping & PAGE_MAPPING_ANON) == 0) - return; - - /* - * We hold the mmap_sem lock. So no need to call page_lock_anon_vma. - */ - anon_vma = (struct anon_vma *) (mapping - PAGE_MAPPING_ANON); - spin_lock(&anon_vma->lock); - - list_for_each_entry(vma, &anon_vma->head, anon_vma_node) - remove_vma_swap(vma, page); - - spin_unlock(&anon_vma->lock); - delete_from_swap_cache(page); -} -EXPORT_SYMBOL(remove_from_swap); -#endif - /* * At what user virtual address is page expected in vma? */ diff --git a/mm/swapfile.c b/mm/swapfile.c index e3b1362372c2..fbceed67a075 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -618,15 +618,6 @@ static int unuse_mm(struct mm_struct *mm, return 0; } -#ifdef CONFIG_MIGRATION -int remove_vma_swap(struct vm_area_struct *vma, struct page *page) -{ - swp_entry_t entry = { .val = page_private(page) }; - - return unuse_vma(vma, entry, page); -} -#endif - /* * Scan swap_map from current position to next entry still in use. * Recycle to start on reaching the end, returning 0 when empty. -- cgit v1.2.3 From 04e62a29bf157ce1edd168f2b71b533c80d13628 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Fri, 23 Jun 2006 02:03:38 -0700 Subject: [PATCH] More page migration: use migration entries for file pages This implements the use of migration entries to preserve ptes of file backed pages during migration. Processes can therefore be migrated back and forth without loosing their connection to pagecache pages. Note that we implement the migration entries only for linear mappings. Nonlinear mappings still require the unmapping of the ptes for migration. And another writepage() ugliness shows up. writepage() can drop the page lock. Therefore we have to remove migration ptes before calling writepages() in order to avoid having migration entries point to unlocked pages. Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/swap.h | 15 ------ mm/migrate.c | 127 ++++++++++++++++++++++++++++++++++++++++----------- mm/rmap.c | 11 +++++ mm/vmscan.c | 14 +++++- 4 files changed, 124 insertions(+), 43 deletions(-) (limited to 'include') diff --git a/include/linux/swap.h b/include/linux/swap.h index 7cee73ef4f15..1cf234e8df55 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -186,20 +186,6 @@ extern unsigned long shrink_all_memory(unsigned long nr_pages); extern int vm_swappiness; extern int remove_mapping(struct address_space *mapping, struct page *page); -/* possible outcome of pageout() */ -typedef enum { - /* failed to write page out, page is locked */ - PAGE_KEEP, - /* move page to the active list, page is locked */ - PAGE_ACTIVATE, - /* page has been sent to the disk successfully, page is unlocked */ - PAGE_SUCCESS, - /* page is clean and locked */ - PAGE_CLEAN, -} pageout_t; - -extern pageout_t pageout(struct page *page, struct address_space *mapping); - #ifdef CONFIG_NUMA extern int zone_reclaim_mode; extern int zone_reclaim_interval; @@ -259,7 +245,6 @@ extern int remove_exclusive_swap_page(struct page *); struct backing_dev_info; extern spinlock_t swap_lock; -extern int remove_vma_swap(struct vm_area_struct *vma, struct page *page); /* linux/mm/thrash.c */ extern struct mm_struct * swap_token_mm; diff --git a/mm/migrate.c b/mm/migrate.c index 96b9546e69e0..b5000d463893 100644 --- a/mm/migrate.c +++ b/mm/migrate.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "internal.h" @@ -123,7 +124,7 @@ static inline int is_swap_pte(pte_t pte) /* * Restore a potential migration pte to a working pte entry */ -static void remove_migration_pte(struct vm_area_struct *vma, unsigned long addr, +static void remove_migration_pte(struct vm_area_struct *vma, struct page *old, struct page *new) { struct mm_struct *mm = vma->vm_mm; @@ -133,6 +134,10 @@ static void remove_migration_pte(struct vm_area_struct *vma, unsigned long addr, pmd_t *pmd; pte_t *ptep, pte; spinlock_t *ptl; + unsigned long addr = page_address_in_vma(new, vma); + + if (addr == -EFAULT) + return; pgd = pgd_offset(mm, addr); if (!pgd_present(*pgd)) @@ -169,19 +174,47 @@ static void remove_migration_pte(struct vm_area_struct *vma, unsigned long addr, if (is_write_migration_entry(entry)) pte = pte_mkwrite(pte); set_pte_at(mm, addr, ptep, pte); - page_add_anon_rmap(new, vma, addr); + + if (PageAnon(new)) + page_add_anon_rmap(new, vma, addr); + else + page_add_file_rmap(new); + + /* No need to invalidate - it was non-present before */ + update_mmu_cache(vma, addr, pte); + lazy_mmu_prot_update(pte); + out: pte_unmap_unlock(ptep, ptl); } /* - * Get rid of all migration entries and replace them by - * references to the indicated page. - * + * Note that remove_file_migration_ptes will only work on regular mappings, + * Nonlinear mappings do not use migration entries. + */ +static void remove_file_migration_ptes(struct page *old, struct page *new) +{ + struct vm_area_struct *vma; + struct address_space *mapping = page_mapping(new); + struct prio_tree_iter iter; + pgoff_t pgoff = new->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT); + + if (!mapping) + return; + + spin_lock(&mapping->i_mmap_lock); + + vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, pgoff, pgoff) + remove_migration_pte(vma, old, new); + + spin_unlock(&mapping->i_mmap_lock); +} + +/* * Must hold mmap_sem lock on at least one of the vmas containing * the page so that the anon_vma cannot vanish. */ -static void remove_migration_ptes(struct page *old, struct page *new) +static void remove_anon_migration_ptes(struct page *old, struct page *new) { struct anon_vma *anon_vma; struct vm_area_struct *vma; @@ -199,12 +232,23 @@ static void remove_migration_ptes(struct page *old, struct page *new) spin_lock(&anon_vma->lock); list_for_each_entry(vma, &anon_vma->head, anon_vma_node) - remove_migration_pte(vma, page_address_in_vma(new, vma), - old, new); + remove_migration_pte(vma, old, new); spin_unlock(&anon_vma->lock); } +/* + * Get rid of all migration entries and replace them by + * references to the indicated page. + */ +static void remove_migration_ptes(struct page *old, struct page *new) +{ + if (PageAnon(new)) + remove_anon_migration_ptes(old, new); + else + remove_file_migration_ptes(old, new); +} + /* * Something used the pte of a page under migration. We need to * get to the page and wait until migration is finished. @@ -424,30 +468,59 @@ int buffer_migrate_page(struct address_space *mapping, } EXPORT_SYMBOL(buffer_migrate_page); -static int fallback_migrate_page(struct address_space *mapping, - struct page *newpage, struct page *page) +/* + * Writeback a page to clean the dirty state + */ +static int writeout(struct address_space *mapping, struct page *page) { + struct writeback_control wbc = { + .sync_mode = WB_SYNC_NONE, + .nr_to_write = 1, + .range_start = 0, + .range_end = LLONG_MAX, + .nonblocking = 1, + .for_reclaim = 1 + }; + int rc; + + if (!mapping->a_ops->writepage) + /* No write method for the address space */ + return -EINVAL; + + if (!clear_page_dirty_for_io(page)) + /* Someone else already triggered a write */ + return -EAGAIN; + /* - * Default handling if a filesystem does not provide - * a migration function. We can only migrate clean - * pages so try to write out any dirty pages first. + * A dirty page may imply that the underlying filesystem has + * the page on some queue. So the page must be clean for + * migration. Writeout may mean we loose the lock and the + * page state is no longer what we checked for earlier. + * At this point we know that the migration attempt cannot + * be successful. */ - if (PageDirty(page)) { - switch (pageout(page, mapping)) { - case PAGE_KEEP: - case PAGE_ACTIVATE: - return -EAGAIN; + remove_migration_ptes(page, page); - case PAGE_SUCCESS: - /* Relock since we lost the lock */ - lock_page(page); - /* Must retry since page state may have changed */ - return -EAGAIN; + rc = mapping->a_ops->writepage(page, &wbc); + if (rc < 0) + /* I/O Error writing */ + return -EIO; - case PAGE_CLEAN: - ; /* try to migrate the page below */ - } - } + if (rc != AOP_WRITEPAGE_ACTIVATE) + /* unlocked. Relock */ + lock_page(page); + + return -EAGAIN; +} + +/* + * Default handling if a filesystem does not provide a migration function. + */ +static int fallback_migrate_page(struct address_space *mapping, + struct page *newpage, struct page *page) +{ + if (PageDirty(page)) + return writeout(mapping, page); /* * Buffers may be managed in a filesystem specific way. diff --git a/mm/rmap.c b/mm/rmap.c index 05d6d73a692d..882a85826bb2 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -596,6 +596,7 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma, spin_unlock(&mmlist_lock); } dec_mm_counter(mm, anon_rss); +#ifdef CONFIG_MIGRATION } else { /* * Store the pfn of the page in a special migration @@ -604,12 +605,22 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma, */ BUG_ON(!migration); entry = make_migration_entry(page, pte_write(pteval)); +#endif } set_pte_at(mm, address, pte, swp_entry_to_pte(entry)); BUG_ON(pte_file(*pte)); } else +#ifdef CONFIG_MIGRATION + if (migration) { + /* Establish migration entry for a file page */ + swp_entry_t entry; + entry = make_migration_entry(page, pte_write(pteval)); + set_pte_at(mm, address, pte, swp_entry_to_pte(entry)); + } else +#endif dec_mm_counter(mm, file_rss); + page_remove_rmap(page); page_cache_release(page); diff --git a/mm/vmscan.c b/mm/vmscan.c index bc5d4f43036c..71a02e295037 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -290,11 +290,23 @@ static void handle_write_error(struct address_space *mapping, unlock_page(page); } +/* possible outcome of pageout() */ +typedef enum { + /* failed to write page out, page is locked */ + PAGE_KEEP, + /* move page to the active list, page is locked */ + PAGE_ACTIVATE, + /* page has been sent to the disk successfully, page is unlocked */ + PAGE_SUCCESS, + /* page is clean and locked */ + PAGE_CLEAN, +} pageout_t; + /* * pageout is called by shrink_page_list() for each dirty page. * Calls ->writepage(). */ -pageout_t pageout(struct page *page, struct address_space *mapping) +static pageout_t pageout(struct page *page, struct address_space *mapping) { /* * If the page is dirty, only perform writeback if that write -- cgit v1.2.3 From 30c253e6da655d73eb8bfe2adca9b8f4d82fb81e Mon Sep 17 00:00:00 2001 From: Andy Whitcroft Date: Fri, 23 Jun 2006 02:03:41 -0700 Subject: [PATCH] sparsemem: record nid during memory present Record the node id as we mark sections for instantiation. Use this nid during instantiation to direct allocations. Signed-off-by: Andy Whitcroft Cc: Mike Kravetz Cc: Dave Hansen Cc: Mel Gorman Cc: Bob Picco Cc: Jack Steiner Cc: Yasunori Goto Cc: Martin Bligh Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mmzone.h | 5 +++++ mm/sparse.c | 22 ++++++++++++++++++++-- 2 files changed, 25 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index e82fc1a52cd0..d6120fa69116 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -509,6 +509,10 @@ struct mem_section { * pages. However, it is stored with some other magic. * (see sparse.c::sparse_init_one_section()) * + * Additionally during early boot we encode node id of + * the location of the section here to guide allocation. + * (see sparse.c::memory_present()) + * * Making it a UL at least makes someone do a cast * before using it wrong. */ @@ -548,6 +552,7 @@ extern int __section_nr(struct mem_section* ms); #define SECTION_HAS_MEM_MAP (1UL<<1) #define SECTION_MAP_LAST_BIT (1UL<<2) #define SECTION_MAP_MASK (~(SECTION_MAP_LAST_BIT-1)) +#define SECTION_NID_SHIFT 2 static inline struct page *__section_mem_map_addr(struct mem_section *section) { diff --git a/mm/sparse.c b/mm/sparse.c index 100040c0dfb6..e0a3fe48aa37 100644 --- a/mm/sparse.c +++ b/mm/sparse.c @@ -99,6 +99,22 @@ int __section_nr(struct mem_section* ms) return (root_nr * SECTIONS_PER_ROOT) + (ms - root); } +/* + * During early boot, before section_mem_map is used for an actual + * mem_map, we use section_mem_map to store the section's NUMA + * node. This keeps us from having to use another data structure. The + * node information is cleared just before we store the real mem_map. + */ +static inline unsigned long sparse_encode_early_nid(int nid) +{ + return (nid << SECTION_NID_SHIFT); +} + +static inline int sparse_early_nid(struct mem_section *section) +{ + return (section->section_mem_map >> SECTION_NID_SHIFT); +} + /* Record a memory area against a node. */ void memory_present(int nid, unsigned long start, unsigned long end) { @@ -113,7 +129,8 @@ void memory_present(int nid, unsigned long start, unsigned long end) ms = __nr_to_section(section); if (!ms->section_mem_map) - ms->section_mem_map = SECTION_MARKED_PRESENT; + ms->section_mem_map = sparse_encode_early_nid(nid) | + SECTION_MARKED_PRESENT; } } @@ -164,6 +181,7 @@ static int sparse_init_one_section(struct mem_section *ms, if (!valid_section(ms)) return -EINVAL; + ms->section_mem_map &= ~SECTION_MAP_MASK; ms->section_mem_map |= sparse_encode_mem_map(mem_map, pnum); return 1; @@ -172,8 +190,8 @@ static int sparse_init_one_section(struct mem_section *ms, static struct page *sparse_early_mem_map_alloc(unsigned long pnum) { struct page *map; - int nid = early_pfn_to_nid(section_nr_to_pfn(pnum)); struct mem_section *ms = __nr_to_section(pnum); + int nid = sparse_early_nid(ms); map = alloc_remap(nid, sizeof(struct page) * PAGES_PER_SECTION); if (map) -- cgit v1.2.3 From bd96b9eb7cfd6ab24ba244360a09980a720874d2 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 23 Jun 2006 02:03:42 -0700 Subject: [PATCH] mm: fix swap unused warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If CONFIG_SWAP is not defined we get: mm/vmscan.c: In function ‘remove_mapping’: mm/vmscan.c:387: warning: unused variable ‘swap’ Convert defines in swap.h into blank inline functions to fix this warning and be consistent. Signed-off-by: Con Kolivas Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/swap.h | 64 +++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 53 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/include/linux/swap.h b/include/linux/swap.h index 1cf234e8df55..f1a827a972e0 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -282,18 +282,60 @@ static inline void disable_swap_token(void) #define free_pages_and_swap_cache(pages, nr) \ release_pages((pages), (nr), 0); -#define show_swap_cache_info() /*NOTHING*/ -#define free_swap_and_cache(swp) /*NOTHING*/ -#define swap_duplicate(swp) /*NOTHING*/ -#define swap_free(swp) /*NOTHING*/ -#define read_swap_cache_async(swp,vma,addr) NULL -#define lookup_swap_cache(swp) NULL -#define valid_swaphandles(swp, off) 0 +static inline void show_swap_cache_info(void) +{ +} + +static inline void free_swap_and_cache(swp_entry_t swp) +{ +} + +static inline int swap_duplicate(swp_entry_t swp) +{ + return 0; +} + +static inline void swap_free(swp_entry_t swp) +{ +} + +static inline struct page *read_swap_cache_async(swp_entry_t swp, + struct vm_area_struct *vma, unsigned long addr) +{ + return NULL; +} + +static inline struct page *lookup_swap_cache(swp_entry_t swp) +{ + return NULL; +} + +static inline int valid_swaphandles(swp_entry_t entry, unsigned long *offset) +{ + return 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*/ -#define delete_from_swap_cache(p) /*NOTHING*/ + +static inline int move_to_swap_cache(struct page *page, swp_entry_t entry) +{ + return 1; +} + +static inline int move_from_swap_cache(struct page *page, unsigned long index, + struct address_space *mapping) +{ + return 1; +} + +static inline void __delete_from_swap_cache(struct page *page) +{ +} + +static inline void delete_from_swap_cache(struct page *page) +{ +} + #define swap_token_default_timeout 0 static inline int remove_exclusive_swap_page(struct page *p) -- cgit v1.2.3 From 9637a5efd4fbe36164c5ce7f6a0ee68b2bf22b7f Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 23 Jun 2006 02:03:43 -0700 Subject: [PATCH] add page_mkwrite() vm_operations method Add a new VMA operation to notify a filesystem or other driver about the MMU generating a fault because userspace attempted to write to a page mapped through a read-only PTE. This facility permits the filesystem or driver to: (*) Implement storage allocation/reservation on attempted write, and so to deal with problems such as ENOSPC more gracefully (perhaps by generating SIGBUS). (*) Delay making the page writable until the contents have been written to a backing cache. This is useful for NFS/AFS when using FS-Cache/CacheFS. It permits the filesystem to have some guarantee about the state of the cache. (*) Account and limit number of dirty pages. This is one piece of the puzzle needed to make shared writable mapping work safely in FUSE. Needed by cachefs (Or is it cachefiles? Or fscache? ). At least four other groups have stated an interest in it or a desire to use the functionality it provides: FUSE, OCFS2, NTFS and JFFS2. Also, things like EXT3 really ought to use it to deal with the case of shared-writable mmap encountering ENOSPC before we permit the page to be dirtied. From: Peter Zijlstra get_user_pages(.write=1, .force=1) can generate COW hits on read-only shared mappings, this patch traps those as mkpage_write candidates and fails to handle them the old way. Signed-off-by: David Howells Cc: Miklos Szeredi Cc: Joel Becker Cc: Mark Fasheh Cc: Anton Altaparmakov Cc: David Woodhouse Cc: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mm.h | 4 +++ mm/memory.c | 100 ++++++++++++++++++++++++++++++++++++++++------------- mm/mmap.c | 12 +++++-- mm/mprotect.c | 11 ++++-- 4 files changed, 99 insertions(+), 28 deletions(-) (limited to 'include') diff --git a/include/linux/mm.h b/include/linux/mm.h index 697c6bf248c2..3b09444121d9 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -199,6 +199,10 @@ struct vm_operations_struct { void (*close)(struct vm_area_struct * area); struct page * (*nopage)(struct vm_area_struct * area, unsigned long address, int *type); int (*populate)(struct vm_area_struct * area, unsigned long address, unsigned long len, pgprot_t prot, unsigned long pgoff, int nonblock); + + /* notification that a previously read-only page is about to become + * writable, if an error is returned it will cause a SIGBUS */ + int (*page_mkwrite)(struct vm_area_struct *vma, struct page *page); #ifdef CONFIG_NUMA int (*set_policy)(struct vm_area_struct *vma, struct mempolicy *new); struct mempolicy *(*get_policy)(struct vm_area_struct *vma, diff --git a/mm/memory.c b/mm/memory.c index 11673c5d2c20..247b5c312b9b 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -1457,25 +1457,60 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct *vma, { struct page *old_page, *new_page; pte_t entry; - int ret = VM_FAULT_MINOR; + int reuse, ret = VM_FAULT_MINOR; old_page = vm_normal_page(vma, address, orig_pte); if (!old_page) goto gotten; - if (PageAnon(old_page) && !TestSetPageLocked(old_page)) { - int reuse = can_share_swap_page(old_page); - unlock_page(old_page); - if (reuse) { - flush_cache_page(vma, address, pte_pfn(orig_pte)); - entry = pte_mkyoung(orig_pte); - entry = maybe_mkwrite(pte_mkdirty(entry), vma); - ptep_set_access_flags(vma, address, page_table, entry, 1); - update_mmu_cache(vma, address, entry); - lazy_mmu_prot_update(entry); - ret |= VM_FAULT_WRITE; - goto unlock; + if (unlikely((vma->vm_flags & (VM_SHARED|VM_WRITE)) == + (VM_SHARED|VM_WRITE))) { + if (vma->vm_ops && vma->vm_ops->page_mkwrite) { + /* + * Notify the address space that the page is about to + * become writable so that it can prohibit this or wait + * for the page to get into an appropriate state. + * + * We do this without the lock held, so that it can + * sleep if it needs to. + */ + page_cache_get(old_page); + pte_unmap_unlock(page_table, ptl); + + if (vma->vm_ops->page_mkwrite(vma, old_page) < 0) + goto unwritable_page; + + page_cache_release(old_page); + + /* + * Since we dropped the lock we need to revalidate + * the PTE as someone else may have changed it. If + * they did, we just return, as we can count on the + * MMU to tell us if they didn't also make it writable. + */ + page_table = pte_offset_map_lock(mm, pmd, address, + &ptl); + if (!pte_same(*page_table, orig_pte)) + goto unlock; } + + reuse = 1; + } else if (PageAnon(old_page) && !TestSetPageLocked(old_page)) { + reuse = can_share_swap_page(old_page); + unlock_page(old_page); + } else { + reuse = 0; + } + + if (reuse) { + flush_cache_page(vma, address, pte_pfn(orig_pte)); + entry = pte_mkyoung(orig_pte); + entry = maybe_mkwrite(pte_mkdirty(entry), vma); + ptep_set_access_flags(vma, address, page_table, entry, 1); + update_mmu_cache(vma, address, entry); + lazy_mmu_prot_update(entry); + ret |= VM_FAULT_WRITE; + goto unlock; } /* @@ -1535,6 +1570,10 @@ oom: if (old_page) page_cache_release(old_page); return VM_FAULT_OOM; + +unwritable_page: + page_cache_release(old_page); + return VM_FAULT_SIGBUS; } /* @@ -2083,18 +2122,31 @@ retry: /* * Should we do an early C-O-W break? */ - if (write_access && !(vma->vm_flags & VM_SHARED)) { - struct page *page; + if (write_access) { + if (!(vma->vm_flags & VM_SHARED)) { + struct page *page; - if (unlikely(anon_vma_prepare(vma))) - goto oom; - page = alloc_page_vma(GFP_HIGHUSER, vma, address); - if (!page) - goto oom; - copy_user_highpage(page, new_page, address); - page_cache_release(new_page); - new_page = page; - anon = 1; + if (unlikely(anon_vma_prepare(vma))) + goto oom; + page = alloc_page_vma(GFP_HIGHUSER, vma, address); + if (!page) + goto oom; + copy_user_highpage(page, new_page, address); + page_cache_release(new_page); + new_page = page; + anon = 1; + + } else { + /* if the page will be shareable, see if the backing + * address space wants to know that the page is about + * to become writable */ + if (vma->vm_ops->page_mkwrite && + vma->vm_ops->page_mkwrite(vma, new_page) < 0 + ) { + page_cache_release(new_page); + return VM_FAULT_SIGBUS; + } + } } page_table = pte_offset_map_lock(mm, pmd, address, &ptl); diff --git a/mm/mmap.c b/mm/mmap.c index e6ee12344b13..6446c6134b04 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1065,7 +1065,8 @@ munmap_back: vma->vm_start = addr; vma->vm_end = addr + len; vma->vm_flags = vm_flags; - vma->vm_page_prot = protection_map[vm_flags & 0x0f]; + vma->vm_page_prot = protection_map[vm_flags & + (VM_READ|VM_WRITE|VM_EXEC|VM_SHARED)]; vma->vm_pgoff = pgoff; if (file) { @@ -1089,6 +1090,12 @@ munmap_back: goto free_vma; } + /* Don't make the VMA automatically writable if it's shared, but the + * backer wishes to know when pages are first written to */ + if (vma->vm_ops && vma->vm_ops->page_mkwrite) + vma->vm_page_prot = + protection_map[vm_flags & (VM_READ|VM_WRITE|VM_EXEC)]; + /* We set VM_ACCOUNT in a shared mapping's vm_flags, to inform * shmem_zero_setup (perhaps called through /dev/zero's ->mmap) * that memory reservation must be checked; but that reservation @@ -1921,7 +1928,8 @@ unsigned long do_brk(unsigned long addr, unsigned long len) vma->vm_end = addr + len; vma->vm_pgoff = pgoff; vma->vm_flags = flags; - vma->vm_page_prot = protection_map[flags & 0x0f]; + vma->vm_page_prot = protection_map[flags & + (VM_READ|VM_WRITE|VM_EXEC|VM_SHARED)]; vma_link(mm, vma, prev, rb_link, rb_parent); out: mm->total_vm += len >> PAGE_SHIFT; diff --git a/mm/mprotect.c b/mm/mprotect.c index 14f93e62270f..638edabaff71 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c @@ -123,6 +123,7 @@ mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev, unsigned long oldflags = vma->vm_flags; long nrpages = (end - start) >> PAGE_SHIFT; unsigned long charged = 0; + unsigned int mask; pgprot_t newprot; pgoff_t pgoff; int error; @@ -149,8 +150,6 @@ mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev, } } - newprot = protection_map[newflags & 0xf]; - /* * First try to merge with previous and/or next vma. */ @@ -177,6 +176,14 @@ mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev, } success: + /* Don't make the VMA automatically writable if it's shared, but the + * backer wishes to know when pages are first written to */ + mask = VM_READ|VM_WRITE|VM_EXEC|VM_SHARED; + if (vma->vm_ops && vma->vm_ops->page_mkwrite) + mask &= ~VM_SHARED; + + newprot = protection_map[newflags & mask]; + /* * vm_flags and vm_page_prot are protected by the mmap_sem * held in write mode. -- cgit v1.2.3 From bd1e22b8e0a90f9a91e4c27db14ca15773659bf7 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Fri, 23 Jun 2006 02:03:47 -0700 Subject: [PATCH] initialise total_memory() earlier Initialise total_memory earlier in boot. Because if for some reason we run page reclaim early in boot, we don't want total_memory to be zero when we use it as a divisor. And rename total_memory to vm_total_pages to avoid naming clashes with architectures. Cc: Yasunori Goto Cc: KAMEZAWA Hiroyuki Cc: Martin Bligh Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/swap.h | 1 + mm/page_alloc.c | 6 +++--- mm/vmscan.c | 5 ++--- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/linux/swap.h b/include/linux/swap.h index f1a827a972e0..dc3f3aa0c83e 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -185,6 +185,7 @@ extern unsigned long try_to_free_pages(struct zone **, gfp_t); extern unsigned long shrink_all_memory(unsigned long nr_pages); extern int vm_swappiness; extern int remove_mapping(struct address_space *mapping, struct page *page); +extern long vm_total_pages; #ifdef CONFIG_NUMA extern int zone_reclaim_mode; diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 5af33186a25f..71a0b2a23f5b 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1725,9 +1725,9 @@ void __meminit build_all_zonelists(void) stop_machine_run(__build_all_zonelists, NULL, NR_CPUS); /* cpuset refresh routine should be here */ } - - printk("Built %i zonelists\n", num_online_nodes()); - + vm_total_pages = nr_free_pagecache_pages(); + printk("Built %i zonelists. Total pages: %ld\n", + num_online_nodes(), vm_total_pages); } /* diff --git a/mm/vmscan.c b/mm/vmscan.c index 71a02e295037..72babac71dea 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -110,7 +110,7 @@ struct shrinker { * From 0 .. 100. Higher means more swappy. */ int vm_swappiness = 60; -static long total_memory; +long vm_total_pages; /* The total number of pages which the VM controls */ static LIST_HEAD(shrinker_list); static DECLARE_RWSEM(shrinker_rwsem); @@ -743,7 +743,7 @@ static void shrink_active_list(unsigned long nr_pages, struct zone *zone, * how much memory * is mapped. */ - mapped_ratio = (sc->nr_mapped * 100) / total_memory; + mapped_ratio = (sc->nr_mapped * 100) / vm_total_pages; /* * Now decide how much we really want to unmap some pages. The @@ -1482,7 +1482,6 @@ static int __init kswapd_init(void) pgdat->kswapd = find_task_by_pid(pid); read_unlock(&tasklist_lock); } - total_memory = nr_free_pagecache_pages(); hotcpu_notifier(cpu_callback, 0); return 0; } -- cgit v1.2.3 From 800590f523bf3bde9fa6c8e4d6763e4bf6a2c8ec Mon Sep 17 00:00:00 2001 From: Paul Drynoff Date: Fri, 23 Jun 2006 02:03:48 -0700 Subject: [PATCH] slab: kmalloc, kzalloc comments cleanup and fix - Move comments for kmalloc to right place, currently it near __do_kmalloc - Comments for kzalloc - More detailed comments for kmalloc - Appearance of "kmalloc" and "kzalloc" man pages after "make mandocs" [rdunlap@xenotime.net: simplification] Signed-off-by: Paul Drynoff Acked-by: Randy Dunlap Cc: Pekka Enberg Cc: Manfred Spraul Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/DocBook/kernel-api.tmpl | 1 + include/linux/slab.h | 50 +++++++++++++++++++++++++++++++++++ mm/slab.c | 20 ++------------ 3 files changed, 53 insertions(+), 18 deletions(-) (limited to 'include') diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl index ca02e04a906c..6dab3dd36995 100644 --- a/Documentation/DocBook/kernel-api.tmpl +++ b/Documentation/DocBook/kernel-api.tmpl @@ -117,6 +117,7 @@ X!Ilib/string.c Memory Management in Linux The Slab Cache +!Iinclude/linux/slab.h !Emm/slab.c User Space Memory Access diff --git a/include/linux/slab.h b/include/linux/slab.h index 9dc93163e065..45ad55b70d1c 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -86,6 +86,51 @@ extern void *__kmalloc_track_caller(size_t, gfp_t, void*); __kmalloc_track_caller(size, flags, __builtin_return_address(0)) #endif +/** + * kmalloc - allocate memory + * @size: how many bytes of memory are required. + * @flags: the type of memory to allocate. + * + * kmalloc is the normal method of allocating memory + * in the kernel. + * + * The @flags argument may be one of: + * + * %GFP_USER - Allocate memory on behalf of user. May sleep. + * + * %GFP_KERNEL - Allocate normal kernel ram. May sleep. + * + * %GFP_ATOMIC - Allocation will not sleep. + * For example, use this inside interrupt handlers. + * + * %GFP_HIGHUSER - Allocate pages from high memory. + * + * %GFP_NOIO - Do not do any I/O at all while trying to get memory. + * + * %GFP_NOFS - Do not make any fs calls while trying to get memory. + * + * Also it is possible to set different flags by OR'ing + * in one or more of the following additional @flags: + * + * %__GFP_COLD - Request cache-cold pages instead of + * trying to return cache-warm pages. + * + * %__GFP_DMA - Request memory from the DMA-capable zone. + * + * %__GFP_HIGH - This allocation has high priority and may use emergency pools. + * + * %__GFP_HIGHMEM - Allocated memory may be from highmem. + * + * %__GFP_NOFAIL - Indicate that this allocation is in no way allowed to fail + * (think twice before using). + * + * %__GFP_NORETRY - If memory is not immediately available, + * then give up at once. + * + * %__GFP_NOWARN - If allocation fails, don't issue any warnings. + * + * %__GFP_REPEAT - If allocation fails initially, try once more before failing. + */ static inline void *kmalloc(size_t size, gfp_t flags) { if (__builtin_constant_p(size)) { @@ -111,6 +156,11 @@ found: extern void *__kzalloc(size_t, gfp_t); +/** + * kzalloc - allocate memory. The memory is set to zero. + * @size: how many bytes of memory are required. + * @flags: the type of memory to allocate (see kmalloc). + */ static inline void *kzalloc(size_t size, gfp_t flags) { if (__builtin_constant_p(size)) { diff --git a/mm/slab.c b/mm/slab.c index 664c3a10acf2..98ac20bc0de9 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -3277,26 +3277,10 @@ EXPORT_SYMBOL(kmalloc_node); #endif /** - * kmalloc - allocate memory + * __do_kmalloc - allocate memory * @size: how many bytes of memory are required. - * @flags: the type of memory to allocate. + * @flags: the type of memory to allocate (see kmalloc). * @caller: function caller for debug tracking of the caller - * - * kmalloc is the normal method of allocating memory - * in the kernel. - * - * The @flags argument may be one of: - * - * %GFP_USER - Allocate memory on behalf of user. May sleep. - * - * %GFP_KERNEL - Allocate normal kernel ram. May sleep. - * - * %GFP_ATOMIC - Allocation will not sleep. Use inside interrupt handlers. - * - * Additionally, the %GFP_DMA flag may be set to indicate the memory - * must be suitable for DMA. This can mean different things on different - * platforms. For example, on i386, it means that the memory must come - * from the first 16MB. */ static __always_inline void *__do_kmalloc(size_t size, gfp_t flags, void *caller) -- cgit v1.2.3 From d501e62bc7796e90b0312648e23ac39490dfbf87 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Fri, 23 Jun 2006 02:03:50 -0700 Subject: [PATCH] Delete unused definitions of kvaddr_to_nid Signed-off-by: Ralf Baechle Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-mips/mmzone.h | 1 - include/asm-parisc/mmzone.h | 5 ----- include/asm-x86_64/mmzone.h | 1 - 3 files changed, 7 deletions(-) (limited to 'include') diff --git a/include/asm-mips/mmzone.h b/include/asm-mips/mmzone.h index dc231c89bef9..f53ec54c92ff 100644 --- a/include/asm-mips/mmzone.h +++ b/include/asm-mips/mmzone.h @@ -10,7 +10,6 @@ #ifdef CONFIG_DISCONTIGMEM -#define kvaddr_to_nid(kvaddr) pa_to_nid(__pa(kvaddr)) #define pfn_to_nid(pfn) pa_to_nid((pfn) << PAGE_SHIFT) #endif /* CONFIG_DISCONTIGMEM */ diff --git a/include/asm-parisc/mmzone.h b/include/asm-parisc/mmzone.h index ceb9b73199d1..c87813662d4d 100644 --- a/include/asm-parisc/mmzone.h +++ b/include/asm-parisc/mmzone.h @@ -14,11 +14,6 @@ extern struct node_map_data node_data[]; #define NODE_DATA(nid) (&node_data[nid].pg_data) -/* - * Given a kernel address, find the home node of the underlying memory. - */ -#define kvaddr_to_nid(kaddr) pfn_to_nid(__pa(kaddr) >> PAGE_SHIFT) - #define node_start_pfn(nid) (NODE_DATA(nid)->node_start_pfn) #define node_end_pfn(nid) \ ({ \ diff --git a/include/asm-x86_64/mmzone.h b/include/asm-x86_64/mmzone.h index 70bb9969766e..c38ebdf6f426 100644 --- a/include/asm-x86_64/mmzone.h +++ b/include/asm-x86_64/mmzone.h @@ -42,7 +42,6 @@ static inline __attribute__((pure)) int phys_to_nid(unsigned long addr) #ifdef CONFIG_DISCONTIGMEM #define pfn_to_nid(pfn) phys_to_nid((unsigned long)(pfn) << PAGE_SHIFT) -#define kvaddr_to_nid(kaddr) phys_to_nid(__pa(kaddr)) extern int pfn_valid(unsigned long pfn); #endif -- cgit v1.2.3 From aaa994b300a172afafab47938804836b923e5ef7 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Fri, 23 Jun 2006 02:03:52 -0700 Subject: [PATCH] page migration: handle freeing of pages in migrate_pages() Do not leave pages on the lists passed to migrate_pages(). Seems that we will not need any postprocessing of pages. This will simplify the handling of pages by the callers of migrate_pages(). Signed-off-by: Christoph Lameter Cc: Hugh Dickins Cc: Jes Sorensen Cc: KAMEZAWA Hiroyuki Cc: Lee Schermerhorn Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/migrate.h | 7 +++---- mm/mempolicy.c | 8 +------- mm/migrate.c | 48 +++++++++++++++++++++++------------------------- 3 files changed, 27 insertions(+), 36 deletions(-) (limited to 'include') diff --git a/include/linux/migrate.h b/include/linux/migrate.h index 287c47b5e5df..83af25949fa9 100644 --- a/include/linux/migrate.h +++ b/include/linux/migrate.h @@ -8,8 +8,7 @@ extern int isolate_lru_page(struct page *p, struct list_head *pagelist); extern int putback_lru_pages(struct list_head *l); extern int migrate_page(struct address_space *, struct page *, struct page *); -extern int migrate_pages(struct list_head *l, struct list_head *t, - struct list_head *moved, struct list_head *failed); +extern int migrate_pages(struct list_head *l, struct list_head *t); extern int migrate_pages_to(struct list_head *pagelist, struct vm_area_struct *vma, int dest); extern int fail_migrate_page(struct address_space *, @@ -22,8 +21,8 @@ extern int migrate_prep(void); static inline int isolate_lru_page(struct page *p, struct list_head *list) { return -ENOSYS; } static inline int putback_lru_pages(struct list_head *l) { return 0; } -static inline int migrate_pages(struct list_head *l, struct list_head *t, - struct list_head *moved, struct list_head *failed) { return -ENOSYS; } +static inline int migrate_pages(struct list_head *l, struct list_head *t) + { return -ENOSYS; } static inline int migrate_pages_to(struct list_head *pagelist, struct vm_area_struct *vma, int dest) { return 0; } diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 8778f58880c4..244f3f130e4a 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -603,11 +603,8 @@ int migrate_to_node(struct mm_struct *mm, int source, int dest, int flags) check_range(mm, mm->mmap->vm_start, TASK_SIZE, &nmask, flags | MPOL_MF_DISCONTIG_OK, &pagelist); - if (!list_empty(&pagelist)) { + if (!list_empty(&pagelist)) err = migrate_pages_to(&pagelist, NULL, dest); - if (!list_empty(&pagelist)) - putback_lru_pages(&pagelist); - } return err; } @@ -773,9 +770,6 @@ long do_mbind(unsigned long start, unsigned long len, err = -EIO; } - if (!list_empty(&pagelist)) - putback_lru_pages(&pagelist); - up_write(&mm->mmap_sem); mpol_free(new); return err; diff --git a/mm/migrate.c b/mm/migrate.c index 09038163bfec..d3a1810a4c9f 100644 --- a/mm/migrate.c +++ b/mm/migrate.c @@ -624,6 +624,15 @@ unlock: unlock_page(page); ret: if (rc != -EAGAIN) { + /* + * A page that has been migrated has all references + * removed and will be freed. A page that has not been + * migrated will have kepts its references and be + * restored. + */ + list_del(&page->lru); + move_to_lru(page); + list_del(&newpage->lru); move_to_lru(newpage); } @@ -640,12 +649,12 @@ ret: * * The function returns after 10 attempts or if no pages * are movable anymore because to has become empty - * or no retryable pages exist anymore. + * or no retryable pages exist anymore. All pages will be + * retruned to the LRU or freed. * - * Return: Number of pages not migrated when "to" ran empty. + * Return: Number of pages not migrated. */ -int migrate_pages(struct list_head *from, struct list_head *to, - struct list_head *moved, struct list_head *failed) +int migrate_pages(struct list_head *from, struct list_head *to) { int retry = 1; int nr_failed = 0; @@ -675,11 +684,9 @@ int migrate_pages(struct list_head *from, struct list_head *to, retry++; break; case 0: - list_move(&page->lru, moved); break; default: /* Permanent failure */ - list_move(&page->lru, failed); nr_failed++; break; } @@ -689,6 +696,7 @@ int migrate_pages(struct list_head *from, struct list_head *to, if (!swapwrite) current->flags &= ~PF_SWAPWRITE; + putback_lru_pages(from); return nr_failed + retry; } @@ -702,11 +710,10 @@ int migrate_pages_to(struct list_head *pagelist, struct vm_area_struct *vma, int dest) { LIST_HEAD(newlist); - LIST_HEAD(moved); - LIST_HEAD(failed); int err = 0; unsigned long offset = 0; int nr_pages; + int nr_failed = 0; struct page *page; struct list_head *p; @@ -740,26 +747,17 @@ redo: if (nr_pages > MIGRATE_CHUNK_SIZE) break; } - err = migrate_pages(pagelist, &newlist, &moved, &failed); + err = migrate_pages(pagelist, &newlist); - putback_lru_pages(&moved); /* Call release pages instead ?? */ - - if (err >= 0 && list_empty(&newlist) && !list_empty(pagelist)) - goto redo; -out: - /* Return leftover allocated pages */ - while (!list_empty(&newlist)) { - page = list_entry(newlist.next, struct page, lru); - list_del(&page->lru); - __free_page(page); + if (err >= 0) { + nr_failed += err; + if (list_empty(&newlist) && !list_empty(pagelist)) + goto redo; } - list_splice(&failed, pagelist); - if (err < 0) - return err; +out: /* Calculate number of leftover pages */ - nr_pages = 0; list_for_each(p, pagelist) - nr_pages++; - return nr_pages; + nr_failed++; + return nr_failed; } -- cgit v1.2.3 From 95a402c3847cc16f4ba03013cd01404fa0f14c2e Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Fri, 23 Jun 2006 02:03:53 -0700 Subject: [PATCH] page migration: use allocator function for migrate_pages() Instead of passing a list of new pages, pass a function to allocate a new page. This allows the correct placement of MPOL_INTERLEAVE pages during page migration. It also further simplifies the callers of migrate pages. migrate_pages() becomes similar to migrate_pages_to() so drop migrate_pages_to(). The batching of new page allocations becomes unnecessary. Signed-off-by: Christoph Lameter Cc: Hugh Dickins Cc: Jes Sorensen Cc: KAMEZAWA Hiroyuki Cc: Lee Schermerhorn Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/migrate.h | 11 ++--- mm/mempolicy.c | 23 +++++++++- mm/migrate.c | 115 ++++++++++++++---------------------------------- 3 files changed, 59 insertions(+), 90 deletions(-) (limited to 'include') diff --git a/include/linux/migrate.h b/include/linux/migrate.h index 83af25949fa9..5b95d6568dc4 100644 --- a/include/linux/migrate.h +++ b/include/linux/migrate.h @@ -3,14 +3,15 @@ #include +typedef struct page *new_page_t(struct page *, unsigned long private); + #ifdef CONFIG_MIGRATION extern int isolate_lru_page(struct page *p, struct list_head *pagelist); extern int putback_lru_pages(struct list_head *l); extern int migrate_page(struct address_space *, struct page *, struct page *); -extern int migrate_pages(struct list_head *l, struct list_head *t); -extern int migrate_pages_to(struct list_head *pagelist, - struct vm_area_struct *vma, int dest); +extern int migrate_pages(struct list_head *l, new_page_t x, unsigned long); + extern int fail_migrate_page(struct address_space *, struct page *, struct page *); @@ -21,8 +22,8 @@ extern int migrate_prep(void); static inline int isolate_lru_page(struct page *p, struct list_head *list) { return -ENOSYS; } static inline int putback_lru_pages(struct list_head *l) { return 0; } -static inline int migrate_pages(struct list_head *l, struct list_head *t) - { return -ENOSYS; } +static inline int migrate_pages(struct list_head *l, new_page_t x, + unsigned long private) { return -ENOSYS; } static inline int migrate_pages_to(struct list_head *pagelist, struct vm_area_struct *vma, int dest) { return 0; } diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 244f3f130e4a..f432642e9e66 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -87,6 +87,7 @@ #include #include #include +#include #include #include @@ -587,6 +588,11 @@ static void migrate_page_add(struct page *page, struct list_head *pagelist, isolate_lru_page(page, pagelist); } +static struct page *new_node_page(struct page *page, unsigned long node) +{ + return alloc_pages_node(node, GFP_HIGHUSER, 0); +} + /* * Migrate pages from one node to a target node. * Returns error or the number of pages not migrated. @@ -604,7 +610,8 @@ int migrate_to_node(struct mm_struct *mm, int source, int dest, int flags) flags | MPOL_MF_DISCONTIG_OK, &pagelist); if (!list_empty(&pagelist)) - err = migrate_pages_to(&pagelist, NULL, dest); + err = migrate_pages(&pagelist, new_node_page, dest); + return err; } @@ -691,6 +698,12 @@ int do_migrate_pages(struct mm_struct *mm, } +static struct page *new_vma_page(struct page *page, unsigned long private) +{ + struct vm_area_struct *vma = (struct vm_area_struct *)private; + + return alloc_page_vma(GFP_HIGHUSER, vma, page_address_in_vma(page, vma)); +} #else static void migrate_page_add(struct page *page, struct list_head *pagelist, @@ -703,6 +716,11 @@ int do_migrate_pages(struct mm_struct *mm, { return -ENOSYS; } + +static struct page *new_vma_page(struct page *page, unsigned long private) +{ + return NULL; +} #endif long do_mbind(unsigned long start, unsigned long len, @@ -764,7 +782,8 @@ long do_mbind(unsigned long start, unsigned long len, err = mbind_range(vma, start, end, new); if (!list_empty(&pagelist)) - nr_failed = migrate_pages_to(&pagelist, vma, -1); + nr_failed = migrate_pages(&pagelist, new_vma_page, + (unsigned long)vma); if (!err && nr_failed && (flags & MPOL_MF_STRICT)) err = -EIO; diff --git a/mm/migrate.c b/mm/migrate.c index d3a1810a4c9f..251a8d158257 100644 --- a/mm/migrate.c +++ b/mm/migrate.c @@ -28,9 +28,6 @@ #include "internal.h" -/* The maximum number of pages to take off the LRU for migration */ -#define MIGRATE_CHUNK_SIZE 256 - #define lru_to_page(_head) (list_entry((_head)->prev, struct page, lru)) /* @@ -587,18 +584,23 @@ static int move_to_new_page(struct page *newpage, struct page *page) * Obtain the lock on page, remove all ptes and migrate the page * to the newly allocated page in newpage. */ -static int unmap_and_move(struct page *newpage, struct page *page, int force) +static int unmap_and_move(new_page_t get_new_page, unsigned long private, + struct page *page, int force) { int rc = 0; + struct page *newpage = get_new_page(page, private); + + if (!newpage) + return -ENOMEM; if (page_count(page) == 1) /* page was freed from under us. So we are done. */ - goto ret; + goto move_newpage; rc = -EAGAIN; if (TestSetPageLocked(page)) { if (!force) - goto ret; + goto move_newpage; lock_page(page); } @@ -622,7 +624,7 @@ static int unmap_and_move(struct page *newpage, struct page *page, int force) remove_migration_ptes(page, page); unlock: unlock_page(page); -ret: + if (rc != -EAGAIN) { /* * A page that has been migrated has all references @@ -632,29 +634,33 @@ ret: */ list_del(&page->lru); move_to_lru(page); - - list_del(&newpage->lru); - move_to_lru(newpage); } + +move_newpage: + /* + * Move the new page to the LRU. If migration was not successful + * then this will free the page. + */ + move_to_lru(newpage); return rc; } /* * migrate_pages * - * Two lists are passed to this function. The first list - * contains the pages isolated from the LRU to be migrated. - * The second list contains new pages that the isolated pages - * can be moved to. + * The function takes one list of pages to migrate and a function + * that determines from the page to be migrated and the private data + * the target of the move and allocates the page. * * The function returns after 10 attempts or if no pages * are movable anymore because to has become empty * or no retryable pages exist anymore. All pages will be * retruned to the LRU or freed. * - * Return: Number of pages not migrated. + * Return: Number of pages not migrated or error code. */ -int migrate_pages(struct list_head *from, struct list_head *to) +int migrate_pages(struct list_head *from, + new_page_t get_new_page, unsigned long private) { int retry = 1; int nr_failed = 0; @@ -671,15 +677,14 @@ int migrate_pages(struct list_head *from, struct list_head *to) retry = 0; list_for_each_entry_safe(page, page2, from, lru) { - - if (list_empty(to)) - break; - cond_resched(); - rc = unmap_and_move(lru_to_page(to), page, pass > 2); + rc = unmap_and_move(get_new_page, private, + page, pass > 2); switch(rc) { + case -ENOMEM: + goto out; case -EAGAIN: retry++; break; @@ -692,72 +697,16 @@ int migrate_pages(struct list_head *from, struct list_head *to) } } } - + rc = 0; +out: if (!swapwrite) current->flags &= ~PF_SWAPWRITE; putback_lru_pages(from); - return nr_failed + retry; -} -/* - * Migrate the list 'pagelist' of pages to a certain destination. - * - * Specify destination with either non-NULL vma or dest_node >= 0 - * Return the number of pages not migrated or error code - */ -int migrate_pages_to(struct list_head *pagelist, - struct vm_area_struct *vma, int dest) -{ - LIST_HEAD(newlist); - int err = 0; - unsigned long offset = 0; - int nr_pages; - int nr_failed = 0; - struct page *page; - struct list_head *p; - -redo: - nr_pages = 0; - list_for_each(p, pagelist) { - if (vma) { - /* - * The address passed to alloc_page_vma is used to - * generate the proper interleave behavior. We fake - * the address here by an increasing offset in order - * to get the proper distribution of pages. - * - * No decision has been made as to which page - * a certain old page is moved to so we cannot - * specify the correct address. - */ - page = alloc_page_vma(GFP_HIGHUSER, vma, - offset + vma->vm_start); - offset += PAGE_SIZE; - } - else - page = alloc_pages_node(dest, GFP_HIGHUSER, 0); - - if (!page) { - err = -ENOMEM; - goto out; - } - list_add_tail(&page->lru, &newlist); - nr_pages++; - if (nr_pages > MIGRATE_CHUNK_SIZE) - break; - } - err = migrate_pages(pagelist, &newlist); - - if (err >= 0) { - nr_failed += err; - if (list_empty(&newlist) && !list_empty(pagelist)) - goto redo; - } -out: + if (rc) + return rc; - /* Calculate number of leftover pages */ - list_for_each(p, pagelist) - nr_failed++; - return nr_failed; + return nr_failed + retry; } + -- cgit v1.2.3 From 742755a1d8ce2b548428f7aacf1758b4bba50080 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Fri, 23 Jun 2006 02:03:55 -0700 Subject: [PATCH] page migration: sys_move_pages(): support moving of individual pages move_pages() is used to move individual pages of a process. The function can be used to determine the location of pages and to move them onto the desired node. move_pages() returns status information for each page. long move_pages(pid, number_of_pages_to_move, addresses_of_pages[], nodes[] or NULL, status[], flags); The addresses of pages is an array of void * pointing to the pages to be moved. The nodes array contains the node numbers that the pages should be moved to. If a NULL is passed instead of an array then no pages are moved but the status array is updated. The status request may be used to determine the page state before issuing another move_pages() to move pages. The status array will contain the state of all individual page migration attempts when the function terminates. The status array is only valid if move_pages() completed successfullly. Possible page states in status[]: 0..MAX_NUMNODES The page is now on the indicated node. -ENOENT Page is not present -EACCES Page is mapped by multiple processes and can only be moved if MPOL_MF_MOVE_ALL is specified. -EPERM The page has been mlocked by a process/driver and cannot be moved. -EBUSY Page is busy and cannot be moved. Try again later. -EFAULT Invalid address (no VMA or zero page). -ENOMEM Unable to allocate memory on target node. -EIO Unable to write back page. The page must be written back in order to move it since the page is dirty and the filesystem does not provide a migration function that would allow the moving of dirty pages. -EINVAL A dirty page cannot be moved. The filesystem does not provide a migration function and has no ability to write back pages. The flags parameter indicates what types of pages to move: MPOL_MF_MOVE Move pages that are only mapped by the process. MPOL_MF_MOVE_ALL Also move pages that are mapped by multiple processes. Requires sufficient capabilities. Possible return codes from move_pages() -ENOENT No pages found that would require moving. All pages are either already on the target node, not present, had an invalid address or could not be moved because they were mapped by multiple processes. -EINVAL Flags other than MPOL_MF_MOVE(_ALL) specified or an attempt to migrate pages in a kernel thread. -EPERM MPOL_MF_MOVE_ALL specified without sufficient priviledges. or an attempt to move a process belonging to another user. -EACCES One of the target nodes is not allowed by the current cpuset. -ENODEV One of the target nodes is not online. -ESRCH Process does not exist. -E2BIG Too many pages to move. -ENOMEM Not enough memory to allocate control array. -EFAULT Parameters could not be accessed. A test program for move_pages() may be found with the patches on ftp.kernel.org:/pub/linux/kernel/people/christoph/pmig/patches-2.6.17-rc4-mm3 From: Christoph Lameter Detailed results for sys_move_pages() Pass a pointer to an integer to get_new_page() that may be used to indicate where the completion status of a migration operation should be placed. This allows sys_move_pags() to report back exactly what happened to each page. Wish there would be a better way to do this. Looks a bit hacky. Signed-off-by: Christoph Lameter Cc: Hugh Dickins Cc: Jes Sorensen Cc: KAMEZAWA Hiroyuki Cc: Lee Schermerhorn Cc: Andi Kleen Cc: Michael Kerrisk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/vm/page_migration | 29 ++--- arch/ia64/kernel/entry.S | 2 +- include/asm-ia64/unistd.h | 2 +- include/linux/migrate.h | 2 +- include/linux/syscalls.h | 5 + kernel/sys_ni.c | 1 + mm/mempolicy.c | 4 +- mm/migrate.c | 268 +++++++++++++++++++++++++++++++++++++++- 8 files changed, 288 insertions(+), 25 deletions(-) (limited to 'include') diff --git a/Documentation/vm/page_migration b/Documentation/vm/page_migration index 0a5d5fb18854..99f89aa10169 100644 --- a/Documentation/vm/page_migration +++ b/Documentation/vm/page_migration @@ -26,8 +26,13 @@ a process are located. See also the numa_maps manpage in the numactl package. Manual migration is useful if for example the scheduler has relocated a process to a processor on a distant node. A batch scheduler or an administrator may detect the situation and move the pages of the process -nearer to the new processor. At some point in the future we may have -some mechanism in the scheduler that will automatically move the pages. +nearer to the new processor. The kernel itself does only provide +manual page migration support. Automatic page migration may be implemented +through user space processes that move pages. A special function call +"move_pages" allows the moving of individual pages within a process. +A NUMA profiler may f.e. obtain a log showing frequent off node +accesses and may use the result to move pages to more advantageous +locations. Larger installations usually partition the system using cpusets into sections of nodes. Paul Jackson has equipped cpusets with the ability to @@ -62,22 +67,14 @@ A. In kernel use of migrate_pages() It also prevents the swapper or other scans to encounter the page. -2. Generate a list of newly allocates pages. These pages will contain the - contents of the pages from the first list after page migration is - complete. +2. We need to have a function of type new_page_t that can be + passed to migrate_pages(). This function should figure out + how to allocate the correct new page given the old page. 3. The migrate_pages() function is called which attempts - to do the migration. It returns the moved pages in the - list specified as the third parameter and the failed - migrations in the fourth parameter. When the function - returns the first list will contain the pages that could still be retried. - -4. The leftover pages of various types are returned - to the LRU using putback_to_lru_pages() or otherwise - disposed of. The pages will still have the refcount as - increased by isolate_lru_pages() if putback_to_lru_pages() is not - used! The kernel may want to handle the various cases of failures in - different ways. + to do the migration. It will call the function to allocate + the new page for each page that is considered for + moving. B. How migrate_pages() works ---------------------------- diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index bcb80ca5cf40..32c999f58d12 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S @@ -1584,7 +1584,7 @@ sys_call_table: data8 sys_keyctl data8 sys_ioprio_set data8 sys_ioprio_get // 1275 - data8 sys_ni_syscall + data8 sys_move_pages data8 sys_inotify_init data8 sys_inotify_add_watch data8 sys_inotify_rm_watch diff --git a/include/asm-ia64/unistd.h b/include/asm-ia64/unistd.h index 632f2eedf72c..bb0eb727dcd0 100644 --- a/include/asm-ia64/unistd.h +++ b/include/asm-ia64/unistd.h @@ -265,7 +265,7 @@ #define __NR_keyctl 1273 #define __NR_ioprio_set 1274 #define __NR_ioprio_get 1275 -/* 1276 is available for reuse (was briefly sys_set_zone_reclaim) */ +#define __NR_move_pages 1276 #define __NR_inotify_init 1277 #define __NR_inotify_add_watch 1278 #define __NR_inotify_rm_watch 1279 diff --git a/include/linux/migrate.h b/include/linux/migrate.h index 5b95d6568dc4..5dba23a1c0d0 100644 --- a/include/linux/migrate.h +++ b/include/linux/migrate.h @@ -3,7 +3,7 @@ #include -typedef struct page *new_page_t(struct page *, unsigned long private); +typedef struct page *new_page_t(struct page *, unsigned long private, int **); #ifdef CONFIG_MIGRATION extern int isolate_lru_page(struct page *p, struct list_head *pagelist); diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index bd67a4413df7..7e3f23490918 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -516,6 +516,11 @@ asmlinkage long sys_set_mempolicy(int mode, unsigned long __user *nmask, asmlinkage long sys_migrate_pages(pid_t pid, unsigned long maxnode, const unsigned long __user *from, const unsigned long __user *to); +asmlinkage long sys_move_pages(pid_t pid, unsigned long nr_pages, + const void __user * __user *pages, + const int __user *nodes, + int __user *status, + int flags); asmlinkage long sys_mbind(unsigned long start, unsigned long len, unsigned long mode, unsigned long __user *nmask, diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c index 5433195040f1..597229749dec 100644 --- a/kernel/sys_ni.c +++ b/kernel/sys_ni.c @@ -87,6 +87,7 @@ cond_syscall(sys_inotify_init); cond_syscall(sys_inotify_add_watch); cond_syscall(sys_inotify_rm_watch); cond_syscall(sys_migrate_pages); +cond_syscall(sys_move_pages); cond_syscall(sys_chown16); cond_syscall(sys_fchown16); cond_syscall(sys_getegid16); diff --git a/mm/mempolicy.c b/mm/mempolicy.c index f432642e9e66..05b84acf0bb3 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -588,7 +588,7 @@ static void migrate_page_add(struct page *page, struct list_head *pagelist, isolate_lru_page(page, pagelist); } -static struct page *new_node_page(struct page *page, unsigned long node) +static struct page *new_node_page(struct page *page, unsigned long node, int **x) { return alloc_pages_node(node, GFP_HIGHUSER, 0); } @@ -698,7 +698,7 @@ int do_migrate_pages(struct mm_struct *mm, } -static struct page *new_vma_page(struct page *page, unsigned long private) +static struct page *new_vma_page(struct page *page, unsigned long private, int **x) { struct vm_area_struct *vma = (struct vm_area_struct *)private; diff --git a/mm/migrate.c b/mm/migrate.c index 251a8d158257..033a12f4c949 100644 --- a/mm/migrate.c +++ b/mm/migrate.c @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include "internal.h" @@ -62,9 +64,8 @@ int isolate_lru_page(struct page *page, struct list_head *pagelist) } /* - * migrate_prep() needs to be called after we have compiled the list of pages - * to be migrated using isolate_lru_page() but before we begin a series of calls - * to migrate_pages(). + * migrate_prep() needs to be called before we start compiling a list of pages + * to be migrated using isolate_lru_page(). */ int migrate_prep(void) { @@ -588,7 +589,8 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private, struct page *page, int force) { int rc = 0; - struct page *newpage = get_new_page(page, private); + int *result = NULL; + struct page *newpage = get_new_page(page, private, &result); if (!newpage) return -ENOMEM; @@ -642,6 +644,12 @@ move_newpage: * then this will free the page. */ move_to_lru(newpage); + if (result) { + if (rc) + *result = rc; + else + *result = page_to_nid(newpage); + } return rc; } @@ -710,3 +718,255 @@ out: return nr_failed + retry; } +#ifdef CONFIG_NUMA +/* + * Move a list of individual pages + */ +struct page_to_node { + unsigned long addr; + struct page *page; + int node; + int status; +}; + +static struct page *new_page_node(struct page *p, unsigned long private, + int **result) +{ + struct page_to_node *pm = (struct page_to_node *)private; + + while (pm->node != MAX_NUMNODES && pm->page != p) + pm++; + + if (pm->node == MAX_NUMNODES) + return NULL; + + *result = &pm->status; + + return alloc_pages_node(pm->node, GFP_HIGHUSER, 0); +} + +/* + * Move a set of pages as indicated in the pm array. The addr + * field must be set to the virtual address of the page to be moved + * and the node number must contain a valid target node. + */ +static int do_move_pages(struct mm_struct *mm, struct page_to_node *pm, + int migrate_all) +{ + int err; + struct page_to_node *pp; + LIST_HEAD(pagelist); + + down_read(&mm->mmap_sem); + + /* + * Build a list of pages to migrate + */ + migrate_prep(); + for (pp = pm; pp->node != MAX_NUMNODES; pp++) { + struct vm_area_struct *vma; + struct page *page; + + /* + * A valid page pointer that will not match any of the + * pages that will be moved. + */ + pp->page = ZERO_PAGE(0); + + err = -EFAULT; + vma = find_vma(mm, pp->addr); + if (!vma) + goto set_status; + + page = follow_page(vma, pp->addr, FOLL_GET); + err = -ENOENT; + if (!page) + goto set_status; + + if (PageReserved(page)) /* Check for zero page */ + goto put_and_set; + + pp->page = page; + err = page_to_nid(page); + + if (err == pp->node) + /* + * Node already in the right place + */ + goto put_and_set; + + err = -EACCES; + if (page_mapcount(page) > 1 && + !migrate_all) + goto put_and_set; + + err = isolate_lru_page(page, &pagelist); +put_and_set: + /* + * Either remove the duplicate refcount from + * isolate_lru_page() or drop the page ref if it was + * not isolated. + */ + put_page(page); +set_status: + pp->status = err; + } + + if (!list_empty(&pagelist)) + err = migrate_pages(&pagelist, new_page_node, + (unsigned long)pm); + else + err = -ENOENT; + + up_read(&mm->mmap_sem); + return err; +} + +/* + * Determine the nodes of a list of pages. The addr in the pm array + * must have been set to the virtual address of which we want to determine + * the node number. + */ +static int do_pages_stat(struct mm_struct *mm, struct page_to_node *pm) +{ + down_read(&mm->mmap_sem); + + for ( ; pm->node != MAX_NUMNODES; pm++) { + struct vm_area_struct *vma; + struct page *page; + int err; + + err = -EFAULT; + vma = find_vma(mm, pm->addr); + if (!vma) + goto set_status; + + page = follow_page(vma, pm->addr, 0); + err = -ENOENT; + /* Use PageReserved to check for zero page */ + if (!page || PageReserved(page)) + goto set_status; + + err = page_to_nid(page); +set_status: + pm->status = err; + } + + up_read(&mm->mmap_sem); + return 0; +} + +/* + * Move a list of pages in the address space of the currently executing + * process. + */ +asmlinkage long sys_move_pages(pid_t pid, unsigned long nr_pages, + const void __user * __user *pages, + const int __user *nodes, + int __user *status, int flags) +{ + int err = 0; + int i; + struct task_struct *task; + nodemask_t task_nodes; + struct mm_struct *mm; + struct page_to_node *pm = NULL; + + /* Check flags */ + if (flags & ~(MPOL_MF_MOVE|MPOL_MF_MOVE_ALL)) + return -EINVAL; + + if ((flags & MPOL_MF_MOVE_ALL) && !capable(CAP_SYS_NICE)) + return -EPERM; + + /* Find the mm_struct */ + read_lock(&tasklist_lock); + task = pid ? find_task_by_pid(pid) : current; + if (!task) { + read_unlock(&tasklist_lock); + return -ESRCH; + } + mm = get_task_mm(task); + read_unlock(&tasklist_lock); + + if (!mm) + return -EINVAL; + + /* + * Check if this process has the right to modify the specified + * process. The right exists if the process has administrative + * capabilities, superuser privileges or the same + * userid as the target process. + */ + if ((current->euid != task->suid) && (current->euid != task->uid) && + (current->uid != task->suid) && (current->uid != task->uid) && + !capable(CAP_SYS_NICE)) { + err = -EPERM; + goto out2; + } + + task_nodes = cpuset_mems_allowed(task); + + /* Limit nr_pages so that the multiplication may not overflow */ + if (nr_pages >= ULONG_MAX / sizeof(struct page_to_node) - 1) { + err = -E2BIG; + goto out2; + } + + pm = vmalloc((nr_pages + 1) * sizeof(struct page_to_node)); + if (!pm) { + err = -ENOMEM; + goto out2; + } + + /* + * Get parameters from user space and initialize the pm + * array. Return various errors if the user did something wrong. + */ + for (i = 0; i < nr_pages; i++) { + const void *p; + + err = -EFAULT; + if (get_user(p, pages + i)) + goto out; + + pm[i].addr = (unsigned long)p; + if (nodes) { + int node; + + if (get_user(node, nodes + i)) + goto out; + + err = -ENODEV; + if (!node_online(node)) + goto out; + + err = -EACCES; + if (!node_isset(node, task_nodes)) + goto out; + + pm[i].node = node; + } + } + /* End marker */ + pm[nr_pages].node = MAX_NUMNODES; + + if (nodes) + err = do_move_pages(mm, pm, flags & MPOL_MF_MOVE_ALL); + else + err = do_pages_stat(mm, pm); + + if (err >= 0) + /* Return status information */ + for (i = 0; i < nr_pages; i++) + if (put_user(pm[i].status, status + i)) + err = -EFAULT; + +out: + vfree(pm); +out2: + mmput(mm); + return err; +} +#endif + -- cgit v1.2.3 From b63d64a324056cf3c2f7a1a1fe8134100edbb058 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Fri, 23 Jun 2006 02:03:56 -0700 Subject: [PATCH] sys_move_pages: x86_64 support sys_move_pages support for x86_64 Signed-off-by: Christoph Lameter Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-x86_64/unistd.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/asm-x86_64/unistd.h b/include/asm-x86_64/unistd.h index 0aff22bdbb21..94387c915e53 100644 --- a/include/asm-x86_64/unistd.h +++ b/include/asm-x86_64/unistd.h @@ -617,10 +617,12 @@ __SYSCALL(__NR_tee, sys_tee) __SYSCALL(__NR_sync_file_range, sys_sync_file_range) #define __NR_vmsplice 278 __SYSCALL(__NR_vmsplice, sys_vmsplice) +#define __NR_move_pages 279 +__SYSCALL(__NR_move_pages, sys_move_pages) #ifdef __KERNEL__ -#define __NR_syscall_max __NR_vmsplice +#define __NR_syscall_max __NR_move_pages #ifndef __NO_STUBS -- cgit v1.2.3 From 1b2db9fb7adc4d67d9ce7d16ce79c41ee84730fe Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Fri, 23 Jun 2006 02:03:56 -0700 Subject: [PATCH] sys_move_pages: 32bit support (i386, x86_64) sys_move_pages() support for 32bit (i386 plus x86_64 compat layer) Add support for move_pages() on i386 and also add the compat functions necessary to run 32 bit binaries on x86_64. Add compat_sys_move_pages to the x86_64 32bit binary layer. Note that it is not up to date so I added the missing pieces. Not sure if this is done the right way. [akpm@osdl.org: compile fix] Signed-off-by: Christoph Lameter Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/syscall_table.S | 1 + arch/x86_64/ia32/ia32entry.S | 1 + include/asm-i386/unistd.h | 3 ++- include/linux/syscalls.h | 5 +++++ kernel/compat.c | 23 +++++++++++++++++++++++ kernel/sys_ni.c | 1 + 6 files changed, 33 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/arch/i386/kernel/syscall_table.S b/arch/i386/kernel/syscall_table.S index af56987f69b0..dd63d4775398 100644 --- a/arch/i386/kernel/syscall_table.S +++ b/arch/i386/kernel/syscall_table.S @@ -316,3 +316,4 @@ ENTRY(sys_call_table) .long sys_sync_file_range .long sys_tee /* 315 */ .long sys_vmsplice + .long sys_move_pages diff --git a/arch/x86_64/ia32/ia32entry.S b/arch/x86_64/ia32/ia32entry.S index 5a92fed2d1d5..4ec594ab1a98 100644 --- a/arch/x86_64/ia32/ia32entry.S +++ b/arch/x86_64/ia32/ia32entry.S @@ -696,4 +696,5 @@ ia32_sys_call_table: .quad sys_sync_file_range .quad sys_tee .quad compat_sys_vmsplice + .quad compat_sys_move_pages ia32_syscall_end: diff --git a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h index de2ccc149e34..fc1c8ddae149 100644 --- a/include/asm-i386/unistd.h +++ b/include/asm-i386/unistd.h @@ -322,10 +322,11 @@ #define __NR_sync_file_range 314 #define __NR_tee 315 #define __NR_vmsplice 316 +#define __NR_move_pages 317 #ifdef __KERNEL__ -#define NR_syscalls 317 +#define NR_syscalls 318 /* * user-visible error numbers are in the range -1 - -128: see diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 7e3f23490918..e42738c69166 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -521,6 +521,11 @@ asmlinkage long sys_move_pages(pid_t pid, unsigned long nr_pages, const int __user *nodes, int __user *status, int flags); +asmlinkage long compat_sys_move_pages(pid_t pid, unsigned long nr_page, + void __user *pages, + const int __user *nodes, + int __user *status, + int flags); asmlinkage long sys_mbind(unsigned long start, unsigned long len, unsigned long mode, unsigned long __user *nmask, diff --git a/kernel/compat.c b/kernel/compat.c index c1601a84f8d8..ccea93e28954 100644 --- a/kernel/compat.c +++ b/kernel/compat.c @@ -21,6 +21,7 @@ #include #include #include +#include #include @@ -934,3 +935,25 @@ asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp) return ret; } + +#ifdef CONFIG_NUMA +asmlinkage long compat_sys_move_pages(pid_t pid, unsigned long nr_pages, + void __user *pages32, + const int __user *nodes, + int __user *status, + int flags) +{ + const void __user * __user *pages; + int i; + + pages = compat_alloc_user_space(nr_pages * sizeof(void *)); + for (i = 0; i < nr_pages; i++) { + compat_uptr_t p; + + if (get_user(p, (compat_uptr_t *)(pages32 + i)) || + put_user(compat_ptr(p), pages + i)) + return -EFAULT; + } + return sys_move_pages(pid, nr_pages, pages, nodes, status, flags); +} +#endif diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c index 597229749dec..6991bece67e8 100644 --- a/kernel/sys_ni.c +++ b/kernel/sys_ni.c @@ -133,3 +133,4 @@ cond_syscall(sys_mincore); cond_syscall(sys_madvise); cond_syscall(sys_mremap); cond_syscall(sys_remap_file_pages); +cond_syscall(compat_sys_move_pages); -- cgit v1.2.3 From 9216dfad4fc97ab639ef0885efc713f3d7a20d5b Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Fri, 23 Jun 2006 02:03:57 -0700 Subject: [PATCH] move_pages: fix 32 -> 64 bit compat function The definition of the third parameter is a pointer to an array of virtual addresses which give us some trouble. The existing code calculated the wrong address in the array since I used void to avoid having to specify a type. I now use the correct type "compat_uptr_t __user *" in the definition of the function in kernel/compat.c. However, I used __u32 in syscalls.h. Would have to include compat.h there in order to provide the same definition which would generate an ugly include situation. On both ia64 and x86_64 compat_uptr_t is u32. So this works although parameter declarations differ. Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/syscalls.h | 2 +- kernel/compat.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index e42738c69166..33785b79d548 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -522,7 +522,7 @@ asmlinkage long sys_move_pages(pid_t pid, unsigned long nr_pages, int __user *status, int flags); asmlinkage long compat_sys_move_pages(pid_t pid, unsigned long nr_page, - void __user *pages, + __u32 __user *pages, const int __user *nodes, int __user *status, int flags); diff --git a/kernel/compat.c b/kernel/compat.c index ccea93e28954..2f672332430f 100644 --- a/kernel/compat.c +++ b/kernel/compat.c @@ -938,7 +938,7 @@ asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp) #ifdef CONFIG_NUMA asmlinkage long compat_sys_move_pages(pid_t pid, unsigned long nr_pages, - void __user *pages32, + compat_uptr_t __user *pages32, const int __user *nodes, int __user *status, int flags) @@ -950,7 +950,7 @@ asmlinkage long compat_sys_move_pages(pid_t pid, unsigned long nr_pages, for (i = 0; i < nr_pages; i++) { compat_uptr_t p; - if (get_user(p, (compat_uptr_t *)(pages32 + i)) || + if (get_user(p, pages32 + i) || put_user(compat_ptr(p), pages + i)) return -EFAULT; } -- cgit v1.2.3 From 03e68060636e05989ea94bcb671ab633948f328c Mon Sep 17 00:00:00 2001 From: James Morris Date: Fri, 23 Jun 2006 02:03:58 -0700 Subject: [PATCH] lsm: add task_setioprio hook Implement an LSM hook for setting a task's IO priority, similar to the hook for setting a tasks's nice value. A previous version of this LSM hook was included in an older version of multiadm by Jan Engelhardt, although I don't recall it being submitted upstream. Also included is the corresponding SELinux hook, which re-uses the setsched permission in the proccess class. Signed-off-by: James Morris Acked-by: Stephen Smalley Cc: Jan Engelhardt Cc: Chris Wright Cc: Jens Axboe Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ioprio.c | 6 ++++++ include/linux/security.h | 16 ++++++++++++++++ security/dummy.c | 6 ++++++ security/selinux/hooks.c | 6 ++++++ 4 files changed, 34 insertions(+) (limited to 'include') diff --git a/fs/ioprio.c b/fs/ioprio.c index ca77008146c0..7fa76ed53c10 100644 --- a/fs/ioprio.c +++ b/fs/ioprio.c @@ -24,15 +24,21 @@ #include #include #include +#include static int set_task_ioprio(struct task_struct *task, int ioprio) { + int err; struct io_context *ioc; if (task->uid != current->euid && task->uid != current->uid && !capable(CAP_SYS_NICE)) return -EPERM; + err = security_task_setioprio(task, ioprio); + if (err) + return err; + task_lock(task); task->ioprio = ioprio; diff --git a/include/linux/security.h b/include/linux/security.h index 383c320fc834..65b32a0c6207 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -577,6 +577,11 @@ struct swap_info_struct; * @p contains the task_struct of process. * @nice contains the new nice value. * Return 0 if permission is granted. + * @task_setioprio + * Check permission before setting the ioprio value of @p to @ioprio. + * @p contains the task_struct of process. + * @ioprio contains the new ioprio value + * Return 0 if permission is granted. * @task_setrlimit: * Check permission before setting the resource limits of the current * process for @resource to @new_rlim. The old resource limit values can @@ -1210,6 +1215,7 @@ struct security_operations { int (*task_getsid) (struct task_struct * p); int (*task_setgroups) (struct group_info *group_info); int (*task_setnice) (struct task_struct * p, int nice); + int (*task_setioprio) (struct task_struct * p, int ioprio); int (*task_setrlimit) (unsigned int resource, struct rlimit * new_rlim); int (*task_setscheduler) (struct task_struct * p, int policy, struct sched_param * lp); @@ -1836,6 +1842,11 @@ static inline int security_task_setnice (struct task_struct *p, int nice) return security_ops->task_setnice (p, nice); } +static inline int security_task_setioprio (struct task_struct *p, int ioprio) +{ + return security_ops->task_setioprio (p, ioprio); +} + static inline int security_task_setrlimit (unsigned int resource, struct rlimit *new_rlim) { @@ -2478,6 +2489,11 @@ static inline int security_task_setnice (struct task_struct *p, int nice) return 0; } +static inline int security_task_setioprio (struct task_struct *p, int ioprio) +{ + return 0; +} + static inline int security_task_setrlimit (unsigned int resource, struct rlimit *new_rlim) { diff --git a/security/dummy.c b/security/dummy.c index c98d553984ec..879a98523b1b 100644 --- a/security/dummy.c +++ b/security/dummy.c @@ -516,6 +516,11 @@ static int dummy_task_setnice (struct task_struct *p, int nice) return 0; } +static int dummy_task_setioprio (struct task_struct *p, int ioprio) +{ + return 0; +} + static int dummy_task_setrlimit (unsigned int resource, struct rlimit *new_rlim) { return 0; @@ -972,6 +977,7 @@ void security_fixup_ops (struct security_operations *ops) set_to_dummy_if_null(ops, task_getsid); set_to_dummy_if_null(ops, task_setgroups); set_to_dummy_if_null(ops, task_setnice); + set_to_dummy_if_null(ops, task_setioprio); set_to_dummy_if_null(ops, task_setrlimit); set_to_dummy_if_null(ops, task_setscheduler); set_to_dummy_if_null(ops, task_getscheduler); diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 093efba4d9b6..9dcf298921d4 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2645,6 +2645,11 @@ static int selinux_task_setnice(struct task_struct *p, int nice) return task_has_perm(current,p, PROCESS__SETSCHED); } +static int selinux_task_setioprio(struct task_struct *p, int ioprio) +{ + return task_has_perm(current, p, PROCESS__SETSCHED); +} + static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim) { struct rlimit *old_rlim = current->signal->rlim + resource; @@ -4383,6 +4388,7 @@ static struct security_operations selinux_ops = { .task_getsid = selinux_task_getsid, .task_setgroups = selinux_task_setgroups, .task_setnice = selinux_task_setnice, + .task_setioprio = selinux_task_setioprio, .task_setrlimit = selinux_task_setrlimit, .task_setscheduler = selinux_task_setscheduler, .task_getscheduler = selinux_task_getscheduler, -- cgit v1.2.3 From 35601547baf92d984b6e59cf3583649da04baea5 Mon Sep 17 00:00:00 2001 From: David Quigley Date: Fri, 23 Jun 2006 02:04:01 -0700 Subject: [PATCH] SELinux: add task_movememory hook This patch adds new security hook, task_movememory, to be called when memory owened by a task is to be moved (e.g. when migrating pages to a this hook is identical to the setscheduler implementation, but a separate hook introduced to allow this check to be specialized in the future if necessary. Since the last posting, the hook has been renamed following feedback from Christoph Lameter. Signed-off-by: David Quigley Acked-by: Stephen Smalley Signed-off-by: James Morris Cc: Christoph Lameter Cc: Andi Kleen Acked-by: Chris Wright Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/security.h | 15 +++++++++++++++ security/dummy.c | 6 ++++++ security/selinux/hooks.c | 6 ++++++ 3 files changed, 27 insertions(+) (limited to 'include') diff --git a/include/linux/security.h b/include/linux/security.h index 65b32a0c6207..d2c17bd91a29 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -601,6 +601,10 @@ struct swap_info_struct; * @p. * @p contains the task_struct for process. * Return 0 if permission is granted. + * @task_movememory + * Check permission before moving memory owned by process @p. + * @p contains the task_struct for process. + * Return 0 if permission is granted. * @task_kill: * Check permission before sending signal @sig to @p. @info can be NULL, * the constant 1, or a pointer to a siginfo structure. If @info is 1 or @@ -1220,6 +1224,7 @@ struct security_operations { int (*task_setscheduler) (struct task_struct * p, int policy, struct sched_param * lp); int (*task_getscheduler) (struct task_struct * p); + int (*task_movememory) (struct task_struct * p); int (*task_kill) (struct task_struct * p, struct siginfo * info, int sig); int (*task_wait) (struct task_struct * p); @@ -1865,6 +1870,11 @@ static inline int security_task_getscheduler (struct task_struct *p) return security_ops->task_getscheduler (p); } +static inline int security_task_movememory (struct task_struct *p) +{ + return security_ops->task_movememory (p); +} + static inline int security_task_kill (struct task_struct *p, struct siginfo *info, int sig) { @@ -2512,6 +2522,11 @@ static inline int security_task_getscheduler (struct task_struct *p) return 0; } +static inline int security_task_movememory (struct task_struct *p) +{ + return 0; +} + static inline int security_task_kill (struct task_struct *p, struct siginfo *info, int sig) { diff --git a/security/dummy.c b/security/dummy.c index 879a98523b1b..c3c5493581e2 100644 --- a/security/dummy.c +++ b/security/dummy.c @@ -537,6 +537,11 @@ static int dummy_task_getscheduler (struct task_struct *p) return 0; } +static int dummy_task_movememory (struct task_struct *p) +{ + return 0; +} + static int dummy_task_wait (struct task_struct *p) { return 0; @@ -981,6 +986,7 @@ void security_fixup_ops (struct security_operations *ops) set_to_dummy_if_null(ops, task_setrlimit); set_to_dummy_if_null(ops, task_setscheduler); set_to_dummy_if_null(ops, task_getscheduler); + set_to_dummy_if_null(ops, task_movememory); set_to_dummy_if_null(ops, task_wait); set_to_dummy_if_null(ops, task_kill); set_to_dummy_if_null(ops, task_prctl); diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 9dcf298921d4..79c16e31c884 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2679,6 +2679,11 @@ static int selinux_task_getscheduler(struct task_struct *p) return task_has_perm(current, p, PROCESS__GETSCHED); } +static int selinux_task_movememory(struct task_struct *p) +{ + return task_has_perm(current, p, PROCESS__SETSCHED); +} + static int selinux_task_kill(struct task_struct *p, struct siginfo *info, int sig) { u32 perm; @@ -4392,6 +4397,7 @@ static struct security_operations selinux_ops = { .task_setrlimit = selinux_task_setrlimit, .task_setscheduler = selinux_task_setscheduler, .task_getscheduler = selinux_task_getscheduler, + .task_movememory = selinux_task_movememory, .task_kill = selinux_task_kill, .task_wait = selinux_task_wait, .task_prctl = selinux_task_prctl, -- cgit v1.2.3 From a8a77573c9e5345bcf6a963858745cd83c923f44 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 23 Jun 2006 02:04:03 -0700 Subject: [PATCH] frv: __user infrastructure Add general annotations to the FRV arch for sparse. Signed-off-by: Al Viro Signed-off-by: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/frv/kernel/uaccess.c | 6 ++--- include/asm-frv/uaccess.h | 64 +++++++++++++++++++++++++++-------------------- 2 files changed, 40 insertions(+), 30 deletions(-) (limited to 'include') diff --git a/arch/frv/kernel/uaccess.c b/arch/frv/kernel/uaccess.c index 9b751c0f0e84..9fb771a20df3 100644 --- a/arch/frv/kernel/uaccess.c +++ b/arch/frv/kernel/uaccess.c @@ -17,7 +17,7 @@ /* * copy a null terminated string from userspace */ -long strncpy_from_user(char *dst, const char *src, long count) +long strncpy_from_user(char *dst, const char __user *src, long count) { unsigned long max; char *p, ch; @@ -70,9 +70,9 @@ EXPORT_SYMBOL(strncpy_from_user); * * Return 0 on exception, a value greater than N if too long */ -long strnlen_user(const char *src, long count) +long strnlen_user(const char __user *src, long count) { - const char *p; + const char __user *p; long err = 0; char ch; diff --git a/include/asm-frv/uaccess.h b/include/asm-frv/uaccess.h index a1d140438863..3d90e1018ee2 100644 --- a/include/asm-frv/uaccess.h +++ b/include/asm-frv/uaccess.h @@ -22,7 +22,7 @@ #define HAVE_ARCH_UNMAPPED_AREA /* we decide where to put mmaps */ -#define __ptr(x) ((unsigned long *)(x)) +#define __ptr(x) ((unsigned long __force *)(x)) #define VERIFY_READ 0 #define VERIFY_WRITE 1 @@ -64,7 +64,7 @@ static inline int ___range_ok(unsigned long addr, unsigned long size) #define __range_ok(addr,size) ___range_ok((unsigned long) (addr), (unsigned long) (size)) -#define access_ok(type,addr,size) (__range_ok((addr), (size)) == 0) +#define access_ok(type,addr,size) (__range_ok((void __user *)(addr), (size)) == 0) #define __access_ok(addr,size) (__range_ok((addr), (size)) == 0) /* @@ -97,6 +97,7 @@ extern unsigned long search_exception_table(unsigned long); int __pu_err = 0; \ \ typeof(*(ptr)) __pu_val = (x); \ + __chk_user_ptr(ptr); \ \ switch (sizeof (*(ptr))) { \ case 1: \ @@ -120,7 +121,7 @@ extern unsigned long search_exception_table(unsigned long); #define put_user(x, ptr) \ ({ \ - typeof(&*ptr) _p = (ptr); \ + typeof(*(ptr)) __user *_p = (ptr); \ int _e; \ \ _e = __range_ok(_p, sizeof(*_p)); \ @@ -175,33 +176,44 @@ do { \ */ #define __get_user(x, ptr) \ ({ \ - typeof(*(ptr)) __gu_val = 0; \ int __gu_err = 0; \ + __chk_user_ptr(ptr); \ \ switch (sizeof(*(ptr))) { \ - case 1: \ - __get_user_asm(__gu_err, *(u8*)&__gu_val, ptr, "ub", "=r"); \ + case 1: { \ + unsigned char __gu_val; \ + __get_user_asm(__gu_err, __gu_val, ptr, "ub", "=r"); \ + (x) = *(__force __typeof__(*(ptr)) *) &__gu_val; \ break; \ - case 2: \ - __get_user_asm(__gu_err, *(u16*)&__gu_val, ptr, "uh", "=r"); \ + } \ + case 2: { \ + unsigned short __gu_val; \ + __get_user_asm(__gu_err, __gu_val, ptr, "uh", "=r"); \ + (x) = *(__force __typeof__(*(ptr)) *) &__gu_val; \ break; \ - case 4: \ - __get_user_asm(__gu_err, *(u32*)&__gu_val, ptr, "", "=r"); \ + } \ + case 4: { \ + unsigned int __gu_val; \ + __get_user_asm(__gu_err, __gu_val, ptr, "", "=r"); \ + (x) = *(__force __typeof__(*(ptr)) *) &__gu_val; \ break; \ - case 8: \ - __get_user_asm(__gu_err, *(u64*)&__gu_val, ptr, "d", "=e"); \ + } \ + case 8: { \ + unsigned long long __gu_val; \ + __get_user_asm(__gu_err, __gu_val, ptr, "d", "=e"); \ + (x) = *(__force __typeof__(*(ptr)) *) &__gu_val; \ break; \ + } \ default: \ __gu_err = __get_user_bad(); \ break; \ } \ - (x) = __gu_val; \ __gu_err; \ }) #define get_user(x, ptr) \ ({ \ - typeof(&*ptr) _p = (ptr); \ + const typeof(*(ptr)) __user *_p = (ptr);\ int _e; \ \ _e = __range_ok(_p, sizeof(*_p)); \ @@ -248,19 +260,20 @@ do { \ /* * */ +#define ____force(x) (__force void *)(void __user *)(x) #ifdef CONFIG_MMU extern long __memset_user(void *dst, unsigned long count); extern long __memcpy_user(void *dst, const void *src, unsigned long count); -#define clear_user(dst,count) __memset_user((dst), (count)) -#define __copy_from_user_inatomic(to, from, n) __memcpy_user((to), (from), (n)) -#define __copy_to_user_inatomic(to, from, n) __memcpy_user((to), (from), (n)) +#define clear_user(dst,count) __memset_user(____force(dst), (count)) +#define __copy_from_user_inatomic(to, from, n) __memcpy_user((to), ____force(from), (n)) +#define __copy_to_user_inatomic(to, from, n) __memcpy_user(____force(to), (from), (n)) #else -#define clear_user(dst,count) (memset((dst), 0, (count)), 0) -#define __copy_from_user_inatomic(to, from, n) (memcpy((to), (from), (n)), 0) -#define __copy_to_user_inatomic(to, from, n) (memcpy((to), (from), (n)), 0) +#define clear_user(dst,count) (memset(____force(dst), 0, (count)), 0) +#define __copy_from_user_inatomic(to, from, n) (memcpy((to), ____force(from), (n)), 0) +#define __copy_to_user_inatomic(to, from, n) (memcpy(____force(to), (from), (n)), 0) #endif @@ -278,7 +291,7 @@ __copy_from_user(void *to, const void __user *from, unsigned long n) return __copy_from_user_inatomic(to, from, n); } -static inline long copy_from_user(void *to, const void *from, unsigned long n) +static inline long copy_from_user(void *to, const void __user *from, unsigned long n) { unsigned long ret = n; @@ -291,16 +304,13 @@ static inline long copy_from_user(void *to, const void *from, unsigned long n) return ret; } -static inline long copy_to_user(void *to, const void *from, unsigned long n) +static inline long copy_to_user(void __user *to, const void *from, unsigned long n) { return likely(__access_ok(to, n)) ? __copy_to_user(to, from, n) : n; } -#define copy_to_user_ret(to,from,n,retval) ({ if (copy_to_user(to,from,n)) return retval; }) -#define copy_from_user_ret(to,from,n,retval) ({ if (copy_from_user(to,from,n)) return retval; }) - -extern long strncpy_from_user(char *dst, const char *src, long count); -extern long strnlen_user(const char *src, long count); +extern long strncpy_from_user(char *dst, const char __user *src, long count); +extern long strnlen_user(const char __user *src, long count); #define strlen_user(str) strnlen_user(str, 32767) -- cgit v1.2.3 From 3f4cd389c3564caf1eec70957fcbd9d88c995d45 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 23 Jun 2006 02:04:03 -0700 Subject: [PATCH] frv: basic __iomem annotations Add annotations to the FRV I/O handling functions for sparse. Signed-off-by: Al Viro Signed-off-by: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/frv/mm/kmap.c | 6 +++--- include/asm-frv/io.h | 38 +++++++++++++++++++------------------- include/asm-frv/mb-regs.h | 27 +++++++++++++++++++-------- 3 files changed, 41 insertions(+), 30 deletions(-) (limited to 'include') diff --git a/arch/frv/mm/kmap.c b/arch/frv/mm/kmap.c index c54f18e65ea6..40b62c5c2951 100644 --- a/arch/frv/mm/kmap.c +++ b/arch/frv/mm/kmap.c @@ -31,15 +31,15 @@ * Map some physical address range into the kernel address space. */ -void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag) +void __iomem *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag) { - return (void *)physaddr; + return (void __iomem *)physaddr; } /* * Unmap a ioremap()ed region again */ -void iounmap(void *addr) +void iounmap(void volatile __iomem *addr) { } diff --git a/include/asm-frv/io.h b/include/asm-frv/io.h index b56eba59e3cd..f49398a82977 100644 --- a/include/asm-frv/io.h +++ b/include/asm-frv/io.h @@ -40,13 +40,13 @@ static inline unsigned long _swapl(unsigned long v) //#define __iormb() asm volatile("membar") //#define __iowmb() asm volatile("membar") -#define __raw_readb(addr) __builtin_read8((void *) (addr)) -#define __raw_readw(addr) __builtin_read16((void *) (addr)) -#define __raw_readl(addr) __builtin_read32((void *) (addr)) +#define __raw_readb __builtin_read8 +#define __raw_readw __builtin_read16 +#define __raw_readl __builtin_read32 -#define __raw_writeb(datum, addr) __builtin_write8((void *) (addr), datum) -#define __raw_writew(datum, addr) __builtin_write16((void *) (addr), datum) -#define __raw_writel(datum, addr) __builtin_write32((void *) (addr), datum) +#define __raw_writeb(datum, addr) __builtin_write8(addr, datum) +#define __raw_writew(datum, addr) __builtin_write16(addr, datum) +#define __raw_writel(datum, addr) __builtin_write32(addr, datum) static inline void io_outsb(unsigned int addr, const void *buf, int len) { @@ -128,12 +128,12 @@ static inline void memcpy_toio(volatile void __iomem *dst, const void *src, int static inline uint8_t inb(unsigned long addr) { - return __builtin_read8((void *)addr); + return __builtin_read8((void __iomem *)addr); } static inline uint16_t inw(unsigned long addr) { - uint16_t ret = __builtin_read16((void *)addr); + uint16_t ret = __builtin_read16((void __iomem *)addr); if (__is_PCI_IO(addr)) ret = _swapw(ret); @@ -143,7 +143,7 @@ static inline uint16_t inw(unsigned long addr) static inline uint32_t inl(unsigned long addr) { - uint32_t ret = __builtin_read32((void *)addr); + uint32_t ret = __builtin_read32((void __iomem *)addr); if (__is_PCI_IO(addr)) ret = _swapl(ret); @@ -153,21 +153,21 @@ static inline uint32_t inl(unsigned long addr) static inline void outb(uint8_t datum, unsigned long addr) { - __builtin_write8((void *)addr, datum); + __builtin_write8((void __iomem *)addr, datum); } static inline void outw(uint16_t datum, unsigned long addr) { if (__is_PCI_IO(addr)) datum = _swapw(datum); - __builtin_write16((void *)addr, datum); + __builtin_write16((void __iomem *)addr, datum); } static inline void outl(uint32_t datum, unsigned long addr) { if (__is_PCI_IO(addr)) datum = _swapl(datum); - __builtin_write32((void *)addr, datum); + __builtin_write32((void __iomem *)addr, datum); } #define inb_p(addr) inb(addr) @@ -189,12 +189,12 @@ static inline void outl(uint32_t datum, unsigned long addr) static inline uint8_t readb(const volatile void __iomem *addr) { - return __builtin_read8((volatile uint8_t __force *) addr); + return __builtin_read8((__force void volatile __iomem *) addr); } static inline uint16_t readw(const volatile void __iomem *addr) { - uint16_t ret = __builtin_read16((volatile uint16_t __force *)addr); + uint16_t ret = __builtin_read16((__force void volatile __iomem *)addr); if (__is_PCI_MEM(addr)) ret = _swapw(ret); @@ -203,7 +203,7 @@ static inline uint16_t readw(const volatile void __iomem *addr) static inline uint32_t readl(const volatile void __iomem *addr) { - uint32_t ret = __builtin_read32((volatile uint32_t __force *)addr); + uint32_t ret = __builtin_read32((__force void volatile __iomem *)addr); if (__is_PCI_MEM(addr)) ret = _swapl(ret); @@ -217,7 +217,7 @@ static inline uint32_t readl(const volatile void __iomem *addr) static inline void writeb(uint8_t datum, volatile void __iomem *addr) { - __builtin_write8((volatile uint8_t __force *) addr, datum); + __builtin_write8(addr, datum); if (__is_PCI_MEM(addr)) __flush_PCI_writes(); } @@ -227,7 +227,7 @@ static inline void writew(uint16_t datum, volatile void __iomem *addr) if (__is_PCI_MEM(addr)) datum = _swapw(datum); - __builtin_write16((volatile uint16_t __force *) addr, datum); + __builtin_write16(addr, datum); if (__is_PCI_MEM(addr)) __flush_PCI_writes(); } @@ -237,7 +237,7 @@ static inline void writel(uint32_t datum, volatile void __iomem *addr) if (__is_PCI_MEM(addr)) datum = _swapl(datum); - __builtin_write32((volatile uint32_t __force *) addr, datum); + __builtin_write32(addr, datum); if (__is_PCI_MEM(addr)) __flush_PCI_writes(); } @@ -271,7 +271,7 @@ static inline void __iomem *ioremap_fullcache(unsigned long physaddr, unsigned l return __ioremap(physaddr, size, IOMAP_FULL_CACHING); } -extern void iounmap(void __iomem *addr); +extern void iounmap(void volatile __iomem *addr); static inline void __iomem *ioport_map(unsigned long port, unsigned int nr) { diff --git a/include/asm-frv/mb-regs.h b/include/asm-frv/mb-regs.h index 93fa732fb0cd..219e5f926f18 100644 --- a/include/asm-frv/mb-regs.h +++ b/include/asm-frv/mb-regs.h @@ -16,6 +16,17 @@ #include #include +#ifndef __ASSEMBLY__ +/* gcc builtins, annotated */ + +unsigned long __builtin_read8(volatile void __iomem *); +unsigned long __builtin_read16(volatile void __iomem *); +unsigned long __builtin_read32(volatile void __iomem *); +void __builtin_write8(volatile void __iomem *, unsigned char); +void __builtin_write16(volatile void __iomem *, unsigned short); +void __builtin_write32(volatile void __iomem *, unsigned long); +#endif + #define __region_IO KERNEL_IO_START /* the region from 0xe0000000 to 0xffffffff has suitable * protection laid over the top for use in memory-mapped * I/O @@ -59,7 +70,7 @@ #define __region_PCI_MEM (__region_CS2 + 0x08000000UL) #define __flush_PCI_writes() \ do { \ - __builtin_write8((volatile void *) __region_PCI_MEM, 0); \ + __builtin_write8((volatile void __iomem *) __region_PCI_MEM, 0); \ } while(0) #define __is_PCI_IO(addr) \ @@ -83,15 +94,15 @@ extern int __nongprelbss mb93090_mb00_detected; #define __set_LEDS(X) \ do { \ if (mb93090_mb00_detected) \ - __builtin_write32((void *) __addr_LEDS(), ~(X)); \ + __builtin_write32((void __iomem *) __addr_LEDS(), ~(X)); \ } while (0) #else #define __set_LEDS(X) #endif #define __addr_LCD() (__region_CS2 + 0x01200008UL) -#define __get_LCD(B) __builtin_read32((volatile void *) (B)) -#define __set_LCD(B,X) __builtin_write32((volatile void *) (B), (X)) +#define __get_LCD(B) __builtin_read32((volatile void __iomem *) (B)) +#define __set_LCD(B,X) __builtin_write32((volatile void __iomem *) (B), (X)) #define LCD_D 0x000000ff /* LCD data bus */ #define LCD_RW 0x00000100 /* LCD R/W signal */ @@ -161,11 +172,11 @@ do { \ #define __get_CLKIN() 66000000UL #define __addr_LEDS() (__region_CS2 + 0x00000023UL) -#define __set_LEDS(X) __builtin_write8((volatile void *) __addr_LEDS(), (X)) +#define __set_LEDS(X) __builtin_write8((volatile void __iomem *) __addr_LEDS(), (X)) #define __addr_FPGATR() (__region_CS2 + 0x00000030UL) -#define __set_FPGATR(X) __builtin_write32((volatile void *) __addr_FPGATR(), (X)) -#define __get_FPGATR() __builtin_read32((volatile void *) __addr_FPGATR()) +#define __set_FPGATR(X) __builtin_write32((volatile void __iomem *) __addr_FPGATR(), (X)) +#define __get_FPGATR() __builtin_read32((volatile void __iomem *) __addr_FPGATR()) #define MB93093_FPGA_FPGATR_AUDIO_CLK 0x00000003 @@ -180,7 +191,7 @@ do { \ #define MB93093_FPGA_SWR_PUSHSWMASK (0x1F<<26) #define MB93093_FPGA_SWR_PUSHSW4 (1<<29) -#define __addr_FPGA_SWR ((volatile void *)(__region_CS2 + 0x28UL)) +#define __addr_FPGA_SWR ((volatile void __iomem *)(__region_CS2 + 0x28UL)) #define __get_FPGA_PUSHSW1_5() (__builtin_read32(__addr_FPGA_SWR) & MB93093_FPGA_SWR_PUSHSWMASK) -- cgit v1.2.3 From 9e4d11f8630d5350adc5d4d65180e69991c498f8 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 23 Jun 2006 02:04:04 -0700 Subject: [PATCH] frv: signal annotations Add annotations to the FRV signal handling for sparse. Signed-off-by: Al Viro Signed-off-by: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/frv/kernel/signal.c | 20 ++++++++++---------- include/asm-frv/signal.h | 6 +++--- 2 files changed, 13 insertions(+), 13 deletions(-) (limited to 'include') diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c index 679c1d5cc958..dd5e6fdd85fd 100644 --- a/arch/frv/kernel/signal.c +++ b/arch/frv/kernel/signal.c @@ -98,7 +98,7 @@ int sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss) struct sigframe { - void (*pretcode)(void); + __sigrestore_t pretcode; int sig; struct sigcontext sc; unsigned long extramask[_NSIG_WORDS-1]; @@ -107,10 +107,10 @@ struct sigframe struct rt_sigframe { - void (*pretcode)(void); + __sigrestore_t pretcode; int sig; - struct siginfo *pinfo; - void *puc; + struct siginfo __user *pinfo; + void __user *puc; struct siginfo info; struct ucontext uc; uint32_t retcode[2]; @@ -284,7 +284,7 @@ static int setup_frame(int sig, struct k_sigaction *ka, sigset_t *set) * setlos #__NR_sigreturn,gr7 * tira gr0,0 */ - if (__put_user((void (*)(void))frame->retcode, &frame->pretcode) || + if (__put_user((__sigrestore_t)frame->retcode, &frame->pretcode) || __put_user(0x8efc0000|__NR_sigreturn, &frame->retcode[0]) || __put_user(0xc0700000, &frame->retcode[1])) goto give_sigsegv; @@ -300,7 +300,7 @@ static int setup_frame(int sig, struct k_sigaction *ka, sigset_t *set) if (get_personality & FDPIC_FUNCPTRS) { struct fdpic_func_descriptor __user *funcptr = - (struct fdpic_func_descriptor *) ka->sa.sa_handler; + (struct fdpic_func_descriptor __user *) ka->sa.sa_handler; __get_user(__frame->pc, &funcptr->text); __get_user(__frame->gr15, &funcptr->GOT); } else { @@ -359,8 +359,8 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, /* Create the ucontext. */ if (__put_user(0, &frame->uc.uc_flags) || - __put_user(0, &frame->uc.uc_link) || - __put_user((void*)current->sas_ss_sp, &frame->uc.uc_stack.ss_sp) || + __put_user(NULL, &frame->uc.uc_link) || + __put_user((void __user *)current->sas_ss_sp, &frame->uc.uc_stack.ss_sp) || __put_user(sas_ss_flags(__frame->sp), &frame->uc.uc_stack.ss_flags) || __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size)) goto give_sigsegv; @@ -382,7 +382,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, * setlos #__NR_sigreturn,gr7 * tira gr0,0 */ - if (__put_user((void (*)(void))frame->retcode, &frame->pretcode) || + if (__put_user((__sigrestore_t)frame->retcode, &frame->pretcode) || __put_user(0x8efc0000|__NR_rt_sigreturn, &frame->retcode[0]) || __put_user(0xc0700000, &frame->retcode[1])) goto give_sigsegv; @@ -398,7 +398,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, __frame->gr9 = (unsigned long) &frame->info; if (get_personality & FDPIC_FUNCPTRS) { - struct fdpic_func_descriptor *funcptr = + struct fdpic_func_descriptor __user *funcptr = (struct fdpic_func_descriptor __user *) ka->sa.sa_handler; __get_user(__frame->pc, &funcptr->text); __get_user(__frame->gr15, &funcptr->GOT); diff --git a/include/asm-frv/signal.h b/include/asm-frv/signal.h index 67366894780f..dcc1b3592918 100644 --- a/include/asm-frv/signal.h +++ b/include/asm-frv/signal.h @@ -114,13 +114,13 @@ struct old_sigaction { __sighandler_t sa_handler; old_sigset_t sa_mask; unsigned long sa_flags; - void (*sa_restorer)(void); + __sigrestore_t sa_restorer; }; struct sigaction { __sighandler_t sa_handler; unsigned long sa_flags; - void (*sa_restorer)(void); + __sigrestore_t sa_restorer; sigset_t sa_mask; /* mask last for extensibility */ }; @@ -146,7 +146,7 @@ struct sigaction { #endif /* __KERNEL__ */ typedef struct sigaltstack { - void *ss_sp; + void __user *ss_sp; int ss_flags; size_t ss_size; } stack_t; -- cgit v1.2.3 From 53470aaa02ef3c83187f1ffe0d2cb647274fe397 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 23 Jun 2006 02:04:06 -0700 Subject: [PATCH] frv: misc __user annotations Signed-off-by: Al Viro Signed-off-by: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/frv/kernel/irq.c | 6 +++--- arch/frv/kernel/process.c | 2 +- arch/frv/kernel/sys_frv.c | 2 +- include/asm-frv/checksum.h | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/arch/frv/kernel/irq.c b/arch/frv/kernel/irq.c index 11fa326a8f62..8b112b361914 100644 --- a/arch/frv/kernel/irq.c +++ b/arch/frv/kernel/irq.c @@ -625,7 +625,7 @@ static struct proc_dir_entry * irq_dir [NR_IRQS]; #define HEX_DIGITS 8 -static unsigned int parse_hex_value (const char *buffer, +static unsigned int parse_hex_value (const char __user *buffer, unsigned long count, unsigned long *ret) { unsigned char hexnum [HEX_DIGITS]; @@ -672,7 +672,7 @@ static int prof_cpu_mask_read_proc (char *page, char **start, off_t off, return sprintf (page, "%08lx\n", *mask); } -static int prof_cpu_mask_write_proc (struct file *file, const char *buffer, +static int prof_cpu_mask_write_proc (struct file *file, const char __user *buffer, unsigned long count, void *data) { unsigned long *mask = (unsigned long *) data, full_count = count, err; @@ -711,7 +711,7 @@ void init_irq_proc (void) int i; /* create /proc/irq */ - root_irq_dir = proc_mkdir("irq", 0); + root_irq_dir = proc_mkdir("irq", NULL); /* create /proc/irq/prof_cpu_mask */ entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir); diff --git a/arch/frv/kernel/process.c b/arch/frv/kernel/process.c index 0fff8a61ef2a..489e6c489cbe 100644 --- a/arch/frv/kernel/process.c +++ b/arch/frv/kernel/process.c @@ -246,7 +246,7 @@ int copy_thread(int nr, unsigned long clone_flags, /* * sys_execve() executes a new program. */ -asmlinkage int sys_execve(char *name, char **argv, char **envp) +asmlinkage int sys_execve(char __user *name, char __user * __user *argv, char __user * __user *envp) { int error; char * filename; diff --git a/arch/frv/kernel/sys_frv.c b/arch/frv/kernel/sys_frv.c index 931aa6d895e3..c4d4348c9e8e 100644 --- a/arch/frv/kernel/sys_frv.c +++ b/arch/frv/kernel/sys_frv.c @@ -32,7 +32,7 @@ * sys_pipe() is the normal C calling standard for creating * a pipe. It's not the way unix traditionally does this, though. */ -asmlinkage long sys_pipe(unsigned long * fildes) +asmlinkage long sys_pipe(unsigned long __user * fildes) { int fd[2]; int error; diff --git a/include/asm-frv/checksum.h b/include/asm-frv/checksum.h index 10236f6802db..42bf0db2287a 100644 --- a/include/asm-frv/checksum.h +++ b/include/asm-frv/checksum.h @@ -43,7 +43,7 @@ unsigned int csum_partial_copy(const char *src, char *dst, int len, int sum); * here even more important to align src and dst on a 32-bit (or even * better 64-bit) boundary */ -extern unsigned int csum_partial_copy_from_user(const char *src, char *dst, +extern unsigned int csum_partial_copy_from_user(const char __user *src, char *dst, int len, int sum, int *csum_err); #define csum_partial_copy_nocheck(src, dst, len, sum) \ -- cgit v1.2.3 From 576132b42647e3facd28e3148a20307fadfd9afc Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 23 Jun 2006 02:04:07 -0700 Subject: [PATCH] frv: misc sparse annotations Signed-off-by: Al Viro Signed-off-by: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/frv/kernel/irq-routing.c | 8 ++++---- arch/frv/mb93090-mb00/pci-irq.c | 10 +++++----- include/asm-frv/highmem.h | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/arch/frv/kernel/irq-routing.c b/arch/frv/kernel/irq-routing.c index d4776d1f4e82..b90b70a761d1 100644 --- a/arch/frv/kernel/irq-routing.c +++ b/arch/frv/kernel/irq-routing.c @@ -112,7 +112,7 @@ struct irq_source frv_cpuuart[2] = { #define __CPUUART(X, A) \ [X] = { \ .muxname = "uart", \ - .muxdata = (volatile void __iomem *) A, \ + .muxdata = (volatile void __iomem *)(unsigned long)A,\ .irqmask = 1 << IRQ_CPU_UART##X, \ .doirq = frv_cpuuart_doirq, \ } @@ -136,7 +136,7 @@ struct irq_source frv_cpudma[8] = { #define __CPUDMA(X, A) \ [X] = { \ .muxname = "dma", \ - .muxdata = (volatile void __iomem *) A, \ + .muxdata = (volatile void __iomem *)(unsigned long)A,\ .irqmask = 1 << IRQ_CPU_DMA##X, \ .doirq = frv_cpudma_doirq, \ } @@ -164,7 +164,7 @@ struct irq_source frv_cputimer[3] = { #define __CPUTIMER(X) \ [X] = { \ .muxname = "timer", \ - .muxdata = 0, \ + .muxdata = NULL, \ .irqmask = 1 << IRQ_CPU_TIMER##X, \ .doirq = frv_cputimer_doirq, \ } @@ -187,7 +187,7 @@ struct irq_source frv_cpuexternal[8] = { #define __CPUEXTERNAL(X) \ [X] = { \ .muxname = "ext", \ - .muxdata = 0, \ + .muxdata = NULL, \ .irqmask = 1 << IRQ_CPU_EXTERNAL##X, \ .doirq = frv_cpuexternal_doirq, \ } diff --git a/arch/frv/mb93090-mb00/pci-irq.c b/arch/frv/mb93090-mb00/pci-irq.c index c4a1144c98b0..45ae39d84b69 100644 --- a/arch/frv/mb93090-mb00/pci-irq.c +++ b/arch/frv/mb93090-mb00/pci-irq.c @@ -32,11 +32,11 @@ */ static const uint8_t __initdata pci_bus0_irq_routing[32][4] = { - [0 ] { IRQ_FPGA_MB86943_PCI_INTA }, - [16] { IRQ_FPGA_RTL8029_INTA }, - [17] { IRQ_FPGA_PCI_INTC, IRQ_FPGA_PCI_INTD, IRQ_FPGA_PCI_INTA, IRQ_FPGA_PCI_INTB }, - [18] { IRQ_FPGA_PCI_INTB, IRQ_FPGA_PCI_INTC, IRQ_FPGA_PCI_INTD, IRQ_FPGA_PCI_INTA }, - [19] { IRQ_FPGA_PCI_INTA, IRQ_FPGA_PCI_INTB, IRQ_FPGA_PCI_INTC, IRQ_FPGA_PCI_INTD }, + [0 ] = { IRQ_FPGA_MB86943_PCI_INTA }, + [16] = { IRQ_FPGA_RTL8029_INTA }, + [17] = { IRQ_FPGA_PCI_INTC, IRQ_FPGA_PCI_INTD, IRQ_FPGA_PCI_INTA, IRQ_FPGA_PCI_INTB }, + [18] = { IRQ_FPGA_PCI_INTB, IRQ_FPGA_PCI_INTC, IRQ_FPGA_PCI_INTD, IRQ_FPGA_PCI_INTA }, + [19] = { IRQ_FPGA_PCI_INTA, IRQ_FPGA_PCI_INTB, IRQ_FPGA_PCI_INTC, IRQ_FPGA_PCI_INTD }, }; void __init pcibios_irq_init(void) diff --git a/include/asm-frv/highmem.h b/include/asm-frv/highmem.h index cfbf7d3a1feb..e2247c22a638 100644 --- a/include/asm-frv/highmem.h +++ b/include/asm-frv/highmem.h @@ -134,7 +134,7 @@ static inline void *kmap_atomic(struct page *page, enum km_type type) default: BUG(); - return 0; + return NULL; } } -- cgit v1.2.3 From be2338f3ceb6d80170ebb495190d6aee79d8c7e3 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 23 Jun 2006 02:04:07 -0700 Subject: [PATCH] frv: wrong syscall The FRV arch should use fstatat64 not newfstatat. Signed-off-by: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/frv/kernel/entry.S | 2 +- include/asm-frv/unistd.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/arch/frv/kernel/entry.S b/arch/frv/kernel/entry.S index a9b59527a741..81d94e41a189 100644 --- a/arch/frv/kernel/entry.S +++ b/arch/frv/kernel/entry.S @@ -1474,7 +1474,7 @@ sys_call_table: .long sys_mknodat .long sys_fchownat .long sys_futimesat - .long sys_newfstatat /* 300 */ + .long sys_fstatat64 /* 300 */ .long sys_unlinkat .long sys_renameat .long sys_linkat diff --git a/include/asm-frv/unistd.h b/include/asm-frv/unistd.h index 7c2e712c3b73..91a171decfce 100644 --- a/include/asm-frv/unistd.h +++ b/include/asm-frv/unistd.h @@ -306,7 +306,7 @@ #define __NR_mknodat 297 #define __NR_fchownat 298 #define __NR_futimesat 299 -#define __NR_newfstatat 300 +#define __NR_fstatat64 300 #define __NR_unlinkat 301 #define __NR_renameat 302 #define __NR_linkat 303 -- cgit v1.2.3 From 7f788435568795c4cd29301bb4ccf7aff54f5051 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 23 Jun 2006 02:04:09 -0700 Subject: [PATCH] frv: NULL noise removal in frv xchg() Clean up the FRV arch's xchg() function. Signed-off-by: Al Viro Signed-off-by: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-frv/atomic.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/asm-frv/atomic.h b/include/asm-frv/atomic.h index 9a4ff03c3969..066386ac238e 100644 --- a/include/asm-frv/atomic.h +++ b/include/asm-frv/atomic.h @@ -227,7 +227,7 @@ extern unsigned long atomic_test_and_XOR_mask(unsigned long mask, volatile unsig break; \ \ default: \ - __xg_orig = 0; \ + __xg_orig = (__typeof__(__xg_orig))0; \ asm volatile("break"); \ break; \ } \ @@ -247,7 +247,7 @@ extern uint32_t __xchg_32(uint32_t i, volatile void *v); switch (sizeof(__xg_orig)) { \ case 4: __xg_orig = (__typeof__(*(ptr))) __xchg_32((uint32_t) x, __xg_ptr); break; \ default: \ - __xg_orig = 0; \ + __xg_orig = (__typeof__(__xg_orig))0; \ asm volatile("break"); \ break; \ } \ -- cgit v1.2.3 From 5e591a55576b60156ac3dbc5087660ed82646d66 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 23 Jun 2006 02:04:11 -0700 Subject: [PATCH] frv: Add missing qualifier to memcpy_fromio() prototype The memcpy_fromio() function should have a const qualifier on its source pointer. Signed-off-by: Al Viro Signed-off-by: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-frv/io.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/asm-frv/io.h b/include/asm-frv/io.h index f49398a82977..7765f5528894 100644 --- a/include/asm-frv/io.h +++ b/include/asm-frv/io.h @@ -116,7 +116,7 @@ static inline void memset_io(volatile void __iomem *addr, unsigned char val, int memset((void __force *) addr, val, count); } -static inline void memcpy_fromio(void *dst, volatile void __iomem *src, int count) +static inline void memcpy_fromio(void *dst, const volatile void __iomem *src, int count) { memcpy(dst, (void __force *) src, count); } -- cgit v1.2.3 From c52c17622e27876c2395f59cfe342497a399de41 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 23 Jun 2006 02:04:13 -0700 Subject: [PATCH] frv: clean frv unistd.h Remove _syscall invocations that aren't used in the kernel. Signed-off-by: Al Viro Signed-off-by: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-frv/unistd.h | 17 ----------------- 1 file changed, 17 deletions(-) (limited to 'include') diff --git a/include/asm-frv/unistd.h b/include/asm-frv/unistd.h index 91a171decfce..b80dbd839475 100644 --- a/include/asm-frv/unistd.h +++ b/include/asm-frv/unistd.h @@ -460,24 +460,7 @@ type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg * some others too. */ #define __NR__exit __NR_exit -static inline _syscall0(int,pause) -static inline _syscall0(int,sync) -static inline _syscall0(pid_t,setsid) -static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count) -static inline _syscall3(int,read,int,fd,char *,buf,off_t,count) -static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count) -static inline _syscall1(int,dup,int,fd) static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp) -static inline _syscall3(int,open,const char *,file,int,flag,int,mode) -static inline _syscall1(int,close,int,fd) -static inline _syscall1(int,_exit,int,exitcode) -static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) -static inline _syscall1(int,delete_module,const char *,name) - -static inline pid_t wait(int * wait_stat) -{ - return waitpid(-1,wait_stat,0); -} #endif /* __KERNEL_SYSCALLS__ */ -- cgit v1.2.3 From f2c780c1fdbe5008c902c2d7e37242ac5e60f0b9 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Fri, 23 Jun 2006 02:04:13 -0700 Subject: [PATCH] Au1550/1200: add missing PSC #define's, make OSS driver use the proper ones Add missing PSC #define's required for the drivers using PSC on DBAu1550 board (also fixing Au1550 PSC3 address) and all Au1200-based boards as well. Make the OSS driver use the correct PSC definitions fo each board. Signed-off-by: Sergei Shtylyov Cc: Ralf Baechle Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-mips/mach-au1x00/au1xxx_psc.h | 9 ++++++++- include/asm-mips/mach-db1x00/db1x00.h | 12 ++++++++++++ sound/oss/au1550_ac97.c | 2 +- 3 files changed, 21 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/asm-mips/mach-au1x00/au1xxx_psc.h b/include/asm-mips/mach-au1x00/au1xxx_psc.h index 5c3e2a38ce12..d7cbacdd21fe 100644 --- a/include/asm-mips/mach-au1x00/au1xxx_psc.h +++ b/include/asm-mips/mach-au1x00/au1xxx_psc.h @@ -39,7 +39,12 @@ #define PSC0_BASE_ADDR 0xb1a00000 #define PSC1_BASE_ADDR 0xb1b00000 #define PSC2_BASE_ADDR 0xb0a00000 -#define PSC3_BASE_ADDR 0xb0d00000 +#define PSC3_BASE_ADDR 0xb0b00000 +#endif + +#ifdef CONFIG_SOC_AU1200 +#define PSC0_BASE_ADDR 0xb1a00000 +#define PSC1_BASE_ADDR 0xb1b00000 #endif /* The PSC select and control registers are common to @@ -227,6 +232,8 @@ typedef struct psc_i2s { #define PSC_I2SCFG_DD_DISABLE (1 << 27) #define PSC_I2SCFG_DE_ENABLE (1 << 26) #define PSC_I2SCFG_SET_WS(x) (((((x) / 2) - 1) & 0x7f) << 16) +#define PSC_I2SCFG_WS(n) ((n & 0xFF) << 16) +#define PSC_I2SCFG_WS_MASK (PSC_I2SCFG_WS(0x3F)) #define PSC_I2SCFG_WI (1 << 15) #define PSC_I2SCFG_DIV_MASK (3 << 13) diff --git a/include/asm-mips/mach-db1x00/db1x00.h b/include/asm-mips/mach-db1x00/db1x00.h index 8fbb4b42a8b5..0f5f4c29f4e8 100644 --- a/include/asm-mips/mach-db1x00/db1x00.h +++ b/include/asm-mips/mach-db1x00/db1x00.h @@ -30,8 +30,20 @@ #ifdef CONFIG_MIPS_DB1550 + +#define DBDMA_AC97_TX_CHAN DSCR_CMD0_PSC1_TX +#define DBDMA_AC97_RX_CHAN DSCR_CMD0_PSC1_RX +#define DBDMA_I2S_TX_CHAN DSCR_CMD0_PSC3_TX +#define DBDMA_I2S_RX_CHAN DSCR_CMD0_PSC3_RX + +#define SPI_PSC_BASE PSC0_BASE_ADDR +#define AC97_PSC_BASE PSC1_BASE_ADDR +#define SMBUS_PSC_BASE PSC2_BASE_ADDR +#define I2S_PSC_BASE PSC3_BASE_ADDR + #define BCSR_KSEG1_ADDR 0xAF000000 #define NAND_PHYS_ADDR 0x20000000 + #else #define BCSR_KSEG1_ADDR 0xAE000000 #endif diff --git a/sound/oss/au1550_ac97.c b/sound/oss/au1550_ac97.c index c1168fae6be6..9011abe241ab 100644 --- a/sound/oss/au1550_ac97.c +++ b/sound/oss/au1550_ac97.c @@ -57,9 +57,9 @@ #include #include #include -#include #include #include +#include #undef OSS_DOCUMENTED_MIXER_SEMANTICS -- cgit v1.2.3 From c22ce143d15eb288543fe9873e1c5ac1c01b69a1 Mon Sep 17 00:00:00 2001 From: Hiro Yoshioka Date: Fri, 23 Jun 2006 02:04:16 -0700 Subject: [PATCH] x86: cache pollution aware __copy_from_user_ll() Use the x86 cache-bypassing copy instructions for copy_from_user(). Some performance data are Total of GLOBAL_POWER_EVENTS (CPU cycle samples) 2.6.12.4.orig 1921587 2.6.12.4.nt 1599424 1599424/1921587=83.23% (16.77% reduction) BSQ_CACHE_REFERENCE (L3 cache miss) 2.6.12.4.orig 57427 2.6.12.4.nt 20858 20858/57427=36.32% (63.7% reduction) L3 cache miss reduction of __copy_from_user_ll samples % 37408 65.1412 vmlinux __copy_from_user_ll 23 0.1103 vmlinux __copy_user_zeroing_intel_nocache 23/37408=0.061% (99.94% reduction) Top 5 of 2.6.12.4.nt Counted GLOBAL_POWER_EVENTS events (time during which processor is not stopped) with a unit mask of 0x01 (mandatory) count 100000 samples % app name symbol name 128392 8.0274 vmlinux __copy_user_zeroing_intel_nocache 64206 4.0143 vmlinux journal_add_journal_head 59746 3.7355 vmlinux do_get_write_access 47674 2.9807 vmlinux journal_put_journal_head 46021 2.8774 vmlinux journal_dirty_metadata pattern9-0-cpu4-0-09011728/summary.out Counted BSQ_CACHE_REFERENCE events (cache references seen by the bus unit) with a unit mask of 0x3f (multiple flags) count 3000 samples % app name symbol name 69755 4.2861 vmlinux __copy_user_zeroing_intel_nocache 55685 3.4215 vmlinux journal_add_journal_head 52371 3.2179 vmlinux __find_get_block 45504 2.7960 vmlinux journal_put_journal_head 36005 2.2123 vmlinux journal_stop pattern9-0-cpu4-0-09011744/summary.out Counted BSQ_CACHE_REFERENCE events (cache references seen by the bus unit) with a unit mask of 0x200 (read 3rd level cache miss) count 3000 samples % app name symbol name 1147 5.4994 vmlinux journal_add_journal_head 881 4.2240 vmlinux journal_dirty_data 872 4.1809 vmlinux blk_rq_map_sg 734 3.5192 vmlinux journal_commit_transaction 617 2.9582 vmlinux radix_tree_delete pattern9-0-cpu4-0-09011731/summary.out iozone results are original 2.6.12.4 CPU time = 207.768 sec cache aware CPU time = 184.783 sec (three times run) 184.783/207.768=88.94% (11.06% reduction) original: pattern9-0-cpu4-0-08191720/iozone.out: CPU Utilization: Wall time 45.997 CPU time 64.527 CPU utilization 140.28 % pattern9-0-cpu4-0-08191741/iozone.out: CPU Utilization: Wall time 46.878 CPU time 71.933 CPU utilization 153.45 % pattern9-0-cpu4-0-08191743/iozone.out: CPU Utilization: Wall time 45.152 CPU time 71.308 CPU utilization 157.93 % cache awre: pattern9-0-cpu4-0-09011728/iozone.out: CPU Utilization: Wall time 44.842 CPU time 62.465 CPU utilization 139.30 % pattern9-0-cpu4-0-09011731/iozone.out: CPU Utilization: Wall time 44.718 CPU time 59.273 CPU utilization 132.55 % pattern9-0-cpu4-0-09011744/iozone.out: CPU Utilization: Wall time 44.367 CPU time 63.045 CPU utilization 142.10 % Signed-off-by: Hiro Yoshioka Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/lib/usercopy.c | 137 ++++++++++++++++++++++++++++++++++++++++++--- include/asm-i386/uaccess.h | 33 +++++++++++ include/linux/uaccess.h | 22 ++++++++ mm/filemap.c | 4 +- mm/filemap.h | 6 +- 5 files changed, 189 insertions(+), 13 deletions(-) create mode 100644 include/linux/uaccess.h (limited to 'include') diff --git a/arch/i386/lib/usercopy.c b/arch/i386/lib/usercopy.c index 4cf981d70f45..6979297ce278 100644 --- a/arch/i386/lib/usercopy.c +++ b/arch/i386/lib/usercopy.c @@ -425,15 +425,121 @@ __copy_user_zeroing_intel(void *to, const void __user *from, unsigned long size) : "eax", "edx", "memory"); return size; } + +/* + * Non Temporal Hint version of __copy_user_zeroing_intel. It is cache aware. + * hyoshiok@miraclelinux.com + */ + +static unsigned long __copy_user_zeroing_intel_nocache(void *to, + const void __user *from, unsigned long size) +{ + int d0, d1; + + __asm__ __volatile__( + " .align 2,0x90\n" + "0: movl 32(%4), %%eax\n" + " cmpl $67, %0\n" + " jbe 2f\n" + "1: movl 64(%4), %%eax\n" + " .align 2,0x90\n" + "2: movl 0(%4), %%eax\n" + "21: movl 4(%4), %%edx\n" + " movnti %%eax, 0(%3)\n" + " movnti %%edx, 4(%3)\n" + "3: movl 8(%4), %%eax\n" + "31: movl 12(%4),%%edx\n" + " movnti %%eax, 8(%3)\n" + " movnti %%edx, 12(%3)\n" + "4: movl 16(%4), %%eax\n" + "41: movl 20(%4), %%edx\n" + " movnti %%eax, 16(%3)\n" + " movnti %%edx, 20(%3)\n" + "10: movl 24(%4), %%eax\n" + "51: movl 28(%4), %%edx\n" + " movnti %%eax, 24(%3)\n" + " movnti %%edx, 28(%3)\n" + "11: movl 32(%4), %%eax\n" + "61: movl 36(%4), %%edx\n" + " movnti %%eax, 32(%3)\n" + " movnti %%edx, 36(%3)\n" + "12: movl 40(%4), %%eax\n" + "71: movl 44(%4), %%edx\n" + " movnti %%eax, 40(%3)\n" + " movnti %%edx, 44(%3)\n" + "13: movl 48(%4), %%eax\n" + "81: movl 52(%4), %%edx\n" + " movnti %%eax, 48(%3)\n" + " movnti %%edx, 52(%3)\n" + "14: movl 56(%4), %%eax\n" + "91: movl 60(%4), %%edx\n" + " movnti %%eax, 56(%3)\n" + " movnti %%edx, 60(%3)\n" + " addl $-64, %0\n" + " addl $64, %4\n" + " addl $64, %3\n" + " cmpl $63, %0\n" + " ja 0b\n" + " sfence \n" + "5: movl %0, %%eax\n" + " shrl $2, %0\n" + " andl $3, %%eax\n" + " cld\n" + "6: rep; movsl\n" + " movl %%eax,%0\n" + "7: rep; movsb\n" + "8:\n" + ".section .fixup,\"ax\"\n" + "9: lea 0(%%eax,%0,4),%0\n" + "16: pushl %0\n" + " pushl %%eax\n" + " xorl %%eax,%%eax\n" + " rep; stosb\n" + " popl %%eax\n" + " popl %0\n" + " jmp 8b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 0b,16b\n" + " .long 1b,16b\n" + " .long 2b,16b\n" + " .long 21b,16b\n" + " .long 3b,16b\n" + " .long 31b,16b\n" + " .long 4b,16b\n" + " .long 41b,16b\n" + " .long 10b,16b\n" + " .long 51b,16b\n" + " .long 11b,16b\n" + " .long 61b,16b\n" + " .long 12b,16b\n" + " .long 71b,16b\n" + " .long 13b,16b\n" + " .long 81b,16b\n" + " .long 14b,16b\n" + " .long 91b,16b\n" + " .long 6b,9b\n" + " .long 7b,16b\n" + ".previous" + : "=&c"(size), "=&D" (d0), "=&S" (d1) + : "1"(to), "2"(from), "0"(size) + : "eax", "edx", "memory"); + return size; +} + #else + /* * Leave these declared but undefined. They should not be any references to * them */ -unsigned long -__copy_user_zeroing_intel(void *to, const void __user *from, unsigned long size); -unsigned long -__copy_user_intel(void __user *to, const void *from, unsigned long size); +unsigned long __copy_user_zeroing_intel(void *to, const void __user *from, + unsigned long size); +unsigned long __copy_user_intel(void __user *to, const void *from, + unsigned long size); +unsigned long __copy_user_zeroing_intel_nocache(void *to, + const void __user *from, unsigned long size); #endif /* CONFIG_X86_INTEL_USERCOPY */ /* Generic arbitrary sized copy. */ @@ -515,8 +621,8 @@ do { \ : "memory"); \ } while (0) - -unsigned long __copy_to_user_ll(void __user *to, const void *from, unsigned long n) +unsigned long __copy_to_user_ll(void __user *to, const void *from, + unsigned long n) { BUG_ON((long) n < 0); #ifndef CONFIG_X86_WP_WORKS_OK @@ -576,8 +682,8 @@ survive: } EXPORT_SYMBOL(__copy_to_user_ll); -unsigned long -__copy_from_user_ll(void *to, const void __user *from, unsigned long n) +unsigned long __copy_from_user_ll(void *to, const void __user *from, + unsigned long n) { BUG_ON((long)n < 0); if (movsl_is_ok(to, from, n)) @@ -588,6 +694,21 @@ __copy_from_user_ll(void *to, const void __user *from, unsigned long n) } EXPORT_SYMBOL(__copy_from_user_ll); +unsigned long __copy_from_user_ll_nocache(void *to, const void __user *from, + unsigned long n) +{ + BUG_ON((long)n < 0); +#ifdef CONFIG_X86_INTEL_USERCOPY + if ( n > 64 && cpu_has_xmm2) + n = __copy_user_zeroing_intel_nocache(to, from, n); + else + __copy_user_zeroing(to, from, n); +#else + __copy_user_zeroing(to, from, n); +#endif + return n; +} + /** * copy_to_user: - Copy a block of data into user space. * @to: Destination address, in user space. diff --git a/include/asm-i386/uaccess.h b/include/asm-i386/uaccess.h index 1ec65523ea5e..82af28a943ab 100644 --- a/include/asm-i386/uaccess.h +++ b/include/asm-i386/uaccess.h @@ -390,6 +390,8 @@ unsigned long __must_check __copy_to_user_ll(void __user *to, const void *from, unsigned long n); unsigned long __must_check __copy_from_user_ll(void *to, const void __user *from, unsigned long n); +unsigned long __must_check __copy_from_user_ll_nocache(void *to, + const void __user *from, unsigned long n); /* * Here we special-case 1, 2 and 4-byte copy_*_user invocations. On a fault @@ -478,12 +480,43 @@ __copy_from_user_inatomic(void *to, const void __user *from, unsigned long n) return __copy_from_user_ll(to, from, n); } +#define ARCH_HAS_NOCACHE_UACCESS + +static __always_inline unsigned long __copy_from_user_inatomic_nocache(void *to, + const void __user *from, unsigned long n) +{ + if (__builtin_constant_p(n)) { + unsigned long ret; + + switch (n) { + case 1: + __get_user_size(*(u8 *)to, from, 1, ret, 1); + return ret; + case 2: + __get_user_size(*(u16 *)to, from, 2, ret, 2); + return ret; + case 4: + __get_user_size(*(u32 *)to, from, 4, ret, 4); + return ret; + } + } + return __copy_from_user_ll_nocache(to, from, n); +} + static __always_inline unsigned long __copy_from_user(void *to, const void __user *from, unsigned long n) { might_sleep(); return __copy_from_user_inatomic(to, from, n); } + +static __always_inline unsigned long +__copy_from_user_nocache(void *to, const void __user *from, unsigned long n) +{ + might_sleep(); + return __copy_from_user_inatomic_nocache(to, from, n); +} + unsigned long __must_check copy_to_user(void __user *to, const void *from, unsigned long n); unsigned long __must_check copy_from_user(void *to, diff --git a/include/linux/uaccess.h b/include/linux/uaccess.h new file mode 100644 index 000000000000..391e7ed1eb3f --- /dev/null +++ b/include/linux/uaccess.h @@ -0,0 +1,22 @@ +#ifndef __LINUX_UACCESS_H__ +#define __LINUX_UACCESS_H__ + +#include + +#ifndef ARCH_HAS_NOCACHE_UACCESS + +static inline unsigned long __copy_from_user_inatomic_nocache(void *to, + const void __user *from, unsigned long n) +{ + return __copy_from_user_inatomic(to, from, n); +} + +static inline unsigned long __copy_from_user_nocache(void *to, + const void __user *from, unsigned long n) +{ + return __copy_from_user(to, from, n); +} + +#endif /* ARCH_HAS_NOCACHE_UACCESS */ + +#endif /* __LINUX_UACCESS_H__ */ diff --git a/mm/filemap.c b/mm/filemap.c index 368678c2d531..807a463fd5ed 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -38,7 +39,6 @@ */ #include /* for generic_osync_inode */ -#include #include static ssize_t @@ -1902,7 +1902,7 @@ __filemap_copy_from_user_iovec(char *vaddr, int copy = min(bytes, iov->iov_len - base); base = 0; - left = __copy_from_user_inatomic(vaddr, buf, copy); + left = __copy_from_user_inatomic_nocache(vaddr, buf, copy); copied += copy; bytes -= copy; vaddr += copy; diff --git a/mm/filemap.h b/mm/filemap.h index 13793ba0ce17..5683cde22055 100644 --- a/mm/filemap.h +++ b/mm/filemap.h @@ -13,7 +13,7 @@ #include #include #include -#include +#include size_t __filemap_copy_from_user_iovec(char *vaddr, @@ -34,13 +34,13 @@ filemap_copy_from_user(struct page *page, unsigned long offset, int left; kaddr = kmap_atomic(page, KM_USER0); - left = __copy_from_user_inatomic(kaddr + offset, buf, bytes); + left = __copy_from_user_inatomic_nocache(kaddr + offset, buf, bytes); kunmap_atomic(kaddr, KM_USER0); if (left != 0) { /* Do it the slow way */ kaddr = kmap(page); - left = __copy_from_user(kaddr + offset, buf, bytes); + left = __copy_from_user_nocache(kaddr + offset, buf, bytes); kunmap(page); } return bytes - left; -- cgit v1.2.3 From a0b4da91f4c5710b9c20219a19e905145647b48b Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Fri, 23 Jun 2006 02:04:17 -0700 Subject: [PATCH] arch/i386/kernel/apic.c: make modern_apic() static Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/apic.c | 2 +- include/asm-i386/apic.h | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'include') diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c index 3d4b2f3d116a..261796ff83c3 100644 --- a/arch/i386/kernel/apic.c +++ b/arch/i386/kernel/apic.c @@ -62,7 +62,7 @@ int apic_verbosity; static void apic_pm_activate(void); -int modern_apic(void) +static int modern_apic(void) { unsigned int lvr, version; /* AMD systems use old APIC versions, so check the CPU */ diff --git a/include/asm-i386/apic.h b/include/asm-i386/apic.h index cc9b940fb7e8..1d8362cb2c5d 100644 --- a/include/asm-i386/apic.h +++ b/include/asm-i386/apic.h @@ -138,8 +138,6 @@ void switch_ipi_to_APIC_timer(void *cpumask); extern int timer_over_8254; -extern int modern_apic(void); - #else /* !CONFIG_X86_LOCAL_APIC */ static inline void lapic_shutdown(void) { } -- cgit v1.2.3 From 27b07da7332f03a935cd13b6a6beb780bf19e7a4 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Fri, 23 Jun 2006 02:04:18 -0700 Subject: [PATCH] Don't trigger full rebuild via CONFIG_MTRR Only drm, framebuffer, mtrr parts + misc files here and there. Signed-off-by: Alexey Dobriyan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/cpu/common.c | 1 + arch/i386/power/cpu.c | 1 + include/asm-i386/mtrr.h | 4 ++++ include/asm-i386/processor.h | 8 -------- 4 files changed, 6 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c index a06a49075f10..f2a2b0ac9a18 100644 --- a/arch/i386/kernel/cpu/common.c +++ b/arch/i386/kernel/cpu/common.c @@ -11,6 +11,7 @@ #include #include #include +#include #ifdef CONFIG_X86_LOCAL_APIC #include #include diff --git a/arch/i386/power/cpu.c b/arch/i386/power/cpu.c index 79b2370c7fac..63d25ca6306f 100644 --- a/arch/i386/power/cpu.c +++ b/arch/i386/power/cpu.c @@ -10,6 +10,7 @@ #include #include #include +#include static struct saved_context saved_context; diff --git a/include/asm-i386/mtrr.h b/include/asm-i386/mtrr.h index 5a46de08efea..07f063ae26ea 100644 --- a/include/asm-i386/mtrr.h +++ b/include/asm-i386/mtrr.h @@ -76,6 +76,8 @@ extern int mtrr_add_page (unsigned long base, unsigned long size, extern int mtrr_del (int reg, unsigned long base, unsigned long size); extern int mtrr_del_page (int reg, unsigned long base, unsigned long size); extern void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi); +extern void mtrr_ap_init(void); +extern void mtrr_bp_init(void); # else static __inline__ int mtrr_add (unsigned long base, unsigned long size, unsigned int type, char increment) @@ -100,6 +102,8 @@ static __inline__ int mtrr_del_page (int reg, unsigned long base, static __inline__ void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi) {;} +#define mtrr_ap_init() do {} while (0) +#define mtrr_bp_init() do {} while (0) # endif #endif diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h index 4df3818e4122..5116465272ec 100644 --- a/include/asm-i386/processor.h +++ b/include/asm-i386/processor.h @@ -728,14 +728,6 @@ extern unsigned long boot_option_idle_override; extern void enable_sep_cpu(void); extern int sysenter_setup(void); -#ifdef CONFIG_MTRR -extern void mtrr_ap_init(void); -extern void mtrr_bp_init(void); -#else -#define mtrr_ap_init() do {} while (0) -#define mtrr_bp_init() do {} while (0) -#endif - #ifdef CONFIG_X86_MCE extern void mcheck_init(struct cpuinfo_x86 *c); #else -- cgit v1.2.3 From a03a3e287b119c7bcbcff1d68f81864ce33b1ad2 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Fri, 23 Jun 2006 02:04:20 -0700 Subject: [PATCH] Don't trigger full rebuild via CONFIG_X86_MCE Signed-off-by: Alexey Dobriyan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/cpu/common.c | 1 + arch/i386/power/cpu.c | 1 + include/asm-i386/mce.h | 5 +++++ include/asm-i386/processor.h | 6 ------ 4 files changed, 7 insertions(+), 6 deletions(-) create mode 100644 include/asm-i386/mce.h (limited to 'include') diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c index f2a2b0ac9a18..44f2c5f2dda1 100644 --- a/arch/i386/kernel/cpu/common.c +++ b/arch/i386/kernel/cpu/common.c @@ -12,6 +12,7 @@ #include #include #include +#include #ifdef CONFIG_X86_LOCAL_APIC #include #include diff --git a/arch/i386/power/cpu.c b/arch/i386/power/cpu.c index 63d25ca6306f..e6517915fe3e 100644 --- a/arch/i386/power/cpu.c +++ b/arch/i386/power/cpu.c @@ -11,6 +11,7 @@ #include #include #include +#include static struct saved_context saved_context; diff --git a/include/asm-i386/mce.h b/include/asm-i386/mce.h new file mode 100644 index 000000000000..7cc1a973bf00 --- /dev/null +++ b/include/asm-i386/mce.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_X86_MCE +extern void mcheck_init(struct cpuinfo_x86 *c); +#else +#define mcheck_init(c) do {} while(0) +#endif diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h index 5116465272ec..0c83cf12eec9 100644 --- a/include/asm-i386/processor.h +++ b/include/asm-i386/processor.h @@ -728,10 +728,4 @@ extern unsigned long boot_option_idle_override; extern void enable_sep_cpu(void); extern int sysenter_setup(void); -#ifdef CONFIG_X86_MCE -extern void mcheck_init(struct cpuinfo_x86 *c); -#else -#define mcheck_init(c) do {} while(0) -#endif - #endif /* __ASM_I386_PROCESSOR_H */ -- cgit v1.2.3 From 1b61b910e99059abdd54c93aa70e84e076e33d16 Mon Sep 17 00:00:00 2001 From: Zhang Yanmin Date: Fri, 23 Jun 2006 02:04:22 -0700 Subject: [PATCH] x86: kernel irq balance doesn't work On i386, kernel irq balance doesn't work. 1) In function do_irq_balance, after kernel finds the min_loaded cpu but before calling set_pending_irq to really pin the selected_irq to the target cpu, kernel does a cpus_and with irq_affinity[selected_irq]. Later on, when the irq is acked, kernel would calls move_native_irq=>desc->handler->set_affinity to change the irq affinity. However, every function pointed by hw_interrupt_type->set_affinity(unsigned int irq, cpumask_t cpumask) always changes irq_affinity[irq] to cpumask. Next time when recalling do_irq_balance, it has to do cpu_ands again with irq_affinity[selected_irq], but irq_affinity[selected_irq] already becomes one cpu selected by the first irq balance. 2) Function balance_irq in file arch/i386/kernel/io_apic.c has the same issue. [akpm@osdl.org: cleanups] Signed-off-by: Zhang Yanmin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/io_apic.c | 31 ++++++++++++++++++++----------- include/linux/irq.h | 8 ++++++++ kernel/irq/proc.c | 3 +++ 3 files changed, 31 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index d70f2ade5cde..a62df3e764c5 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c @@ -267,7 +267,7 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t cpumask) # include /* kmalloc() */ # include /* time_after() */ -# ifdef CONFIG_BALANCED_IRQ_DEBUG +#ifdef CONFIG_BALANCED_IRQ_DEBUG # define TDprintk(x...) do { printk("<%ld:%s:%d>: ", jiffies, __FILE__, __LINE__); printk(x); } while (0) # define Dprintk(x...) do { TDprintk(x); } while (0) # else @@ -275,10 +275,15 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t cpumask) # define Dprintk(x...) # endif - #define IRQBALANCE_CHECK_ARCH -999 -static int irqbalance_disabled = IRQBALANCE_CHECK_ARCH; -static int physical_balance = 0; +#define MAX_BALANCED_IRQ_INTERVAL (5*HZ) +#define MIN_BALANCED_IRQ_INTERVAL (HZ/2) +#define BALANCED_IRQ_MORE_DELTA (HZ/10) +#define BALANCED_IRQ_LESS_DELTA (HZ) + +static int irqbalance_disabled __read_mostly = IRQBALANCE_CHECK_ARCH; +static int physical_balance __read_mostly; +static long balanced_irq_interval __read_mostly = MAX_BALANCED_IRQ_INTERVAL; static struct irq_cpu_info { unsigned long * last_irq; @@ -297,12 +302,14 @@ static struct irq_cpu_info { #define CPU_TO_PACKAGEINDEX(i) (first_cpu(cpu_sibling_map[i])) -#define MAX_BALANCED_IRQ_INTERVAL (5*HZ) -#define MIN_BALANCED_IRQ_INTERVAL (HZ/2) -#define BALANCED_IRQ_MORE_DELTA (HZ/10) -#define BALANCED_IRQ_LESS_DELTA (HZ) +static cpumask_t balance_irq_affinity[NR_IRQS] = { + [0 ... NR_IRQS-1] = CPU_MASK_ALL +}; -static long balanced_irq_interval = MAX_BALANCED_IRQ_INTERVAL; +void set_balance_irq_affinity(unsigned int irq, cpumask_t mask) +{ + balance_irq_affinity[irq] = mask; +} static unsigned long move(int curr_cpu, cpumask_t allowed_mask, unsigned long now, int direction) @@ -340,7 +347,7 @@ static inline void balance_irq(int cpu, int irq) if (irqbalance_disabled) return; - cpus_and(allowed_mask, cpu_online_map, irq_affinity[irq]); + cpus_and(allowed_mask, cpu_online_map, balance_irq_affinity[irq]); new_cpu = move(cpu, allowed_mask, now, 1); if (cpu != new_cpu) { set_pending_irq(irq, cpumask_of_cpu(new_cpu)); @@ -529,7 +536,9 @@ tryanotherirq: } } - cpus_and(allowed_mask, cpu_online_map, irq_affinity[selected_irq]); + cpus_and(allowed_mask, + cpu_online_map, + balance_irq_affinity[selected_irq]); target_cpu_mask = cpumask_of_cpu(min_loaded); cpus_and(tmp, target_cpu_mask, allowed_mask); diff --git a/include/linux/irq.h b/include/linux/irq.h index 42c9cd562860..e8a07e75e4fb 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -164,6 +164,14 @@ static inline void set_irq_info(int irq, cpumask_t mask) #endif // CONFIG_SMP +#ifdef CONFIG_IRQBALANCE +extern void set_balance_irq_affinity(unsigned int irq, cpumask_t mask); +#else +static inline void set_balance_irq_affinity(unsigned int irq, cpumask_t mask) +{ +} +#endif + extern int no_irq_affinity; extern int noirqdebug_setup(char *str); diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c index d03b5eef8ce0..afacd6f585fa 100644 --- a/kernel/irq/proc.c +++ b/kernel/irq/proc.c @@ -24,6 +24,8 @@ static struct proc_dir_entry *smp_affinity_entry[NR_IRQS]; #ifdef CONFIG_GENERIC_PENDING_IRQ void proc_set_irq_affinity(unsigned int irq, cpumask_t mask_val) { + set_balance_irq_affinity(irq, mask_val); + /* * Save these away for later use. Re-progam when the * interrupt is pending @@ -33,6 +35,7 @@ void proc_set_irq_affinity(unsigned int irq, cpumask_t mask_val) #else void proc_set_irq_affinity(unsigned int irq, cpumask_t mask_val) { + set_balance_irq_affinity(irq, mask_val); irq_affinity[irq] = mask_val; irq_desc[irq].handler->set_affinity(irq, mask_val); } -- cgit v1.2.3 From 722f4f5b2600b8930b63a096e48b878cd6e0e15a Mon Sep 17 00:00:00 2001 From: Roman Zippel Date: Fri, 23 Jun 2006 02:04:31 -0700 Subject: [PATCH] x86: fix __range_ok constraint An immediate operand can't be the destination of the cmpl instruction, so exclude it. Signed-off-by: Roman Zippel Cc: Mattia Dongili Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-i386/uaccess.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/asm-i386/uaccess.h b/include/asm-i386/uaccess.h index 82af28a943ab..8462f8e0e658 100644 --- a/include/asm-i386/uaccess.h +++ b/include/asm-i386/uaccess.h @@ -58,7 +58,7 @@ extern struct movsl_mask { __chk_user_ptr(addr); \ asm("addl %3,%1 ; sbbl %0,%0; cmpl %1,%4; sbbl $0,%0" \ :"=&r" (flag), "=r" (sum) \ - :"1" (addr),"g" ((int)(size)),"g" (current_thread_info()->addr_limit.seg)); \ + :"1" (addr),"g" ((int)(size)),"rm" (current_thread_info()->addr_limit.seg)); \ flag; }) /** -- cgit v1.2.3 From 224f611c1639cb6c134a934dae7f7b9f0ac3b540 Mon Sep 17 00:00:00 2001 From: Michal Ludvig Date: Fri, 23 Jun 2006 02:04:32 -0700 Subject: [PATCH] x86: VIA C7 CPU flags New CPU flags for next generation of crypto engine as found in VIA C7 processors. Signed-off-by: Michal Ludvig Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/cpu/proc.c | 2 +- include/asm-i386/cpufeature.h | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/arch/i386/kernel/cpu/proc.c b/arch/i386/kernel/cpu/proc.c index f94cdb7aca50..a19fcb262dbb 100644 --- a/arch/i386/kernel/cpu/proc.c +++ b/arch/i386/kernel/cpu/proc.c @@ -52,7 +52,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) /* VIA/Cyrix/Centaur-defined */ NULL, NULL, "rng", "rng_en", NULL, NULL, "ace", "ace_en", - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + "ace2", "ace2_en", "phe", "phe_en", "pmm", "pmm_en", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, diff --git a/include/asm-i386/cpufeature.h b/include/asm-i386/cpufeature.h index b44bfc6239cb..3ecedbafa8ce 100644 --- a/include/asm-i386/cpufeature.h +++ b/include/asm-i386/cpufeature.h @@ -88,6 +88,12 @@ #define X86_FEATURE_XSTORE_EN (5*32+ 3) /* on-CPU RNG enabled */ #define X86_FEATURE_XCRYPT (5*32+ 6) /* on-CPU crypto (xcrypt insn) */ #define X86_FEATURE_XCRYPT_EN (5*32+ 7) /* on-CPU crypto enabled */ +#define X86_FEATURE_ACE2 (5*32+ 8) /* Advanced Cryptography Engine v2 */ +#define X86_FEATURE_ACE2_EN (5*32+ 9) /* ACE v2 enabled */ +#define X86_FEATURE_PHE (5*32+ 10) /* PadLock Hash Engine */ +#define X86_FEATURE_PHE_EN (5*32+ 11) /* PHE enabled */ +#define X86_FEATURE_PMM (5*32+ 12) /* PadLock Montgomery Multiplier */ +#define X86_FEATURE_PMM_EN (5*32+ 13) /* PMM enabled */ /* More extended AMD flags: CPUID level 0x80000001, ecx, word 6 */ #define X86_FEATURE_LAHF_LM (6*32+ 0) /* LAHF/SAHF in long mode */ @@ -121,6 +127,12 @@ #define cpu_has_xstore_enabled boot_cpu_has(X86_FEATURE_XSTORE_EN) #define cpu_has_xcrypt boot_cpu_has(X86_FEATURE_XCRYPT) #define cpu_has_xcrypt_enabled boot_cpu_has(X86_FEATURE_XCRYPT_EN) +#define cpu_has_ace2 boot_cpu_has(X86_FEATURE_ACE2) +#define cpu_has_ace2_enabled boot_cpu_has(X86_FEATURE_ACE2_EN) +#define cpu_has_phe boot_cpu_has(X86_FEATURE_PHE) +#define cpu_has_phe_enabled boot_cpu_has(X86_FEATURE_PHE_EN) +#define cpu_has_pmm boot_cpu_has(X86_FEATURE_PMM) +#define cpu_has_pmm_enabled boot_cpu_has(X86_FEATURE_PMM_EN) #endif /* __ASM_I386_CPUFEATURE_H */ -- cgit v1.2.3 From 30343d6c3d4e3fe961369e7be19935683e808c88 Mon Sep 17 00:00:00 2001 From: Kirill Smelkov Date: Fri, 23 Jun 2006 02:04:33 -0700 Subject: [PATCH] x86: compile fix for asm-i386/alternatives.h compile fix: needs for 'u8' -- just look at struct alt_instr. My module includes as the first header, and as of 2.6.17 this leads to compilation errors. Signed-off-by: Kirill Smelkov Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-i386/alternative.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/asm-i386/alternative.h b/include/asm-i386/alternative.h index e201decea0c9..d79e9ee10fd7 100644 --- a/include/asm-i386/alternative.h +++ b/include/asm-i386/alternative.h @@ -3,6 +3,8 @@ #ifdef __KERNEL__ +#include + struct alt_instr { u8 *instr; /* original instruction */ u8 *replacement; -- cgit v1.2.3 From ce4ab0012b32c1a4a1d6e934aeb73bf3151c48d9 Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Fri, 23 Jun 2006 02:04:44 -0700 Subject: [PATCH] swsusp: add architecture special saveable pages support 1. Add architecture specific pages save/restore support. Next two patches will use this to save/restore 'ACPI NVS' pages. 2. Allow reserved pages 'nosave'. This could avoid save/restore BIOS reserved pages. Signed-off-by: Shaohua Li Cc: Pavel Machek Cc: "Rafael J. Wysocki" Cc: Nigel Cunningham Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/suspend.h | 1 + kernel/power/power.h | 4 ++ kernel/power/snapshot.c | 110 +++++++++++++++++++++++++++++++++++++++++++++++- kernel/power/swsusp.c | 18 ++------ 4 files changed, 118 insertions(+), 15 deletions(-) (limited to 'include') diff --git a/include/linux/suspend.h b/include/linux/suspend.h index 96e31aa64cc7..e82cb10fb3ea 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -71,6 +71,7 @@ struct saved_context; void __save_processor_state(struct saved_context *ctxt); void __restore_processor_state(struct saved_context *ctxt); unsigned long get_safe_page(gfp_t gfp_mask); +int swsusp_add_arch_pages(unsigned long start, unsigned long end); /* * XXX: We try to keep some more pages free so that I/O operations succeed diff --git a/kernel/power/power.h b/kernel/power/power.h index f06f12f21767..c81f0ed3eeba 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h @@ -105,6 +105,10 @@ extern struct bitmap_page *alloc_bitmap(unsigned int nr_bits); extern unsigned long alloc_swap_page(int swap, struct bitmap_page *bitmap); extern void free_all_swap_pages(int swap, struct bitmap_page *bitmap); +extern unsigned int count_special_pages(void); +extern int save_special_mem(void); +extern int restore_special_mem(void); + extern int swsusp_check(void); extern int swsusp_shrink_memory(void); extern void swsusp_free(void); diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index 3eeedbb13b78..7f511d89c667 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c @@ -39,6 +39,88 @@ static unsigned int nr_copy_pages; static unsigned int nr_meta_pages; static unsigned long *buffer; +struct arch_saveable_page { + unsigned long start; + unsigned long end; + char *data; + struct arch_saveable_page *next; +}; +static struct arch_saveable_page *arch_pages; + +int swsusp_add_arch_pages(unsigned long start, unsigned long end) +{ + struct arch_saveable_page *tmp; + + while (start < end) { + tmp = kzalloc(sizeof(struct arch_saveable_page), GFP_KERNEL); + if (!tmp) + return -ENOMEM; + tmp->start = start; + tmp->end = ((start >> PAGE_SHIFT) + 1) << PAGE_SHIFT; + if (tmp->end > end) + tmp->end = end; + tmp->next = arch_pages; + start = tmp->end; + arch_pages = tmp; + } + return 0; +} + +static unsigned int count_arch_pages(void) +{ + unsigned int count = 0; + struct arch_saveable_page *tmp = arch_pages; + while (tmp) { + count++; + tmp = tmp->next; + } + return count; +} + +static int save_arch_mem(void) +{ + char *kaddr; + struct arch_saveable_page *tmp = arch_pages; + int offset; + + pr_debug("swsusp: Saving arch specific memory"); + while (tmp) { + tmp->data = (char *)__get_free_page(GFP_ATOMIC); + if (!tmp->data) + return -ENOMEM; + offset = tmp->start - (tmp->start & PAGE_MASK); + /* arch pages might haven't a 'struct page' */ + kaddr = kmap_atomic_pfn(tmp->start >> PAGE_SHIFT, KM_USER0); + memcpy(tmp->data + offset, kaddr + offset, + tmp->end - tmp->start); + kunmap_atomic(kaddr, KM_USER0); + + tmp = tmp->next; + } + return 0; +} + +static int restore_arch_mem(void) +{ + char *kaddr; + struct arch_saveable_page *tmp = arch_pages; + int offset; + + while (tmp) { + if (!tmp->data) + continue; + offset = tmp->start - (tmp->start & PAGE_MASK); + kaddr = kmap_atomic_pfn(tmp->start >> PAGE_SHIFT, KM_USER0); + memcpy(kaddr + offset, tmp->data + offset, + tmp->end - tmp->start); + kunmap_atomic(kaddr, KM_USER0); + free_page((long)tmp->data); + tmp->data = NULL; + tmp = tmp->next; + } + return 0; +} + #ifdef CONFIG_HIGHMEM unsigned int count_highmem_pages(void) { @@ -150,8 +232,35 @@ int restore_highmem(void) } return 0; } +#else +static unsigned int count_highmem_pages(void) {return 0;} +static int save_highmem(void) {return 0;} +static int restore_highmem(void) {return 0;} #endif +unsigned int count_special_pages(void) +{ + return count_arch_pages() + count_highmem_pages(); +} + +int save_special_mem(void) +{ + int ret; + ret = save_arch_mem(); + if (!ret) + ret = save_highmem(); + return ret; +} + +int restore_special_mem(void) +{ + int ret; + ret = restore_arch_mem(); + if (!ret) + ret = restore_highmem(); + return ret; +} + static int pfn_is_nosave(unsigned long pfn) { unsigned long nosave_begin_pfn = __pa(&__nosave_begin) >> PAGE_SHIFT; @@ -177,7 +286,6 @@ static int saveable(struct zone *zone, unsigned long *zone_pfn) return 0; page = pfn_to_page(pfn); - BUG_ON(PageReserved(page) && PageNosave(page)); if (PageNosave(page)) return 0; if (PageReserved(page) && pfn_is_nosave(pfn)) diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c index f9238faf76e4..78b6e71b0813 100644 --- a/kernel/power/swsusp.c +++ b/kernel/power/swsusp.c @@ -62,16 +62,6 @@ unsigned long image_size = 500 * 1024 * 1024; int in_suspend __nosavedata = 0; -#ifdef CONFIG_HIGHMEM -unsigned int count_highmem_pages(void); -int save_highmem(void); -int restore_highmem(void); -#else -static int save_highmem(void) { return 0; } -static int restore_highmem(void) { return 0; } -static unsigned int count_highmem_pages(void) { return 0; } -#endif - /** * The following functions are used for tracing the allocated * swap pages, so that they can be freed in case of an error. @@ -192,7 +182,7 @@ int swsusp_shrink_memory(void) printk("Shrinking memory... "); do { - size = 2 * count_highmem_pages(); + size = 2 * count_special_pages(); size += size / 50 + count_data_pages(); size += (size + PBES_PER_PAGE - 1) / PBES_PER_PAGE + PAGES_FOR_IO; @@ -234,7 +224,7 @@ int swsusp_suspend(void) goto Enable_irqs; } - if ((error = save_highmem())) { + if ((error = save_special_mem())) { printk(KERN_ERR "swsusp: Not enough free pages for highmem\n"); goto Restore_highmem; } @@ -245,7 +235,7 @@ int swsusp_suspend(void) /* Restore control flow magically appears here */ restore_processor_state(); Restore_highmem: - restore_highmem(); + restore_special_mem(); device_power_up(); Enable_irqs: local_irq_enable(); @@ -271,7 +261,7 @@ int swsusp_resume(void) */ swsusp_free(); restore_processor_state(); - restore_highmem(); + restore_special_mem(); touch_softlockup_watchdog(); device_power_up(); local_irq_enable(); -- cgit v1.2.3 From 5a232eafedc385249ef1931d186169f9eed2ad93 Mon Sep 17 00:00:00 2001 From: Roman Zippel Date: Fri, 23 Jun 2006 02:04:54 -0700 Subject: [PATCH] m68k: cleanup unistd.h Remove long obsolete kernel syscalls, only execve is still used. Signed-off-by: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-m68k/unistd.h | 39 --------------------------------------- 1 file changed, 39 deletions(-) (limited to 'include') diff --git a/include/asm-m68k/unistd.h b/include/asm-m68k/unistd.h index f236fe92156f..7c0b6296b45c 100644 --- a/include/asm-m68k/unistd.h +++ b/include/asm-m68k/unistd.h @@ -410,46 +410,7 @@ __syscall_return(type,__res); \ #ifdef __KERNEL_SYSCALLS__ -#include -#include -#include - -/* - * we need this inline - forking from kernel space will result - * in NO COPY ON WRITE (!!!), until an execve is executed. This - * is no problem, but for the stack. This is handled by not letting - * main() use the stack at all after fork(). Thus, no function - * calls - which means inline code for fork too, as otherwise we - * would use the stack upon exit from 'fork()'. - * - * Actually only pause and fork are needed inline, so that there - * won't be any messing with the stack from main(), but we define - * some others too. - */ -#define __NR__exit __NR_exit -static inline _syscall0(pid_t,setsid) -static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count) -static inline _syscall3(int,read,int,fd,char *,buf,off_t,count) -static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count) -static inline _syscall1(int,dup,int,fd) static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp) -static inline _syscall3(int,open,const char *,file,int,flag,int,mode) -static inline _syscall1(int,close,int,fd) -static inline _syscall1(int,_exit,int,exitcode) -static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) - -asmlinkage long sys_mmap2( - unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff); -asmlinkage int sys_execve(char *name, char **argv, char **envp); -asmlinkage int sys_pipe(unsigned long *fildes); -struct pt_regs; -struct sigaction; -asmlinkage long sys_rt_sigaction(int sig, - const struct sigaction __user *act, - struct sigaction __user *oact, - size_t sigsetsize); #endif /* __KERNEL_SYSCALLS__ */ -- cgit v1.2.3 From 98317f1271e7fd472983b013c76df6cc15fbef22 Mon Sep 17 00:00:00 2001 From: Roman Zippel Date: Fri, 23 Jun 2006 02:04:54 -0700 Subject: [PATCH] m68k: Remove some unused definitions in zorro.h These definitions have long been superseded by asm-offsets.h Signed-off-by: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/zorro.h | 42 ------------------------------------------ 1 file changed, 42 deletions(-) (limited to 'include') diff --git a/include/linux/zorro.h b/include/linux/zorro.h index 2f135cf6eef1..913bfc226dda 100644 --- a/include/linux/zorro.h +++ b/include/linux/zorro.h @@ -11,8 +11,6 @@ #ifndef _LINUX_ZORRO_H #define _LINUX_ZORRO_H -#ifndef __ASSEMBLY__ - #include @@ -112,45 +110,6 @@ struct ConfigDev { __u32 cd_Unused[4]; /* for whatever the driver wants */ } __attribute__ ((packed)); -#else /* __ASSEMBLY__ */ - -LN_Succ = 0 -LN_Pred = LN_Succ+4 -LN_Type = LN_Pred+4 -LN_Pri = LN_Type+1 -LN_Name = LN_Pri+1 -LN_sizeof = LN_Name+4 - -ER_Type = 0 -ER_Product = ER_Type+1 -ER_Flags = ER_Product+1 -ER_Reserved03 = ER_Flags+1 -ER_Manufacturer = ER_Reserved03+1 -ER_SerialNumber = ER_Manufacturer+2 -ER_InitDiagVec = ER_SerialNumber+4 -ER_Reserved0c = ER_InitDiagVec+2 -ER_Reserved0d = ER_Reserved0c+1 -ER_Reserved0e = ER_Reserved0d+1 -ER_Reserved0f = ER_Reserved0e+1 -ER_sizeof = ER_Reserved0f+1 - -CD_Node = 0 -CD_Flags = CD_Node+LN_sizeof -CD_Pad = CD_Flags+1 -CD_Rom = CD_Pad+1 -CD_BoardAddr = CD_Rom+ER_sizeof -CD_BoardSize = CD_BoardAddr+4 -CD_SlotAddr = CD_BoardSize+4 -CD_SlotSize = CD_SlotAddr+2 -CD_Driver = CD_SlotSize+2 -CD_NextCD = CD_Driver+4 -CD_Unused = CD_NextCD+4 -CD_sizeof = CD_Unused+(4*4) - -#endif /* __ASSEMBLY__ */ - -#ifndef __ASSEMBLY__ - #define ZORRO_NUM_AUTO 16 #ifdef __KERNEL__ @@ -290,7 +249,6 @@ extern DECLARE_BITMAP(zorro_unused_z2ram, 128); #define Z2RAM_CHUNKSHIFT (16) -#endif /* !__ASSEMBLY__ */ #endif /* __KERNEL__ */ #endif /* _LINUX_ZORRO_H */ -- cgit v1.2.3 From f6c4192e77dffbc50ee1b9a24a1063ff961aaf04 Mon Sep 17 00:00:00 2001 From: Roman Zippel Date: Fri, 23 Jun 2006 02:04:55 -0700 Subject: [PATCH] m68k: use c99 initializer Signed-off-by: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-m68k/processor.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/asm-m68k/processor.h b/include/asm-m68k/processor.h index 352799e71f08..8455f778b601 100644 --- a/include/asm-m68k/processor.h +++ b/include/asm-m68k/processor.h @@ -71,10 +71,10 @@ struct thread_struct { }; #define INIT_THREAD { \ - ksp: sizeof(init_stack) + (unsigned long) init_stack, \ - sr: PS_S, \ - fs: __KERNEL_DS, \ - info: INIT_THREAD_INFO(init_task) \ + .ksp = sizeof(init_stack) + (unsigned long) init_stack, \ + .sr = PS_S, \ + .fs = __KERNEL_DS, \ + .info = INIT_THREAD_INFO(init_task), \ } /* -- cgit v1.2.3 From d94af931af42152e34539dd4782b1724084a89fb Mon Sep 17 00:00:00 2001 From: Roman Zippel Date: Fri, 23 Jun 2006 02:05:00 -0700 Subject: [PATCH] m68k: clean up uaccess.h This uninlines a few large functions in uaccess.h and cleans up the rest. It includes a (hopefully temporary) workaround for the broken typeof of gcc-4.1. Signed-off-by: Roman Zippel Cc: Geert Uytterhoeven Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/m68k/lib/Makefile | 4 +- arch/m68k/lib/uaccess.c | 222 +++++++++ include/asm-m68k/uaccess.h | 1084 +++++++++++--------------------------------- 3 files changed, 495 insertions(+), 815 deletions(-) create mode 100644 arch/m68k/lib/uaccess.c (limited to 'include') diff --git a/arch/m68k/lib/Makefile b/arch/m68k/lib/Makefile index ebe51a513817..6bbf19f96007 100644 --- a/arch/m68k/lib/Makefile +++ b/arch/m68k/lib/Makefile @@ -4,5 +4,5 @@ EXTRA_AFLAGS := -traditional -lib-y := ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \ - checksum.o string.o semaphore.o +lib-y := ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \ + checksum.o string.o semaphore.o uaccess.o diff --git a/arch/m68k/lib/uaccess.c b/arch/m68k/lib/uaccess.c new file mode 100644 index 000000000000..1bc188c0d983 --- /dev/null +++ b/arch/m68k/lib/uaccess.c @@ -0,0 +1,222 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#include +#include + +unsigned long __generic_copy_from_user(void *to, const void __user *from, + unsigned long n) +{ + unsigned long tmp, res; + + asm volatile ("\n" + " tst.l %0\n" + " jeq 2f\n" + "1: moves.l (%1)+,%3\n" + " move.l %3,(%2)+\n" + " subq.l #1,%0\n" + " jne 1b\n" + "2: btst #1,%5\n" + " jeq 4f\n" + "3: moves.w (%1)+,%3\n" + " move.w %3,(%2)+\n" + "4: btst #0,%5\n" + " jeq 6f\n" + "5: moves.b (%1)+,%3\n" + " move.b %3,(%2)+\n" + "6:\n" + " .section .fixup,\"ax\"\n" + " .even\n" + "10: move.l %0,%3\n" + "7: clr.l (%2)+\n" + " subq.l #1,%3\n" + " jne 7b\n" + " lsl.l #2,%0\n" + " btst #1,%5\n" + " jeq 8f\n" + "30: clr.w (%2)+\n" + " addq.l #2,%0\n" + "8: btst #0,%5\n" + " jeq 6b\n" + "50: clr.b (%2)+\n" + " addq.l #1,%0\n" + " jra 6b\n" + " .previous\n" + "\n" + " .section __ex_table,\"a\"\n" + " .align 4\n" + " .long 1b,10b\n" + " .long 3b,30b\n" + " .long 5b,50b\n" + " .previous" + : "=d" (res), "+a" (from), "+a" (to), "=&r" (tmp) + : "0" (n / 4), "d" (n & 3)); + + return res; +} +EXPORT_SYMBOL(__generic_copy_from_user); + +unsigned long __generic_copy_to_user(void __user *to, const void *from, + unsigned long n) +{ + unsigned long tmp, res; + + asm volatile ("\n" + " tst.l %0\n" + " jeq 4f\n" + "1: move.l (%1)+,%3\n" + "2: moves.l %3,(%2)+\n" + "3: subq.l #1,%0\n" + " jne 1b\n" + "4: btst #1,%5\n" + " jeq 6f\n" + " move.w (%1)+,%3\n" + "5: moves.w %3,(%2)+\n" + "6: btst #0,%5\n" + " jeq 8f\n" + " move.b (%1)+,%3\n" + "7: moves.b %3,(%2)+\n" + "8:\n" + " .section .fixup,\"ax\"\n" + " .even\n" + "20: lsl.l #2,%0\n" + "50: add.l %5,%0\n" + " jra 7b\n" + " .previous\n" + "\n" + " .section __ex_table,\"a\"\n" + " .align 4\n" + " .long 2b,20b\n" + " .long 3b,20b\n" + " .long 5b,50b\n" + " .long 6b,50b\n" + " .long 7b,50b\n" + " .long 8b,50b\n" + " .previous" + : "=d" (res), "+a" (from), "+a" (to), "=&r" (tmp) + : "0" (n / 4), "d" (n & 3)); + + return res; +} +EXPORT_SYMBOL(__generic_copy_to_user); + +/* + * Copy a null terminated string from userspace. + */ +long strncpy_from_user(char *dst, const char __user *src, long count) +{ + long res; + char c; + + if (count <= 0) + return count; + + asm volatile ("\n" + "1: moves.b (%2)+,%4\n" + " move.b %4,(%1)+\n" + " jeq 2f\n" + " subq.l #1,%3\n" + " jne 1b\n" + "2: sub.l %3,%0\n" + "3:\n" + " .section .fixup,\"ax\"\n" + " .even\n" + "10: move.l %5,%0\n" + " jra 3b\n" + " .previous\n" + "\n" + " .section __ex_table,\"a\"\n" + " .align 4\n" + " .long 1b,10b\n" + " .previous" + : "=d" (res), "+a" (dst), "+a" (src), "+r" (count), "=&d" (c) + : "i" (-EFAULT), "0" (count)); + + return res; +} +EXPORT_SYMBOL(strncpy_from_user); + +/* + * Return the size of a string (including the ending 0) + * + * Return 0 on exception, a value greater than N if too long + */ +long strnlen_user(const char __user *src, long n) +{ + char c; + long res; + + asm volatile ("\n" + "1: subq.l #1,%1\n" + " jmi 3f\n" + "2: moves.b (%0)+,%2\n" + " tst.b %2\n" + " jne 1b\n" + " jra 4f\n" + "\n" + "3: addq.l #1,%0\n" + "4: sub.l %4,%0\n" + "5:\n" + " .section .fixup,\"ax\"\n" + " .even\n" + "20: sub.l %0,%0\n" + " jra 5b\n" + " .previous\n" + "\n" + " .section __ex_table,\"a\"\n" + " .align 4\n" + " .long 2b,20b\n" + " .previous\n" + : "=&a" (res), "+d" (n), "=&d" (c) + : "0" (src), "r" (src)); + + return res; +} +EXPORT_SYMBOL(strnlen_user); + +/* + * Zero Userspace + */ + +unsigned long clear_user(void __user *to, unsigned long n) +{ + unsigned long res; + + asm volatile ("\n" + " tst.l %0\n" + " jeq 3f\n" + "1: moves.l %2,(%1)+\n" + "2: subq.l #1,%0\n" + " jne 1b\n" + "3: btst #1,%4\n" + " jeq 5f\n" + "4: moves.w %2,(%1)+\n" + "5: btst #0,%4\n" + " jeq 7f\n" + "6: moves.b %2,(%1)\n" + "7:\n" + " .section .fixup,\"ax\"\n" + " .even\n" + "10: lsl.l #2,%0\n" + "40: add.l %4,%0\n" + " jra 7b\n" + " .previous\n" + "\n" + " .section __ex_table,\"a\"\n" + " .align 4\n" + " .long 1b,10b\n" + " .long 2b,10b\n" + " .long 4b,40b\n" + " .long 5b,40b\n" + " .long 6b,40b\n" + " .long 7b,40b\n" + " .previous" + : "=d" (res), "+a" (to) + : "r" (0), "0" (n / 4), "d" (n & 3)); + + return res; +} +EXPORT_SYMBOL(clear_user); diff --git a/include/asm-m68k/uaccess.h b/include/asm-m68k/uaccess.h index 2ffd87b0a769..b761ef218cea 100644 --- a/include/asm-m68k/uaccess.h +++ b/include/asm-m68k/uaccess.h @@ -4,8 +4,9 @@ /* * User space memory access functions */ +#include #include -#include +#include #include #define VERIFY_READ 0 @@ -32,858 +33,315 @@ struct exception_table_entry unsigned long insn, fixup; }; +extern int __put_user_bad(void); +extern int __get_user_bad(void); + +#define __put_user_asm(res, x, ptr, bwl, reg, err) \ +asm volatile ("\n" \ + "1: moves."#bwl" %2,%1\n" \ + "2:\n" \ + " .section .fixup,\"ax\"\n" \ + " .even\n" \ + "10: moveq.l %3,%0\n" \ + " jra 2b\n" \ + " .previous\n" \ + "\n" \ + " .section __ex_table,\"a\"\n" \ + " .align 4\n" \ + " .long 1b,10b\n" \ + " .long 2b,10b\n" \ + " .previous" \ + : "+d" (res), "=m" (*(ptr)) \ + : #reg (x), "i" (err)) /* * These are the main single-value transfer routines. They automatically * use the right size if we just have the right pointer type. */ -#define put_user(x, ptr) \ -({ \ - int __pu_err; \ - typeof(*(ptr)) __pu_val = (x); \ - __chk_user_ptr(ptr); \ - switch (sizeof (*(ptr))) { \ - case 1: \ - __put_user_asm(__pu_err, __pu_val, ptr, b); \ - break; \ - case 2: \ - __put_user_asm(__pu_err, __pu_val, ptr, w); \ - break; \ - case 4: \ - __put_user_asm(__pu_err, __pu_val, ptr, l); \ - break; \ - case 8: \ - __pu_err = __constant_copy_to_user(ptr, &__pu_val, 8); \ - break; \ - default: \ - __pu_err = __put_user_bad(); \ - break; \ - } \ - __pu_err; \ +#define __put_user(x, ptr) \ +({ \ + typeof(*(ptr)) __pu_val = (x); \ + int __pu_err = 0; \ + __chk_user_ptr(ptr); \ + switch (sizeof (*(ptr))) { \ + case 1: \ + __put_user_asm(__pu_err, __pu_val, ptr, b, d, -EFAULT); \ + break; \ + case 2: \ + __put_user_asm(__pu_err, __pu_val, ptr, w, d, -EFAULT); \ + break; \ + case 4: \ + __put_user_asm(__pu_err, __pu_val, ptr, l, r, -EFAULT); \ + break; \ + case 8: \ + { \ + const void *__pu_ptr = (ptr); \ + asm volatile ("\n" \ + "1: moves.l %2,(%1)+\n" \ + "2: moves.l %R2,(%1)\n" \ + "3:\n" \ + " .section .fixup,\"ax\"\n" \ + " .even\n" \ + "10: movel %3,%0\n" \ + " jra 3b\n" \ + " .previous\n" \ + "\n" \ + " .section __ex_table,\"a\"\n" \ + " .align 4\n" \ + " .long 1b,10b\n" \ + " .long 2b,10b\n" \ + " .long 3b,10b\n" \ + " .previous" \ + : "+d" (__pu_err), "+a" (__pu_ptr) \ + : "r" (__pu_val), "i" (-EFAULT) \ + : "memory"); \ + break; \ + } \ + default: \ + __pu_err = __put_user_bad(); \ + break; \ + } \ + __pu_err; \ }) -#define __put_user(x, ptr) put_user(x, ptr) +#define put_user(x, ptr) __put_user(x, ptr) -extern int __put_user_bad(void); -/* - * Tell gcc we read from memory instead of writing: this is because - * we do not write to any memory gcc knows about, so there are no - * aliasing issues. - */ -#define __put_user_asm(err,x,ptr,bwl) \ -__asm__ __volatile__ \ - ("21:moves" #bwl " %2,%1\n" \ - "1:\n" \ - ".section .fixup,\"ax\"\n" \ - " .even\n" \ - "2: movel %3,%0\n" \ - " jra 1b\n" \ - ".previous\n" \ - ".section __ex_table,\"a\"\n" \ - " .align 4\n" \ - " .long 21b,2b\n" \ - " .long 1b,2b\n" \ - ".previous" \ - : "=d"(err) \ - : "m"(*(ptr)), "r"(x), "i"(-EFAULT), "0"(0)) - -#define get_user(x, ptr) \ -({ \ - int __gu_err; \ - typeof(*(ptr)) __gu_val; \ - __chk_user_ptr(ptr); \ - switch (sizeof(*(ptr))) { \ - case 1: \ - __get_user_asm(__gu_err, __gu_val, ptr, b, "=d"); \ - break; \ - case 2: \ - __get_user_asm(__gu_err, __gu_val, ptr, w, "=r"); \ - break; \ - case 4: \ - __get_user_asm(__gu_err, __gu_val, ptr, l, "=r"); \ - break; \ - case 8: \ - __gu_err = __constant_copy_from_user(&__gu_val, ptr, 8); \ - break; \ - default: \ - __gu_val = (typeof(*(ptr)))0; \ - __gu_err = __get_user_bad(); \ - break; \ - } \ - (x) = __gu_val; \ - __gu_err; \ +#define __get_user_asm(res, x, ptr, type, bwl, reg, err) ({ \ + type __gu_val; \ + asm volatile ("\n" \ + "1: moves."#bwl" %2,%1\n" \ + "2:\n" \ + " .section .fixup,\"ax\"\n" \ + " .even\n" \ + "10: move.l %3,%0\n" \ + " sub."#bwl" %1,%1\n" \ + " jra 2b\n" \ + " .previous\n" \ + "\n" \ + " .section __ex_table,\"a\"\n" \ + " .align 4\n" \ + " .long 1b,10b\n" \ + " .previous" \ + : "+d" (res), "=&" #reg (__gu_val) \ + : "m" (*(ptr)), "i" (err)); \ + (x) = (typeof(*(ptr)))(long)__gu_val; \ }) -#define __get_user(x, ptr) get_user(x, ptr) -extern int __get_user_bad(void); +#define __get_user(x, ptr) \ +({ \ + int __gu_err = 0; \ + __chk_user_ptr(ptr); \ + switch (sizeof(*(ptr))) { \ + case 1: \ + __get_user_asm(__gu_err, x, ptr, u8, b, d, -EFAULT); \ + break; \ + case 2: \ + __get_user_asm(__gu_err, x, ptr, u16, w, d, -EFAULT); \ + break; \ + case 4: \ + __get_user_asm(__gu_err, x, ptr, u32, l, r, -EFAULT); \ + break; \ +/* case 8: disabled because gcc-4.1 has a broken typeof \ + { \ + const void *__gu_ptr = (ptr); \ + u64 __gu_val; \ + asm volatile ("\n" \ + "1: moves.l (%2)+,%1\n" \ + "2: moves.l (%2),%R1\n" \ + "3:\n" \ + " .section .fixup,\"ax\"\n" \ + " .even\n" \ + "10: move.l %3,%0\n" \ + " sub.l %1,%1\n" \ + " sub.l %R1,%R1\n" \ + " jra 3b\n" \ + " .previous\n" \ + "\n" \ + " .section __ex_table,\"a\"\n" \ + " .align 4\n" \ + " .long 1b,10b\n" \ + " .long 2b,10b\n" \ + " .previous" \ + : "+d" (__gu_err), "=&r" (__gu_val), \ + "+a" (__gu_ptr) \ + : "i" (-EFAULT) \ + : "memory"); \ + (x) = (typeof(*(ptr)))__gu_val; \ + break; \ + } */ \ + default: \ + __gu_err = __get_user_bad(); \ + break; \ + } \ + __gu_err; \ +}) +#define get_user(x, ptr) __get_user(x, ptr) -#define __get_user_asm(err,x,ptr,bwl,reg) \ -__asm__ __volatile__ \ - ("1: moves" #bwl " %2,%1\n" \ - "2:\n" \ - ".section .fixup,\"ax\"\n" \ - " .even\n" \ - "3: movel %3,%0\n" \ - " sub" #bwl " %1,%1\n" \ - " jra 2b\n" \ - ".previous\n" \ - ".section __ex_table,\"a\"\n" \ - " .align 4\n" \ - " .long 1b,3b\n" \ - ".previous" \ - : "=d"(err), reg(x) \ - : "m"(*(ptr)), "i" (-EFAULT), "0"(0)) +unsigned long __generic_copy_from_user(void *to, const void __user *from, unsigned long n); +unsigned long __generic_copy_to_user(void __user *to, const void *from, unsigned long n); -static inline unsigned long -__generic_copy_from_user(void *to, const void __user *from, unsigned long n) -{ - unsigned long tmp; - __asm__ __volatile__ - (" tstl %2\n" - " jeq 2f\n" - "1: movesl (%1)+,%3\n" - " movel %3,(%0)+\n" - " subql #1,%2\n" - " jne 1b\n" - "2: movel %4,%2\n" - " bclr #1,%2\n" - " jeq 4f\n" - "3: movesw (%1)+,%3\n" - " movew %3,(%0)+\n" - "4: bclr #0,%2\n" - " jeq 6f\n" - "5: movesb (%1)+,%3\n" - " moveb %3,(%0)+\n" - "6:\n" - ".section .fixup,\"ax\"\n" - " .even\n" - "7: movel %2,%%d0\n" - "71:clrl (%0)+\n" - " subql #1,%%d0\n" - " jne 71b\n" - " lsll #2,%2\n" - " addl %4,%2\n" - " btst #1,%4\n" - " jne 81f\n" - " btst #0,%4\n" - " jne 91f\n" - " jra 6b\n" - "8: addql #2,%2\n" - "81:clrw (%0)+\n" - " btst #0,%4\n" - " jne 91f\n" - " jra 6b\n" - "9: addql #1,%2\n" - "91:clrb (%0)+\n" - " jra 6b\n" - ".previous\n" - ".section __ex_table,\"a\"\n" - " .align 4\n" - " .long 1b,7b\n" - " .long 3b,8b\n" - " .long 5b,9b\n" - ".previous" - : "=a"(to), "=a"(from), "=d"(n), "=&d"(tmp) - : "d"(n & 3), "0"(to), "1"(from), "2"(n/4) - : "d0", "memory"); - return n; -} - -static inline unsigned long -__generic_copy_to_user(void __user *to, const void *from, unsigned long n) +static __always_inline unsigned long +__constant_copy_from_user(void *to, const void __user *from, unsigned long n) { - unsigned long tmp; - __asm__ __volatile__ - (" tstl %2\n" - " jeq 3f\n" - "1: movel (%1)+,%3\n" - "22:movesl %3,(%0)+\n" - "2: subql #1,%2\n" - " jne 1b\n" - "3: movel %4,%2\n" - " bclr #1,%2\n" - " jeq 4f\n" - " movew (%1)+,%3\n" - "24:movesw %3,(%0)+\n" - "4: bclr #0,%2\n" - " jeq 5f\n" - " moveb (%1)+,%3\n" - "25:movesb %3,(%0)+\n" - "5:\n" - ".section .fixup,\"ax\"\n" - " .even\n" - "60:addql #1,%2\n" - "6: lsll #2,%2\n" - " addl %4,%2\n" - " jra 5b\n" - "7: addql #2,%2\n" - " jra 5b\n" - "8: addql #1,%2\n" - " jra 5b\n" - ".previous\n" - ".section __ex_table,\"a\"\n" - " .align 4\n" - " .long 1b,60b\n" - " .long 22b,6b\n" - " .long 2b,6b\n" - " .long 24b,7b\n" - " .long 3b,60b\n" - " .long 4b,7b\n" - " .long 25b,8b\n" - " .long 5b,8b\n" - ".previous" - : "=a"(to), "=a"(from), "=d"(n), "=&d"(tmp) - : "r"(n & 3), "0"(to), "1"(from), "2"(n / 4) - : "memory"); - return n; -} + unsigned long res = 0, tmp; -#define __copy_from_user_big(to, from, n, fixup, copy) \ - __asm__ __volatile__ \ - ("10: movesl (%1)+,%%d0\n" \ - " movel %%d0,(%0)+\n" \ - " subql #1,%2\n" \ - " jne 10b\n" \ - ".section .fixup,\"ax\"\n" \ - " .even\n" \ - "11: movel %2,%%d0\n" \ - "13: clrl (%0)+\n" \ - " subql #1,%%d0\n" \ - " jne 13b\n" \ - " lsll #2,%2\n" \ - fixup "\n" \ - " jra 12f\n" \ - ".previous\n" \ - ".section __ex_table,\"a\"\n" \ - " .align 4\n" \ - " .long 10b,11b\n" \ - ".previous\n" \ - copy "\n" \ - "12:" \ - : "=a"(to), "=a"(from), "=d"(n) \ - : "0"(to), "1"(from), "2"(n/4) \ - : "d0", "memory") + /* limit the inlined version to 3 moves */ + if (n == 11 || n > 12) + return __generic_copy_from_user(to, from, n); -static inline unsigned long -__constant_copy_from_user(void *to, const void __user *from, unsigned long n) -{ - switch (n) { - case 0: - break; - case 1: - __asm__ __volatile__ - ("1: movesb (%1)+,%%d0\n" - " moveb %%d0,(%0)+\n" - "2:\n" - ".section .fixup,\"ax\"\n" - " .even\n" - "3: addql #1,%2\n" - " clrb (%0)+\n" - " jra 2b\n" - ".previous\n" - ".section __ex_table,\"a\"\n" - " .align 4\n" - " .long 1b,3b\n" - ".previous" - : "=a"(to), "=a"(from), "=d"(n) - : "0"(to), "1"(from), "2"(0) - : "d0", "memory"); - break; - case 2: - __asm__ __volatile__ - ("1: movesw (%1)+,%%d0\n" - " movew %%d0,(%0)+\n" - "2:\n" - ".section .fixup,\"ax\"\n" - " .even\n" - "3: addql #2,%2\n" - " clrw (%0)+\n" - " jra 2b\n" - ".previous\n" - ".section __ex_table,\"a\"\n" - " .align 4\n" - " .long 1b,3b\n" - ".previous" - : "=a"(to), "=a"(from), "=d"(n) - : "0"(to), "1"(from), "2"(0) - : "d0", "memory"); - break; - case 3: - __asm__ __volatile__ - ("1: movesw (%1)+,%%d0\n" - " movew %%d0,(%0)+\n" - "2: movesb (%1)+,%%d0\n" - " moveb %%d0,(%0)+\n" - "3:" - ".section .fixup,\"ax\"\n" - " .even\n" - "4: addql #2,%2\n" - " clrw (%0)+\n" - "5: addql #1,%2\n" - " clrb (%0)+\n" - " jra 3b\n" - ".previous\n" - ".section __ex_table,\"a\"\n" - " .align 4\n" - " .long 1b,4b\n" - " .long 2b,5b\n" - ".previous" - : "=a"(to), "=a"(from), "=d"(n) - : "0"(to), "1"(from), "2"(0) - : "d0", "memory"); - break; - case 4: - __asm__ __volatile__ - ("1: movesl (%1)+,%%d0\n" - " movel %%d0,(%0)+\n" - "2:" - ".section .fixup,\"ax\"\n" - " .even\n" - "3: addql #4,%2\n" - " clrl (%0)+\n" - " jra 2b\n" - ".previous\n" - ".section __ex_table,\"a\"\n" - " .align 4\n" - " .long 1b,3b\n" - ".previous" - : "=a"(to), "=a"(from), "=d"(n) - : "0"(to), "1"(from), "2"(0) - : "d0", "memory"); - break; - case 8: - __asm__ __volatile__ - ("1: movesl (%1)+,%%d0\n" - " movel %%d0,(%0)+\n" - "2: movesl (%1)+,%%d0\n" - " movel %%d0,(%0)+\n" - "3:" - ".section .fixup,\"ax\"\n" - " .even\n" - "4: addql #4,%2\n" - " clrl (%0)+\n" - "5: addql #4,%2\n" - " clrl (%0)+\n" - " jra 3b\n" - ".previous\n" - ".section __ex_table,\"a\"\n" - " .align 4\n" - " .long 1b,4b\n" - " .long 2b,5b\n" - ".previous" - : "=a"(to), "=a"(from), "=d"(n) - : "0"(to), "1"(from), "2"(0) - : "d0", "memory"); - break; - case 12: - __asm__ __volatile__ - ("1: movesl (%1)+,%%d0\n" - " movel %%d0,(%0)+\n" - "2: movesl (%1)+,%%d0\n" - " movel %%d0,(%0)+\n" - "3: movesl (%1)+,%%d0\n" - " movel %%d0,(%0)+\n" - "4:" - ".section .fixup,\"ax\"\n" - " .even\n" - "5: addql #4,%2\n" - " clrl (%0)+\n" - "6: addql #4,%2\n" - " clrl (%0)+\n" - "7: addql #4,%2\n" - " clrl (%0)+\n" - " jra 4b\n" - ".previous\n" - ".section __ex_table,\"a\"\n" - " .align 4\n" - " .long 1b,5b\n" - " .long 2b,6b\n" - " .long 3b,7b\n" - ".previous" - : "=a"(to), "=a"(from), "=d"(n) - : "0"(to), "1"(from), "2"(0) - : "d0", "memory"); - break; - case 16: - __asm__ __volatile__ - ("1: movesl (%1)+,%%d0\n" - " movel %%d0,(%0)+\n" - "2: movesl (%1)+,%%d0\n" - " movel %%d0,(%0)+\n" - "3: movesl (%1)+,%%d0\n" - " movel %%d0,(%0)+\n" - "4: movesl (%1)+,%%d0\n" - " movel %%d0,(%0)+\n" - "5:" - ".section .fixup,\"ax\"\n" - " .even\n" - "6: addql #4,%2\n" - " clrl (%0)+\n" - "7: addql #4,%2\n" - " clrl (%0)+\n" - "8: addql #4,%2\n" - " clrl (%0)+\n" - "9: addql #4,%2\n" - " clrl (%0)+\n" - " jra 5b\n" - ".previous\n" - ".section __ex_table,\"a\"\n" - " .align 4\n" - " .long 1b,6b\n" - " .long 2b,7b\n" - " .long 3b,8b\n" - " .long 4b,9b\n" - ".previous" - : "=a"(to), "=a"(from), "=d"(n) - : "0"(to), "1"(from), "2"(0) - : "d0", "memory"); - break; - default: - switch (n & 3) { - case 0: - __copy_from_user_big(to, from, n, "", ""); - break; + switch (n) { case 1: - __copy_from_user_big(to, from, n, - /* fixup */ - "1: addql #1,%2\n" - " clrb (%0)+", - /* copy */ - "2: movesb (%1)+,%%d0\n" - " moveb %%d0,(%0)+\n" - ".section __ex_table,\"a\"\n" - " .long 2b,1b\n" - ".previous"); - break; + __get_user_asm(res, *(u8 *)to, (u8 *)from, u8, b, d, 1); + return res; case 2: - __copy_from_user_big(to, from, n, - /* fixup */ - "1: addql #2,%2\n" - " clrw (%0)+", - /* copy */ - "2: movesw (%1)+,%%d0\n" - " movew %%d0,(%0)+\n" - ".section __ex_table,\"a\"\n" - " .long 2b,1b\n" - ".previous"); - break; - case 3: - __copy_from_user_big(to, from, n, - /* fixup */ - "1: addql #2,%2\n" - " clrw (%0)+\n" - "2: addql #1,%2\n" - " clrb (%0)+", - /* copy */ - "3: movesw (%1)+,%%d0\n" - " movew %%d0,(%0)+\n" - "4: movesb (%1)+,%%d0\n" - " moveb %%d0,(%0)+\n" - ".section __ex_table,\"a\"\n" - " .long 3b,1b\n" - " .long 4b,2b\n" - ".previous"); - break; + __get_user_asm(res, *(u16 *)to, (u16 *)from, u16, w, d, 2); + return res; + case 4: + __get_user_asm(res, *(u32 *)to, (u32 *)from, u32, l, r, 4); + return res; } - break; - } - return n; -} -#define __copy_to_user_big(to, from, n, fixup, copy) \ - __asm__ __volatile__ \ - ("10: movel (%1)+,%%d0\n" \ - "31: movesl %%d0,(%0)+\n" \ - "11: subql #1,%2\n" \ - " jne 10b\n" \ - "41:\n" \ - ".section .fixup,\"ax\"\n" \ - " .even\n" \ - "22: addql #1,%2\n" \ - "12: lsll #2,%2\n" \ - fixup "\n" \ - " jra 13f\n" \ - ".previous\n" \ - ".section __ex_table,\"a\"\n" \ - " .align 4\n" \ - " .long 10b,22b\n" \ - " .long 31b,12b\n" \ - " .long 11b,12b\n" \ - " .long 41b,22b\n" \ - ".previous\n" \ - copy "\n" \ - "13:" \ - : "=a"(to), "=a"(from), "=d"(n) \ - : "0"(to), "1"(from), "2"(n/4) \ - : "d0", "memory") + asm volatile ("\n" + " .ifndef .Lfrom_user\n" + " .set .Lfrom_user,1\n" + " .macro copy_from_user to,from,tmp\n" + " .if .Lcnt >= 4\n" + "1: moves.l (\\from)+,\\tmp\n" + " move.l \\tmp,(\\to)+\n" + " .set .Lcnt,.Lcnt-4\n" + " .elseif .Lcnt & 2\n" + "1: moves.w (\\from)+,\\tmp\n" + " move.w \\tmp,(\\to)+\n" + " .set .Lcnt,.Lcnt-2\n" + " .elseif .Lcnt & 1\n" + "1: moves.b (\\from)+,\\tmp\n" + " move.b \\tmp,(\\to)+\n" + " .set .Lcnt,.Lcnt-1\n" + " .else\n" + " .exitm\n" + " .endif\n" + "\n" + " .section __ex_table,\"a\"\n" + " .align 4\n" + " .long 1b,3f\n" + " .previous\n" + " .endm\n" + " .endif\n" + "\n" + " .set .Lcnt,%c4\n" + " copy_from_user %1,%2,%3\n" + " copy_from_user %1,%2,%3\n" + " copy_from_user %1,%2,%3\n" + "2:\n" + " .section .fixup,\"ax\"\n" + " .even\n" + "3: moveq.l %4,%0\n" + " move.l %5,%1\n" + " .rept %c4 / 4\n" + " clr.l (%1)+\n" + " .endr\n" + " .if %c4 & 2\n" + " clr.w (%1)+\n" + " .endif\n" + " .if %c4 & 1\n" + " clr.b (%1)+\n" + " .endif\n" + " jra 2b\n" + " .previous\n" + : "+r" (res), "+a" (to), "+a" (from), "=&d" (tmp) + : "i" (n), "g" (to) + : "memory"); -#define __copy_to_user_inatomic __copy_to_user -#define __copy_from_user_inatomic __copy_from_user + return res; +} -static inline unsigned long +static __always_inline unsigned long __constant_copy_to_user(void __user *to, const void *from, unsigned long n) { - switch (n) { - case 0: - break; - case 1: - __asm__ __volatile__ - (" moveb (%1)+,%%d0\n" - "21:movesb %%d0,(%0)+\n" - "1:\n" - ".section .fixup,\"ax\"\n" - " .even\n" - "2: addql #1,%2\n" - " jra 1b\n" - ".previous\n" - ".section __ex_table,\"a\"\n" - " .align 4\n " - " .long 21b,2b\n" - " .long 1b,2b\n" - ".previous" - : "=a"(to), "=a"(from), "=d"(n) - : "0"(to), "1"(from), "2"(0) - : "d0", "memory"); - break; - case 2: - __asm__ __volatile__ - (" movew (%1)+,%%d0\n" - "21:movesw %%d0,(%0)+\n" - "1:\n" - ".section .fixup,\"ax\"\n" - " .even\n" - "2: addql #2,%2\n" - " jra 1b\n" - ".previous\n" - ".section __ex_table,\"a\"\n" - " .align 4\n" - " .long 21b,2b\n" - " .long 1b,2b\n" - ".previous" - : "=a"(to), "=a"(from), "=d"(n) - : "0"(to), "1"(from), "2"(0) - : "d0", "memory"); - break; - case 3: - __asm__ __volatile__ - (" movew (%1)+,%%d0\n" - "21:movesw %%d0,(%0)+\n" - "1: moveb (%1)+,%%d0\n" - "22:movesb %%d0,(%0)+\n" - "2:\n" - ".section .fixup,\"ax\"\n" - " .even\n" - "3: addql #2,%2\n" - "4: addql #1,%2\n" - " jra 2b\n" - ".previous\n" - ".section __ex_table,\"a\"\n" - " .align 4\n" - " .long 21b,3b\n" - " .long 1b,3b\n" - " .long 22b,4b\n" - " .long 2b,4b\n" - ".previous" - : "=a"(to), "=a"(from), "=d"(n) - : "0"(to), "1"(from), "2"(0) - : "d0", "memory"); - break; - case 4: - __asm__ __volatile__ - (" movel (%1)+,%%d0\n" - "21:movesl %%d0,(%0)+\n" - "1:\n" - ".section .fixup,\"ax\"\n" - " .even\n" - "2: addql #4,%2\n" - " jra 1b\n" - ".previous\n" - ".section __ex_table,\"a\"\n" - " .align 4\n" - " .long 21b,2b\n" - " .long 1b,2b\n" - ".previous" - : "=a"(to), "=a"(from), "=d"(n) - : "0"(to), "1"(from), "2"(0) - : "d0", "memory"); - break; - case 8: - __asm__ __volatile__ - (" movel (%1)+,%%d0\n" - "21:movesl %%d0,(%0)+\n" - "1: movel (%1)+,%%d0\n" - "22:movesl %%d0,(%0)+\n" - "2:\n" - ".section .fixup,\"ax\"\n" - " .even\n" - "3: addql #4,%2\n" - "4: addql #4,%2\n" - " jra 2b\n" - ".previous\n" - ".section __ex_table,\"a\"\n" - " .align 4\n" - " .long 21b,3b\n" - " .long 1b,3b\n" - " .long 22b,4b\n" - " .long 2b,4b\n" - ".previous" - : "=a"(to), "=a"(from), "=d"(n) - : "0"(to), "1"(from), "2"(0) - : "d0", "memory"); - break; - case 12: - __asm__ __volatile__ - (" movel (%1)+,%%d0\n" - "21:movesl %%d0,(%0)+\n" - "1: movel (%1)+,%%d0\n" - "22:movesl %%d0,(%0)+\n" - "2: movel (%1)+,%%d0\n" - "23:movesl %%d0,(%0)+\n" - "3:\n" - ".section .fixup,\"ax\"\n" - " .even\n" - "4: addql #4,%2\n" - "5: addql #4,%2\n" - "6: addql #4,%2\n" - " jra 3b\n" - ".previous\n" - ".section __ex_table,\"a\"\n" - " .align 4\n" - " .long 21b,4b\n" - " .long 1b,4b\n" - " .long 22b,5b\n" - " .long 2b,5b\n" - " .long 23b,6b\n" - " .long 3b,6b\n" - ".previous" - : "=a"(to), "=a"(from), "=d"(n) - : "0"(to), "1"(from), "2"(0) - : "d0", "memory"); - break; - case 16: - __asm__ __volatile__ - (" movel (%1)+,%%d0\n" - "21:movesl %%d0,(%0)+\n" - "1: movel (%1)+,%%d0\n" - "22:movesl %%d0,(%0)+\n" - "2: movel (%1)+,%%d0\n" - "23:movesl %%d0,(%0)+\n" - "3: movel (%1)+,%%d0\n" - "24:movesl %%d0,(%0)+\n" - "4:" - ".section .fixup,\"ax\"\n" - " .even\n" - "5: addql #4,%2\n" - "6: addql #4,%2\n" - "7: addql #4,%2\n" - "8: addql #4,%2\n" - " jra 4b\n" - ".previous\n" - ".section __ex_table,\"a\"\n" - " .align 4\n" - " .long 21b,5b\n" - " .long 1b,5b\n" - " .long 22b,6b\n" - " .long 2b,6b\n" - " .long 23b,7b\n" - " .long 3b,7b\n" - " .long 24b,8b\n" - " .long 4b,8b\n" - ".previous" - : "=a"(to), "=a"(from), "=d"(n) - : "0"(to), "1"(from), "2"(0) - : "d0", "memory"); - break; - default: - switch (n & 3) { - case 0: - __copy_to_user_big(to, from, n, "", ""); - break; + unsigned long res = 0, tmp; + + /* limit the inlined version to 3 moves */ + if (n == 11 || n > 12) + return __generic_copy_to_user(to, from, n); + + switch (n) { case 1: - __copy_to_user_big(to, from, n, - /* fixup */ - "1: addql #1,%2", - /* copy */ - " moveb (%1)+,%%d0\n" - "22:movesb %%d0,(%0)+\n" - "2:" - ".section __ex_table,\"a\"\n" - " .long 22b,1b\n" - " .long 2b,1b\n" - ".previous"); - break; + __put_user_asm(res, *(u8 *)from, (u8 *)to, b, d, 1); + return res; case 2: - __copy_to_user_big(to, from, n, - /* fixup */ - "1: addql #2,%2", - /* copy */ - " movew (%1)+,%%d0\n" - "22:movesw %%d0,(%0)+\n" - "2:" - ".section __ex_table,\"a\"\n" - " .long 22b,1b\n" - " .long 2b,1b\n" - ".previous"); - break; - case 3: - __copy_to_user_big(to, from, n, - /* fixup */ - "1: addql #2,%2\n" - "2: addql #1,%2", - /* copy */ - " movew (%1)+,%%d0\n" - "23:movesw %%d0,(%0)+\n" - "3: moveb (%1)+,%%d0\n" - "24:movesb %%d0,(%0)+\n" - "4:" - ".section __ex_table,\"a\"\n" - " .long 23b,1b\n" - " .long 3b,1b\n" - " .long 24b,2b\n" - " .long 4b,2b\n" - ".previous"); - break; + __put_user_asm(res, *(u16 *)from, (u16 *)to, w, d, 2); + return res; + case 4: + __put_user_asm(res, *(u32 *)from, (u32 *)to, l, r, 4); + return res; } - break; - } - return n; + + asm volatile ("\n" + " .ifndef .Lto_user\n" + " .set .Lto_user,1\n" + " .macro copy_to_user to,from,tmp\n" + " .if .Lcnt >= 4\n" + " move.l (\\from)+,\\tmp\n" + "11: moves.l \\tmp,(\\to)+\n" + "12: .set .Lcnt,.Lcnt-4\n" + " .elseif .Lcnt & 2\n" + " move.w (\\from)+,\\tmp\n" + "11: moves.w \\tmp,(\\to)+\n" + "12: .set .Lcnt,.Lcnt-2\n" + " .elseif .Lcnt & 1\n" + " move.b (\\from)+,\\tmp\n" + "11: moves.b \\tmp,(\\to)+\n" + "12: .set .Lcnt,.Lcnt-1\n" + " .else\n" + " .exitm\n" + " .endif\n" + "\n" + " .section __ex_table,\"a\"\n" + " .align 4\n" + " .long 11b,3f\n" + " .long 12b,3f\n" + " .previous\n" + " .endm\n" + " .endif\n" + "\n" + " .set .Lcnt,%c4\n" + " copy_to_user %1,%2,%3\n" + " copy_to_user %1,%2,%3\n" + " copy_to_user %1,%2,%3\n" + "2:\n" + " .section .fixup,\"ax\"\n" + " .even\n" + "3: moveq.l %4,%0\n" + " jra 2b\n" + " .previous\n" + : "+r" (res), "+a" (to), "+a" (from), "=&d" (tmp) + : "i" (n) + : "memory"); + + return res; } -#define copy_from_user(to, from, n) \ +#define __copy_from_user(to, from, n) \ (__builtin_constant_p(n) ? \ __constant_copy_from_user(to, from, n) : \ __generic_copy_from_user(to, from, n)) -#define copy_to_user(to, from, n) \ +#define __copy_to_user(to, from, n) \ (__builtin_constant_p(n) ? \ __constant_copy_to_user(to, from, n) : \ __generic_copy_to_user(to, from, n)) -#define __copy_from_user(to, from, n) copy_from_user(to, from, n) -#define __copy_to_user(to, from, n) copy_to_user(to, from, n) +#define __copy_to_user_inatomic __copy_to_user +#define __copy_from_user_inatomic __copy_from_user -/* - * Copy a null terminated string from userspace. - */ +#define copy_from_user(to, from, n) __copy_from_user(to, from, n) +#define copy_to_user(to, from, n) __copy_to_user(to, from, n) -static inline long -strncpy_from_user(char *dst, const char __user *src, long count) -{ - long res; - if (count == 0) return count; - __asm__ __volatile__ - ("1: movesb (%2)+,%%d0\n" - "12:moveb %%d0,(%1)+\n" - " jeq 2f\n" - " subql #1,%3\n" - " jne 1b\n" - "2: subl %3,%0\n" - "3:\n" - ".section .fixup,\"ax\"\n" - " .even\n" - "4: movel %4,%0\n" - " jra 3b\n" - ".previous\n" - ".section __ex_table,\"a\"\n" - " .align 4\n" - " .long 1b,4b\n" - " .long 12b,4b\n" - ".previous" - : "=d"(res), "=a"(dst), "=a"(src), "=d"(count) - : "i"(-EFAULT), "0"(count), "1"(dst), "2"(src), "3"(count) - : "d0", "memory"); - return res; -} - -/* - * Return the size of a string (including the ending 0) - * - * Return 0 on exception, a value greater than N if too long - */ -static inline long strnlen_user(const char __user *src, long n) -{ - long res; - - res = -(unsigned long)src; - __asm__ __volatile__ - ("1:\n" - " tstl %2\n" - " jeq 3f\n" - "2: movesb (%1)+,%%d0\n" - "22:\n" - " subql #1,%2\n" - " tstb %%d0\n" - " jne 1b\n" - " jra 4f\n" - "3:\n" - " addql #1,%0\n" - "4:\n" - " addl %1,%0\n" - "5:\n" - ".section .fixup,\"ax\"\n" - " .even\n" - "6: moveq %3,%0\n" - " jra 5b\n" - ".previous\n" - ".section __ex_table,\"a\"\n" - " .align 4\n" - " .long 2b,6b\n" - " .long 22b,6b\n" - ".previous" - : "=d"(res), "=a"(src), "=d"(n) - : "i"(0), "0"(res), "1"(src), "2"(n) - : "d0"); - return res; -} +long strncpy_from_user(char *dst, const char __user *src, long count); +long strnlen_user(const char __user *src, long n); +unsigned long clear_user(void __user *to, unsigned long n); #define strlen_user(str) strnlen_user(str, 32767) -/* - * Zero Userspace - */ - -static inline unsigned long -clear_user(void __user *to, unsigned long n) -{ - __asm__ __volatile__ - (" tstl %1\n" - " jeq 3f\n" - "1: movesl %3,(%0)+\n" - "2: subql #1,%1\n" - " jne 1b\n" - "3: movel %2,%1\n" - " bclr #1,%1\n" - " jeq 4f\n" - "24:movesw %3,(%0)+\n" - "4: bclr #0,%1\n" - " jeq 5f\n" - "25:movesb %3,(%0)+\n" - "5:\n" - ".section .fixup,\"ax\"\n" - " .even\n" - "61:addql #1,%1\n" - "6: lsll #2,%1\n" - " addl %2,%1\n" - " jra 5b\n" - "7: addql #2,%1\n" - " jra 5b\n" - "8: addql #1,%1\n" - " jra 5b\n" - ".previous\n" - ".section __ex_table,\"a\"\n" - " .align 4\n" - " .long 1b,61b\n" - " .long 2b,6b\n" - " .long 3b,61b\n" - " .long 24b,7b\n" - " .long 4b,7b\n" - " .long 25b,8b\n" - " .long 5b,8b\n" - ".previous" - : "=a"(to), "=d"(n) - : "r"(n & 3), "r"(0), "0"(to), "1"(n/4)); - return n; -} - #endif /* _M68K_UACCESS_H */ -- cgit v1.2.3 From de290166552a037234bca44ed4bcbf4a4e9f5be9 Mon Sep 17 00:00:00 2001 From: Jan Altenberg Date: Fri, 23 Jun 2006 02:05:01 -0700 Subject: [PATCH] m68k: ptrace.h typo fix Signed-off-by: Jan Altenberg Cc: Geert Uytterhoeven Cc: Greg Ungerer Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-m68knommu/ptrace.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/asm-m68knommu/ptrace.h b/include/asm-m68knommu/ptrace.h index f65bd90749e6..1e19c457de7d 100644 --- a/include/asm-m68knommu/ptrace.h +++ b/include/asm-m68knommu/ptrace.h @@ -70,7 +70,7 @@ struct switch_stack { /* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */ #define PTRACE_GETREGS 12 #define PTRACE_SETREGS 13 -#ifdef COFNIG_FPU +#ifdef CONFIG_FPU #define PTRACE_GETFPREGS 14 #define PTRACE_SETFPREGS 15 #endif -- cgit v1.2.3 From b9e122c80cd2e10fe18678c63db4717871ed31cf Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Fri, 23 Jun 2006 02:05:04 -0700 Subject: [PATCH] xtensa: remove verify_area macros verify_area() is still alive on xtensa in 2.6.17-rc3-git13 It would be nice to finally be rid of that function across the board. Signed-off-by: Chris Zankel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/xtensa/Kconfig | 4 ---- arch/xtensa/kernel/entry.S | 2 +- arch/xtensa/kernel/signal.c | 10 +++++----- include/asm-xtensa/checksum.h | 3 +-- include/asm-xtensa/rwsem.h | 7 ++++++- include/asm-xtensa/uaccess.h | 34 ---------------------------------- 6 files changed, 13 insertions(+), 47 deletions(-) (limited to 'include') diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index dbeb3504c3c8..848f173db257 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -34,10 +34,6 @@ config GENERIC_HARDIRQS bool default y -config RWSEM_GENERIC_SPINLOCK - bool - default y - source "init/Kconfig" menu "Processor type and features" diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S index 5c018c503dfa..89e409e9e0de 100644 --- a/arch/xtensa/kernel/entry.S +++ b/arch/xtensa/kernel/entry.S @@ -1102,7 +1102,7 @@ ENTRY(fast_syscall_sysxtensa) s32i a7, a2, PT_AREG7 movi a7, 4 # sizeof(unsigned int) - verify_area a3, a7, a0, a2, .Leac + access_ok a0, a3, a7, a2, .Leac _beqi a6, SYSXTENSA_ATOMIC_SET, .Lset _beqi a6, SYSXTENSA_ATOMIC_EXG_ADD, .Lexg diff --git a/arch/xtensa/kernel/signal.c b/arch/xtensa/kernel/signal.c index e252b61e45a5..beba497e78df 100644 --- a/arch/xtensa/kernel/signal.c +++ b/arch/xtensa/kernel/signal.c @@ -104,7 +104,7 @@ sys_sigaction(int sig, const struct old_sigaction *act, if (act) { old_sigset_t mask; - if (verify_area(VERIFY_READ, act, sizeof(*act)) || + if (!access_ok(VERIFY_READ, act, sizeof(*act)) || __get_user(new_ka.sa.sa_handler, &act->sa_handler) || __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) return -EFAULT; @@ -116,7 +116,7 @@ sys_sigaction(int sig, const struct old_sigaction *act, ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); if (!ret && oact) { - if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) || + if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) return -EFAULT; @@ -236,7 +236,7 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc) err |= __copy_from_user (regs->areg, sc->sc_areg, XCHAL_NUM_AREGS*4); err |= __get_user(buf, &sc->sc_cpstate); if (buf) { - if (verify_area(VERIFY_READ, buf, sizeof(*buf))) + if (!access_ok(VERIFY_READ, buf, sizeof(*buf))) goto badframe; err |= restore_cpextra(buf); } @@ -357,7 +357,7 @@ asmlinkage int sys_sigreturn(struct pt_regs *regs) if (regs->depc > 64) panic ("Double exception sys_sigreturn\n"); - if (verify_area(VERIFY_READ, frame, sizeof(*frame))) + if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) goto badframe; if (__get_user(set.sig[0], &frame->sc.oldmask) @@ -394,7 +394,7 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) return 0; } - if (verify_area(VERIFY_READ, frame, sizeof(*frame))) + if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) goto badframe; if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) diff --git a/include/asm-xtensa/checksum.h b/include/asm-xtensa/checksum.h index bdc00ae9be48..03114f8d1e18 100644 --- a/include/asm-xtensa/checksum.h +++ b/include/asm-xtensa/checksum.h @@ -43,8 +43,7 @@ asmlinkage unsigned int csum_partial_copy_generic( const char *src, char *dst, i * Note: when you get a NULL pointer exception here this means someone * passed in an incorrect kernel address to one of these functions. * - * If you use these functions directly please don't forget the - * verify_area(). + * If you use these functions directly please don't forget the access_ok(). */ static inline unsigned int csum_partial_copy_nocheck ( const char *src, char *dst, diff --git a/include/asm-xtensa/rwsem.h b/include/asm-xtensa/rwsem.h index 3c02b0e033f0..abcd86dc5ab9 100644 --- a/include/asm-xtensa/rwsem.h +++ b/include/asm-xtensa/rwsem.h @@ -172,4 +172,9 @@ static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem) return atomic_add_return(delta, (atomic_t *)(&sem->count)); } -#endif /* _XTENSA_RWSEM_XADD_H */ +static inline int rwsem_is_locked(struct rw_semaphore *sem) +{ + return (sem->count != 0); +} + +#endif /* _XTENSA_RWSEM_H */ diff --git a/include/asm-xtensa/uaccess.h b/include/asm-xtensa/uaccess.h index 06a22b83ba17..88a64e1144d5 100644 --- a/include/asm-xtensa/uaccess.h +++ b/include/asm-xtensa/uaccess.h @@ -154,35 +154,6 @@ .Laccess_ok_\@: .endm -/* - * verify_area determines whether a memory access is allowed. It's - * mostly an unnecessary wrapper for access_ok, but we provide it as a - * duplicate of the verify_area() C inline function below. See the - * equivalent C version below for clarity. - * - * On error, verify_area branches to a label indicated by parameter - * . This implies that the macro falls through to the next - * instruction on success. - * - * Note that we assume success is the common case, and we optimize the - * branch fall-through case on success. - * - * On Entry: - * register containing memory address - * register containing memory size - * temp register - * label to branch to on error; implies fall-through - * macro on success - * On Exit: - * preserved - * preserved - * destroyed - */ - .macro verify_area aa, as, at, sp, error - access_ok \at, \aa, \as, \sp, \error - .endm - - #else /* __ASSEMBLY__ not defined */ #include @@ -211,11 +182,6 @@ #define __access_ok(addr,size) (__kernel_ok || __user_ok((addr),(size))) #define access_ok(type,addr,size) __access_ok((unsigned long)(addr),(size)) -static inline int verify_area(int type, const void * addr, unsigned long size) -{ - return access_ok(type,addr,size) ? 0 : -EFAULT; -} - /* * These are the main single-value transfer routines. They * automatically use the right size if we just have the right pointer -- cgit v1.2.3 From c330dda908b5a46469a997eea90b66f2f9f02b34 Mon Sep 17 00:00:00 2001 From: Jeff Moyer Date: Fri, 23 Jun 2006 02:05:07 -0700 Subject: [PATCH] Add a sysfs file to determine if a kexec kernel is loaded Create two files in /sys/kernel, kexec_loaded and kexec_crash_loaded. Each file contains a simple boolean value indicating whether the relevant kernel has been loaded into memory. The motivation for this is geared around support. Signed-off-by: Jeff Moyer Cc: "Eric W. Biederman" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/kexec.h | 1 + kernel/kexec.c | 6 +++--- kernel/ksysfs.c | 19 +++++++++++++++++++ 3 files changed, 23 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/linux/kexec.h b/include/linux/kexec.h index cfb3410e32b1..6427949ddf99 100644 --- a/include/linux/kexec.h +++ b/include/linux/kexec.h @@ -106,6 +106,7 @@ extern struct page *kimage_alloc_control_pages(struct kimage *image, extern void crash_kexec(struct pt_regs *); int kexec_should_crash(struct task_struct *); extern struct kimage *kexec_image; +extern struct kimage *kexec_crash_image; #define KEXEC_ON_CRASH 0x00000001 #define KEXEC_ARCH_MASK 0xffff0000 diff --git a/kernel/kexec.c b/kernel/kexec.c index bf39d28e4c0e..58f0f382597c 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c @@ -902,14 +902,14 @@ static int kimage_load_segment(struct kimage *image, * kexec does not sync, or unmount filesystems so if you need * that to happen you need to do that yourself. */ -struct kimage *kexec_image = NULL; -static struct kimage *kexec_crash_image = NULL; +struct kimage *kexec_image; +struct kimage *kexec_crash_image; /* * A home grown binary mutex. * Nothing can wait so this mutex is safe to use * in interrupt context :) */ -static int kexec_lock = 0; +static int kexec_lock; asmlinkage long sys_kexec_load(unsigned long entry, unsigned long nr_segments, struct kexec_segment __user *segments, diff --git a/kernel/ksysfs.c b/kernel/ksysfs.c index f119e098e67b..9e28478a17a5 100644 --- a/kernel/ksysfs.c +++ b/kernel/ksysfs.c @@ -14,6 +14,7 @@ #include #include #include +#include #define KERNEL_ATTR_RO(_name) \ static struct subsys_attribute _name##_attr = __ATTR_RO(_name) @@ -48,6 +49,20 @@ static ssize_t uevent_helper_store(struct subsystem *subsys, const char *page, s KERNEL_ATTR_RW(uevent_helper); #endif +#ifdef CONFIG_KEXEC +static ssize_t kexec_loaded_show(struct subsystem *subsys, char *page) +{ + return sprintf(page, "%d\n", !!kexec_image); +} +KERNEL_ATTR_RO(kexec_loaded); + +static ssize_t kexec_crash_loaded_show(struct subsystem *subsys, char *page) +{ + return sprintf(page, "%d\n", !!kexec_crash_image); +} +KERNEL_ATTR_RO(kexec_crash_loaded); +#endif /* CONFIG_KEXEC */ + decl_subsys(kernel, NULL, NULL); EXPORT_SYMBOL_GPL(kernel_subsys); @@ -55,6 +70,10 @@ static struct attribute * kernel_attrs[] = { #if defined(CONFIG_HOTPLUG) && defined(CONFIG_NET) &uevent_seqnum_attr.attr, &uevent_helper_attr.attr, +#endif +#ifdef CONFIG_KEXEC + &kexec_loaded_attr.attr, + &kexec_crash_loaded_attr.attr, #endif NULL }; -- cgit v1.2.3 From 090d2b185d8680fc26a2eaf4245d4171dcf4baf1 Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Fri, 23 Jun 2006 02:05:08 -0700 Subject: [PATCH] read_mapping_page for address space Add read_mapping_page() which is used for callers that pass mapping->a_ops->readpage as the filler for read_cache_page. This removes some duplication from filesystem code. Signed-off-by: Pekka Enberg Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/afs/dir.c | 4 +--- fs/afs/mntpt.c | 11 ++--------- fs/cramfs/inode.c | 4 +--- fs/ext2/dir.c | 3 +-- fs/freevxfs/vxfs_subr.c | 3 +-- fs/hfs/bnode.c | 2 +- fs/hfs/btree.c | 2 +- fs/hfsplus/bitmap.c | 15 +++++++-------- fs/hfsplus/bnode.c | 2 +- fs/hfsplus/btree.c | 2 +- fs/jfs/jfs_metapage.c | 5 ++--- fs/minix/dir.c | 3 +-- fs/namei.c | 3 +-- fs/ntfs/aops.h | 3 +-- fs/ntfs/attrib.c | 6 ++---- fs/ntfs/file.c | 3 +-- fs/ocfs2/symlink.c | 3 +-- fs/partitions/check.c | 4 ++-- fs/reiserfs/xattr.c | 3 +-- fs/sysv/dir.c | 3 +-- include/linux/pagemap.h | 7 +++++++ mm/swapfile.c | 3 +-- 22 files changed, 38 insertions(+), 56 deletions(-) (limited to 'include') diff --git a/fs/afs/dir.c b/fs/afs/dir.c index a6dff6a4f204..2fc99877cb0d 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c @@ -185,9 +185,7 @@ static struct page *afs_dir_get_page(struct inode *dir, unsigned long index) _enter("{%lu},%lu", dir->i_ino, index); - page = read_cache_page(dir->i_mapping,index, - (filler_t *) dir->i_mapping->a_ops->readpage, - NULL); + page = read_mapping_page(dir->i_mapping, index, NULL); if (!IS_ERR(page)) { wait_on_page_locked(page); kmap(page); diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c index 4e6eeb59b83c..b5cf9e1205ad 100644 --- a/fs/afs/mntpt.c +++ b/fs/afs/mntpt.c @@ -63,7 +63,6 @@ unsigned long afs_mntpt_expiry_timeout = 20; int afs_mntpt_check_symlink(struct afs_vnode *vnode) { struct page *page; - filler_t *filler; size_t size; char *buf; int ret; @@ -71,10 +70,7 @@ int afs_mntpt_check_symlink(struct afs_vnode *vnode) _enter("{%u,%u}", vnode->fid.vnode, vnode->fid.unique); /* read the contents of the symlink into the pagecache */ - filler = (filler_t *) AFS_VNODE_TO_I(vnode)->i_mapping->a_ops->readpage; - - page = read_cache_page(AFS_VNODE_TO_I(vnode)->i_mapping, 0, - filler, NULL); + page = read_mapping_page(AFS_VNODE_TO_I(vnode)->i_mapping, 0, NULL); if (IS_ERR(page)) { ret = PTR_ERR(page); goto out; @@ -160,7 +156,6 @@ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt) struct page *page = NULL; size_t size; char *buf, *devname = NULL, *options = NULL; - filler_t *filler; int ret; kenter("{%s}", mntpt->d_name.name); @@ -182,9 +177,7 @@ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt) goto error; /* read the contents of the AFS special symlink */ - filler = (filler_t *)mntpt->d_inode->i_mapping->a_ops->readpage; - - page = read_cache_page(mntpt->d_inode->i_mapping, 0, filler, NULL); + page = read_mapping_page(mntpt->d_inode->i_mapping, 0, NULL); if (IS_ERR(page)) { ret = PTR_ERR(page); goto error; diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c index 8a9d5d3b3262..c45d73860803 100644 --- a/fs/cramfs/inode.c +++ b/fs/cramfs/inode.c @@ -181,9 +181,7 @@ static void *cramfs_read(struct super_block *sb, unsigned int offset, unsigned i struct page *page = NULL; if (blocknr + i < devsize) { - page = read_cache_page(mapping, blocknr + i, - (filler_t *)mapping->a_ops->readpage, - NULL); + page = read_mapping_page(mapping, blocknr + i, NULL); /* synchronous error? */ if (IS_ERR(page)) page = NULL; diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c index d672aa9f4061..3c1c9aaaca6b 100644 --- a/fs/ext2/dir.c +++ b/fs/ext2/dir.c @@ -159,8 +159,7 @@ fail: static struct page * ext2_get_page(struct inode *dir, unsigned long n) { struct address_space *mapping = dir->i_mapping; - struct page *page = read_cache_page(mapping, n, - (filler_t*)mapping->a_ops->readpage, NULL); + struct page *page = read_mapping_page(mapping, n, NULL); if (!IS_ERR(page)) { wait_on_page_locked(page); kmap(page); diff --git a/fs/freevxfs/vxfs_subr.c b/fs/freevxfs/vxfs_subr.c index 50aae77651b2..c1be118fc067 100644 --- a/fs/freevxfs/vxfs_subr.c +++ b/fs/freevxfs/vxfs_subr.c @@ -71,8 +71,7 @@ vxfs_get_page(struct address_space *mapping, u_long n) { struct page * pp; - pp = read_cache_page(mapping, n, - (filler_t*)mapping->a_ops->readpage, NULL); + pp = read_mapping_page(mapping, n, NULL); if (!IS_ERR(pp)) { wait_on_page_locked(pp); diff --git a/fs/hfs/bnode.c b/fs/hfs/bnode.c index 1e44dcfe49c4..13231dd5ce66 100644 --- a/fs/hfs/bnode.c +++ b/fs/hfs/bnode.c @@ -280,7 +280,7 @@ static struct hfs_bnode *__hfs_bnode_create(struct hfs_btree *tree, u32 cnid) block = off >> PAGE_CACHE_SHIFT; node->page_offset = off & ~PAGE_CACHE_MASK; for (i = 0; i < tree->pages_per_bnode; i++) { - page = read_cache_page(mapping, block++, (filler_t *)mapping->a_ops->readpage, NULL); + page = read_mapping_page(mapping, block++, NULL); if (IS_ERR(page)) goto fail; if (PageError(page)) { diff --git a/fs/hfs/btree.c b/fs/hfs/btree.c index d20131ce4b95..400357994319 100644 --- a/fs/hfs/btree.c +++ b/fs/hfs/btree.c @@ -59,7 +59,7 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id, btree_keycmp ke unlock_new_inode(tree->inode); mapping = tree->inode->i_mapping; - page = read_cache_page(mapping, 0, (filler_t *)mapping->a_ops->readpage, NULL); + page = read_mapping_page(mapping, 0, NULL); if (IS_ERR(page)) goto free_tree; diff --git a/fs/hfsplus/bitmap.c b/fs/hfsplus/bitmap.c index 9fb51632303c..d128a25b74d2 100644 --- a/fs/hfsplus/bitmap.c +++ b/fs/hfsplus/bitmap.c @@ -31,8 +31,7 @@ int hfsplus_block_allocate(struct super_block *sb, u32 size, u32 offset, u32 *ma dprint(DBG_BITMAP, "block_allocate: %u,%u,%u\n", size, offset, len); mutex_lock(&HFSPLUS_SB(sb).alloc_file->i_mutex); mapping = HFSPLUS_SB(sb).alloc_file->i_mapping; - page = read_cache_page(mapping, offset / PAGE_CACHE_BITS, - (filler_t *)mapping->a_ops->readpage, NULL); + page = read_mapping_page(mapping, offset / PAGE_CACHE_BITS, NULL); pptr = kmap(page); curr = pptr + (offset & (PAGE_CACHE_BITS - 1)) / 32; i = offset % 32; @@ -72,8 +71,8 @@ int hfsplus_block_allocate(struct super_block *sb, u32 size, u32 offset, u32 *ma offset += PAGE_CACHE_BITS; if (offset >= size) break; - page = read_cache_page(mapping, offset / PAGE_CACHE_BITS, - (filler_t *)mapping->a_ops->readpage, NULL); + page = read_mapping_page(mapping, offset / PAGE_CACHE_BITS, + NULL); curr = pptr = kmap(page); if ((size ^ offset) / PAGE_CACHE_BITS) end = pptr + PAGE_CACHE_BITS / 32; @@ -119,8 +118,8 @@ found: set_page_dirty(page); kunmap(page); offset += PAGE_CACHE_BITS; - page = read_cache_page(mapping, offset / PAGE_CACHE_BITS, - (filler_t *)mapping->a_ops->readpage, NULL); + page = read_mapping_page(mapping, offset / PAGE_CACHE_BITS, + NULL); pptr = kmap(page); curr = pptr; end = pptr + PAGE_CACHE_BITS / 32; @@ -167,7 +166,7 @@ int hfsplus_block_free(struct super_block *sb, u32 offset, u32 count) mutex_lock(&HFSPLUS_SB(sb).alloc_file->i_mutex); mapping = HFSPLUS_SB(sb).alloc_file->i_mapping; pnr = offset / PAGE_CACHE_BITS; - page = read_cache_page(mapping, pnr, (filler_t *)mapping->a_ops->readpage, NULL); + page = read_mapping_page(mapping, pnr, NULL); pptr = kmap(page); curr = pptr + (offset & (PAGE_CACHE_BITS - 1)) / 32; end = pptr + PAGE_CACHE_BITS / 32; @@ -199,7 +198,7 @@ int hfsplus_block_free(struct super_block *sb, u32 offset, u32 count) break; set_page_dirty(page); kunmap(page); - page = read_cache_page(mapping, ++pnr, (filler_t *)mapping->a_ops->readpage, NULL); + page = read_mapping_page(mapping, ++pnr, NULL); pptr = kmap(page); curr = pptr; end = pptr + PAGE_CACHE_BITS / 32; diff --git a/fs/hfsplus/bnode.c b/fs/hfsplus/bnode.c index 746abc9ecf70..77bf434da679 100644 --- a/fs/hfsplus/bnode.c +++ b/fs/hfsplus/bnode.c @@ -440,7 +440,7 @@ static struct hfs_bnode *__hfs_bnode_create(struct hfs_btree *tree, u32 cnid) block = off >> PAGE_CACHE_SHIFT; node->page_offset = off & ~PAGE_CACHE_MASK; for (i = 0; i < tree->pages_per_bnode; block++, i++) { - page = read_cache_page(mapping, block, (filler_t *)mapping->a_ops->readpage, NULL); + page = read_mapping_page(mapping, block, NULL); if (IS_ERR(page)) goto fail; if (PageError(page)) { diff --git a/fs/hfsplus/btree.c b/fs/hfsplus/btree.c index effa8991999c..cfc852fdd1b5 100644 --- a/fs/hfsplus/btree.c +++ b/fs/hfsplus/btree.c @@ -38,7 +38,7 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id) goto free_tree; mapping = tree->inode->i_mapping; - page = read_cache_page(mapping, 0, (filler_t *)mapping->a_ops->readpage, NULL); + page = read_mapping_page(mapping, 0, NULL); if (IS_ERR(page)) goto free_tree; diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c index 2b220dd6b4e7..7f6e88039700 100644 --- a/fs/jfs/jfs_metapage.c +++ b/fs/jfs/jfs_metapage.c @@ -632,10 +632,9 @@ struct metapage *__get_metapage(struct inode *inode, unsigned long lblock, } SetPageUptodate(page); } else { - page = read_cache_page(mapping, page_index, - (filler_t *)mapping->a_ops->readpage, NULL); + page = read_mapping_page(mapping, page_index, NULL); if (IS_ERR(page) || !PageUptodate(page)) { - jfs_err("read_cache_page failed!"); + jfs_err("read_mapping_page failed!"); return NULL; } lock_page(page); diff --git a/fs/minix/dir.c b/fs/minix/dir.c index 69224d1fe043..2b0a389d1987 100644 --- a/fs/minix/dir.c +++ b/fs/minix/dir.c @@ -60,8 +60,7 @@ static int dir_commit_chunk(struct page *page, unsigned from, unsigned to) static struct page * dir_get_page(struct inode *dir, unsigned long n) { struct address_space *mapping = dir->i_mapping; - struct page *page = read_cache_page(mapping, n, - (filler_t*)mapping->a_ops->readpage, NULL); + struct page *page = read_mapping_page(mapping, n, NULL); if (!IS_ERR(page)) { wait_on_page_locked(page); kmap(page); diff --git a/fs/namei.c b/fs/namei.c index 184fe4acf824..bb4a3e40e432 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -2577,8 +2577,7 @@ static char *page_getlink(struct dentry * dentry, struct page **ppage) { struct page * page; struct address_space *mapping = dentry->d_inode->i_mapping; - page = read_cache_page(mapping, 0, (filler_t *)mapping->a_ops->readpage, - NULL); + page = read_mapping_page(mapping, 0, NULL); if (IS_ERR(page)) goto sync_fail; wait_on_page_locked(page); diff --git a/fs/ntfs/aops.h b/fs/ntfs/aops.h index 3b74e66ca2ff..325ce261a107 100644 --- a/fs/ntfs/aops.h +++ b/fs/ntfs/aops.h @@ -86,8 +86,7 @@ static inline void ntfs_unmap_page(struct page *page) static inline struct page *ntfs_map_page(struct address_space *mapping, unsigned long index) { - struct page *page = read_cache_page(mapping, index, - (filler_t*)mapping->a_ops->readpage, NULL); + struct page *page = read_mapping_page(mapping, index, NULL); if (!IS_ERR(page)) { wait_on_page_locked(page); diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c index 1663f5c3c6aa..6708e1d68a9e 100644 --- a/fs/ntfs/attrib.c +++ b/fs/ntfs/attrib.c @@ -2529,8 +2529,7 @@ int ntfs_attr_set(ntfs_inode *ni, const s64 ofs, const s64 cnt, const u8 val) end >>= PAGE_CACHE_SHIFT; /* If there is a first partial page, need to do it the slow way. */ if (start_ofs) { - page = read_cache_page(mapping, idx, - (filler_t*)mapping->a_ops->readpage, NULL); + page = read_mapping_page(mapping, idx, NULL); if (IS_ERR(page)) { ntfs_error(vol->sb, "Failed to read first partial " "page (sync error, index 0x%lx).", idx); @@ -2600,8 +2599,7 @@ int ntfs_attr_set(ntfs_inode *ni, const s64 ofs, const s64 cnt, const u8 val) } /* If there is a last partial page, need to do it the slow way. */ if (end_ofs) { - page = read_cache_page(mapping, idx, - (filler_t*)mapping->a_ops->readpage, NULL); + page = read_mapping_page(mapping, idx, NULL); if (IS_ERR(page)) { ntfs_error(vol->sb, "Failed to read last partial page " "(sync error, index 0x%lx).", idx); diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c index 36e1e136bb0c..88292f9e4b9b 100644 --- a/fs/ntfs/file.c +++ b/fs/ntfs/file.c @@ -231,8 +231,7 @@ do_non_resident_extend: * Read the page. If the page is not present, this will zero * the uninitialized regions for us. */ - page = read_cache_page(mapping, index, - (filler_t*)mapping->a_ops->readpage, NULL); + page = read_mapping_page(mapping, index, NULL); if (IS_ERR(page)) { err = PTR_ERR(page); goto init_err_out; diff --git a/fs/ocfs2/symlink.c b/fs/ocfs2/symlink.c index f6986bd79e75..0c8a1294ec96 100644 --- a/fs/ocfs2/symlink.c +++ b/fs/ocfs2/symlink.c @@ -64,8 +64,7 @@ static char *ocfs2_page_getlink(struct dentry * dentry, { struct page * page; struct address_space *mapping = dentry->d_inode->i_mapping; - page = read_cache_page(mapping, 0, - (filler_t *)mapping->a_ops->readpage, NULL); + page = read_mapping_page(mapping, 0, NULL); if (IS_ERR(page)) goto sync_fail; wait_on_page_locked(page); diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 8851b81e7c5a..cd885b23cb5c 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -499,8 +499,8 @@ unsigned char *read_dev_sector(struct block_device *bdev, sector_t n, Sector *p) struct address_space *mapping = bdev->bd_inode->i_mapping; struct page *page; - page = read_cache_page(mapping, (pgoff_t)(n >> (PAGE_CACHE_SHIFT-9)), - (filler_t *)mapping->a_ops->readpage, NULL); + page = read_mapping_page(mapping, (pgoff_t)(n >> (PAGE_CACHE_SHIFT-9)), + NULL); if (!IS_ERR(page)) { wait_on_page_locked(page); if (!PageUptodate(page)) diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c index ffb79c48c5bf..39fedaa88a0c 100644 --- a/fs/reiserfs/xattr.c +++ b/fs/reiserfs/xattr.c @@ -452,8 +452,7 @@ static struct page *reiserfs_get_page(struct inode *dir, unsigned long n) /* We can deadlock if we try to free dentries, and an unlink/rmdir has just occured - GFP_NOFS avoids this */ mapping_set_gfp_mask(mapping, GFP_NOFS); - page = read_cache_page(mapping, n, - (filler_t *) mapping->a_ops->readpage, NULL); + page = read_mapping_page(mapping, n, NULL); if (!IS_ERR(page)) { wait_on_page_locked(page); kmap(page); diff --git a/fs/sysv/dir.c b/fs/sysv/dir.c index d7074341ee87..f2bef962d309 100644 --- a/fs/sysv/dir.c +++ b/fs/sysv/dir.c @@ -53,8 +53,7 @@ static int dir_commit_chunk(struct page *page, unsigned from, unsigned to) static struct page * dir_get_page(struct inode *dir, unsigned long n) { struct address_space *mapping = dir->i_mapping; - struct page *page = read_cache_page(mapping, n, - (filler_t*)mapping->a_ops->readpage, NULL); + struct page *page = read_mapping_page(mapping, n, NULL); if (!IS_ERR(page)) { wait_on_page_locked(page); kmap(page); diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h index 7a1af574dedf..1245df7141aa 100644 --- a/include/linux/pagemap.h +++ b/include/linux/pagemap.h @@ -99,6 +99,13 @@ extern struct page * read_cache_page(struct address_space *mapping, extern int read_cache_pages(struct address_space *mapping, struct list_head *pages, filler_t *filler, void *data); +static inline struct page *read_mapping_page(struct address_space *mapping, + unsigned long index, void *data) +{ + filler_t *filler = (filler_t *)mapping->a_ops->readpage; + return read_cache_page(mapping, index, filler, data); +} + int add_to_page_cache(struct page *page, struct address_space *mapping, unsigned long index, gfp_t gfp_mask); int add_to_page_cache_lru(struct page *page, struct address_space *mapping, diff --git a/mm/swapfile.c b/mm/swapfile.c index f2824c3c31b4..cc367f7e75d8 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -1477,8 +1477,7 @@ asmlinkage long sys_swapon(const char __user * specialfile, int swap_flags) error = -EINVAL; goto bad_swap; } - page = read_cache_page(mapping, 0, - (filler_t *)mapping->a_ops->readpage, swap_file); + page = read_mapping_page(mapping, 0, swap_file); if (IS_ERR(page)) { error = PTR_ERR(page); goto bad_swap; -- cgit v1.2.3 From 75e1fcc0b18df0a65ab113198e9dc0e98999a08c Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Fri, 23 Jun 2006 02:05:12 -0700 Subject: [PATCH] vfs: add lock owner argument to flush operation Pass the POSIX lock owner ID to the flush operation. This is useful for filesystems which don't want to store any locking state in inode->i_flock but want to handle locking/unlocking POSIX locks internally. FUSE is one such filesystem but I think it possible that some network filesystems would need this also. Also add a flag to indicate that a POSIX locking request was generated by close(), so filesystems using the above feature won't send an extra locking request in this case. Signed-off-by: Miklos Szeredi Cc: Trond Myklebust Cc: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ia64/kernel/perfmon.c | 3 +-- drivers/input/evdev.c | 2 +- drivers/scsi/osst.c | 2 +- drivers/scsi/st.c | 2 +- fs/cifs/cifsfs.h | 2 +- fs/cifs/file.c | 2 +- fs/coda/file.c | 2 +- fs/fuse/file.c | 2 +- fs/locks.c | 2 +- fs/nfs/file.c | 4 ++-- fs/open.c | 2 +- include/linux/coda_linux.h | 2 +- include/linux/fs.h | 3 ++- ipc/mqueue.c | 2 +- 14 files changed, 16 insertions(+), 16 deletions(-) (limited to 'include') diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c index 2359e2809f50..6d7bc8ff7b3a 100644 --- a/arch/ia64/kernel/perfmon.c +++ b/arch/ia64/kernel/perfmon.c @@ -532,7 +532,6 @@ static ctl_table pfm_sysctl_root[] = { static struct ctl_table_header *pfm_sysctl_header; static int pfm_context_unload(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs); -static int pfm_flush(struct file *filp); #define pfm_get_cpu_var(v) __ia64_per_cpu_var(v) #define pfm_get_cpu_data(a,b) per_cpu(a, b) @@ -1774,7 +1773,7 @@ pfm_syswide_cleanup_other_cpu(pfm_context_t *ctx) * When caller is self-monitoring, the context is unloaded. */ static int -pfm_flush(struct file *filp) +pfm_flush(struct file *filp, fl_owner_t id) { pfm_context_t *ctx; struct task_struct *task; diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index ba325f16d077..5f561fce32d8 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -82,7 +82,7 @@ static int evdev_fasync(int fd, struct file *file, int on) return retval < 0 ? retval : 0; } -static int evdev_flush(struct file * file) +static int evdev_flush(struct file * file, fl_owner_t id) { struct evdev_list *list = file->private_data; if (!list->evdev->exist) return -ENODEV; diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c index ce0ba3a174f9..4a2fed350d4e 100644 --- a/drivers/scsi/osst.c +++ b/drivers/scsi/osst.c @@ -4724,7 +4724,7 @@ err_out: /* Flush the tape buffer before close */ -static int os_scsi_tape_flush(struct file * filp) +static int os_scsi_tape_flush(struct file * filp, fl_owner_t id) { int result = 0, result2; struct osst_tape * STp = filp->private_data; diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index ad87d73f88ee..1272dd249af3 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -1193,7 +1193,7 @@ static int st_open(struct inode *inode, struct file *filp) /* Flush the tape buffer before close */ -static int st_flush(struct file *filp) +static int st_flush(struct file *filp, fl_owner_t id) { int result = 0, result2; unsigned char cmd[MAX_COMMAND_SIZE]; diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index c98755dca868..d56c0577c710 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -74,7 +74,7 @@ extern ssize_t cifs_user_write(struct file *file, const char __user *write_data, size_t write_size, loff_t * poffset); extern int cifs_lock(struct file *, int, struct file_lock *); extern int cifs_fsync(struct file *, struct dentry *, int); -extern int cifs_flush(struct file *); +extern int cifs_flush(struct file *, fl_owner_t id); extern int cifs_file_mmap(struct file * , struct vm_area_struct *); extern const struct file_operations cifs_dir_ops; extern int cifs_dir_open(struct inode *inode, struct file *file); diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 487ea8b3baaa..b4a18c1cab0a 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -1417,7 +1417,7 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync) * As file closes, flush all cached write data for this inode checking * for write behind errors. */ -int cifs_flush(struct file *file) +int cifs_flush(struct file *file, fl_owner_t id) { struct inode * inode = file->f_dentry->d_inode; int rc = 0; diff --git a/fs/coda/file.c b/fs/coda/file.c index 7c2642431fa5..cc66c681bd11 100644 --- a/fs/coda/file.c +++ b/fs/coda/file.c @@ -164,7 +164,7 @@ int coda_open(struct inode *coda_inode, struct file *coda_file) return 0; } -int coda_flush(struct file *coda_file) +int coda_flush(struct file *coda_file, fl_owner_t id) { unsigned short flags = coda_file->f_flags & ~O_EXCL; unsigned short coda_flags = coda_flags_to_cflags(flags); diff --git a/fs/fuse/file.c b/fs/fuse/file.c index fc342cf7c2cc..087f3b734f40 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -169,7 +169,7 @@ static int fuse_release(struct inode *inode, struct file *file) return fuse_release_common(inode, file, 0); } -static int fuse_flush(struct file *file) +static int fuse_flush(struct file *file, fl_owner_t id) { struct inode *inode = file->f_dentry->d_inode; struct fuse_conn *fc = get_fuse_conn(inode); diff --git a/fs/locks.c b/fs/locks.c index e588e1c265f7..f8a634ac1121 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -1907,7 +1907,7 @@ void locks_remove_posix(struct file *filp, fl_owner_t owner) return; lock.fl_type = F_UNLCK; - lock.fl_flags = FL_POSIX; + lock.fl_flags = FL_POSIX | FL_CLOSE; lock.fl_start = 0; lock.fl_end = OFFSET_MAX; lock.fl_owner = owner; diff --git a/fs/nfs/file.c b/fs/nfs/file.c index fade02c15e6e..fa05c027ea11 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -43,7 +43,7 @@ static int nfs_file_mmap(struct file *, struct vm_area_struct *); static ssize_t nfs_file_sendfile(struct file *, loff_t *, size_t, read_actor_t, void *); static ssize_t nfs_file_read(struct kiocb *, char __user *, size_t, loff_t); static ssize_t nfs_file_write(struct kiocb *, const char __user *, size_t, loff_t); -static int nfs_file_flush(struct file *); +static int nfs_file_flush(struct file *, fl_owner_t id); static int nfs_fsync(struct file *, struct dentry *dentry, int datasync); static int nfs_check_flags(int flags); static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl); @@ -188,7 +188,7 @@ static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin) * */ static int -nfs_file_flush(struct file *file) +nfs_file_flush(struct file *file, fl_owner_t id) { struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data; struct inode *inode = file->f_dentry->d_inode; diff --git a/fs/open.c b/fs/open.c index a37ff861108f..5fb16e5267dc 100644 --- a/fs/open.c +++ b/fs/open.c @@ -1152,7 +1152,7 @@ int filp_close(struct file *filp, fl_owner_t id) } if (filp->f_op && filp->f_op->flush) - retval = filp->f_op->flush(filp); + retval = filp->f_op->flush(filp, id); dnotify_flush(filp, id); locks_remove_posix(filp, id); diff --git a/include/linux/coda_linux.h b/include/linux/coda_linux.h index b3ecf8f71d97..7b5c5df5cb69 100644 --- a/include/linux/coda_linux.h +++ b/include/linux/coda_linux.h @@ -36,7 +36,7 @@ extern const struct file_operations coda_ioctl_operations; /* operations shared over more than one file */ int coda_open(struct inode *i, struct file *f); -int coda_flush(struct file *f); +int coda_flush(struct file *f, fl_owner_t id); int coda_release(struct inode *i, struct file *f); int coda_permission(struct inode *inode, int mask, struct nameidata *nd); int coda_revalidate_inode(struct dentry *); diff --git a/include/linux/fs.h b/include/linux/fs.h index e917403f4d58..56d8bf0d0a77 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -683,6 +683,7 @@ extern spinlock_t files_lock; #define FL_FLOCK 2 #define FL_ACCESS 8 /* not trying to lock, just looking */ #define FL_LEASE 32 /* lease held on this file */ +#define FL_CLOSE 64 /* unlock on close */ #define FL_SLEEP 128 /* A blocking lock */ /* @@ -1025,7 +1026,7 @@ struct file_operations { long (*compat_ioctl) (struct file *, unsigned int, unsigned long); int (*mmap) (struct file *, struct vm_area_struct *); int (*open) (struct inode *, struct file *); - int (*flush) (struct file *); + int (*flush) (struct file *, fl_owner_t id); int (*release) (struct inode *, struct file *); int (*fsync) (struct file *, struct dentry *, int datasync); int (*aio_fsync) (struct kiocb *, int datasync); diff --git a/ipc/mqueue.c b/ipc/mqueue.c index 0a2a24b6ebe4..02e6f6798972 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -359,7 +359,7 @@ static ssize_t mqueue_read_file(struct file *filp, char __user *u_data, return count; } -static int mqueue_flush_file(struct file *filp) +static int mqueue_flush_file(struct file *filp, fl_owner_t id) { struct mqueue_inode_info *info = MQUEUE_I(filp->f_dentry->d_inode); -- cgit v1.2.3 From b0904e147f7cbe4be3b4dae49ddccd627bb66f16 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Fri, 23 Jun 2006 02:05:13 -0700 Subject: [PATCH] fs/locks.c: make posix_locks_deadlock() static We can now make posix_locks_deadlock() static. Signed-off-by: Adrian Bunk Cc: Trond Myklebust Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/locks.c | 4 +--- include/linux/fs.h | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) (limited to 'include') diff --git a/fs/locks.c b/fs/locks.c index f8a634ac1121..1ad29c9b6252 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -703,7 +703,7 @@ EXPORT_SYMBOL(posix_test_lock); * from a broken NFS client. But broken NFS clients have a lot more to * worry about than proper deadlock detection anyway... --okir */ -int posix_locks_deadlock(struct file_lock *caller_fl, +static int posix_locks_deadlock(struct file_lock *caller_fl, struct file_lock *block_fl) { struct list_head *tmp; @@ -722,8 +722,6 @@ next_task: return 0; } -EXPORT_SYMBOL(posix_locks_deadlock); - /* Try to create a FLOCK lock on filp. We always insert new FLOCK locks * at the head of the list, but that's secret knowledge known only to * flock_lock_file and posix_lock_file. diff --git a/include/linux/fs.h b/include/linux/fs.h index 56d8bf0d0a77..dba4cbd157ee 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -776,7 +776,6 @@ extern int posix_lock_file_conf(struct file *, struct file_lock *, struct file_l extern int posix_lock_file(struct file *, struct file_lock *); extern int posix_lock_file_wait(struct file *, struct file_lock *); extern int posix_unblock_lock(struct file *, struct file_lock *); -extern int posix_locks_deadlock(struct file_lock *, struct file_lock *); extern int flock_lock_file_wait(struct file *filp, struct file_lock *fl); extern int __break_lease(struct inode *inode, unsigned int flags); extern void lease_get_mtime(struct inode *, struct timespec *time); -- cgit v1.2.3 From 8d27e9084b372441dc8c9cf361a965ee58032767 Mon Sep 17 00:00:00 2001 From: Xose Vazquez Perez Date: Fri, 23 Jun 2006 02:05:13 -0700 Subject: [PATCH] module.h: updated comments with a new license "Dual MIT/GPL" is also accepted (kernel/module.c), so updated comments. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/module.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/linux/module.h b/include/linux/module.h index c2d89e037af0..2d366098eab5 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -105,6 +105,8 @@ extern struct module __this_module; * "GPL and additional rights" [GNU Public License v2 rights and more] * "Dual BSD/GPL" [GNU Public License v2 * or BSD license choice] + * "Dual MIT/GPL" [GNU Public License v2 + * or MIT license choice] * "Dual MPL/GPL" [GNU Public License v2 * or Mozilla license choice] * -- cgit v1.2.3 From 260ea1013283d8acbb451459ed1ca560c1445c20 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 23 Jun 2006 02:05:18 -0700 Subject: [PATCH] ptrace: document the locking rules After a lot of reading the code and thinking about how it behaves I have managed to figure out what the current ptrace locking rules are. The current code is in much better that it appears at first glance. The troublesome code paths are actually the code paths that violate the current rules. ptrace uses simple exclusive access as it's locking. You can only touch task->ptrace if the task is stopped and you are the ptracer, or if the task is running and are the task itself. Very simple, very easy to maintain. It just needs to be documented so people know not to touch ptrace from elsewhere. Currently we do have a few pieces of code that are in violation of this rule. Particularly the core dump code, and ptrace_attach. But so far the code looks fixable. Signed-off-by: Eric W. Biederman Cc: Oleg Nesterov Cc: Roland McGrath Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/ptrace.h | 4 ++++ include/linux/sched.h | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h index 0d36750fc0f1..ee918bc6e18c 100644 --- a/include/linux/ptrace.h +++ b/include/linux/ptrace.h @@ -51,6 +51,10 @@ #ifdef __KERNEL__ /* * Ptrace flags + * + * The owner ship rules for task->ptrace which holds the ptrace + * flags is simple. When a task is running it owns it's task->ptrace + * flags. When the a task is stopped the ptracer owns task->ptrace. */ #define PT_PTRACED 0x00000001 diff --git a/include/linux/sched.h b/include/linux/sched.h index 267f15257040..a9d23c7d1b25 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1225,7 +1225,7 @@ static inline int thread_group_empty(task_t *p) (thread_group_leader(p) && !thread_group_empty(p)) /* - * Protects ->fs, ->files, ->mm, ->ptrace, ->group_info, ->comm, keyring + * Protects ->fs, ->files, ->mm, ->group_info, ->comm, keyring * subscriptions and synchronises with wait4(). Also used in procfs. Also * pins the final release of task.io_context. Also protects ->cpuset. * -- cgit v1.2.3 From 0216bfcffe424a5473daa4da47440881b36c1f41 Mon Sep 17 00:00:00 2001 From: Mingming Cao Date: Fri, 23 Jun 2006 02:05:41 -0700 Subject: [PATCH] percpu counter data type changes to suppport more than 2**31 ext3 free blocks counter The percpu counter data type are changed in this set of patches to support more users like ext3 who need more than 32 bit to store the free blocks total in the filesystem. - Generic perpcu counters data type changes. The size of the global counter and local counter were explictly specified using s64 and s32. The global counter is changed from long to s64, while the local counter is changed from long to s32, so we could avoid doing 64 bit update in most cases. - Users of the percpu counters are updated to make use of the new percpu_counter_init() routine now taking an additional parameter to allow users to pass the initial value of the global counter. Signed-off-by: Mingming Cao Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ext2/super.c | 25 +++++++++++++------------ fs/ext3/super.c | 36 +++++++++++++++++++----------------- fs/file_table.c | 2 +- include/linux/percpu_counter.h | 38 ++++++++++++++++++++------------------ lib/percpu_counter.c | 10 +++++----- 5 files changed, 58 insertions(+), 53 deletions(-) (limited to 'include') diff --git a/fs/ext2/super.c b/fs/ext2/super.c index a6c4d6e02324..ee4ba759581e 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -834,9 +834,6 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) printk ("EXT2-fs: not enough memory\n"); goto failed_mount; } - percpu_counter_init(&sbi->s_freeblocks_counter); - percpu_counter_init(&sbi->s_freeinodes_counter); - percpu_counter_init(&sbi->s_dirs_counter); bgl_lock_init(&sbi->s_blockgroup_lock); sbi->s_debts = kmalloc(sbi->s_groups_count * sizeof(*sbi->s_debts), GFP_KERNEL); @@ -863,6 +860,13 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) sbi->s_gdb_count = db_count; get_random_bytes(&sbi->s_next_generation, sizeof(u32)); spin_lock_init(&sbi->s_next_gen_lock); + + percpu_counter_init(&sbi->s_freeblocks_counter, + ext2_count_free_blocks(sb)); + percpu_counter_init(&sbi->s_freeinodes_counter, + ext2_count_free_inodes(sb)); + percpu_counter_init(&sbi->s_dirs_counter, + ext2_count_dirs(sb)); /* * set up enough so that it can read an inode */ @@ -874,24 +878,18 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) if (!sb->s_root) { iput(root); printk(KERN_ERR "EXT2-fs: get root inode failed\n"); - goto failed_mount2; + goto failed_mount3; } if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) { dput(sb->s_root); sb->s_root = NULL; printk(KERN_ERR "EXT2-fs: corrupt root inode, run e2fsck\n"); - goto failed_mount2; + goto failed_mount3; } if (EXT2_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) ext2_warning(sb, __FUNCTION__, "mounting ext3 filesystem as ext2"); ext2_setup_super (sb, es, sb->s_flags & MS_RDONLY); - percpu_counter_mod(&sbi->s_freeblocks_counter, - ext2_count_free_blocks(sb)); - percpu_counter_mod(&sbi->s_freeinodes_counter, - ext2_count_free_inodes(sb)); - percpu_counter_mod(&sbi->s_dirs_counter, - ext2_count_dirs(sb)); return 0; cantfind_ext2: @@ -899,7 +897,10 @@ cantfind_ext2: printk("VFS: Can't find an ext2 filesystem on dev %s.\n", sb->s_id); goto failed_mount; - +failed_mount3: + percpu_counter_destroy(&sbi->s_freeblocks_counter); + percpu_counter_destroy(&sbi->s_freeinodes_counter); + percpu_counter_destroy(&sbi->s_dirs_counter); failed_mount2: for (i = 0; i < db_count; i++) brelse(sbi->s_group_desc[i]); diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 1a198b3985c9..a60cc6ec130f 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -1580,9 +1580,6 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) goto failed_mount; } - percpu_counter_init(&sbi->s_freeblocks_counter); - percpu_counter_init(&sbi->s_freeinodes_counter); - percpu_counter_init(&sbi->s_dirs_counter); bgl_lock_init(&sbi->s_blockgroup_lock); for (i = 0; i < db_count; i++) { @@ -1602,6 +1599,14 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) sbi->s_gdb_count = db_count; get_random_bytes(&sbi->s_next_generation, sizeof(u32)); spin_lock_init(&sbi->s_next_gen_lock); + + percpu_counter_init(&sbi->s_freeblocks_counter, + ext3_count_free_blocks(sb)); + percpu_counter_init(&sbi->s_freeinodes_counter, + ext3_count_free_inodes(sb)); + percpu_counter_init(&sbi->s_dirs_counter, + ext3_count_dirs(sb)); + /* per fileystem reservation list head & lock */ spin_lock_init(&sbi->s_rsv_window_lock); sbi->s_rsv_window_root = RB_ROOT; @@ -1640,16 +1645,16 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) if (!test_opt(sb, NOLOAD) && EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) { if (ext3_load_journal(sb, es, journal_devnum)) - goto failed_mount2; + goto failed_mount3; } else if (journal_inum) { if (ext3_create_journal(sb, es, journal_inum)) - goto failed_mount2; + goto failed_mount3; } else { if (!silent) printk (KERN_ERR "ext3: No journal on filesystem on %s\n", sb->s_id); - goto failed_mount2; + goto failed_mount3; } /* We have now updated the journal if required, so we can @@ -1672,7 +1677,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) (sbi->s_journal, 0, 0, JFS_FEATURE_INCOMPAT_REVOKE)) { printk(KERN_ERR "EXT3-fs: Journal does not support " "requested data journaling mode\n"); - goto failed_mount3; + goto failed_mount4; } default: break; @@ -1695,13 +1700,13 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) if (!sb->s_root) { printk(KERN_ERR "EXT3-fs: get root inode failed\n"); iput(root); - goto failed_mount3; + goto failed_mount4; } if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) { dput(sb->s_root); sb->s_root = NULL; printk(KERN_ERR "EXT3-fs: corrupt root inode, run e2fsck\n"); - goto failed_mount3; + goto failed_mount4; } ext3_setup_super (sb, es, sb->s_flags & MS_RDONLY); @@ -1724,13 +1729,6 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) test_opt(sb,DATA_FLAGS) == EXT3_MOUNT_ORDERED_DATA ? "ordered": "writeback"); - percpu_counter_mod(&sbi->s_freeblocks_counter, - ext3_count_free_blocks(sb)); - percpu_counter_mod(&sbi->s_freeinodes_counter, - ext3_count_free_inodes(sb)); - percpu_counter_mod(&sbi->s_dirs_counter, - ext3_count_dirs(sb)); - lock_kernel(); return 0; @@ -1740,8 +1738,12 @@ cantfind_ext3: sb->s_id); goto failed_mount; -failed_mount3: +failed_mount4: journal_destroy(sbi->s_journal); +failed_mount3: + percpu_counter_destroy(&sbi->s_freeblocks_counter); + percpu_counter_destroy(&sbi->s_freeinodes_counter); + percpu_counter_destroy(&sbi->s_dirs_counter); failed_mount2: for (i = 0; i < db_count; i++) brelse(sbi->s_group_desc[i]); diff --git a/fs/file_table.c b/fs/file_table.c index bcea1998b4de..506d5307108d 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -300,5 +300,5 @@ void __init files_init(unsigned long mempages) if (files_stat.max_files < NR_FILE) files_stat.max_files = NR_FILE; files_defer_init(); - percpu_counter_init(&nr_files); + percpu_counter_init(&nr_files, 0); } diff --git a/include/linux/percpu_counter.h b/include/linux/percpu_counter.h index 66b5de404f22..f5aa593ccf32 100644 --- a/include/linux/percpu_counter.h +++ b/include/linux/percpu_counter.h @@ -10,13 +10,14 @@ #include #include #include +#include #ifdef CONFIG_SMP struct percpu_counter { spinlock_t lock; - long count; - long *counters; + s64 count; + s32 *counters; }; #if NR_CPUS >= 16 @@ -25,11 +26,11 @@ struct percpu_counter { #define FBC_BATCH (NR_CPUS*4) #endif -static inline void percpu_counter_init(struct percpu_counter *fbc) +static inline void percpu_counter_init(struct percpu_counter *fbc, s64 amount) { spin_lock_init(&fbc->lock); - fbc->count = 0; - fbc->counters = alloc_percpu(long); + fbc->count = amount; + fbc->counters = alloc_percpu(s32); } static inline void percpu_counter_destroy(struct percpu_counter *fbc) @@ -37,10 +38,10 @@ static inline void percpu_counter_destroy(struct percpu_counter *fbc) free_percpu(fbc->counters); } -void percpu_counter_mod(struct percpu_counter *fbc, long amount); -long percpu_counter_sum(struct percpu_counter *fbc); +void percpu_counter_mod(struct percpu_counter *fbc, s32 amount); +s64 percpu_counter_sum(struct percpu_counter *fbc); -static inline long percpu_counter_read(struct percpu_counter *fbc) +static inline s64 percpu_counter_read(struct percpu_counter *fbc) { return fbc->count; } @@ -48,13 +49,14 @@ static inline long percpu_counter_read(struct percpu_counter *fbc) /* * It is possible for the percpu_counter_read() to return a small negative * number for some counter which should never be negative. + * */ -static inline long percpu_counter_read_positive(struct percpu_counter *fbc) +static inline s64 percpu_counter_read_positive(struct percpu_counter *fbc) { - long ret = fbc->count; + s64 ret = fbc->count; barrier(); /* Prevent reloads of fbc->count */ - if (ret > 0) + if (ret >= 0) return ret; return 1; } @@ -62,12 +64,12 @@ static inline long percpu_counter_read_positive(struct percpu_counter *fbc) #else struct percpu_counter { - long count; + s64 count; }; -static inline void percpu_counter_init(struct percpu_counter *fbc) +static inline void percpu_counter_init(struct percpu_counter *fbc, s64 amount) { - fbc->count = 0; + fbc->count = amount; } static inline void percpu_counter_destroy(struct percpu_counter *fbc) @@ -75,24 +77,24 @@ static inline void percpu_counter_destroy(struct percpu_counter *fbc) } static inline void -percpu_counter_mod(struct percpu_counter *fbc, long amount) +percpu_counter_mod(struct percpu_counter *fbc, s32 amount) { preempt_disable(); fbc->count += amount; preempt_enable(); } -static inline long percpu_counter_read(struct percpu_counter *fbc) +static inline s64 percpu_counter_read(struct percpu_counter *fbc) { return fbc->count; } -static inline long percpu_counter_read_positive(struct percpu_counter *fbc) +static inline s64 percpu_counter_read_positive(struct percpu_counter *fbc) { return fbc->count; } -static inline long percpu_counter_sum(struct percpu_counter *fbc) +static inline s64 percpu_counter_sum(struct percpu_counter *fbc) { return percpu_counter_read_positive(fbc); } diff --git a/lib/percpu_counter.c b/lib/percpu_counter.c index 7a87003f8e8f..850449080e1c 100644 --- a/lib/percpu_counter.c +++ b/lib/percpu_counter.c @@ -5,10 +5,10 @@ #include #include -void percpu_counter_mod(struct percpu_counter *fbc, long amount) +void percpu_counter_mod(struct percpu_counter *fbc, s32 amount) { long count; - long *pcount; + s32 *pcount; int cpu = get_cpu(); pcount = per_cpu_ptr(fbc->counters, cpu); @@ -29,15 +29,15 @@ EXPORT_SYMBOL(percpu_counter_mod); * Add up all the per-cpu counts, return the result. This is a more accurate * but much slower version of percpu_counter_read_positive() */ -long percpu_counter_sum(struct percpu_counter *fbc) +s64 percpu_counter_sum(struct percpu_counter *fbc) { - long ret; + s64 ret; int cpu; spin_lock(&fbc->lock); ret = fbc->count; for_each_possible_cpu(cpu) { - long *pcount = per_cpu_ptr(fbc->counters, cpu); + s32 *pcount = per_cpu_ptr(fbc->counters, cpu); ret += *pcount; } spin_unlock(&fbc->lock); -- cgit v1.2.3 From 368a5fa1f28589e6b54588a139ea872d5b4b1914 Mon Sep 17 00:00:00 2001 From: Hua Zhong Date: Fri, 23 Jun 2006 02:05:42 -0700 Subject: [PATCH] remove unlikely() in might_sleep_if() The likely() profiling tools show that __alloc_page() causes a lot of misses: ! 132 119193 __alloc_pages():mm/page_alloc.c@937 Because most __alloc_page() calls are not atomic. Signed-off-by: Hua Zhong Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/kernel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 25fccd859fbf..8c21aaa248b4 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -78,7 +78,7 @@ extern int cond_resched(void); # define might_sleep() do { might_resched(); } while (0) #endif -#define might_sleep_if(cond) do { if (unlikely(cond)) might_sleep(); } while (0) +#define might_sleep_if(cond) do { if (cond) might_sleep(); } while (0) #define abs(x) ({ \ int __x = (x); \ -- cgit v1.2.3 From 1d31a4ea8cf7a2afc7299d1d3d8732ca54a5934e Mon Sep 17 00:00:00 2001 From: Matt Helsley Date: Fri, 23 Jun 2006 02:05:42 -0700 Subject: [PATCH] Process Events - Header Cleanup Move connector header include to precisely where it's needed. Remove unused time.h header file as well. This was leftover from previous iterations of the process events patches. Signed-off-by: Matt Helsley Cc: Guillaume Thouvenin Cc: Nguyen Anh Quynh Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/connector/cn_proc.c | 1 + include/linux/cn_proc.h | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c index 4b4d7db1ff7b..498aa37bca22 100644 --- a/drivers/connector/cn_proc.c +++ b/drivers/connector/cn_proc.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include diff --git a/include/linux/cn_proc.h b/include/linux/cn_proc.h index 1417de935057..1e3459a14e20 100644 --- a/include/linux/cn_proc.h +++ b/include/linux/cn_proc.h @@ -26,8 +26,6 @@ #define CN_PROC_H #include -#include -#include /* * Userspace sends this enum to register with the kernel that it is listening -- cgit v1.2.3 From 3fa2164d03fb7af17fcfe4f8800dd754fbd99ff7 Mon Sep 17 00:00:00 2001 From: Matt Helsley Date: Fri, 23 Jun 2006 02:05:44 -0700 Subject: [PATCH] Process Events: License Change Change the license on the process event structure passed between kernel and userspace. Signed-off-by: Matt Helsley Acked-by: Guillaume Thouvenin Acked-by: Nguyen Anh Quynh Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/cn_proc.h | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) (limited to 'include') diff --git a/include/linux/cn_proc.h b/include/linux/cn_proc.h index 1e3459a14e20..dbb7769009be 100644 --- a/include/linux/cn_proc.h +++ b/include/linux/cn_proc.h @@ -3,23 +3,16 @@ * * Copyright (C) Matt Helsley, IBM Corp. 2005 * Based on cn_fork.h by Nguyen Anh Quynh and Guillaume Thouvenin - * Original copyright notice follows: * Copyright (C) 2005 Nguyen Anh Quynh * Copyright (C) 2005 Guillaume Thouvenin * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License + * as published by the Free Software Foundation. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ #ifndef CN_PROC_H -- cgit v1.2.3 From 481fad483487ea967fe20bbc9e565d787f7bf20f Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Fri, 23 Jun 2006 02:05:44 -0700 Subject: [PATCH] strstrip() API Add a new strstrip() function to lib/string.c for removing leading and trailing whitespace from a string. Cc: Michael Holzheu Acked-by: Ingo Oeser Acked-by: Joern Engel Cc: Corey Minyard Signed-off-by: Pekka Enberg Acked-by: Michael Holzheu Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/string.h | 1 + lib/string.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) (limited to 'include') diff --git a/include/linux/string.h b/include/linux/string.h index c61306da8c52..e4c755860316 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -56,6 +56,7 @@ extern char * strnchr(const char *, size_t, int); #ifndef __HAVE_ARCH_STRRCHR extern char * strrchr(const char *,int); #endif +extern char * strstrip(char *); #ifndef __HAVE_ARCH_STRSTR extern char * strstr(const char *,const char *); #endif diff --git a/lib/string.c b/lib/string.c index 064f6315b1c3..63077267367e 100644 --- a/lib/string.c +++ b/lib/string.c @@ -301,6 +301,36 @@ char *strnchr(const char *s, size_t count, int c) EXPORT_SYMBOL(strnchr); #endif +/** + * strstrip - Removes leading and trailing whitespace from @s. + * @s: The string to be stripped. + * + * Note that the first trailing whitespace is replaced with a %NUL-terminator + * in the given string @s. Returns a pointer to the first non-whitespace + * character in @s. + */ +char *strstrip(char *s) +{ + size_t size; + char *end; + + size = strlen(s); + + if (!size) + return s; + + end = s + size - 1; + while (end != s && isspace(*end)) + end--; + *(end + 1) = '\0'; + + while (*s && isspace(*s)) + s++; + + return s; +} +EXPORT_SYMBOL(strstrip); + #ifndef __HAVE_ARCH_STRLEN /** * strlen - Find the length of a string -- cgit v1.2.3 From d83015b8f62ee3fcd338f6f009051ed57f77a531 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 23 Jun 2006 02:05:51 -0700 Subject: [PATCH] Make RCU API inaccessible to non-GPL Linux kernel modules Remove synchronize_kernel() (deprecated 2-APR-2005 in http://lkml.org/lkml/2005/4/3/11) and makes the RCU API inaccessible to non-GPL Linux kernel modules (as was announced more than one year ago in http://lkml.org/lkml/2005/4/3/8). Tested on x86 and ppc64. Signed-off-by: "Paul E. McKenney" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/RCU/whatisRCU.txt | 1 - Documentation/feature-removal-schedule.txt | 15 --------------- include/linux/rcupdate.h | 3 +-- kernel/rcupdate.c | 13 ++----------- 4 files changed, 3 insertions(+), 29 deletions(-) (limited to 'include') diff --git a/Documentation/RCU/whatisRCU.txt b/Documentation/RCU/whatisRCU.txt index 07cb93b82ba9..6e459420ee9f 100644 --- a/Documentation/RCU/whatisRCU.txt +++ b/Documentation/RCU/whatisRCU.txt @@ -790,7 +790,6 @@ RCU pointer update: RCU grace period: - synchronize_kernel (deprecated) synchronize_net synchronize_sched synchronize_rcu diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index f7293297f326..027285d0c26c 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -33,21 +33,6 @@ Who: Adrian Bunk --------------------------- -What: RCU API moves to EXPORT_SYMBOL_GPL -When: April 2006 -Files: include/linux/rcupdate.h, kernel/rcupdate.c -Why: Outside of Linux, the only implementations of anything even - vaguely resembling RCU that I am aware of are in DYNIX/ptx, - VM/XA, Tornado, and K42. I do not expect anyone to port binary - drivers or kernel modules from any of these, since the first two - are owned by IBM and the last two are open-source research OSes. - So these will move to GPL after a grace period to allow - people, who might be using implementations that I am not aware - of, to adjust to this upcoming change. -Who: Paul E. McKenney - ---------------------------- - What: raw1394: requests of type RAW1394_REQ_ISO_SEND, RAW1394_REQ_ISO_LISTEN When: November 2006 Why: Deprecated in favour of the new ioctl-based rawiso interface, which is diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 970284f571a6..6312758393b6 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -246,7 +246,7 @@ extern int rcu_needs_cpu(int cpu); * softirq handlers will have completed, since in some kernels, these * handlers can run in process context, and can block. * - * This primitive provides the guarantees made by the (deprecated) + * This primitive provides the guarantees made by the (now removed) * synchronize_kernel() API. In contrast, synchronize_rcu() only * guarantees that rcu_read_lock() sections will have completed. * In "classic RCU", these two guarantees happen to be one and @@ -264,7 +264,6 @@ extern void FASTCALL(call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *head))); extern void FASTCALL(call_rcu_bh(struct rcu_head *head, void (*func)(struct rcu_head *head))); -extern __deprecated_for_modules void synchronize_kernel(void); extern void synchronize_rcu(void); void synchronize_idle(void); extern void rcu_barrier(void); diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c index 2058f88c7bbb..20e9710fc21c 100644 --- a/kernel/rcupdate.c +++ b/kernel/rcupdate.c @@ -612,14 +612,6 @@ void synchronize_rcu(void) wait_for_completion(&rcu.completion); } -/* - * Deprecated, use synchronize_rcu() or synchronize_sched() instead. - */ -void synchronize_kernel(void) -{ - synchronize_rcu(); -} - module_param(blimit, int, 0); module_param(qhimark, int, 0); module_param(qlowmark, int, 0); @@ -627,7 +619,6 @@ module_param(qlowmark, int, 0); module_param(rsinterval, int, 0); #endif EXPORT_SYMBOL_GPL(rcu_batches_completed); -EXPORT_SYMBOL_GPL_FUTURE(call_rcu); /* WARNING: GPL-only in April 2006. */ -EXPORT_SYMBOL_GPL_FUTURE(call_rcu_bh); /* WARNING: GPL-only in April 2006. */ +EXPORT_SYMBOL_GPL(call_rcu); +EXPORT_SYMBOL_GPL(call_rcu_bh); EXPORT_SYMBOL_GPL(synchronize_rcu); -EXPORT_SYMBOL_GPL_FUTURE(synchronize_kernel); /* WARNING: GPL-only in April 2006. */ -- cgit v1.2.3 From f5befceb5cfecba49fdf61f8e0eb4d453200eac9 Mon Sep 17 00:00:00 2001 From: Brent Casavant Date: Fri, 23 Jun 2006 02:05:52 -0700 Subject: [PATCH] SGI IOC4: Detect IO card variant There are three different IO cards which an SGI IOC4 controller may find itself on. One of these variants does not bring out the IDE and serial signals, so we need to disable attaching the corresponding IOC4 subdrivers to such cards. Cleans up message clutter emitted during device probing. Signed-off-by: Brent Casavant Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/ide/pci/sgiioc4.c | 6 +++++ drivers/serial/ioc4_serial.c | 9 +++++++ drivers/sn/ioc4.c | 64 ++++++++++++++++++++++++++++++++++++++++---- include/linux/ioc4.h | 5 ++++ 4 files changed, 79 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c index 27c9eb989a9a..e125032bb403 100644 --- a/drivers/ide/pci/sgiioc4.c +++ b/drivers/ide/pci/sgiioc4.c @@ -723,6 +723,12 @@ static ide_pci_device_t sgiioc4_chipsets[] __devinitdata = { int ioc4_ide_attach_one(struct ioc4_driver_data *idd) { + /* PCI-RT does not bring out IDE connection. + * Do not attach to this particular IOC4. + */ + if (idd->idd_variant == IOC4_VARIANT_PCI_RT) + return 0; + return pci_init_sgiioc4(idd->idd_pdev, &sgiioc4_chipsets[idd->idd_pci_id->driver_data]); } diff --git a/drivers/serial/ioc4_serial.c b/drivers/serial/ioc4_serial.c index c620209d7b9a..717e47bbd784 100644 --- a/drivers/serial/ioc4_serial.c +++ b/drivers/serial/ioc4_serial.c @@ -2646,7 +2646,10 @@ static int ioc4_serial_remove_one(struct ioc4_driver_data *idd) struct ioc4_port *port; struct ioc4_soft *soft; + /* If serial driver did not attach, don't try to detach */ control = idd->idd_serial_data; + if (!control) + return 0; for (port_num = 0; port_num < IOC4_NUM_SERIAL_PORTS; port_num++) { for (port_type = UART_PORT_MIN; @@ -2778,6 +2781,12 @@ ioc4_serial_attach_one(struct ioc4_driver_data *idd) DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __FUNCTION__, idd->idd_pdev, idd->idd_pci_id)); + /* PCI-RT does not bring out serial connections. + * Do not attach to this particular IOC4. + */ + if (idd->idd_variant == IOC4_VARIANT_PCI_RT) + return 0; + /* request serial registers */ tmp_addr1 = idd->idd_bar0 + IOC4_SERIAL_OFFSET; diff --git a/drivers/sn/ioc4.c b/drivers/sn/ioc4.c index cdeff909403e..8256a97eb508 100644 --- a/drivers/sn/ioc4.c +++ b/drivers/sn/ioc4.c @@ -160,9 +160,6 @@ ioc4_clock_calibrate(struct ioc4_driver_data *idd) writel(0, &idd->idd_misc_regs->int_out.raw); mmiowb(); - printk(KERN_INFO - "%s: Calibrating PCI bus speed " - "for pci_dev %s ... ", __FUNCTION__, pci_name(idd->idd_pdev)); /* Set up square wave */ int_out.raw = 0; int_out.fields.count = IOC4_CALIBRATE_COUNT; @@ -206,11 +203,16 @@ ioc4_clock_calibrate(struct ioc4_driver_data *idd) /* Bounds check the result. */ if (period > IOC4_CALIBRATE_LOW_LIMIT || period < IOC4_CALIBRATE_HIGH_LIMIT) { - printk("failed. Assuming PCI clock ticks are %d ns.\n", + printk(KERN_INFO + "IOC4 %s: Clock calibration failed. Assuming" + "PCI clock is %d ns.\n", + pci_name(idd->idd_pdev), IOC4_CALIBRATE_DEFAULT / IOC4_EXTINT_COUNT_DIVISOR); period = IOC4_CALIBRATE_DEFAULT; } else { - printk("succeeded. PCI clock ticks are %ld ns.\n", + printk(KERN_DEBUG + "IOC4 %s: PCI clock is %ld ns.\n", + pci_name(idd->idd_pdev), period / IOC4_EXTINT_COUNT_DIVISOR); } @@ -222,6 +224,51 @@ ioc4_clock_calibrate(struct ioc4_driver_data *idd) idd->count_period = period; } +/* There are three variants of IOC4 cards: IO9, IO10, and PCI-RT. + * Each brings out different combinations of IOC4 signals, thus. + * the IOC4 subdrivers need to know to which we're attached. + * + * We look for the presence of a SCSI (IO9) or SATA (IO10) controller + * on the same PCI bus at slot number 3 to differentiate IO9 from IO10. + * If neither is present, it's a PCI-RT. + */ +static unsigned int +ioc4_variant(struct ioc4_driver_data *idd) +{ + struct pci_dev *pdev = NULL; + int found = 0; + + /* IO9: Look for a QLogic ISP 12160 at the same bus and slot 3. */ + do { + pdev = pci_get_device(PCI_VENDOR_ID_QLOGIC, + PCI_DEVICE_ID_QLOGIC_ISP12160, pdev); + if (pdev && + idd->idd_pdev->bus->number == pdev->bus->number && + 3 == PCI_SLOT(pdev->devfn)) + found = 1; + pci_dev_put(pdev); + } while (pdev && !found); + if (NULL != pdev) + return IOC4_VARIANT_IO9; + + /* IO10: Look for a Vitesse VSC 7174 at the same bus and slot 3. */ + pdev = NULL; + do { + pdev = pci_get_device(PCI_VENDOR_ID_VITESSE, + PCI_DEVICE_ID_VITESSE_VSC7174, pdev); + if (pdev && + idd->idd_pdev->bus->number == pdev->bus->number && + 3 == PCI_SLOT(pdev->devfn)) + found = 1; + pci_dev_put(pdev); + } while (pdev && !found); + if (NULL != pdev) + return IOC4_VARIANT_IO10; + + /* PCI-RT: No SCSI/SATA controller will be present */ + return IOC4_VARIANT_PCI_RT; +} + /* Adds a new instance of an IOC4 card */ static int ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) @@ -286,6 +333,13 @@ ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) /* Failsafe portion of per-IOC4 initialization */ + /* Detect card variant */ + idd->idd_variant = ioc4_variant(idd); + printk(KERN_INFO "IOC4 %s: %s card detected.\n", pci_name(pdev), + idd->idd_variant == IOC4_VARIANT_IO9 ? "IO9" : + idd->idd_variant == IOC4_VARIANT_PCI_RT ? "PCI-RT" : + idd->idd_variant == IOC4_VARIANT_IO10 ? "IO10" : "unknown"); + /* Initialize IOC4 */ pci_read_config_dword(idd->idd_pdev, PCI_COMMAND, &pcmd); pci_write_config_dword(idd->idd_pdev, PCI_COMMAND, diff --git a/include/linux/ioc4.h b/include/linux/ioc4.h index 3dd18b785ebd..de73a3289cc2 100644 --- a/include/linux/ioc4.h +++ b/include/linux/ioc4.h @@ -147,6 +147,10 @@ struct ioc4_misc_regs { #define IOC4_GPCR_EDGE_6 0x40 #define IOC4_GPCR_EDGE_7 0x80 +#define IOC4_VARIANT_IO9 0x0900 +#define IOC4_VARIANT_PCI_RT 0x0901 +#define IOC4_VARIANT_IO10 0x1000 + /* One of these per IOC4 */ struct ioc4_driver_data { struct list_head idd_list; @@ -156,6 +160,7 @@ struct ioc4_driver_data { struct __iomem ioc4_misc_regs *idd_misc_regs; unsigned long count_period; void *idd_serial_data; + unsigned int idd_variant; }; /* One per submodule */ -- cgit v1.2.3 From 54e73770357142e297c916c7865f5fca7499f69c Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Fri, 23 Jun 2006 02:05:54 -0700 Subject: [PATCH] list: introduce list_replace() helper list_replace() is similar to list_replace_rcu(), but unlike list_replace_rcu() it could be used when list_empty(old) == 1 doesn't use barriers Signed-off-by: Oleg Nesterov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/list.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'include') diff --git a/include/linux/list.h b/include/linux/list.h index 76f05718342c..a02642e4710a 100644 --- a/include/linux/list.h +++ b/include/linux/list.h @@ -197,12 +197,35 @@ static inline void list_del_rcu(struct list_head *entry) entry->prev = LIST_POISON2; } +/** + * list_replace - replace old entry by new one + * @old : the element to be replaced + * @new : the new element to insert + * Note: if 'old' was empty, it will be overwritten. + */ +static inline void list_replace(struct list_head *old, + struct list_head *new) +{ + new->next = old->next; + new->next->prev = new; + new->prev = old->prev; + new->prev->next = new; +} + +static inline void list_replace_init(struct list_head *old, + struct list_head *new) +{ + list_replace(old, new); + INIT_LIST_HEAD(old); +} + /* * list_replace_rcu - replace old entry by new one * @old : the element to be replaced * @new : the new element to insert * * The old entry will be replaced with the new entry atomically. + * Note: 'old' should not be empty. */ static inline void list_replace_rcu(struct list_head *old, struct list_head *new) -- cgit v1.2.3 From 908dcecda1d18803b5823f30e6c47d2882dc0cf1 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Fri, 23 Jun 2006 02:06:00 -0700 Subject: [PATCH] adjust handle_IRR_event() return type Correct the return type of handle_IRQ_event() (inconsistency noticed during Xen development), and remove redundant declarations. The return type adjustment required breaking out the definition of irqreturn_t into a separate header, in order to satisfy current include order dependencies. Signed-off-by: Jan Beulich Cc: Richard Henderson Cc: Ivan Kokshaysky Cc: Russell King Cc: Ian Molton Cc: Mikael Starvik Cc: Yoshinori Sato Cc: Hirokazu Takata Cc: Heiko Carstens Cc: Martin Schwidefsky Cc: William Lee Irwin III Cc: "David S. Miller" Cc: Miles Bader Cc: Geert Uytterhoeven Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-alpha/irq.h | 4 ---- include/asm-arm/irq.h | 4 ---- include/asm-arm26/irq.h | 4 ---- include/asm-h8300/irq.h | 4 ---- include/asm-m68k/irq.h | 4 ---- include/asm-m68knommu/irq.h | 4 ---- include/asm-s390/irq.h | 4 ---- include/asm-sparc/irq.h | 4 ---- include/asm-v850/irq.h | 2 -- include/linux/interrupt.h | 21 +-------------------- include/linux/irq.h | 3 ++- include/linux/irqreturn.h | 25 +++++++++++++++++++++++++ kernel/irq/handle.c | 5 +++-- 13 files changed, 31 insertions(+), 57 deletions(-) create mode 100644 include/linux/irqreturn.h (limited to 'include') diff --git a/include/asm-alpha/irq.h b/include/asm-alpha/irq.h index f6de033718a0..917b9fe372cf 100644 --- a/include/asm-alpha/irq.h +++ b/include/asm-alpha/irq.h @@ -92,8 +92,4 @@ extern void enable_irq(unsigned int); struct pt_regs; extern void (*perf_irq)(unsigned long, struct pt_regs *); -struct irqaction; -int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *); - - #endif /* _ALPHA_IRQ_H */ diff --git a/include/asm-arm/irq.h b/include/asm-arm/irq.h index 60b5105c9c93..66e67e60bc56 100644 --- a/include/asm-arm/irq.h +++ b/include/asm-arm/irq.h @@ -47,10 +47,6 @@ void disable_irq_wake(unsigned int irq); void enable_irq_wake(unsigned int irq); int setup_irq(unsigned int, struct irqaction *); -struct irqaction; -struct pt_regs; -int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *); - extern void migrate_irqs(void); #endif diff --git a/include/asm-arm26/irq.h b/include/asm-arm26/irq.h index 06bd5a543d13..9aaac87efba9 100644 --- a/include/asm-arm26/irq.h +++ b/include/asm-arm26/irq.h @@ -44,9 +44,5 @@ extern void enable_irq(unsigned int); int set_irq_type(unsigned int irq, unsigned int type); -int setup_irq(unsigned int, struct irqaction *); -struct pt_regs; -int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *); - #endif diff --git a/include/asm-h8300/irq.h b/include/asm-h8300/irq.h index 73065f5bda0e..42a3ac424a9e 100644 --- a/include/asm-h8300/irq.h +++ b/include/asm-h8300/irq.h @@ -63,8 +63,4 @@ extern void enable_irq(unsigned int); extern void disable_irq(unsigned int); #define disable_irq_nosync(x) disable_irq(x) -struct irqaction; -struct pt_regs; -int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *); - #endif /* _H8300_IRQ_H_ */ diff --git a/include/asm-m68k/irq.h b/include/asm-m68k/irq.h index b4f48b2a6a57..9727ca9d9f26 100644 --- a/include/asm-m68k/irq.h +++ b/include/asm-m68k/irq.h @@ -130,8 +130,4 @@ extern volatile unsigned int num_spurious; */ extern irq_node_t *new_irq_node(void); -struct irqaction; -struct pt_regs; -int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *); - #endif /* _M68K_IRQ_H_ */ diff --git a/include/asm-m68knommu/irq.h b/include/asm-m68knommu/irq.h index 2b408842a30e..c5247516fcfe 100644 --- a/include/asm-m68knommu/irq.h +++ b/include/asm-m68knommu/irq.h @@ -87,8 +87,4 @@ extern void (*mach_disable_irq)(unsigned int); #define disable_irq(x) do { } while (0) #define disable_irq_nosync(x) disable_irq(x) -struct irqaction; -struct pt_regs; -int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *); - #endif /* _M68K_IRQ_H_ */ diff --git a/include/asm-s390/irq.h b/include/asm-s390/irq.h index 916a1aa0b073..bd1a721f7aa2 100644 --- a/include/asm-s390/irq.h +++ b/include/asm-s390/irq.h @@ -21,10 +21,6 @@ enum interruption_class { #define touch_nmi_watchdog() do { } while(0) -struct irqaction; -struct pt_regs; -int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *); - #endif /* __KERNEL__ */ #endif diff --git a/include/asm-sparc/irq.h b/include/asm-sparc/irq.h index f2d64537e29d..3141ddfea97d 100644 --- a/include/asm-sparc/irq.h +++ b/include/asm-sparc/irq.h @@ -181,8 +181,4 @@ extern struct sun4m_intregs *sun4m_interrupts; #define SUN4M_INT_SBUS(x) (1 << (x+7)) #define SUN4M_INT_VME(x) (1 << (x)) -struct irqaction; -struct pt_regs; -int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *); - #endif diff --git a/include/asm-v850/irq.h b/include/asm-v850/irq.h index 44431152b36d..1bf096db8f4c 100644 --- a/include/asm-v850/irq.h +++ b/include/asm-v850/irq.h @@ -62,8 +62,6 @@ extern void disable_irq (unsigned int irq); /* Disable an irq without waiting. */ extern void disable_irq_nosync (unsigned int irq); -extern int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *); - #endif /* !__ASSEMBLY__ */ #endif /* __V850_IRQ_H__ */ diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 9e0fefd7884a..70741e170114 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -7,32 +7,13 @@ #include #include #include +#include #include #include #include #include #include -/* - * For 2.4.x compatibility, 2.4.x can use - * - * typedef void irqreturn_t; - * #define IRQ_NONE - * #define IRQ_HANDLED - * #define IRQ_RETVAL(x) - * - * To mix old-style and new-style irq handler returns. - * - * IRQ_NONE means we didn't handle it. - * IRQ_HANDLED means that we did have a valid interrupt and handled it. - * IRQ_RETVAL(x) selects on the two depending on x being non-zero (for handled) - */ -typedef int irqreturn_t; - -#define IRQ_NONE (0) -#define IRQ_HANDLED (1) -#define IRQ_RETVAL(x) ((x) != 0) - struct irqaction { irqreturn_t (*handler)(int, void *, struct pt_regs *); unsigned long flags; diff --git a/include/linux/irq.h b/include/linux/irq.h index e8a07e75e4fb..676e00dfb21a 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -175,7 +176,7 @@ static inline void set_balance_irq_affinity(unsigned int irq, cpumask_t mask) extern int no_irq_affinity; extern int noirqdebug_setup(char *str); -extern fastcall int handle_IRQ_event(unsigned int irq, struct pt_regs *regs, +extern fastcall irqreturn_t handle_IRQ_event(unsigned int irq, struct pt_regs *regs, struct irqaction *action); extern fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs); extern void note_interrupt(unsigned int irq, irq_desc_t *desc, diff --git a/include/linux/irqreturn.h b/include/linux/irqreturn.h new file mode 100644 index 000000000000..881883c2009d --- /dev/null +++ b/include/linux/irqreturn.h @@ -0,0 +1,25 @@ +/* irqreturn.h */ +#ifndef _LINUX_IRQRETURN_H +#define _LINUX_IRQRETURN_H + +/* + * For 2.4.x compatibility, 2.4.x can use + * + * typedef void irqreturn_t; + * #define IRQ_NONE + * #define IRQ_HANDLED + * #define IRQ_RETVAL(x) + * + * To mix old-style and new-style irq handler returns. + * + * IRQ_NONE means we didn't handle it. + * IRQ_HANDLED means that we did have a valid interrupt and handled it. + * IRQ_RETVAL(x) selects on the two depending on x being non-zero (for handled) + */ +typedef int irqreturn_t; + +#define IRQ_NONE (0) +#define IRQ_HANDLED (1) +#define IRQ_RETVAL(x) ((x) != 0) + +#endif diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c index 51df337b37db..0f6530117105 100644 --- a/kernel/irq/handle.c +++ b/kernel/irq/handle.c @@ -76,10 +76,11 @@ irqreturn_t no_action(int cpl, void *dev_id, struct pt_regs *regs) /* * Have got an event to handle: */ -fastcall int handle_IRQ_event(unsigned int irq, struct pt_regs *regs, +fastcall irqreturn_t handle_IRQ_event(unsigned int irq, struct pt_regs *regs, struct irqaction *action) { - int ret, retval = 0, status = 0; + irqreturn_t ret, retval = IRQ_NONE; + unsigned int status = 0; if (!(action->flags & SA_INTERRUPT)) local_irq_enable(); -- cgit v1.2.3 From 78ce89c92bc6eaf5933b5664bff64253a7103bd7 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Fri, 23 Jun 2006 02:06:05 -0700 Subject: [PATCH] JBD: split checkpoint lists Split the checkpoint list of the transaction into two lists. In the first list we keep the buffers that need to be submitted for IO. In the second list are kept buffers that were already submitted and we just have to wait for the IO to complete. This should simplify a handling of checkpoint lists a bit and can eventually be also a performance gain. Signed-off-by: Jan Kara Cc: Mark Fasheh Cc: "Stephen C. Tweedie" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/jbd/checkpoint.c | 419 ++++++++++++++++++++++++++++++---------------------- include/linux/jbd.h | 8 +- 2 files changed, 246 insertions(+), 181 deletions(-) (limited to 'include') diff --git a/fs/jbd/checkpoint.c b/fs/jbd/checkpoint.c index 3f5102b069db..47678a26c13b 100644 --- a/fs/jbd/checkpoint.c +++ b/fs/jbd/checkpoint.c @@ -24,29 +24,67 @@ #include /* - * Unlink a buffer from a transaction. + * Unlink a buffer from a transaction checkpoint list. * * Called with j_list_lock held. */ - -static inline void __buffer_unlink(struct journal_head *jh) +static inline void __buffer_unlink_first(struct journal_head *jh) { - transaction_t *transaction; - - transaction = jh->b_cp_transaction; - jh->b_cp_transaction = NULL; + transaction_t *transaction = jh->b_cp_transaction; jh->b_cpnext->b_cpprev = jh->b_cpprev; jh->b_cpprev->b_cpnext = jh->b_cpnext; - if (transaction->t_checkpoint_list == jh) + if (transaction->t_checkpoint_list == jh) { transaction->t_checkpoint_list = jh->b_cpnext; - if (transaction->t_checkpoint_list == jh) - transaction->t_checkpoint_list = NULL; + if (transaction->t_checkpoint_list == jh) + transaction->t_checkpoint_list = NULL; + } +} + +/* + * Unlink a buffer from a transaction checkpoint(io) list. + * + * Called with j_list_lock held. + */ +static inline void __buffer_unlink(struct journal_head *jh) +{ + transaction_t *transaction = jh->b_cp_transaction; + + __buffer_unlink_first(jh); + if (transaction->t_checkpoint_io_list == jh) { + transaction->t_checkpoint_io_list = jh->b_cpnext; + if (transaction->t_checkpoint_io_list == jh) + transaction->t_checkpoint_io_list = NULL; + } +} + +/* + * Move a buffer from the checkpoint list to the checkpoint io list + * + * Called with j_list_lock held + */ +static inline void __buffer_relink_io(struct journal_head *jh) +{ + transaction_t *transaction = jh->b_cp_transaction; + + __buffer_unlink_first(jh); + + if (!transaction->t_checkpoint_io_list) { + jh->b_cpnext = jh->b_cpprev = jh; + } else { + jh->b_cpnext = transaction->t_checkpoint_io_list; + jh->b_cpprev = transaction->t_checkpoint_io_list->b_cpprev; + jh->b_cpprev->b_cpnext = jh; + jh->b_cpnext->b_cpprev = jh; + } + transaction->t_checkpoint_io_list = jh; } /* * Try to release a checkpointed buffer from its transaction. - * Returns 1 if we released it. + * Returns 1 if we released it and 2 if we also released the + * whole transaction. + * * Requires j_list_lock * Called under jbd_lock_bh_state(jh2bh(jh)), and drops it */ @@ -57,12 +95,11 @@ static int __try_to_free_cp_buf(struct journal_head *jh) if (jh->b_jlist == BJ_None && !buffer_locked(bh) && !buffer_dirty(bh)) { JBUFFER_TRACE(jh, "remove from checkpoint list"); - __journal_remove_checkpoint(jh); + ret = __journal_remove_checkpoint(jh) + 1; jbd_unlock_bh_state(bh); journal_remove_journal_head(bh); BUFFER_TRACE(bh, "release"); __brelse(bh); - ret = 1; } else { jbd_unlock_bh_state(bh); } @@ -117,83 +154,54 @@ static void jbd_sync_bh(journal_t *journal, struct buffer_head *bh) } /* - * Clean up a transaction's checkpoint list. - * - * We wait for any pending IO to complete and make sure any clean - * buffers are removed from the transaction. - * - * Return 1 if we performed any actions which might have destroyed the - * checkpoint. (journal_remove_checkpoint() deletes the transaction when - * the last checkpoint buffer is cleansed) + * Clean up transaction's list of buffers submitted for io. + * We wait for any pending IO to complete and remove any clean + * buffers. Note that we take the buffers in the opposite ordering + * from the one in which they were submitted for IO. * * Called with j_list_lock held. */ -static int __cleanup_transaction(journal_t *journal, transaction_t *transaction) +static void __wait_cp_io(journal_t *journal, transaction_t *transaction) { - struct journal_head *jh, *next_jh, *last_jh; + struct journal_head *jh; struct buffer_head *bh; - int ret = 0; - - assert_spin_locked(&journal->j_list_lock); - jh = transaction->t_checkpoint_list; - if (!jh) - return 0; - - last_jh = jh->b_cpprev; - next_jh = jh; - do { - jh = next_jh; + tid_t this_tid; + int released = 0; + + this_tid = transaction->t_tid; +restart: + /* Did somebody clean up the transaction in the meanwhile? */ + if (journal->j_checkpoint_transactions != transaction || + transaction->t_tid != this_tid) + return; + while (!released && transaction->t_checkpoint_io_list) { + jh = transaction->t_checkpoint_io_list; bh = jh2bh(jh); + if (!jbd_trylock_bh_state(bh)) { + jbd_sync_bh(journal, bh); + spin_lock(&journal->j_list_lock); + goto restart; + } if (buffer_locked(bh)) { atomic_inc(&bh->b_count); spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); wait_on_buffer(bh); /* the journal_head may have gone by now */ BUFFER_TRACE(bh, "brelse"); __brelse(bh); - goto out_return_1; + spin_lock(&journal->j_list_lock); + goto restart; } - /* - * This is foul + * Now in whatever state the buffer currently is, we know that + * it has been written out and so we can drop it from the list */ - if (!jbd_trylock_bh_state(bh)) { - jbd_sync_bh(journal, bh); - goto out_return_1; - } - - if (jh->b_transaction != NULL) { - transaction_t *t = jh->b_transaction; - tid_t tid = t->t_tid; - - spin_unlock(&journal->j_list_lock); - jbd_unlock_bh_state(bh); - log_start_commit(journal, tid); - log_wait_commit(journal, tid); - goto out_return_1; - } - - /* - * AKPM: I think the buffer_jbddirty test is redundant - it - * shouldn't have NULL b_transaction? - */ - next_jh = jh->b_cpnext; - if (!buffer_dirty(bh) && !buffer_jbddirty(bh)) { - BUFFER_TRACE(bh, "remove from checkpoint"); - __journal_remove_checkpoint(jh); - jbd_unlock_bh_state(bh); - journal_remove_journal_head(bh); - __brelse(bh); - ret = 1; - } else { - jbd_unlock_bh_state(bh); - } - } while (jh != last_jh); - - return ret; -out_return_1: - spin_lock(&journal->j_list_lock); - return 1; + released = __journal_remove_checkpoint(jh); + jbd_unlock_bh_state(bh); + journal_remove_journal_head(bh); + __brelse(bh); + } } #define NR_BATCH 64 @@ -203,9 +211,7 @@ __flush_batch(journal_t *journal, struct buffer_head **bhs, int *batch_count) { int i; - spin_unlock(&journal->j_list_lock); ll_rw_block(SWRITE, *batch_count, bhs); - spin_lock(&journal->j_list_lock); for (i = 0; i < *batch_count; i++) { struct buffer_head *bh = bhs[i]; clear_buffer_jwrite(bh); @@ -221,19 +227,43 @@ __flush_batch(journal_t *journal, struct buffer_head **bhs, int *batch_count) * Return 1 if something happened which requires us to abort the current * scan of the checkpoint list. * - * Called with j_list_lock held. + * Called with j_list_lock held and drops it if 1 is returned * Called under jbd_lock_bh_state(jh2bh(jh)), and drops it */ -static int __flush_buffer(journal_t *journal, struct journal_head *jh, - struct buffer_head **bhs, int *batch_count, - int *drop_count) +static int __process_buffer(journal_t *journal, struct journal_head *jh, + struct buffer_head **bhs, int *batch_count) { struct buffer_head *bh = jh2bh(jh); int ret = 0; - if (buffer_dirty(bh) && !buffer_locked(bh) && jh->b_jlist == BJ_None) { - J_ASSERT_JH(jh, jh->b_transaction == NULL); + if (buffer_locked(bh)) { + atomic_inc(&bh->b_count); + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); + wait_on_buffer(bh); + /* the journal_head may have gone by now */ + BUFFER_TRACE(bh, "brelse"); + __brelse(bh); + ret = 1; + } else if (jh->b_transaction != NULL) { + transaction_t *t = jh->b_transaction; + tid_t tid = t->t_tid; + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); + log_start_commit(journal, tid); + log_wait_commit(journal, tid); + ret = 1; + } else if (!buffer_dirty(bh)) { + J_ASSERT_JH(jh, !buffer_jbddirty(bh)); + BUFFER_TRACE(bh, "remove from checkpoint"); + __journal_remove_checkpoint(jh); + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); + journal_remove_journal_head(bh); + __brelse(bh); + ret = 1; + } else { /* * Important: we are about to write the buffer, and * possibly block, while still holding the journal lock. @@ -246,45 +276,30 @@ static int __flush_buffer(journal_t *journal, struct journal_head *jh, J_ASSERT_BH(bh, !buffer_jwrite(bh)); set_buffer_jwrite(bh); bhs[*batch_count] = bh; + __buffer_relink_io(jh); jbd_unlock_bh_state(bh); (*batch_count)++; if (*batch_count == NR_BATCH) { + spin_unlock(&journal->j_list_lock); __flush_batch(journal, bhs, batch_count); ret = 1; } - } else { - int last_buffer = 0; - if (jh->b_cpnext == jh) { - /* We may be about to drop the transaction. Tell the - * caller that the lists have changed. - */ - last_buffer = 1; - } - if (__try_to_free_cp_buf(jh)) { - (*drop_count)++; - ret = last_buffer; - } } return ret; } /* - * Perform an actual checkpoint. We don't write out only enough to - * satisfy the current blocked requests: rather we submit a reasonably - * sized chunk of the outstanding data to disk at once for - * efficiency. __log_wait_for_space() will retry if we didn't free enough. + * Perform an actual checkpoint. We take the first transaction on the + * list of transactions to be checkpointed and send all its buffers + * to disk. We submit larger chunks of data at once. * - * However, we _do_ take into account the amount requested so that once - * the IO has been queued, we can return as soon as enough of it has - * completed to disk. - * * The journal should be locked before calling this function. */ int log_do_checkpoint(journal_t *journal) { + transaction_t *transaction; + tid_t this_tid; int result; - int batch_count = 0; - struct buffer_head *bhs[NR_BATCH]; jbd_debug(1, "Start checkpoint\n"); @@ -299,79 +314,68 @@ int log_do_checkpoint(journal_t *journal) return result; /* - * OK, we need to start writing disk blocks. Try to free up a - * quarter of the log in a single checkpoint if we can. + * OK, we need to start writing disk blocks. Take one transaction + * and write it. */ + spin_lock(&journal->j_list_lock); + if (!journal->j_checkpoint_transactions) + goto out; + transaction = journal->j_checkpoint_transactions; + this_tid = transaction->t_tid; +restart: /* - * AKPM: check this code. I had a feeling a while back that it - * degenerates into a busy loop at unmount time. + * If someone cleaned up this transaction while we slept, we're + * done (maybe it's a new transaction, but it fell at the same + * address). */ - spin_lock(&journal->j_list_lock); - while (journal->j_checkpoint_transactions) { - transaction_t *transaction; - struct journal_head *jh, *last_jh, *next_jh; - int drop_count = 0; - int cleanup_ret, retry = 0; - tid_t this_tid; - - transaction = journal->j_checkpoint_transactions; - this_tid = transaction->t_tid; - jh = transaction->t_checkpoint_list; - last_jh = jh->b_cpprev; - next_jh = jh; - do { + if (journal->j_checkpoint_transactions == transaction && + transaction->t_tid == this_tid) { + int batch_count = 0; + struct buffer_head *bhs[NR_BATCH]; + struct journal_head *jh; + int retry = 0; + + while (!retry && transaction->t_checkpoint_list) { struct buffer_head *bh; - jh = next_jh; - next_jh = jh->b_cpnext; + jh = transaction->t_checkpoint_list; bh = jh2bh(jh); if (!jbd_trylock_bh_state(bh)) { jbd_sync_bh(journal, bh); - spin_lock(&journal->j_list_lock); retry = 1; break; } - retry = __flush_buffer(journal, jh, bhs, &batch_count, &drop_count); - if (cond_resched_lock(&journal->j_list_lock)) { + retry = __process_buffer(journal, jh, bhs,&batch_count); + if (!retry && lock_need_resched(&journal->j_list_lock)){ + spin_unlock(&journal->j_list_lock); retry = 1; break; } - } while (jh != last_jh && !retry); + } if (batch_count) { + if (!retry) { + spin_unlock(&journal->j_list_lock); + retry = 1; + } __flush_batch(journal, bhs, &batch_count); - retry = 1; } + if (retry) { + spin_lock(&journal->j_list_lock); + goto restart; + } /* - * If someone cleaned up this transaction while we slept, we're - * done - */ - if (journal->j_checkpoint_transactions != transaction) - break; - if (retry) - continue; - /* - * Maybe it's a new transaction, but it fell at the same - * address - */ - if (transaction->t_tid != this_tid) - continue; - /* - * We have walked the whole transaction list without - * finding anything to write to disk. We had better be - * able to make some progress or we are in trouble. + * Now we have cleaned up the first transaction's checkpoint + * list. Let's clean up the second one */ - cleanup_ret = __cleanup_transaction(journal, transaction); - J_ASSERT(drop_count != 0 || cleanup_ret != 0); - if (journal->j_checkpoint_transactions != transaction) - break; + __wait_cp_io(journal, transaction); } +out: spin_unlock(&journal->j_list_lock); result = cleanup_journal_tail(journal); if (result < 0) return result; - return 0; } @@ -455,6 +459,54 @@ int cleanup_journal_tail(journal_t *journal) /* Checkpoint list management */ +/* + * journal_clean_one_cp_list + * + * Find all the written-back checkpoint buffers in the given list and release them. + * + * Called with the journal locked. + * Called with j_list_lock held. + * Returns number of bufers reaped (for debug) + */ + +static int journal_clean_one_cp_list(struct journal_head *jh, int *released) +{ + struct journal_head *last_jh; + struct journal_head *next_jh = jh; + int ret, freed = 0; + + *released = 0; + if (!jh) + return 0; + + last_jh = jh->b_cpprev; + do { + jh = next_jh; + next_jh = jh->b_cpnext; + /* Use trylock because of the ranking */ + if (jbd_trylock_bh_state(jh2bh(jh))) { + ret = __try_to_free_cp_buf(jh); + if (ret) { + freed++; + if (ret == 2) { + *released = 1; + return freed; + } + } + } + /* + * This function only frees up some memory + * if possible so we dont have an obligation + * to finish processing. Bail out if preemption + * requested: + */ + if (need_resched()) + return freed; + } while (jh != last_jh); + + return freed; +} + /* * journal_clean_checkpoint_list * @@ -462,46 +514,44 @@ int cleanup_journal_tail(journal_t *journal) * * Called with the journal locked. * Called with j_list_lock held. - * Returns number of bufers reaped (for debug) + * Returns number of buffers reaped (for debug) */ int __journal_clean_checkpoint_list(journal_t *journal) { transaction_t *transaction, *last_transaction, *next_transaction; int ret = 0; + int released; transaction = journal->j_checkpoint_transactions; - if (transaction == 0) + if (!transaction) goto out; last_transaction = transaction->t_cpprev; next_transaction = transaction; do { - struct journal_head *jh; - transaction = next_transaction; next_transaction = transaction->t_cpnext; - jh = transaction->t_checkpoint_list; - if (jh) { - struct journal_head *last_jh = jh->b_cpprev; - struct journal_head *next_jh = jh; - - do { - jh = next_jh; - next_jh = jh->b_cpnext; - /* Use trylock because of the ranknig */ - if (jbd_trylock_bh_state(jh2bh(jh))) - ret += __try_to_free_cp_buf(jh); - /* - * This function only frees up some memory - * if possible so we dont have an obligation - * to finish processing. Bail out if preemption - * requested: - */ - if (need_resched()) - goto out; - } while (jh != last_jh); - } + ret += journal_clean_one_cp_list(transaction-> + t_checkpoint_list, &released); + /* + * This function only frees up some memory if possible so we + * dont have an obligation to finish processing. Bail out if + * preemption requested: + */ + if (need_resched()) + goto out; + if (released) + continue; + /* + * It is essential that we are as careful as in the case of + * t_checkpoint_list with removing the buffer from the list as + * we can possibly see not yet submitted buffers on io_list + */ + ret += journal_clean_one_cp_list(transaction-> + t_checkpoint_io_list, &released); + if (need_resched()) + goto out; } while (transaction != last_transaction); out: return ret; @@ -516,18 +566,22 @@ out: * buffer updates committed in that transaction have safely been stored * elsewhere on disk. To achieve this, all of the buffers in a * transaction need to be maintained on the transaction's checkpoint - * list until they have been rewritten, at which point this function is + * lists until they have been rewritten, at which point this function is * called to remove the buffer from the existing transaction's - * checkpoint list. + * checkpoint lists. + * + * The function returns 1 if it frees the transaction, 0 otherwise. * * This function is called with the journal locked. * This function is called with j_list_lock held. + * This function is called with jbd_lock_bh_state(jh2bh(jh)) */ -void __journal_remove_checkpoint(struct journal_head *jh) +int __journal_remove_checkpoint(struct journal_head *jh) { transaction_t *transaction; journal_t *journal; + int ret = 0; JBUFFER_TRACE(jh, "entry"); @@ -538,8 +592,10 @@ void __journal_remove_checkpoint(struct journal_head *jh) journal = transaction->t_journal; __buffer_unlink(jh); + jh->b_cp_transaction = NULL; - if (transaction->t_checkpoint_list != NULL) + if (transaction->t_checkpoint_list != NULL || + transaction->t_checkpoint_io_list != NULL) goto out; JBUFFER_TRACE(jh, "transaction has no more buffers"); @@ -565,8 +621,10 @@ void __journal_remove_checkpoint(struct journal_head *jh) /* Just in case anybody was waiting for more transactions to be checkpointed... */ wake_up(&journal->j_wait_logspace); + ret = 1; out: JBUFFER_TRACE(jh, "exit"); + return ret; } /* @@ -628,6 +686,7 @@ void __journal_drop_transaction(journal_t *journal, transaction_t *transaction) J_ASSERT(transaction->t_shadow_list == NULL); J_ASSERT(transaction->t_log_list == NULL); J_ASSERT(transaction->t_checkpoint_list == NULL); + J_ASSERT(transaction->t_checkpoint_io_list == NULL); J_ASSERT(transaction->t_updates == 0); J_ASSERT(journal->j_committing_transaction != transaction); J_ASSERT(journal->j_running_transaction != transaction); diff --git a/include/linux/jbd.h b/include/linux/jbd.h index 6a425e370cb3..20eb34403d0c 100644 --- a/include/linux/jbd.h +++ b/include/linux/jbd.h @@ -500,6 +500,12 @@ struct transaction_s */ struct journal_head *t_checkpoint_list; + /* + * Doubly-linked circular list of all buffers submitted for IO while + * checkpointing. [j_list_lock] + */ + struct journal_head *t_checkpoint_io_list; + /* * Doubly-linked circular list of temporary buffers currently undergoing * IO in the log [j_list_lock] @@ -849,7 +855,7 @@ extern void journal_commit_transaction(journal_t *); /* Checkpoint list management */ int __journal_clean_checkpoint_list(journal_t *journal); -void __journal_remove_checkpoint(struct journal_head *); +int __journal_remove_checkpoint(struct journal_head *); void __journal_insert_checkpoint(struct journal_head *, transaction_t *); /* Buffer IO */ -- cgit v1.2.3 From fda151d9feafc0e8418f23c716587c44394fcdbf Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Mon, 5 Jun 2006 12:09:50 +0200 Subject: [PATCH] blktrace_api.h: endian annotations Signed-off-by: Alexey Dobriyan Signed-off-by: Andrew Morton Signed-off-by: Jens Axboe --- include/linux/blktrace_api.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/linux/blktrace_api.h b/include/linux/blktrace_api.h index eb1a867ed245..a7e8cef73d15 100644 --- a/include/linux/blktrace_api.h +++ b/include/linux/blktrace_api.h @@ -90,9 +90,9 @@ struct blk_io_trace { * The remap event */ struct blk_io_trace_remap { - u32 device; + __be32 device; u32 __pad; - u64 sector; + __be64 sector; }; enum { @@ -224,7 +224,7 @@ static inline void blk_add_trace_pdu_int(struct request_queue *q, u32 what, struct bio *bio, unsigned int pdu) { struct blk_trace *bt = q->blk_trace; - u64 rpdu = cpu_to_be64(pdu); + __be64 rpdu = cpu_to_be64(pdu); if (likely(!bt)) return; -- cgit v1.2.3 From b31dc66a54ad986b6b73bdc49c8efc17cbad1833 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 13 Jun 2006 08:26:10 +0200 Subject: [PATCH] Kill PF_SYNCWRITE flag A process flag to indicate whether we are doing sync io is incredibly ugly. It also causes performance problems when one does a lot of async io and then proceeds to sync it. Part of the io will go out as async, and the other part as sync. This causes a disconnect between the previously submitted io and the synced io. For io schedulers such as CFQ, this will cause us lost merges and suboptimal behaviour in scheduling. Remove PF_SYNCWRITE completely from the fsync/msync paths, and let the O_DIRECT path just directly indicate that the writes are sync by using WRITE_SYNC instead. Signed-off-by: Jens Axboe --- block/as-iosched.c | 2 +- block/cfq-iosched.c | 4 +--- block/ll_rw_blk.c | 3 +++ drivers/usb/gadget/file_storage.c | 2 -- fs/buffer.c | 2 -- fs/direct-io.c | 18 ++++++++---------- fs/fs-writeback.c | 2 -- include/linux/blkdev.h | 2 ++ include/linux/sched.h | 11 +++++------ mm/msync.c | 3 --- 10 files changed, 20 insertions(+), 29 deletions(-) (limited to 'include') diff --git a/block/as-iosched.c b/block/as-iosched.c index 9b13d72ffefa..56c99fa037df 100644 --- a/block/as-iosched.c +++ b/block/as-iosched.c @@ -1339,7 +1339,7 @@ static void as_add_request(request_queue_t *q, struct request *rq) arq->state = AS_RQ_NEW; if (rq_data_dir(arq->request) == READ - || current->flags&PF_SYNCWRITE) + || (arq->request->flags & REQ_RW_SYNC)) arq->is_sync = 1; else arq->is_sync = 0; diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index c88f161d3fb3..4c4e9cc3ae26 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -277,8 +277,6 @@ static struct cfq_queue *cfq_find_cfq_hash(struct cfq_data *, unsigned int, unsi static void cfq_dispatch_insert(request_queue_t *, struct cfq_rq *); static struct cfq_queue *cfq_get_queue(struct cfq_data *cfqd, unsigned int key, struct task_struct *tsk, gfp_t gfp_mask); -#define process_sync(tsk) ((tsk)->flags & PF_SYNCWRITE) - /* * lots of deadline iosched dupes, can be abstracted later... */ @@ -334,7 +332,7 @@ static int cfq_queue_empty(request_queue_t *q) static inline pid_t cfq_queue_pid(struct task_struct *task, int rw) { - if (rw == READ || process_sync(task)) + if (rw == READ || rw == WRITE_SYNC) return task->pid; return CFQ_KEY_ASYNC; diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index 17c42ddd31db..2270bb451385 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -2827,6 +2827,9 @@ static void init_request_from_bio(struct request *req, struct bio *bio) if (unlikely(bio_barrier(bio))) req->flags |= (REQ_HARDBARRIER | REQ_NOMERGE); + if (bio_sync(bio)) + req->flags |= REQ_RW_SYNC; + req->errors = 0; req->hard_sector = req->sector = bio->bi_sector; req->hard_nr_sectors = req->nr_sectors = bio_sectors(bio); diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 6f887478b148..a43dc908ac59 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -1906,7 +1906,6 @@ static int fsync_sub(struct lun *curlun) inode = filp->f_dentry->d_inode; mutex_lock(&inode->i_mutex); - current->flags |= PF_SYNCWRITE; rc = filemap_fdatawrite(inode->i_mapping); err = filp->f_op->fsync(filp, filp->f_dentry, 1); if (!rc) @@ -1914,7 +1913,6 @@ static int fsync_sub(struct lun *curlun) err = filemap_fdatawait(inode->i_mapping); if (!rc) rc = err; - current->flags &= ~PF_SYNCWRITE; mutex_unlock(&inode->i_mutex); VLDBG(curlun, "fdatasync -> %d\n", rc); return rc; diff --git a/fs/buffer.c b/fs/buffer.c index 23f1f3a68077..373bb6292bdc 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -331,7 +331,6 @@ long do_fsync(struct file *file, int datasync) goto out; } - current->flags |= PF_SYNCWRITE; ret = filemap_fdatawrite(mapping); /* @@ -346,7 +345,6 @@ long do_fsync(struct file *file, int datasync) err = filemap_fdatawait(mapping); if (!ret) ret = err; - current->flags &= ~PF_SYNCWRITE; out: return ret; } diff --git a/fs/direct-io.c b/fs/direct-io.c index b05d1b218776..538fb0418fba 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -162,7 +162,7 @@ static int dio_refill_pages(struct dio *dio) NULL); /* vmas */ up_read(¤t->mm->mmap_sem); - if (ret < 0 && dio->blocks_available && (dio->rw == WRITE)) { + if (ret < 0 && dio->blocks_available && (dio->rw & WRITE)) { struct page *page = ZERO_PAGE(dio->curr_user_address); /* * A memory fault, but the filesystem has some outstanding @@ -535,7 +535,7 @@ static int get_more_blocks(struct dio *dio) map_bh->b_state = 0; map_bh->b_size = fs_count << dio->inode->i_blkbits; - create = dio->rw == WRITE; + create = dio->rw & WRITE; if (dio->lock_type == DIO_LOCKING) { if (dio->block_in_file < (i_size_read(dio->inode) >> dio->blkbits)) @@ -867,7 +867,7 @@ do_holes: loff_t i_size_aligned; /* AKPM: eargh, -ENOTBLK is a hack */ - if (dio->rw == WRITE) { + if (dio->rw & WRITE) { page_cache_release(page); return -ENOTBLK; } @@ -1045,7 +1045,7 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode, } } /* end iovec loop */ - if (ret == -ENOTBLK && rw == WRITE) { + if (ret == -ENOTBLK && (rw & WRITE)) { /* * The remaining part of the request will be * be handled by buffered I/O when we return @@ -1089,7 +1089,7 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode, if (dio->is_async) { int should_wait = 0; - if (dio->result < dio->size && rw == WRITE) { + if (dio->result < dio->size && (rw & WRITE)) { dio->waiter = current; should_wait = 1; } @@ -1142,7 +1142,7 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode, ret = transferred; /* We could have also come here on an AIO file extend */ - if (!is_sync_kiocb(iocb) && rw == WRITE && + if (!is_sync_kiocb(iocb) && (rw & WRITE) && ret >= 0 && dio->result == dio->size) /* * For AIO writes where we have completed the @@ -1194,7 +1194,7 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, int acquire_i_mutex = 0; if (rw & WRITE) - current->flags |= PF_SYNCWRITE; + rw = WRITE_SYNC; if (bdev) bdev_blkbits = blksize_bits(bdev_hardsect_size(bdev)); @@ -1270,7 +1270,7 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, * even for AIO, we need to wait for i/o to complete before * returning in this case. */ - dio->is_async = !is_sync_kiocb(iocb) && !((rw == WRITE) && + dio->is_async = !is_sync_kiocb(iocb) && !((rw & WRITE) && (end > i_size_read(inode))); retval = direct_io_worker(rw, iocb, inode, iov, offset, @@ -1284,8 +1284,6 @@ out: mutex_unlock(&inode->i_mutex); else if (acquire_i_mutex) mutex_lock(&inode->i_mutex); - if (rw & WRITE) - current->flags &= ~PF_SYNCWRITE; return retval; } EXPORT_SYMBOL(__blockdev_direct_IO); diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 6db95cf3aaa2..031b27a4bc9a 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -623,7 +623,6 @@ int generic_osync_inode(struct inode *inode, struct address_space *mapping, int int need_write_inode_now = 0; int err2; - current->flags |= PF_SYNCWRITE; if (what & OSYNC_DATA) err = filemap_fdatawrite(mapping); if (what & (OSYNC_METADATA|OSYNC_DATA)) { @@ -636,7 +635,6 @@ int generic_osync_inode(struct inode *inode, struct address_space *mapping, int if (!err) err = err2; } - current->flags &= ~PF_SYNCWRITE; spin_lock(&inode_lock); if ((inode->i_state & I_DIRTY) && diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 3457e7b97363..482a21d67627 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -241,6 +241,7 @@ enum rq_flag_bits { __REQ_PM_RESUME, /* resume request */ __REQ_PM_SHUTDOWN, /* shutdown request */ __REQ_ORDERED_COLOR, /* is before or after barrier */ + __REQ_RW_SYNC, /* request is sync (O_DIRECT) */ __REQ_NR_BITS, /* stops here */ }; @@ -270,6 +271,7 @@ enum rq_flag_bits { #define REQ_PM_RESUME (1 << __REQ_PM_RESUME) #define REQ_PM_SHUTDOWN (1 << __REQ_PM_SHUTDOWN) #define REQ_ORDERED_COLOR (1 << __REQ_ORDERED_COLOR) +#define REQ_RW_SYNC (1 << __REQ_RW_SYNC) /* * State information carried for REQ_PM_SUSPEND and REQ_PM_RESUME diff --git a/include/linux/sched.h b/include/linux/sched.h index a9d23c7d1b25..38b4791e6a5d 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -941,12 +941,11 @@ static inline void put_task_struct(struct task_struct *t) #define PF_KSWAPD 0x00040000 /* I am kswapd */ #define PF_SWAPOFF 0x00080000 /* I am in swapoff */ #define PF_LESS_THROTTLE 0x00100000 /* Throttle me less: I clean memory */ -#define PF_SYNCWRITE 0x00200000 /* I am doing a sync write */ -#define PF_BORROWED_MM 0x00400000 /* I am a kthread doing use_mm */ -#define PF_RANDOMIZE 0x00800000 /* randomize virtual address space */ -#define PF_SWAPWRITE 0x01000000 /* Allowed to write to swap */ -#define PF_SPREAD_PAGE 0x04000000 /* Spread page cache over cpuset */ -#define PF_SPREAD_SLAB 0x08000000 /* Spread some slab caches over cpuset */ +#define PF_BORROWED_MM 0x00200000 /* I am a kthread doing use_mm */ +#define PF_RANDOMIZE 0x00400000 /* randomize virtual address space */ +#define PF_SWAPWRITE 0x00800000 /* Allowed to write to swap */ +#define PF_SPREAD_PAGE 0x01000000 /* Spread page cache over cpuset */ +#define PF_SPREAD_SLAB 0x02000000 /* Spread some slab caches over cpuset */ #define PF_MEMPOLICY 0x10000000 /* Non-default NUMA mempolicy */ /* diff --git a/mm/msync.c b/mm/msync.c index bc6c95376366..d083544df21b 100644 --- a/mm/msync.c +++ b/mm/msync.c @@ -170,8 +170,6 @@ asmlinkage long sys_msync(unsigned long start, size_t len, int flags) * just ignore them, but return -ENOMEM at the end. */ down_read(¤t->mm->mmap_sem); - if (flags & MS_SYNC) - current->flags |= PF_SYNCWRITE; vma = find_vma(current->mm, start); if (!vma) { error = -ENOMEM; @@ -228,7 +226,6 @@ asmlinkage long sys_msync(unsigned long start, size_t len, int flags) } } while (vma && !done); out_unlock: - current->flags &= ~PF_SYNCWRITE; up_read(¤t->mm->mmap_sem); out: return error; -- cgit v1.2.3 From ad3caddaa1708e506f20b8e25a4a8ae586fc7d5b Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 13 Jun 2006 08:46:57 +0200 Subject: [PATCH] Get rid of struct request request_pm_state member The IDE power management can just use the ->end_io_data member to store it's data. Signed-off-by: Jens Axboe --- drivers/ide/ide-io.c | 91 ++++++++++++++++++++++++++++---------------------- drivers/ide/ide.c | 4 +-- include/linux/blkdev.h | 5 --- 3 files changed, 54 insertions(+), 46 deletions(-) (limited to 'include') diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index c01615dec202..4f2f138de2ca 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -142,38 +142,41 @@ enum { static void ide_complete_power_step(ide_drive_t *drive, struct request *rq, u8 stat, u8 error) { + struct request_pm_state *pm = rq->end_io_data; + if (drive->media != ide_disk) return; - switch (rq->pm->pm_step) { + switch (pm->pm_step) { case ide_pm_flush_cache: /* Suspend step 1 (flush cache) complete */ - if (rq->pm->pm_state == PM_EVENT_FREEZE) - rq->pm->pm_step = ide_pm_state_completed; + if (pm->pm_state == PM_EVENT_FREEZE) + pm->pm_step = ide_pm_state_completed; else - rq->pm->pm_step = idedisk_pm_standby; + pm->pm_step = idedisk_pm_standby; break; case idedisk_pm_standby: /* Suspend step 2 (standby) complete */ - rq->pm->pm_step = ide_pm_state_completed; + pm->pm_step = ide_pm_state_completed; break; case idedisk_pm_idle: /* Resume step 1 (idle) complete */ - rq->pm->pm_step = ide_pm_restore_dma; + pm->pm_step = ide_pm_restore_dma; break; } } static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *rq) { + struct request_pm_state *pm = rq->end_io_data; ide_task_t *args = rq->special; memset(args, 0, sizeof(*args)); if (drive->media != ide_disk) { /* skip idedisk_pm_idle for ATAPI devices */ - if (rq->pm->pm_step == idedisk_pm_idle) - rq->pm->pm_step = ide_pm_restore_dma; + if (pm->pm_step == idedisk_pm_idle) + pm->pm_step = ide_pm_restore_dma; } - switch (rq->pm->pm_step) { + switch (pm->pm_step) { case ide_pm_flush_cache: /* Suspend step 1 (flush cache) */ if (drive->media != ide_disk) break; @@ -215,7 +218,7 @@ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request * drive->hwif->ide_dma_check(drive); break; } - rq->pm->pm_step = ide_pm_state_completed; + pm->pm_step = ide_pm_state_completed; return ide_stopped; } @@ -362,12 +365,13 @@ void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err) } } } else if (blk_pm_request(rq)) { + struct request_pm_state *pm = rq->end_io_data; #ifdef DEBUG_PM printk("%s: complete_power_step(step: %d, stat: %x, err: %x)\n", drive->name, rq->pm->pm_step, stat, err); #endif ide_complete_power_step(drive, rq, stat, err); - if (rq->pm->pm_step == ide_pm_state_completed) + if (pm->pm_step == ide_pm_state_completed) ide_complete_pm_request(drive, rq); return; } @@ -871,6 +875,39 @@ done: return ide_stopped; } +static void ide_check_pm_state(ide_drive_t *drive, struct request *rq) +{ + struct request_pm_state *pm = rq->end_io_data; + + if (blk_pm_suspend_request(rq) && + pm->pm_step == ide_pm_state_start_suspend) + /* Mark drive blocked when starting the suspend sequence. */ + drive->blocked = 1; + else if (blk_pm_resume_request(rq) && + pm->pm_step == ide_pm_state_start_resume) { + /* + * The first thing we do on wakeup is to wait for BSY bit to + * go away (with a looong timeout) as a drive on this hwif may + * just be POSTing itself. + * We do that before even selecting as the "other" device on + * the bus may be broken enough to walk on our toes at this + * point. + */ + int rc; +#ifdef DEBUG_PM + printk("%s: Wakeup request inited, waiting for !BSY...\n", drive->name); +#endif + rc = ide_wait_not_busy(HWIF(drive), 35000); + if (rc) + printk(KERN_WARNING "%s: bus not ready on wakeup\n", drive->name); + SELECT_DRIVE(drive); + HWIF(drive)->OUTB(8, HWIF(drive)->io_ports[IDE_CONTROL_OFFSET]); + rc = ide_wait_not_busy(HWIF(drive), 10000); + if (rc) + printk(KERN_WARNING "%s: drive not ready on wakeup\n", drive->name); + } +} + /** * start_request - start of I/O and command issuing for IDE * @@ -909,33 +946,8 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq) if (block == 0 && drive->remap_0_to_1 == 1) block = 1; /* redirect MBR access to EZ-Drive partn table */ - if (blk_pm_suspend_request(rq) && - rq->pm->pm_step == ide_pm_state_start_suspend) - /* Mark drive blocked when starting the suspend sequence. */ - drive->blocked = 1; - else if (blk_pm_resume_request(rq) && - rq->pm->pm_step == ide_pm_state_start_resume) { - /* - * The first thing we do on wakeup is to wait for BSY bit to - * go away (with a looong timeout) as a drive on this hwif may - * just be POSTing itself. - * We do that before even selecting as the "other" device on - * the bus may be broken enough to walk on our toes at this - * point. - */ - int rc; -#ifdef DEBUG_PM - printk("%s: Wakeup request inited, waiting for !BSY...\n", drive->name); -#endif - rc = ide_wait_not_busy(HWIF(drive), 35000); - if (rc) - printk(KERN_WARNING "%s: bus not ready on wakeup\n", drive->name); - SELECT_DRIVE(drive); - HWIF(drive)->OUTB(8, HWIF(drive)->io_ports[IDE_CONTROL_OFFSET]); - rc = ide_wait_not_busy(HWIF(drive), 10000); - if (rc) - printk(KERN_WARNING "%s: drive not ready on wakeup\n", drive->name); - } + if (blk_pm_request(rq)) + ide_check_pm_state(drive, rq); SELECT_DRIVE(drive); if (ide_wait_stat(&startstop, drive, drive->ready_stat, BUSY_STAT|DRQ_STAT, WAIT_READY)) { @@ -950,13 +962,14 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq) else if (rq->flags & REQ_DRIVE_TASKFILE) return execute_drive_cmd(drive, rq); else if (blk_pm_request(rq)) { + struct request_pm_state *pm = rq->end_io_data; #ifdef DEBUG_PM printk("%s: start_power_step(step: %d)\n", drive->name, rq->pm->pm_step); #endif startstop = ide_start_power_step(drive, rq); if (startstop == ide_stopped && - rq->pm->pm_step == ide_pm_state_completed) + pm->pm_step == ide_pm_state_completed) ide_complete_pm_request(drive, rq); return startstop; } diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 9799aed772e1..59fe358048b3 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -1226,7 +1226,7 @@ static int generic_ide_suspend(struct device *dev, pm_message_t state) memset(&args, 0, sizeof(args)); rq.flags = REQ_PM_SUSPEND; rq.special = &args; - rq.pm = &rqpm; + rq.end_io_data = &rqpm; rqpm.pm_step = ide_pm_state_start_suspend; rqpm.pm_state = state.event; @@ -1245,7 +1245,7 @@ static int generic_ide_resume(struct device *dev) memset(&args, 0, sizeof(args)); rq.flags = REQ_PM_RESUME; rq.special = &args; - rq.pm = &rqpm; + rq.end_io_data = &rqpm; rqpm.pm_step = ide_pm_state_start_resume; rqpm.pm_state = PM_EVENT_ON; diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 482a21d67627..371c0ce5f630 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -195,11 +195,6 @@ struct request { unsigned int timeout; int retries; - /* - * For Power Management requests - */ - struct request_pm_state *pm; - /* * completion callback. end_io_data should be folded in with waiting */ -- cgit v1.2.3 From 8f34ee75decb80007ba77bba5a7384eadff4866d Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 13 Jun 2006 09:02:34 +0200 Subject: [PATCH] Rearrange a few struct request members This saves 8 bytes of data in 64-bit archs. Signed-off-by: Jens Axboe --- include/linux/blkdev.h | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 371c0ce5f630..aafe82788b4e 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -151,11 +151,9 @@ struct request { void *elevator_private; void *completion_data; - unsigned short ioprio; - int rq_status; /* should split this into a few status bits */ - struct gendisk *rq_disk; int errors; + struct gendisk *rq_disk; unsigned long start_time; /* Number of scatter-gather DMA addr+len pairs after @@ -170,8 +168,9 @@ struct request { */ unsigned short nr_hw_segments; + unsigned short ioprio; + int tag; - char *buffer; int ref_count; request_queue_t *q; @@ -179,6 +178,7 @@ struct request { struct completion *waiting; void *special; + char *buffer; /* * when request is used as a packet command carrier @@ -187,9 +187,8 @@ struct request { unsigned char cmd[BLK_MAX_CDB]; unsigned int data_len; - void *data; - unsigned int sense_len; + void *data; void *sense; unsigned int timeout; -- cgit v1.2.3 From dd67d051529387f6e44d22d1d5540ef281965fdd Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Wed, 21 Jun 2006 09:36:18 +0200 Subject: [PATCH] rbtree: support functions used by the io schedulers They all duplicate macros to check for empty root and/or node, and clearing a node. So put those in rbtree.h. Signed-off-by: Jens Axboe --- block/as-iosched.c | 17 +++++++---------- block/cfq-iosched.c | 22 ++++++++-------------- block/deadline-iosched.c | 13 +++++-------- include/linux/rbtree.h | 4 ++++ 4 files changed, 24 insertions(+), 32 deletions(-) (limited to 'include') diff --git a/block/as-iosched.c b/block/as-iosched.c index 56c99fa037df..1ec5df466708 100644 --- a/block/as-iosched.c +++ b/block/as-iosched.c @@ -347,9 +347,6 @@ static struct request *as_find_arq_hash(struct as_data *ad, sector_t offset) /* * rb tree support functions */ -#define RB_EMPTY(root) ((root)->rb_node == NULL) -#define ON_RB(node) (rb_parent(node) != node) -#define RB_CLEAR(node) (rb_set_parent(node, node)) #define rb_entry_arq(node) rb_entry((node), struct as_rq, rb_node) #define ARQ_RB_ROOT(ad, arq) (&(ad)->sort_list[(arq)->is_sync]) #define rq_rb_key(rq) (rq)->sector @@ -418,13 +415,13 @@ static void as_add_arq_rb(struct as_data *ad, struct as_rq *arq) static inline void as_del_arq_rb(struct as_data *ad, struct as_rq *arq) { - if (!ON_RB(&arq->rb_node)) { + if (!RB_EMPTY_NODE(&arq->rb_node)) { WARN_ON(1); return; } rb_erase(&arq->rb_node, ARQ_RB_ROOT(ad, arq)); - RB_CLEAR(&arq->rb_node); + RB_CLEAR_NODE(&arq->rb_node); } static struct request * @@ -545,7 +542,7 @@ static struct as_rq *as_find_next_arq(struct as_data *ad, struct as_rq *last) struct rb_node *rbprev = rb_prev(&last->rb_node); struct as_rq *arq_next, *arq_prev; - BUG_ON(!ON_RB(&last->rb_node)); + BUG_ON(!RB_EMPTY_NODE(&last->rb_node)); if (rbprev) arq_prev = rb_entry_arq(rbprev); @@ -1122,7 +1119,7 @@ static void as_move_to_dispatch(struct as_data *ad, struct as_rq *arq) struct request *rq = arq->request; const int data_dir = arq->is_sync; - BUG_ON(!ON_RB(&arq->rb_node)); + BUG_ON(!RB_EMPTY_NODE(&arq->rb_node)); as_antic_stop(ad); ad->antic_status = ANTIC_OFF; @@ -1247,7 +1244,7 @@ static int as_dispatch_request(request_queue_t *q, int force) */ if (reads) { - BUG_ON(RB_EMPTY(&ad->sort_list[REQ_SYNC])); + BUG_ON(RB_EMPTY_ROOT(&ad->sort_list[REQ_SYNC])); if (writes && ad->batch_data_dir == REQ_SYNC) /* @@ -1271,7 +1268,7 @@ static int as_dispatch_request(request_queue_t *q, int force) if (writes) { dispatch_writes: - BUG_ON(RB_EMPTY(&ad->sort_list[REQ_ASYNC])); + BUG_ON(RB_EMPTY_ROOT(&ad->sort_list[REQ_ASYNC])); if (ad->batch_data_dir == REQ_SYNC) { ad->changed_batch = 1; @@ -1591,7 +1588,7 @@ static int as_set_request(request_queue_t *q, struct request *rq, if (arq) { memset(arq, 0, sizeof(*arq)); - RB_CLEAR(&arq->rb_node); + RB_CLEAR_NODE(&arq->rb_node); arq->request = rq; arq->state = AS_RQ_PRESCHED; arq->io_context = NULL; diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 940364edf2b9..e25223e147a2 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -60,11 +60,6 @@ static DEFINE_SPINLOCK(cfq_exit_lock); /* * rb-tree defines */ -#define RB_EMPTY(node) ((node)->rb_node == NULL) -#define RB_CLEAR(node) do { \ - memset(node, 0, sizeof(*node)); \ -} while (0) -#define RB_CLEAR_ROOT(root) ((root)->rb_node = NULL) #define rb_entry_crq(node) rb_entry((node), struct cfq_rq, rb_node) #define rq_rb_key(rq) (rq)->sector @@ -559,7 +554,7 @@ static inline void cfq_del_crq_rb(struct cfq_rq *crq) rb_erase(&crq->rb_node, &cfqq->sort_list); - if (cfq_cfqq_on_rr(cfqq) && RB_EMPTY(&cfqq->sort_list)) + if (cfq_cfqq_on_rr(cfqq) && RB_EMPTY_ROOT(&cfqq->sort_list)) cfq_del_cfqq_rr(cfqd, cfqq); } @@ -914,7 +909,7 @@ static int cfq_arm_slice_timer(struct cfq_data *cfqd, struct cfq_queue *cfqq) struct cfq_io_context *cic; unsigned long sl; - WARN_ON(!RB_EMPTY(&cfqq->sort_list)); + WARN_ON(!RB_EMPTY_ROOT(&cfqq->sort_list)); WARN_ON(cfqq != cfqd->active_queue); /* @@ -1042,7 +1037,7 @@ static struct cfq_queue *cfq_select_queue(struct cfq_data *cfqd) * if queue has requests, dispatch one. if not, check if * enough slice is left to wait for one */ - if (!RB_EMPTY(&cfqq->sort_list)) + if (!RB_EMPTY_ROOT(&cfqq->sort_list)) goto keep_queue; else if (cfq_cfqq_dispatched(cfqq)) { cfqq = NULL; @@ -1066,7 +1061,7 @@ __cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq, { int dispatched = 0; - BUG_ON(RB_EMPTY(&cfqq->sort_list)); + BUG_ON(RB_EMPTY_ROOT(&cfqq->sort_list)); do { struct cfq_rq *crq; @@ -1090,7 +1085,7 @@ __cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq, cfqd->active_cic = crq->io_context; } - if (RB_EMPTY(&cfqq->sort_list)) + if (RB_EMPTY_ROOT(&cfqq->sort_list)) break; } while (dispatched < max_dispatch); @@ -1480,7 +1475,6 @@ retry: INIT_HLIST_NODE(&cfqq->cfq_hash); INIT_LIST_HEAD(&cfqq->cfq_list); - RB_CLEAR_ROOT(&cfqq->sort_list); INIT_LIST_HEAD(&cfqq->fifo); cfqq->key = key; @@ -1873,7 +1867,7 @@ static void cfq_completed_request(request_queue_t *q, struct request *rq) if (cfqd->active_queue == cfqq) { if (time_after(now, cfqq->slice_end)) cfq_slice_expired(cfqd, 0); - else if (sync && RB_EMPTY(&cfqq->sort_list)) { + else if (sync && RB_EMPTY_ROOT(&cfqq->sort_list)) { if (!cfq_arm_slice_timer(cfqd, cfqq)) cfq_schedule_dispatch(cfqd); } @@ -2059,7 +2053,7 @@ cfq_set_request(request_queue_t *q, struct request *rq, struct bio *bio, crq = mempool_alloc(cfqd->crq_pool, gfp_mask); if (crq) { - RB_CLEAR(&crq->rb_node); + RB_CLEAR_NODE(&crq->rb_node); crq->rb_key = 0; crq->request = rq; INIT_HLIST_NODE(&crq->hash); @@ -2151,7 +2145,7 @@ static void cfq_idle_slice_timer(unsigned long data) /* * not expired and it has a request pending, let it dispatch */ - if (!RB_EMPTY(&cfqq->sort_list)) { + if (!RB_EMPTY_ROOT(&cfqq->sort_list)) { cfq_mark_cfqq_must_dispatch(cfqq); goto out_kick; } diff --git a/block/deadline-iosched.c b/block/deadline-iosched.c index e5bccaaed563..4469dd84623c 100644 --- a/block/deadline-iosched.c +++ b/block/deadline-iosched.c @@ -159,9 +159,6 @@ deadline_find_drq_hash(struct deadline_data *dd, sector_t offset) /* * rb tree support functions */ -#define RB_EMPTY(root) ((root)->rb_node == NULL) -#define ON_RB(node) (rb_parent(node) != node) -#define RB_CLEAR(node) (rb_set_parent(node, node)) #define rb_entry_drq(node) rb_entry((node), struct deadline_rq, rb_node) #define DRQ_RB_ROOT(dd, drq) (&(dd)->sort_list[rq_data_dir((drq)->request)]) #define rq_rb_key(rq) (rq)->sector @@ -220,9 +217,9 @@ deadline_del_drq_rb(struct deadline_data *dd, struct deadline_rq *drq) dd->next_drq[data_dir] = rb_entry_drq(rbnext); } - BUG_ON(!ON_RB(&drq->rb_node)); + BUG_ON(!RB_EMPTY_NODE(&drq->rb_node)); rb_erase(&drq->rb_node, DRQ_RB_ROOT(dd, drq)); - RB_CLEAR(&drq->rb_node); + RB_CLEAR_NODE(&drq->rb_node); } static struct request * @@ -496,7 +493,7 @@ static int deadline_dispatch_requests(request_queue_t *q, int force) */ if (reads) { - BUG_ON(RB_EMPTY(&dd->sort_list[READ])); + BUG_ON(RB_EMPTY_ROOT(&dd->sort_list[READ])); if (writes && (dd->starved++ >= dd->writes_starved)) goto dispatch_writes; @@ -512,7 +509,7 @@ static int deadline_dispatch_requests(request_queue_t *q, int force) if (writes) { dispatch_writes: - BUG_ON(RB_EMPTY(&dd->sort_list[WRITE])); + BUG_ON(RB_EMPTY_ROOT(&dd->sort_list[WRITE])); dd->starved = 0; @@ -668,7 +665,7 @@ deadline_set_request(request_queue_t *q, struct request *rq, struct bio *bio, drq = mempool_alloc(dd->drq_pool, gfp_mask); if (drq) { memset(drq, 0, sizeof(*drq)); - RB_CLEAR(&drq->rb_node); + RB_CLEAR_NODE(&drq->rb_node); drq->request = rq; INIT_HLIST_NODE(&drq->hash); diff --git a/include/linux/rbtree.h b/include/linux/rbtree.h index f37006f21664..8d5382e62c08 100644 --- a/include/linux/rbtree.h +++ b/include/linux/rbtree.h @@ -132,6 +132,10 @@ static inline void rb_set_color(struct rb_node *rb, int color) #define RB_ROOT (struct rb_root) { NULL, } #define rb_entry(ptr, type, member) container_of(ptr, type, member) +#define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL) +#define RB_EMPTY_NODE(node) (rb_parent(node) != node) +#define RB_CLEAR_NODE(node) (rb_set_parent(node, node)) + extern void rb_insert_color(struct rb_node *, struct rb_root *); extern void rb_erase(struct rb_node *, struct rb_root *); -- cgit v1.2.3